GPT-6 Luna
by OpenAIReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 37.4 s
- Cost
- $0.0030
- Output tokens
- 5,810
- Spent thinking
- 0 tokens
- Speed
- 162.8 tok/s
- Console errors
- 0
- First token after
- 1.7 s
- First visible text after
- 1.7 s
- Prompt tokens
- 493
- Code size
- 18.3 KB
- Finish reason
- stop
- Served by
- OpenAI
- Model id
openai/gpt-6-luna- Reasoning sent
{"effort":"none"}- Max output
- 64,000 tokens
- Generated
- Nov 10, 2026
What it was asked
The prompt
Build an interactive Kanban board in vanilla HTML, CSS and JavaScript (no framework, no library). Requirements: - Three columns: "To do", "In progress", "Done", each showing its card count. - Pre-populate the board with 6 realistic cards spread across the columns so the first screenshot looks alive. - Each card has a title and a priority (low / medium / high) shown as a colored badge. - Add a card through a small modal form (title required), and delete a card with a button on it. - Drag and drop cards between columns with the mouse, with a clear visual drop indicator. - A search field that filters cards live by title. - A light / dark theme toggle. - State lives in memory only (no storage APIs).
System prompt, sent with every prompt
You are generating a self-contained web demo. It will be rendered automatically in a sandboxed iframe and compared side by side with the output of other AI models given the exact same task. Output rules: - Reply with exactly ONE fenced code block containing the complete file: ```html (or ```svg when the task asks for an SVG). No text before or after the code block. - Everything must be inline: CSS in <style>, JavaScript in <script>. No external files, images, fonts or network requests, except the CDN URLs explicitly allowed by the task. - Do not use localStorage, sessionStorage, cookies, IndexedDB, alert(), confirm(), prompt() or window.open(): they are blocked in the sandbox and will throw. - The page must look right in a 1280×800 viewport and adapt gracefully down to 375px wide. No horizontal scrollbar. - Something meaningful must be visible on first paint: a screenshot is taken automatically about 3 seconds after load, without any interaction. - Everything that makes the demo interesting must be visible within the first seconds: nothing hidden behind a high score, a later level or a long play session. - Games must start in a self-playing demo mode (a simple AI plays) behind a "Click or press a key to start" message, so the game can be judged in action without playing. - The iframe only receives keyboard events after the user clicks it: if the demo uses the keyboard, display a clear "Click or press a key to start" message. - The code must run with zero errors in the console of the latest Chrome.
Code run-1.html · 395 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kanban — Project workspace</title>
<style>
:root {
color-scheme: light;
--bg: #f5f6f8;
--surface: #fff;
--surface-2: #fafbfc;
--text: #20232b;
--muted: #818796;
--line: #e8eaf0;
--accent: #6758e8;
--accent-soft: #efedff;
--shadow: 0 10px 30px rgba(28, 31, 48, .07);
--high: #e45b63;
--medium: #d58b21;
--low: #359875;
}
body.dark {
color-scheme: dark;
--bg: #171922;
--surface: #20232e;
--surface-2: #252936;
--text: #eef0f7;
--muted: #9a9fb0;
--line: #343847;
--accent: #9c91ff;
--accent-soft: #35304f;
--shadow: 0 10px 30px rgba(0, 0, 0, .24);
--high: #ff858b;
--medium: #f3ba63;
--low: #6dd2aa;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
background: var(--bg);
color: var(--text);
font: 14px/1.45 Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
transition: background .2s, color .2s;
}
button, input, select { font: inherit; }
button { color: inherit; }
.app { max-width: 1220px; margin: auto; padding: 0 40px 42px; }
header {
height: 78px;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid var(--line);
}
.brand { display: flex; align-items: center; gap: 11px; font-size: 15px; font-weight: 750; letter-spacing: -.3px; }
.brand-mark {
width: 31px; height: 31px; border-radius: 10px; display: grid; place-items: center;
color: white; background: var(--accent); font-weight: 800; font-size: 17px;
box-shadow: 0 5px 12px color-mix(in srgb, var(--accent), transparent 70%);
}
.header-actions { display: flex; align-items: center; gap: 11px; }
.icon-btn, .secondary-btn, .primary-btn {
border: 1px solid var(--line); background: var(--surface); cursor: pointer; transition: .16s ease;
}
.icon-btn {
width: 38px; height: 38px; border-radius: 11px; display: grid; place-items: center;
color: var(--muted);
}
.icon-btn:hover, .secondary-btn:hover { border-color: var(--accent); color: var(--accent); }
.primary-btn {
border: 0; background: var(--accent); color: white; font-weight: 650;
height: 39px; padding: 0 15px; border-radius: 10px; box-shadow: 0 5px 12px color-mix(in srgb, var(--accent), transparent 80%);
}
.primary-btn:hover { filter: brightness(1.07); transform: translateY(-1px); }
.plus { font-size: 19px; vertical-align: -1px; margin-right: 5px; }
main { padding-top: 34px; }
.topline { display: flex; justify-content: space-between; align-items: flex-end; gap: 20px; }
h1 { margin: 0; font-size: 27px; letter-spacing: -.8px; line-height: 1.2; }
.subtitle { margin-top: 7px; color: var(--muted); font-size: 13px; }
.toolbar { display: flex; align-items: center; gap: 10px; }
.search { position: relative; }
.search svg { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--muted); }
.search input {
width: 220px; height: 39px; padding: 0 12px 0 37px; border: 1px solid var(--line);
border-radius: 10px; outline: none; color: var(--text); background: var(--surface);
}
.search input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent), transparent 87%); }
.board { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 19px; margin-top: 29px; align-items: start; }
.column {
padding: 14px; background: color-mix(in srgb, var(--surface-2), transparent 12%);
border: 1px solid var(--line); border-radius: 14px; min-height: 425px;
transition: border-color .18s, background .18s, box-shadow .18s;
}
.column.drop-target {
border-color: var(--accent); background: color-mix(in srgb, var(--accent-soft), var(--surface) 35%);
box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent), transparent 78%);
}
.column-head { height: 34px; display: flex; justify-content: space-between; align-items: center; margin: 0 1px 12px; }
.column-name { display: flex; align-items: center; gap: 9px; font-weight: 700; font-size: 13px; letter-spacing: .05px; }
.dot { width: 8px; height: 8px; border-radius: 50%; background: #8d92a1; }
.todo .dot { background: #a0a5b3; }
.progress .dot { background: #7063e8; }
.done .dot { background: #3bb187; }
.count { min-width: 23px; height: 22px; padding: 0 6px; display: grid; place-items: center; border-radius: 7px; background: var(--surface); color: var(--muted); font-size: 11px; font-weight: 700; border: 1px solid var(--line); }
.cards { min-height: 350px; }
.card {
background: var(--surface); border: 1px solid var(--line); border-radius: 11px; padding: 14px;
margin-bottom: 10px; box-shadow: 0 2px 5px rgba(22, 27, 45, .025); cursor: grab;
transition: transform .15s, border-color .15s, box-shadow .15s, opacity .15s;
}
.card:hover { transform: translateY(-2px); box-shadow: var(--shadow); border-color: color-mix(in srgb, var(--accent), var(--line) 58%); }
.card.dragging { opacity: .38; transform: rotate(-1deg); }
.card-title { margin: 0 0 14px; font-size: 13px; line-height: 1.5; font-weight: 650; letter-spacing: -.12px; padding-right: 5px; }
.card-bottom { display: flex; justify-content: space-between; align-items: center; }
.badge { border-radius: 6px; padding: 3px 8px; font-size: 10px; font-weight: 700; letter-spacing: .15px; text-transform: capitalize; }
.badge.high { color: var(--high); background: color-mix(in srgb, var(--high), transparent 89%); }
.badge.medium { color: var(--medium); background: color-mix(in srgb, var(--medium), transparent 88%); }
.badge.low { color: var(--low); background: color-mix(in srgb, var(--low), transparent 88%); }
.card-actions { display: flex; align-items: center; gap: 8px; }
.avatar {
display: grid; place-items: center; width: 23px; height: 23px; border-radius: 50%;
color: #6458b9; background: #eeecff; font-size: 9px; font-weight: 750;
}
body.dark .avatar { background: #393454; color: #c2baff; }
.delete-btn {
border: 0; padding: 3px; line-height: 0; color: #a5a9b4; background: transparent;
cursor: pointer; opacity: 0; transition: .15s;
}
.card:hover .delete-btn, .delete-btn:focus { opacity: 1; }
.delete-btn:hover { color: var(--high); }
.empty {
color: var(--muted); font-size: 12px; text-align: center; padding: 28px 8px;
border: 1px dashed var(--line); border-radius: 9px; margin-top: 4px;
}
.board-note { display: flex; align-items: center; gap: 7px; margin-top: 17px; color: var(--muted); font-size: 11px; }
.board-note svg { color: var(--accent); }
.modal-backdrop {
display: none; position: fixed; inset: 0; z-index: 5; background: rgba(14, 17, 28, .44);
align-items: center; justify-content: center; padding: 18px;
}
.modal-backdrop.open { display: flex; }
.modal {
width: min(100%, 420px); background: var(--surface); border: 1px solid var(--line);
border-radius: 16px; padding: 23px; box-shadow: 0 24px 70px rgba(0,0,0,.22);
animation: rise .18s ease-out;
}
@keyframes rise { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }
.modal-top { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 20px; }
.modal h2 { margin: 0; font-size: 19px; letter-spacing: -.4px; }
.modal-copy { margin-top: 5px; color: var(--muted); font-size: 12px; }
.close-btn { border: 0; background: transparent; color: var(--muted); padding: 3px; cursor: pointer; font-size: 20px; line-height: 1; }
label { display: block; margin-bottom: 7px; font-size: 12px; font-weight: 650; }
.field { margin-bottom: 17px; }
.field input, .field select {
width: 100%; height: 41px; border: 1px solid var(--line); border-radius: 9px;
background: var(--surface-2); color: var(--text); padding: 0 11px; outline: none;
}
.field input:focus, .field select:focus { border-color: var(--accent); }
.modal-footer { display: flex; justify-content: flex-end; gap: 8px; margin-top: 21px; }
.secondary-btn { height: 38px; border-radius: 9px; padding: 0 13px; font-weight: 600; }
.modal .primary-btn { height: 38px; }
@media (max-width: 760px) {
.app { padding: 0 20px 30px; }
.board { gap: 12px; }
.column { padding: 10px; }
.card { padding: 11px; }
.search input { width: 190px; }
}
@media (max-width: 560px) {
header { height: 66px; }
.app { padding: 0 15px 26px; }
.brand { font-size: 14px; }
.header-actions { gap: 7px; }
.primary-btn { padding: 0 11px; }
main { padding-top: 25px; }
.topline { align-items: flex-start; flex-direction: column; gap: 16px; }
h1 { font-size: 24px; }
.toolbar { width: 100%; }
.search { flex: 1; }
.search input { width: 100%; }
.board { grid-template-columns: 1fr; margin-top: 20px; gap: 12px; }
.column { min-height: 0; padding: 12px; }
.cards { min-height: 30px; }
.card { padding: 13px; }
.delete-btn { opacity: .7; }
.board-note { margin-top: 13px; }
}
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; } }
</style>
</head>
<body>
<div class="app">
<header>
<div class="brand"><span class="brand-mark">K</span> Orbit workspace</div>
<div class="header-actions">
<button class="icon-btn" id="themeToggle" aria-label="Toggle light or dark theme" title="Toggle theme">
<svg id="themeIcon" width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M4.93 4.93l1.42 1.42m11.3 11.3 1.42 1.42M2 12h2m16 0h2M4.93 19.07l1.42-1.42m11.3-11.3 1.42-1.42"/></svg>
</button>
<button class="primary-btn" id="openModal"><span class="plus">+</span>Add card</button>
</div>
</header>
<main>
<div class="topline">
<div>
<h1>Project board</h1>
<div class="subtitle">Plan, track, and move work forward.</div>
</div>
<div class="toolbar">
<div class="search">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="11" cy="11" r="7"/><path d="m20 20-4-4"/></svg>
<input id="searchInput" type="search" placeholder="Search cards..." aria-label="Search cards">
</div>
</div>
</div>
<section class="board" aria-label="Kanban board">
<div class="column todo" data-status="todo">
<div class="column-head"><div class="column-name"><span class="dot"></span>To do</div><span class="count">0</span></div>
<div class="cards"></div>
</div>
<div class="column progress" data-status="progress">
<div class="column-head"><div class="column-name"><span class="dot"></span>In progress</div><span class="count">0</span></div>
<div class="cards"></div>
</div>
<div class="column done" data-status="done">
<div class="column-head"><div class="dot"></span>Done</div><span class="count">0</span></div>
<div class="cards"></div>
</div>
</section>
<div class="board-note">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v12m0 0 4-4m-4 4-4-4"/><path d="M5 17v3h14v-3"/></svg>
Drag cards between columns to update their status
</div>
</main>
</div>
<div class="modal-backdrop" id="modalBackdrop" role="dialog" aria-modal="true" aria-labelledby="modalTitle">
<form class="modal" id="cardForm">
<div class="modal-top">
<div><h2 id="modalTitle">Add a card</h2><div class="modal-copy">Add a task to your project board.</div></div>
<button type="button" class="close-btn" id="closeModal" aria-label="Close">×</button>
</div>
<div class="field">
<label for="cardTitle">Title</label>
<input id="cardTitle" maxlength="100" placeholder="What needs to get done?" required>
</div>
<div class="field">
<label for="cardPriority">Priority</label>
<select id="cardPriority"><option value="low">Low</option><option value="medium" selected>Medium</option><option value="high">High</option></select>
</div>
<div class="field">
<label for="cardStatus">Column</label>
<select id="cardStatus"><option value="todo">To do</option><option value="progress">In progress</option><option value="done">Done</option></select>
</div>
<div class="modal-footer">
<button type="button" class="secondary-btn" id="cancelModal">Cancel</button>
<button type="submit" class="primary-btn">Create card</button>
</div>
</form>
</div>
<script>
(() => {
let cards = [
{ id: 1, title: "Review Q3 product roadmap", priority: "high", status: "todo", initials: "AM" },
{ id: 2, title: "Gather customer feedback for onboarding", priority: "medium", status: "todo", initials: "JL" },
{ id: 3, title: "Prepare launch announcement copy", priority: "low", status: "todo", initials: "SK" },
{ id: 4, title: "Build analytics dashboard wireframes", priority: "high", status: "progress", initials: "AM" },
{ id: 5, title: "Update API documentation", priority: "medium", status: "progress", initials: "JL" },
{ id: 6, title: "Set up team project workspace", priority: "low", status: "done", initials: "SK" }
];
const board = document.querySelector(".board");
const searchInput = document.getElementById("searchInput");
const backdrop = document.getElementById("modalBackdrop");
const form = document.getElementById("cardForm");
const titleInput = document.getElementById("cardTitle");
let draggedId = null;
let nextId = 7;
function render() {
const query = searchInput.value.trim().toLowerCase();
document.querySelectorAll(".column").forEach(column => {
const status = column.dataset.status;
const list = column.querySelector(".cards");
const matching = cards.filter(card => card.status === status && card.title.toLowerCase().includes(query));
column.querySelector(".count").textContent = cards.filter(card => card.status === status).length;
list.innerHTML = "";
if (!matching.length && query) {
const empty = document.createElement("div");
empty.className = "empty";
empty.textContent = "No matching cards";
list.appendChild(empty);
}
matching.forEach(card => {
const item = document.createElement("article");
item.className = "card";
item.draggable = true;
item.dataset.id = card.id;
item.innerHTML = `<p class="card-title"></p>
<div class="card-bottom">
<span class="badge ${card.priority}">${card.priority}</span>
<div class="card-actions"><span class="avatar" aria-label="Assignee">${card.initials || "ME"}</span>
<button class="delete-btn" aria-label="Delete card" title="Delete card">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18M8 6V4h8v2m3 0-.8 14H5.8L5 6m4 4v6m6-6v6"/></svg>
</button></div>
</div>`;
item.querySelector(".card-title").textContent = card.title;
list.appendChild(item);
});
});
}
board.addEventListener("click", event => {
const button = event.target.closest(".delete-btn");
if (!button) return;
const card = button.closest(".card");
cards = cards.filter(item => item.id !== Number(card.dataset.id));
render();
});
board.addEventListener("dragstart", event => {
const card = event.target.closest(".card");
if (!card) return;
draggedId = Number(card.dataset.id);
card.classList.add("dragging");
event.dataTransfer.effectAllowed = "move";
event.dataTransfer.setData("text/plain", String(draggedId));
});
board.addEventListener("dragend", event => {
const card = event.target.closest(".card");
if (card) card.classList.remove("dragging");
document.querySelectorAll(".drop-target").forEach(el => el.classList.remove("drop-target"));
draggedId = null;
});
document.querySelectorAll(".column").forEach(column => {
column.addEventListener("dragover", event => {
event.preventDefault();
event.dataTransfer.dropEffect = "move";
column.classList.add("drop-target");
});
column.addEventListener("dragleave", event => {
if (!column.contains(event.relatedTarget)) column.classList.remove("drop-target");
});
column.addEventListener("drop", event => {
event.preventDefault();
column.classList.remove("drop-target");
const id = Number(event.dataTransfer.getData("text/plain")) || draggedId;
const card = cards.find(item => item.id === id);
if (card) { card.status = column.dataset.status; render(); }
});
});
searchInput.addEventListener("input", render);
const openModal = () => {
backdrop.classList.add("open");
titleInput.focus();
};
const closeModal = () => {
backdrop.classList.remove("open");
form.reset();
};
document.getElementById("openModal").addEventListener("click", openModal);
document.getElementById("closeModal").addEventListener("click", closeModal);
document.getElementById("cancelModal").addEventListener("click", closeModal);
backdrop.addEventListener("click", event => { if (event.target === backdrop) closeModal(); });
document.addEventListener("keydown", event => { if (event.key === "Escape") closeModal(); });
form.addEventListener("submit", event => {
event.preventDefault();
const title = titleInput.value.trim();
if (!title) { titleInput.focus(); return; }
cards.push({
id: nextId++,
title,
priority: document.getElementById("cardPriority").value,
status: document.getElementById("cardStatus").value,
initials: "ME"
});
render();
closeModal();
});
const themeToggle = document.getElementById("themeToggle");
themeToggle.addEventListener("click", () => {
const dark = document.body.classList.toggle("dark");
document.getElementById("themeIcon").innerHTML = dark
? '<path d="M20.4 15.2A8.5 8.5 0 0 1 8.8 3.6 8.6 8.6 0 1 0 20.4 15.2Z"/>'
: '<circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M4.93 4.93l1.42 1.42m11.3 11.3 1.42 1.42M2 12h2m16 0h2M4.93 19.07l1.42-1.42m11.3-11.3 1.42-1.42"/>';
});
render();
})();
</script>
</body>
</html>