Models 44

Qwen3.8 Flash

by QwenReasoningClean
Open in new window

Running live in a sandboxed frame. Click inside it before using the keyboard.

How it went

Total time
1 min 12 s
Cost
$0.0029
Output tokens
6,099
Spent thinking
0 tokens
Speed
85.7 tok/s
Console errors
0
First token after
1.2 s
First visible text after
1.2 s
Prompt tokens
521
Code size
19.1 KB
Finish reason
stop
Served by
Alibaba
Model id
qwen/qwen3.8-flash
Reasoning sent
{"effort":"none"}
Max output
64,000 tokens
Generated
Nov 11, 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 · 521 lines

<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kanban Board</title>
<style>
  :root{
    --bg:#eef2f7;
    --surface:#ffffff;
    --surface-2:#f6f8fb;
    --column-bg:#eaeef4;
    --text:#1b2536;
    --muted:#6b7688;
    --border:#dde3ec;
    --shadow:rgba(23,34,56,.10);
    --accent:#5b6cff;
    --accent-ink:#ffffff;
    --drop:#cdd9ff;
    --low:#16a34a;   --low-bg:#dcfce7;
    --med:#d97706;   --med-bg:#fef3c7;
    --high:#dc2626;  --high-bg:#fee2e2;
    --dot-low:#22c55e; --dot-med:#f59e0b; --dot-high:#ef4444;
  }
  [data-theme="dark"]{
    --bg:#0f1521;
    --surface:#1a2231;
    --surface-2:#212c3f;
    --column-bg:#141b28;
    --text:#e8edf5;
    --muted:#93a0b4;
    --border:#2b3648;
    --shadow:rgba(0,0,0,.45);
    --accent:#7c8bff;
    --accent-ink:#0f1521;
    --drop:#2a3550;
    --low:#4ade80;   --low-bg:#12331f;
    --med:#fbbf24;   --med-bg:#3a2c0c;
    --high:#f87171;  --high-bg:#3a1414;
    --dot-low:#22c55e; --dot-med:#f59e0b; --dot-high:#ef4444;
  }

  *{box-sizing:border-box}
  html,body{height:100%}
  body{
    margin:0;
    font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
    background:var(--bg);
    color:var(--text);
    display:flex;flex-direction:column;height:100vh;
    transition:background .3s ease,color .3s ease;
  }

  /* ---------- Top bar ---------- */
  .topbar{
    flex:none;display:flex;align-items:center;gap:16px;
    padding:16px 22px;background:var(--surface);
    border-bottom:1px solid var(--border);
    box-shadow:0 1px 0 var(--shadow);
    transition:background .3s,border-color .3s;
  }
  .brand{display:flex;align-items:center;gap:11px;font-weight:800;font-size:18px;letter-spacing:.2px}
  .logo{
    width:34px;height:34px;border-radius:9px;display:grid;place-items:center;
    background:linear-gradient(135deg,var(--accent),#9aa6ff);color:#fff;font-size:18px;
    box-shadow:0 4px 12px -3px var(--accent);
  }
  .spacer{flex:1}

  .search{position:relative;display:flex;align-items:center}
  .search svg{position:absolute;left:11px;width:16px;height:16px;color:var(--muted)}
  .search input{
    padding:9px 30px 9px 34px;border-radius:10px;border:1px solid var(--border);
    background:var(--surface-2);color:var(--text);font-size:14px;width:230px;outline:none;
    transition:border-color .2s,background .3s,width .2s;
  }
  .search input:focus{border-color:var(--accent);width:260px}
  .search .clear{
    position:absolute;right:8px;border:none;background:none;color:var(--muted);cursor:pointer;
    font-size:15px;line-height:1;padding:2px 4px;border-radius:6px;display:none;
  }
  .search .clear:hover{color:var(--text)}
  .search.has-text .clear{display:block}

  .btn{
    border:1px solid transparent;border-radius:10px;cursor:pointer;font-size:14px;font-weight:600;
    display:inline-flex;align-items:center;gap:7px;padding:9px 14px;transition:transform .08s,filter .2s,background .3s,border-color .3s;
  }
  .btn:active{transform:translateY(1px)}
  .btn-primary{background:var(--accent);color:var(--accent-ink)}
  .btn-primary:hover{filter:brightness(1.08)}
  .btn-ghost{background:var(--surface-2);color:var(--text);border-color:var(--border)}
  .btn-ghost:hover{filter:brightness(1.03)}
  .theme-toggle{
    width:42px;height:42px;padding:0;justify-content:center;border-radius:12px;
    background:var(--surface-2);border:1px solid var(--border);color:var(--text);cursor:pointer;font-size:19px;
    transition:background .3s,border-color .3s,transform .15s;
  }
  .theme-toggle:hover{transform:rotate(-12deg) scale(1.05)}

  /* ---------- Board ---------- */
  .board{
    flex:1;min-height:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
    gap:18px;padding:22px;overflow:auto;
  }
  .column{
    display:flex;flex-direction:column;min-height:0;
    background:var(--column-bg);border:1px solid var(--border);border-radius:16px;
    transition:background .3s,border-color .3s;
  }
  .col-head{
    flex:none;display:flex;align-items:center;gap:10px;padding:14px 16px;
    border-bottom:1px solid var(--border);
  }
  .col-dot{width:11px;height:11px;border-radius:50%;flex:none}
  .col-title{font-weight:700;font-size:15px}
  .count{
    margin-left:auto;background:var(--surface);color:var(--muted);
    font-size:12px;font-weight:700;min-width:26px;text-align:center;
    padding:3px 9px;border-radius:999px;border:1px solid var(--border);
  }
  .add-mini{
    border:none;background:var(--surface);color:var(--muted);cursor:pointer;
    width:26px;height:26px;border-radius:8px;font-size:18px;line-height:1;display:grid;place-items:center;
    transition:color .2s,background .2s;
  }
  .add-mini:hover{color:var(--accent);background:var(--surface-2)}

  .cards{
    flex:1;min-height:0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:10px;
    scrollbar-width:thin;
  }
  .cards::-webkit-scrollbar{width:8px}
  .cards::-webkit-scrollbar-thumb{background:var(--border);border-radius:8px}

  .column.drag-over{background:var(--drop);border-color:var(--accent)}

  .placeholder{
    height:6px;border-radius:6px;background:var(--accent);
    box-shadow:0 0 0 3px rgba(91,108,255,.25);margin:0 0 10px;flex:none;
    animation:pulse 1s ease-in-out infinite;
  }
  @keyframes pulse{0%,100%{opacity:.55}50%{opacity:1}}

  .empty-hint{
    color:var(--muted);font-size:13px;text-align:center;padding:26px 10px;
    border:1.5px dashed var(--border);border-radius:12px;margin-top:2px;
  }

  /* ---------- Card ---------- */
  .card{
    background:var(--surface);border:1px solid var(--border);border-radius:12px;
    padding:12px 12px 11px;cursor:grab;position:relative;
    box-shadow:0 1px 2px var(--shadow);
    transition:box-shadow .15s,transform .15s,border-color .2s,opacity .15s;
    animation:pop .22s ease;
  }
  @keyframes pop{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
  .card:hover{box-shadow:0 8px 18px -6px var(--shadow);transform:translateY(-2px);border-color:var(--accent)}
  .card.dragging{opacity:.35;box-shadow:none;transform:none}
  .card.hidden{display:none}

  .card-top{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}
  .card-title{font-size:14px;font-weight:600;line-height:1.35;margin:0;word-break:break-word}
  .del{
    flex:none;border:none;background:none;color:var(--muted);cursor:pointer;
    width:24px;height:24px;border-radius:7px;font-size:18px;line-height:1;display:grid;place-items:center;
    opacity:0;transition:opacity .15s,color .15s,background .15s;
  }
  .card:hover .del{opacity:1}
  .del:hover{color:var(--high);background:var(--high-bg)}

  .badge{
    display:inline-flex;align-items:center;gap:6px;margin-top:10px;
    font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.5px;
    padding:4px 9px;border-radius:999px;
  }
  .badge::before{content:"";width:7px;height:7px;border-radius:50%}
  .badge.low{color:var(--low);background:var(--low-bg)}     .badge.low::before{background:var(--dot-low)}
  .badge.medium{color:var(--med);background:var(--med-bg)}  .badge.medium::before{background:var(--dot-med)}
  .badge.high{color:var(--high);background:var(--high-bg)}  .badge.high::before{background:var(--dot-high)}

  /* ---------- Modal ---------- */
  .overlay{
    position:fixed;inset:0;background:rgba(15,21,33,.55);backdrop-filter:blur(3px);
    display:none;align-items:center;justify-content:center;padding:20px;z-index:50;
  }
  .overlay.open{display:flex;animation:fade .18s ease}
  @keyframes fade{from{opacity:0}to{opacity:1}}
  .modal{
    width:min(420px,100%);background:var(--surface);border:1px solid var(--border);
    border-radius:18px;padding:22px;box-shadow:0 24px 60px -12px rgba(0,0,0,.4);
    animation:rise .22s cubic-bezier(.2,.8,.2,1);
  }
  @keyframes rise{from{opacity:0;transform:translateY(14px) scale(.98)}to{opacity:1;transform:none}}
  .modal h2{margin:0 0 18px;font-size:19px}
  .field{margin-bottom:16px}
  .field label{display:block;font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);margin-bottom:7px}
  .field input,.field select{
    width:100%;padding:11px 12px;border-radius:10px;border:1px solid var(--border);
    background:var(--surface-2);color:var(--text);font-size:14px;outline:none;transition:border-color .2s;
  }
  .field input:focus,.field select:focus{border-color:var(--accent)}
  .err{color:var(--high);font-size:12px;margin-top:6px;min-height:16px;font-weight:600}
  .modal-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:6px}

  @media (max-width:760px){
    .board{grid-template-columns:1fr}
    .search input{width:150px}.search input:focus{width:170px}
    .topbar{flex-wrap:wrap}
    .brand span.txt{display:none}
  }
