// Clone by SamE of:
// "Chat with GPT model" by Starter user
// https://ancientbrain.com/world.php?world=2850716357
// Please leave this clone trail here.
const openrouterURL = "https://openrouter.ai/api/v1/chat/completions";
const defaultModel = "openai/gpt-4o-mini";
let apikey = "";
let conversation = [];
let lastProgramCode = "";
AB.loadCSSstring (`
body {
color: white;
font-family: "Georgia", Times, serif;
margin: 0;
}
.container1 {
background-color: black;
background-image: url("/uploads/se/bg.jpg");
background-size: 100% auto;
}
.container2 {
padding: 5%;
display: grid;
max-width: 75%;
grid-template-columns: 40% 60%;
grid-template-rows: auto 630px 1fr;
grid-template-areas:
"header header"
"prompts mainout"
"textout textout";
grid-gap: 10px;
min-height: 100vh;
}
.top {
grid-area: header;
background: rgba(0,0,0,0.35);
border: 2px inset black;
padding: 15px;
border-radius: 6px;
}
.prompts {
grid-area: prompts;
display: flex;
flex-direction: column;
background: rgba(0,0,0,0.35);
border: 2px inset black;
padding: 15px;
border-radius: 6px;
height: 600px;
overflow: auto;
}
.mainout {
grid-area: mainout;
display: flex;
flex-direction: column;
background: rgba(0,0,0,0.35);
border: 2px inset black;
color: white;
padding: 15px;
border-radius: 6px;
height: 600px;
overflow: auto;
}
.textout {
grid-area: textout;
display: flex;
flex-direction: column;
background: rgba(0,0,0,0.35);
border: 2px inset black;
color: white;
padding: 15px;
border-radius: 6px;
overflow-y: auto;
}
.textbox {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
}
.textbox textarea {
flex: 1;
width: 100%;
box-sizing: border-box;
background: rgba(0,0,0,0.5);
border: 2px inset black;
color: white;
padding: 10px;
resize: none;
overflow: auto;
}
.output-box {
width: 100%;
min-height: 0;
box-sizing: border-box;
padding: 10px;
white-space: pre;
background: rgba(0,0,0,0.5);
border: 2px inset black;
overflow: auto;
}
#debugger, #them {
flex: 0 0 auto;
background: rgba(0,0,0,0.5);
border: 2px inset black;
font-family: "Lucida Console", "Courier New", monospace;
color: white;
margin-top: 10px;
}
.sandbox-frame {
flex: 1;
background: rgba(0,0,0,0.5);
border: 2px inset black;
}
.ab-normbutton {
background-image: linear-gradient(#0dccea, #0d70ea);
border: 0;
border-radius: 4px;
box-shadow: rgba(0, 0, 0, .3) 0 5px 15px;
box-sizing: border-box;
color: #fff;
cursor: pointer;
font-family: Montserrat,sans-serif;
font-size: .9em;
width: auto;
align-self: flex-start;
margin-top: 5px;
padding: 8px 14px;
text-align: center;
user-select: none;
touch-action: manipulation;
}
.ab-normbutton:hover {
background: #005fcc;
}
.apikey {
background: rgba(0,0,0,0.5);
border: 2px inset black;
color: white;
}
`);
document.write(`
<div class="container1">
<div class="container2">
<div class="top">
<h1>OpenRouter Vibecoding Assistant</h1>
<p>Describe the type of program you want in English and an AI will generate the code for you. Uses the OpenRouter API with ChatGPT 4o mini as a model.</p>
<p>Warning: This code is both generated and checked by AI and might not be fully accurate or secure. It's always better to write your own code.</p>
</div>
<div class="prompts">
<h3>Enter API key (OpenRouter only)</h3>
<div id="enterkey">
API key:
<input id="apikey" class="apikey" value="">
<button onclick="setkey();" class="ab-normbutton">Set API key</button>
</div>
<button onclick="resetConvo();" class="ab-normbutton">Reset Conversation</button>
<button class="ab-normbutton" onclick="saveProject();">Save Project</button>
<button class="ab-normbutton" onclick="loadProject();">Load Project</button>
<input type="file" id="fileLoader" style="display:none;" accept=".json">
<h3>Prompt Templates</h3>
<p>Don't know where to start? Use one of these templates to get started!</p>
<button class="ab-normbutton" onclick="insertTemplate('Draw a bouncing ball animation.')">Bouncing Ball</button>
<button class="ab-normbutton" onclick="insertTemplate('Create a particle explosion effect.')">Particle Explosion</button>
<button class="ab-normbutton" onclick="insertTemplate('Make a keyboard-controlled square that moves.')">Keyboard Control</button>
<div class="textbox">
<h3>Describe what you want the program to do</h3>
<textarea id=me>Draw a bouncing ball in JavaScript.</textarea>
<button onclick="sendchat();" class="ab-normbutton">Generate / Update Program</button>
</div>
</div>
<div class="textout">
<h3>AI Response (Code Only Expected)</h3>
<div id="them" class="output-box" style=""></div>
<button onclick="checkCode();" class="ab-normbutton">
Check Code for Bugs
</button>
<h3>Debugger Output</h3>
<div id="debugger" class="output-box"></div>
</div>
<div class="mainout">
<h3>Program Output</h3>
<iframe id="sandbox" class="sandbox-frame"></iframe>
</div>
</div>
</div>
`);
// BASIC HELPERS
function setkey() {
apikey = $("#apikey").val().trim();
$("#enterkey").html("<b>API key has been set.</b>");
}
function insertTemplate(text) {
$("#me").val(text);
}
function resetConvo() {
conversation = [];
$("#them").text("");
$("#debugger").text("");
const iframe = document.getElementById("sandbox");
const newIframe = iframe.cloneNode(false);
iframe.parentNode.replaceChild(newIframe, iframe);
alert("Conversation reset.");
}
function compressConversation() {
if (conversation.length > 10) {
conversation = conversation.slice(-10);
}
}
// SYSTEM PROMPT
const systemPrompt = {
role: "system",
content: `
You are an AI that outputs ONLY valid JavaScript code for execution inside a browser iframe.
STRICT RULES:
- Output ONLY runnable JavaScript. No explanation. No markdown. No backticks.
- The code must be a FULL program that runs immediately.
- Include everything needed (canvas, animation loop, variables, events).
- Do NOT wait for DOMContentLoaded — the script is executed directly.
- No external files, no imports, no modules.
- Rebuild full code from scratch on each message.
- Do NOT produce HTML tags (canvas must be created through JS).
`
};
// SEND CHAT TO API
function sendchat() {
if (!apikey) {
$("#them").html("<font color='red'><b>Enter API key first.</b></font>");
return;
}
$("#them").html("<i>Generating code...</i>");
const userText = $("#me").val();
conversation.push({ role: "user", content: userText });
compressConversation();
const payload = {
model: defaultModel,
messages: [systemPrompt, ...conversation]
};
$.ajaxSetup({
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + apikey,
"HTTP-Referer": "https://ancientbrain.com",
"X-Title": "Vibe Coding World"
}
});
$.ajax({
type: "POST",
url: openrouterURL,
data: JSON.stringify(payload),
dataType: "json",
success: function (data) {
const code = data?.choices?.[0]?.message?.content || "";
$("#them").text(code);
lastProgramCode = code;
runInSandbox(code);
},
error: function (xhr) {
$("#them").html("<font color='red'><b>Error:</b></font> " + xhr.responseText);
}
});
}
// RUN CODE SAFELY IN IFRAME
function runInSandbox(code) {
const iframe = document.getElementById("sandbox");
const newIframe = iframe.cloneNode(false);
iframe.parentNode.replaceChild(newIframe, iframe);
const iframeDoc = newIframe.contentDocument || newIframe.contentWindow.document;
iframeDoc.open();
iframeDoc.write(`<!DOCTYPE html><html><head><meta charset="UTF-8"></head><body></body></html>`);
iframeDoc.close();
const script = iframeDoc.createElement("script");
script.type = "text/javascript";
script.textContent = `
try {
${code}
} catch (e) {
parent.document.getElementById("debugger").textContent =
"Execution error: " + e.message;
}
`;
iframeDoc.body.appendChild(script);
newIframe.contentWindow.onerror = function(msg, url, line, col, err) {
$("#debugger").text("Runtime error: " + msg + " at line " + line);
};
}
// DEBUGGER AI
function checkCode() {
if (!apikey) {
$("#debugger").html("<font color='red'><b>Enter API key first.</b></font>");
return;
}
if (!lastProgramCode) {
$("#debugger").html("<font color='red'><b>No code has been generated yet.</b></font>");
return;
}
$("#debugger").html("<i>Checking code for bugs...</i>");
const debugPrompt = [
{
role: "system",
content: `
You are a strict JavaScript code auditor.
List any possible errors, logic bugs, DOM issues, infinite loops, or unsafe patterns.
Do NOT rewrite code. Do NOT fix code. Plain text numbered list only with white space between every element on the list.
`
},
{ role: "user", content: lastProgramCode }
];
const payload = {
model: defaultModel,
messages: debugPrompt
};
$.ajaxSetup({
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + apikey,
"HTTP-Referer": "https://ancientbrain.com",
"X-Title": "Vibe Coding World Debugger"
}
});
$.ajax({
type: "POST",
url: openrouterURL,
data: JSON.stringify(payload),
dataType: "json",
success: function (data) {
const reply = data?.choices?.[0]?.message?.content || "(no reply)";
$("#debugger").text(reply);
},
error: function (xhr) {
$("#debugger").html("<font color='red'><b>Error:</b></font> " + xhr.responseText);
}
});
}
// SAVE / LOAD CODE
function saveProject() {
if (!lastProgramCode) {
alert("No code generated yet.");
return;
}
const data = { code: lastProgramCode };
const json = JSON.stringify(data, null, 2);
const blob = new Blob([json], { type: "application/json" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "vibe_code_" + Date.now() + ".json";
a.click();
URL.revokeObjectURL(url);
alert("Code downloaded to your computer.");
}
function loadProject() {
document.getElementById("fileLoader").click();
}
document.getElementById("fileLoader").addEventListener("change", function (evt) {
const file = evt.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
let loadedData;
try {
loadedData = JSON.parse(e.target.result);
} catch (err) {
alert("Invalid JSON.");
return;
}
if (!loadedData.code) {
alert("File does not contain valid code.");
return;
}
lastProgramCode = loadedData.code;
$("#them").text(lastProgramCode);
runInSandbox(lastProgramCode);
alert("Code loaded successfully.");
};
reader.readAsText(file);
});