Claude Haiku 5.5
by AnthropicReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 20.4 s
- Cost
- $0.0032
- Output tokens
- 6,169
- Spent thinking
- 0 tokens
- Speed
- 329.6 tok/s
- Console errors
- 0
- First token after
- 1.7 s
- First visible text after
- 1.7 s
- Prompt tokens
- 744
- Code size
- 14.7 KB
- Finish reason
- stop
- Served by
- Claude Platform on AWS
- Model id
anthropic/claude-haiku-5.5- Reasoning sent
{"effort":"none"}- Max output
- 32,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 · 502 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kanban Board</title>
<style>
:root {
--bg: #f3f4f7;
--surface: #ffffff;
--column: #e9ecf2;
--text: #1f2330;
--muted: #6b7280;
--border: #d9dde6;
--accent: #4f46e5;
--accent-text: #ffffff;
--drop: #818cf8;
--low: #16a34a;
--medium: #d97706;
--high: #dc2626;
--shadow: 0 1px 2px rgba(0,0,0,.08);
}
[data-theme="dark"] {
--bg: #0f1117;
--surface: #1a1d27;
--column: #161922;
--text: #e6e8ef;
--muted: #9aa3b5;
--border: #2a2f3d;
--accent: #6366f1;
--accent-text: #ffffff;
--drop: #818cf8;
--shadow: 0 1px 2px rgba(0,0,0,.5);
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
background: var(--bg);
color: var(--text);
overflow-x: hidden;
transition: background .2s, color .2s;
}
header {
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: center;
justify-content: space-between;
padding: 16px 24px;
background: var(--surface);
border-bottom: 1px solid var(--border);
}
header h1 { margin: 0; font-size: 20px; font-weight: 700; }
.controls { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
input[type="search"], input[type="text"], select {
font: inherit;
padding: 8px 12px;
border-radius: 8px;
border: 1px solid var(--border);
background: var(--bg);
color: var(--text);
outline: none;
min-width: 0;
}
input:focus, select:focus { border-color: var(--accent); }
.btn {
font: inherit;
padding: 8px 14px;
border-radius: 8px;
border: 1px solid var(--border);
background: var(--surface);
color: var(--text);
cursor: pointer;
white-space: nowrap;
}
.btn:hover { border-color: var(--accent); }
.btn.primary { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
.btn.primary:hover { filter: brightness(1.08); }
main {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
padding: 20px 24px;
align-items: start;
}
.column {
background: var(--column);
border-radius: 12px;
padding: 12px;
min-height: 420px;
border: 2px solid transparent;
transition: border-color .15s, background .15s;
}
.column.drag-over { border-color: var(--drop); }
.col-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 4px 6px 12px;
font-weight: 600;
font-size: 14px;
text-transform: uppercase;
letter-spacing: .04em;
color: var(--muted);
}
.count {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 999px;
padding: 2px 9px;
font-size: 12px;
color: var(--text);
}
.cards { display: flex; flex-direction: column; gap: 4px; min-height: 60px; }
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 10px;
padding: 12px;
box-shadow: var(--shadow);
cursor: grab;
user-select: none;
position: relative;
}
.card:active { cursor: grabbing; }
.card.dragging { opacity: .4; }
.card-title { font-size: 15px; font-weight: 500; margin: 0 0 10px; word-break: break-word; }
.card-footer { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.badge {
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: .05em;
padding: 3px 8px;
border-radius: 999px;
color: #fff;
}
.badge.low { background: var(--low); }
.badge.medium { background: var(--medium); }
.badge.high { background: var(--high); }
.del {
background: none;
border: none;
color: var(--muted);
cursor: pointer;
font-size: 13px;
padding: 2px 6px;
border-radius: 6px;
}
.del:hover { color: var(--high); background: rgba(220,38,38,.1); }
.drop-indicator {
height: 4px;
border-radius: 4px;
background: var(--drop);
margin: 2px 0;
box-shadow: 0 0 0 2px rgba(129,140,248,.25);
}
.empty {
text-align: center;
color: var(--muted);
font-size: 13px;
padding: 24px 8px;
border: 1px dashed var(--border);
border-radius: 10px;
}
.card.hidden { display: none; }
/* Modal */
.overlay {
position: fixed; inset: 0;
background: rgba(0,0,0,.45);
display: none;
align-items: center;
justify-content: center;
padding: 16px;
z-index: 10;
}
.overlay.open { display: flex; }
.modal {
background: var(--surface);
color: var(--text);
border-radius: 14px;
padding: 22px;
width: 100%;
max-width: 380px;
border: 1px solid var(--border);
box-shadow: 0 10px 30px rgba(0,0,0,.25);
}
.modal h2 { margin: 0 0 16px; font-size: 18px; }
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.field label { font-size: 13px; color: var(--muted); }
.field input, .field select { width: 100%; }
.field .error { color: var(--high); font-size: 12px; min-height: 14px; }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; }
@media (max-width: 900px) {
main { grid-template-columns: 1fr; }
.column { min-height: auto; }
}
@media (max-width: 480px) {
header, main { padding-left: 12px; padding-right: 12px; }
.controls { width: 100%; }
.controls input[type="search"] { flex: 1 1 100%; }
}
</style>
</head>
<body>
<header>
<h1>Kanban Board</h1>
<div class="controls">
<input type="search" id="search" placeholder="Search cards…" aria-label="Search cards">
<button class="btn primary" id="addBtn">+ New card</button>
<button class="btn" id="themeBtn" aria-label="Toggle theme">🌙 Dark</button>
</div>
</header>
<main id="board"></main>
<div class="overlay" id="overlay">
<form class="modal" id="cardForm" novalidate>
<h2>New card</h2>
<div class="field">
<label for="titleInput">Title</label>
<input type="text" id="titleInput" maxlength="120" placeholder="e.g. Write release notes">
<div class="error" id="titleError"></div>
</div>
<div class="field">
<label for="prioInput">Priority</label>
<select id="prioInput">
<option value="low">Low</option>
<option value="medium" selected>Medium</option>
<option value="high">High</option>
</select>
</div>
<div class="field">
<label for="colInput">Column</label>
<select id="colInput">
<option value="todo">To do</option>
<option value="progress">In progress</option>
<option value="done">Done</option>
</select>
</div>
<div class="modal-actions">
<button type="button" class="btn" id="cancelBtn">Cancel</button>
<button type="submit" class="btn primary">Add card</button>
</div>
</form>
</div>
<script>
(function () {
'use strict';
const COLUMNS = [
{ id: 'todo', name: 'To do' },
{ id: 'progress', name: 'In progress' },
{ id: 'done', name: 'Done' }
];
let nextId = 1;
let state = [];
let dragId = null;
let dropIndicator = null;
function makeCard(title, priority, column) {
return { id: nextId++, title, priority, column };
}
function seed() {
state = [
makeCard('Design onboarding flow', 'high', 'todo'),
makeCard('Set up CI pipeline', 'medium', 'todo'),
makeCard('Write API documentation', 'low', 'todo'),
makeCard('Implement login with OAuth', 'high', 'progress'),
makeCard('Refactor settings page', 'medium', 'progress'),
makeCard('Fix mobile nav overlap', 'low', 'done')
];
}
const board = document.getElementById('board');
const search = document.getElementById('search');
function render() {
const q = search.value.trim().toLowerCase();
board.innerHTML = '';
COLUMNS.forEach(col => {
const cards = state.filter(c => c.column === col.id);
const visibleCount = q ? cards.filter(c => c.title.toLowerCase().includes(q)).length : cards.length;
const colEl = document.createElement('section');
colEl.className = 'column';
colEl.dataset.column = col.id;
const header = document.createElement('div');
header.className = 'col-header';
header.innerHTML = `<span>${col.name}</span><span class="count">${cards.length}</span>`;
colEl.appendChild(header);
const list = document.createElement('div');
list.className = 'cards';
list.dataset.column = col.id;
cards.forEach(c => list.appendChild(buildCard(c, q)));
if (cards.length === 0) {
const e = document.createElement('div');
e.className = 'empty';
e.textContent = 'Drop cards here';
list.appendChild(e);
} else if (q && visibleCount === 0) {
const e = document.createElement('div');
e.className = 'empty';
e.textContent = 'No matches';
list.appendChild(e);
}
colEl.appendChild(list);
attachColumnDnD(colEl, list, col.id);
board.appendChild(colEl);
});
}
function buildCard(c, q) {
const el = document.createElement('div');
el.className = 'card';
el.draggable = true;
el.dataset.id = c.id;
if (q && !c.title.toLowerCase().includes(q)) el.classList.add('hidden');
const title = document.createElement('p');
title.className = 'card-title';
title.textContent = c.title;
const footer = document.createElement('div');
footer.className = 'card-footer';
const badge = document.createElement('span');
badge.className = 'badge ' + c.priority;
badge.textContent = c.priority;
const del = document.createElement('button');
del.className = 'del';
del.type = 'button';
del.title = 'Delete card';
del.setAttribute('aria-label', 'Delete card');
del.textContent = '✕ Delete';
del.addEventListener('click', e => {
e.stopPropagation();
state = state.filter(x => x.id !== c.id);
render();
});
footer.append(badge, del);
el.append(title, footer);
el.addEventListener('dragstart', e => {
dragId = c.id;
el.classList.add('dragging');
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/plain', String(c.id));
});
el.addEventListener('dragend', () => {
dragId = null;
el.classList.remove('dragging');
clearIndicator();
document.querySelectorAll('.column.drag-over').forEach(n => n.classList.remove('drag-over'));
});
return el;
}
function attachColumnDnD(colEl, list, colId) {
colEl.addEventListener('dragover', e => {
if (dragId === null) return;
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
colEl.classList.add('drag-over');
placeIndicator(list, e.clientY);
});
colEl.addEventListener('dragleave', e => {
if (!colEl.contains(e.relatedTarget)) {
colEl.classList.remove('drag-over');
clearIndicator();
}
});
colEl.addEventListener('drop', e => {
e.preventDefault();
if (dragId === null) return;
const card = state.find(c => c.id === dragId);
if (!card) return;
const cardsInCol = [...list.querySelectorAll('.card:not(.dragging)')];
let insertBefore = null;
if (dropIndicator && dropIndicator.nextElementSibling && dropIndicator.nextElementSibling.classList.contains('card')) {
insertBefore = Number(dropIndicator.nextElementSibling.dataset.id);
}
// Remove card from state, then reinsert at the right position in its target column.
const fromIdx = state.indexOf(card);
state.splice(fromIdx, 1);
card.column = colId;
if (insertBefore !== null) {
const idx = state.findIndex(c => c.id === insertBefore);
state.splice(idx, 0, card);
} else {
// Append after the last card of the target column.
let lastIdx = -1;
state.forEach((c, i) => { if (c.column === colId) lastIdx = i; });
state.splice(lastIdx + 1, 0, card);
}
clearIndicator();
dragId = null;
render();
});
}
function placeIndicator(list, y) {
const cards = [...list.querySelectorAll('.card:not(.dragging)')];
let before = null;
for (const c of cards) {
const r = c.getBoundingClientRect();
if (y < r.top + r.height / 2) { before = c; break; }
}
if (!dropIndicator) {
dropIndicator = document.createElement('div');
dropIndicator.className = 'drop-indicator';
}
if (before) {
if (dropIndicator.nextElementSibling !== before) list.insertBefore(dropIndicator, before);
} else {
const empty = list.querySelector('.empty');
if (empty) { list.insertBefore(dropIndicator, empty); }
else if (list.lastElementChild !== dropIndicator) list.appendChild(dropIndicator);
}
}
function clearIndicator() {
if (dropIndicator && dropIndicator.parentNode) dropIndicator.parentNode.removeChild(dropIndicator);
dropIndicator = null;
}
// Search
search.addEventListener('input', render);
// Theme
const themeBtn = document.getElementById('themeBtn');
themeBtn.addEventListener('click', () => {
const dark = document.documentElement.getAttribute('data-theme') === 'dark';
if (dark) {
document.documentElement.removeAttribute('data-theme');
themeBtn.textContent = '🌙 Dark';
} else {
document.documentElement.setAttribute('data-theme', 'dark');
themeBtn.textContent = '☀️ Light';
}
});
// Modal
const overlay = document.getElementById('overlay');
const form = document.getElementById('cardForm');
const titleInput = document.getElementById('titleInput');
const titleError = document.getElementById('titleError');
const prioInput = document.getElementById('prioInput');
const colInput = document.getElementById('colInput');
function openModal() {
form.reset();
titleError.textContent = '';
overlay.classList.add('open');
setTimeout(() => titleInput.focus(), 0);
}
function closeModal() { overlay.classList.remove('open'); }
document.getElementById('addBtn').addEventListener('click', openModal);
document.getElementById('cancelBtn').addEventListener('click', closeModal);
overlay.addEventListener('click', e => { if (e.target === overlay) closeModal(); });
document.addEventListener('keydown', e => { if (e.key === 'Escape' && overlay.classList.contains('open')) closeModal(); });
form.addEventListener('submit', e => {
e.preventDefault();
const title = titleInput.value.trim();
if (!title) {
titleError.textContent = 'Title is required.';
titleInput.focus();
return;
}
state.push(makeCard(title, prioInput.value, colInput.value));
closeModal();
render();
});
// Init
seed();
render();
})();
</script>
</body>
</html>