</style>
</head>
<body>
  <header class="topbar">
    <div class="brand"><span class="logo">▦</span><span class="txt">Kanban</span></div>
    <div class="spacer"></div>
    <div class="search" id="searchWrap">
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
      <input type="text" id="search" placeholder="Search cards…" autocomplete="off">
      <button class="clear" id="searchClear" title="Clear">✕</button>
    </div>
    <button class="btn btn-primary" id="newBtn">+ New card</button>
    <button class="theme-toggle" id="themeToggle" title="Toggle theme" aria-label="Toggle theme">☀️</button>
  </header>

  <main class="board" id="board"></main>

  <!-- Modal -->
  <div class="overlay" id="overlay">
    <form class="modal" id="modalForm" novalidate>
      <h2>New card</h2>
      <div class="field">
        <label for="fTitle">Title</label>
        <input type="text" id="fTitle" placeholder="What needs doing?">
        <div class="err" id="titleErr"></div>
      </div>
      <div class="field">
        <label for="fPriority">Priority</label>
        <select id="fPriority">
          <option value="low">Low</option>
          <option value="medium" selected>Medium</option>
          <option value="high">High</option>
        </select>
      </div>
      <div class="field">
        <label for="fColumn">Add to column</label>
        <select id="fColumn">
          <option value="todo">To do</option>
          <option value="doing">In progress</option>
          <option value="done">Done</option>
        </select>
      </div>
      <div class="modal-actions">
        <button type="button" class="btn btn-ghost" id="cancelBtn">Cancel</button>
        <button type="submit" class="btn btn-primary">Add card</button>
      </div>
    </form>
  </div>

<script>
(function(){
  "use strict";

  const COLUMNS = [
    {id:'todo',  title:'To do',       dot:'#94a3b8'},
    {id:'doing', title:'In progress', dot:'#f59e0b'},
    {id:'done',  title:'Done',        dot:'#22c55e'}
  ];

  let uid = 1;
  const state = {
    todo:[], doing:[], done:[], query:''
  };

  // Pre-populate realistic cards
  function seed(){
    add('Design the new landing page hero', 'high', 'todo');
    add('Write onboarding email sequence', 'medium', 'todo');
    add('Refactor authentication middleware', 'medium', 'doing');
    add('Fix mobile nav overlap bug', 'high', 'doing');
    add('Set up CI pipeline', 'low', 'done');
    add('Publish v1.2 release notes', 'low', 'done');
  }
  function add(title, priority, col){
    state[col].push({id:uid++, title:title.trim(), priority});
  }

  const board = document.getElementById('board');

  // Build column shells once
  COLUMNS.forEach(col=>{
    const c = document.createElement('section');
    c.className = 'column';
    c.dataset.col = col.id;
    c.innerHTML =
      '<div class="col-head">' +
        '<span class="col-dot" style="background:'+col.dot+'"></span>' +
        '<span class="col-title">'+col.title+'</span>' +
        '<span class="count" data-count="'+col.id+'">0</span>' +
        '<button class="add-mini" data-add="'+col.id+'" title="Add card here">+</button>' +
      '</div>' +
      '<div class="cards" data-cards="'+col.id+'"></div>';
    board.appendChild(c);
  });

  // ---- Drag & drop ----
  let dragId = null, fromCol = null;
  const placeholder = document.createElement('div');
  placeholder.className = 'placeholder';

  function getAfter(container, y){
    const els = [...container.querySelectorAll('.card:not(.dragging):not(.hidden)')];
    return els.reduce((closest, child)=>{
      const box = child.getBoundingClientRect();
      const offset = y - box.top - box.height/2;
      if(offset < 0 && offset > closest.offset) return {offset, element:child};
      return closest;
    }, {offset:-Infinity}).element;
  }

  function clearDropUI(){
    document.querySelectorAll('.column.drag-over').forEach(c=>c.classList.remove('drag-over'));
    if(placeholder.parentNode) placeholder.parentNode.removeChild(placeholder);
  }

  board.addEventListener('dragstart', e=>{
    const card = e.target.closest('.card');
    if(!card) return;
    dragId = +card.dataset.id;
    fromCol = card.parentElement.dataset.cards;
    card.classList.add('dragging');
    e.dataTransfer.effectAllowed = 'move';
    try{ e.dataTransfer.setData('text/plain', String(dragId)); }catch(_){}
  });

  board.addEventListener('dragover', e=>{
    if(dragId === null) return;
    const container = e.target.closest('.cards');
    if(!container) return;
    e.preventDefault();
    e.dataTransfer.dropEffect = 'move';
    clearDropUI();
    container.closest('.column').classList.add('drag-over');
    const after = getAfter(container, e.clientY);
    if(after == null) container.appendChild(placeholder);
    else container.insertBefore(placeholder, after);
  });

  board.addEventListener('drop', e=>{
    if(dragId === null) return;
    e.preventDefault();
    const container = e.target.closest('.cards');
    if(!container) return;
    const targetCol = container.dataset.cards;
    const idx = placeholder.nextElementSibling ?
      [...container.querySelectorAll('.card')].indexOf(placeholder.nextElementSibling) :
      state[targetCol].length;
    moveCard(dragId, targetCol, idx);
    finishDrag();
  });

  board.addEventListener('dragend', ()=>{
    const d = board.querySelector('.card.dragging');
    if(d) d.classList.remove('dragging');
    finishDrag();
  });

  function finishDrag(){ clearDropUI(); dragId = null; fromCol = null; render(); }

  function moveCard(id, targetCol, index){
    let card = null;
    ['todo','doing','done'].forEach(k=>{
      const i = state[k].findIndex(c=>c.id===id);
      if(i>-1){ card = state[k][i]; state[k].splice(i,1); }
    });
    if(!card) return;
    index = Math.max(0, Math.min(index, state[targetCol].length));
    state[targetCol].splice(index, 0, card);
  }

  // ---- Delete / add via delegation ----
  board.addEventListener('click', e=>{
    const del = e.target.closest('.del');
    if(del){
      const id = +del.closest('.card').dataset.id;
      ['todo','doing','done'].forEach(k=>{
        state[k] = state[k].filter(c=>c.id!==id);
      });
      render();
      return;
    }
    const addBtn = e.target.closest('[data-add]');
    if(addBtn){ openModal(addBtn.dataset.add); }
  });

  // ---- Search ----
  const searchInput = document.getElementById('search');
  const searchWrap = document.getElementById('searchWrap');
  const searchClear = document.getElementById('searchClear');
  searchInput.addEventListener('input', ()=>{
    state.query = searchInput.value.toLowerCase().trim();
    searchWrap.classList.toggle('has-text', !!state.query);
    applyFilter();
  });
  searchClear.addEventListener('click', ()=>{
    searchInput.value=''; state.query='';
    searchWrap.classList.remove('has-text');
    applyFilter(); searchInput.focus();
  });

  function applyFilter(){
    document.querySelectorAll('.card').forEach(card=>{
      const t = card.querySelector('.card-title').textContent.toLowerCase();
      card.classList.toggle('hidden', !t.includes(state.query));
    });
    updateCounts();
    COLUMNS.forEach(col=>updateEmptyHint(col.id));
  }

  function updateEmptyHint(colId){
    const container = board.querySelector('[data-cards="'+colId+'"]');
    const visible = container.querySelectorAll('.card:not(.hidden)').length;
    let hint = container.querySelector('.empty-hint');
    if(visible === 0){
      if(!hint){
        hint = document.createElement('div');
        hint.className = 'empty-hint';
        hint.textContent = state.query ? 'No matching cards' : 'Drop cards here';
        container.appendChild(hint);
      } else {
        hint.textContent = state.query ? 'No matching cards' : 'Drop cards here';
      }
    } else if(hint){ hint.remove(); }
  }

  function updateCounts(){
    COLUMNS.forEach(col=>{
      const el = board.querySelector('[data-count="'+col.id+'"]');
      el.textContent = state[col.id].filter(c=>c.title.toLowerCase().includes(state.query)).length;
    });
  }

  // ---- Render ----
  function makeCardEl(card){
    const el = document.createElement('article');
    el.className = 'card';
    el.dataset.id = card.id;
    el.draggable = true;
    el.innerHTML =
      '<div class="card-top">' +
        '<p class="card-title"></p>' +
        '<button class="del" title="Delete card">×</button>' +
      '</div>' +
      '<span class="badge '+card.priority+'">'+card.priority+'</span>';
    el.querySelector('.card-title').textContent = card.title;
    return el;
  }

  function render(){
    COLUMNS.forEach(col=>{
      const container = board.querySelector('[data-cards="'+col.id+'"]');
      container.innerHTML = '';
      state[col.id].forEach(card=>container.appendChild(makeCardEl(card)));
    });
    applyFilter();
  }

  // ---- Modal ----
  const overlay = document.getElementById('overlay');
  const form = document.getElementById('modalForm');
  const fTitle = document.getElementById('fTitle');
  const fPriority = document.getElementById('fPriority');
  const fColumn = document.getElementById('fColumn');
  const titleErr = document.getElementById('titleErr');

  function openModal(col){
    form.reset();
    fPriority.value = 'medium';
    fColumn.value = col || 'todo';
    titleErr.textContent = '';
    overlay.classList.add('open');
    setTimeout(()=>fTitle.focus(), 30);
  }
  function closeModal(){ overlay.classList.remove('open'); }

  document.getElementById('newBtn').addEventListener('click', ()=>openModal('todo'));
  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 = fTitle.value.trim();
    if(!title){
      titleErr.textContent = 'Please enter a title.';
      fTitle.focus();
      return;
    }
    add(title, fPriority.value, fColumn.value);
    closeModal();
    render();
  });

  // ---- Theme toggle ----
  const themeToggle = document.getElementById('themeToggle');
  themeToggle.addEventListener('click', ()=>{
    const root = document.documentElement;
    const dark = root.getAttribute('data-theme') === 'dark';
    root.setAttribute('data-theme', dark ? 'light' : 'dark');
    themeToggle.textContent = dark ? '☀️' : '🌙';
  });

  // ---- Init ----
  seed();
  render();
})();
</script>
</body>
</html>