Step 5 Preview: Free OpenCode Frontend HTML Benchmark

Three complete HTML outputs, two incomplete game attempts, and a reproducible task-board bug through OpenCode’s free route.
Co-Founder & Lead Programmer of AcceleratedLogic AI
What Step 5 Preview is
Free access and the test method
step-5-preview-free with free input and output for a limited time. It also says this route’s provider follows a zero-retention policy and does not train on submitted data. We checked the public catalog and selected opencode/step-5-preview-free in the installed OpenCode 1.18.35 client. The base model’s maximum context is not a guarantee that this free serving route exposes the same limit. Free availability and terms may change.opencode run --pure --format json --model opencode/step-5-preview-free. The default build agent and sampling settings were retained. External plugins were disabled, and every prompt prohibited tools, filesystem access, and shell commands. The response had to contain one complete HTML file. The two 3D tasks could import one pinned Three.js module; the SVG and task board had no external dependencies. The first game response was incomplete, so we repeated that exact prompt once in another fresh session. No repair prompt or model substitution was used. The requests overlapped, so their timings are not a controlled serial latency comparison.Results at a glance
| Task / attempt | Step time | Delivered result | Check result |
|---|---|---|---|
| Glass crane | 229.4 s | Complete HTML | Local SVG references resolve; no external assets |
| Procedural globe | 367.2 s | Complete HTML | JavaScript parses; simulated no-WebGL fallback passes |
| Wizard game, attempt 1 | 362.3 s | Incomplete HTML | Stray tool markup, invalid script, no game implementation |
| Wizard game, attempt 2 | 496.7 s | Incomplete HTML | Ends mid-sentence in start-panel markup; no game JavaScript |
| Task board | 93.6 s | Complete HTML | 15/16 DOM cases pass; empty saved board reloads incorrectly |
Test 1: Glass sphere and origami crane
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="dark">
<title>Crane Suspended — Origami in a Glass Sphere</title>
<style>
:root{
--bg-top:#16202f;
--bg-mid:#0b1018;
--bg-bot:#05070b;
--txt:#cbd8e8;
--muted:#7f90a6;
--accent:#a8e2f5;
}
*,*::before,*::after{box-sizing:border-box}
html,body{height:100%}
body{
margin:0;
min-height:100dvh;
display:flex;
align-items:center;
justify-content:center;
padding:clamp(14px,3.5vmin,52px);
background:
radial-gradient(120% 90% at 50% -12%, var(--bg-top) 0%, var(--bg-mid) 46%, var(--bg-bot) 100%);
color:var(--txt);
font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
-webkit-font-smoothing:antialiased;
}
.stage{width:100%;max-width:min(88vw,860px)}
figure{margin:0;display:block}
svg.art{display:block;width:100%;height:auto}
.sr-only{
position:absolute;width:1px;height:1px;padding:0;margin:-1px;
overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}
figcaption{
margin-top:clamp(8px,1.8vmin,18px);
text-align:center;line-height:1.45;
}
figcaption .kicker{
display:block;
font-size:clamp(9px,1.35vmin,11px);
letter-spacing:.34em;text-transform:uppercase;
color:var(--muted);margin-bottom:.5em;
}
figcaption .title{
display:block;
font-size:clamp(15px,2.6vmin,22px);
font-weight:550;letter-spacing:.02em;
color:#eaf4ff;
}
figcaption .title em{
font-style:normal;
background:linear-gradient(92deg,#ffffff 0%,var(--accent) 55%,#cfe9ff 100%);
-webkit-background-clip:text;background-clip:text;color:transparent;
}
figcaption .note{
display:block;margin-top:.55em;
font-size:clamp(10px,1.6vmin,12.5px);color:var(--muted);
letter-spacing:.06em;
}
/* ---------- motion ---------- */
@keyframes drift{
0%,100%{transform:translateY(0)}
50%{transform:translateY(-7px)}
}
@keyframes sway{
0%,100%{transform:translate(0,0) rotate(-2.4deg)}
50%{transform:translate(-2px,-3.5px) rotate(2.2deg)}
}
@keyframes glint{
0%,100%{opacity:.42}
50%{opacity:.95}
}
@keyframes twinkle{
0%,100%{transform:scale(.35);opacity:0}
50%{transform:scale(1);opacity:.95}
}
@keyframes causticPulse{
0%,100%{opacity:.55}
50%{opacity:.95}
}
.drift{animation:drift 11s cubic-bezier(.45,0,.55,1) infinite}
.sway{animation:sway 9s ease-in-out infinite}
.glint{animation:glint 6.5s ease-in-out infinite}
.twinkle{animation:twinkle 4.6s ease-in-out infinite;transform-origin:center}
.twinkle.b{animation-duration:6.1s;animation-delay:-2.4s}
.caustic-pulse{animation:causticPulse 7.4s ease-in-out infinite}
@media (prefers-reduced-motion: reduce){
.drift,.sway,.glint,.twinkle,.caustic-pulse{animation:none}
.twinkle{opacity:.8;transform:none}
.glint{opacity:.75}
}
</style>
</head>
<body>
<main class="stage">
<figure>
<h1 class="sr-only">A folded origami crane suspended inside a clear glass sphere</h1>
<svg class="art" viewBox="0 0 460 420" preserveAspectRatio="xMidYMid meet"
role="img" aria-labelledby="artTitle artDesc" xmlns="http://www.w3.org/2000/svg">
<title id="artTitle">Origami crane inside a glass sphere</title>
<desc id="artDesc">A polished glass sphere rests on a dark surface, lit softly from the upper left. Inside the sphere a folded paper crane hovers, its sharp facets and crease lines catching light and shadow. The glass shows refracted echoes of the crane near its base, a bright caustic on the surface below, colorful chromatic edges, and crisp specular highlights on the sphere.</desc>
<defs>
<!-- paper facets -->
<linearGradient id="gPaperA" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#fffdf8"/><stop offset="1" stop-color="#f3e7d2"/>
</linearGradient>
<linearGradient id="gPaperB" x1="0" y1="0" x2=".7" y2="1">
<stop offset="0" stop-color="#fbf2e3"/><stop offset="1" stop-color="#e4d0ab"/>
</linearGradient>
<linearGradient id="gPaperC" x1=".1" y1="0" x2=".9" y2="1">
<stop offset="0" stop-color="#ecd6b4"/><stop offset="1" stop-color="#c0a279"/>
</linearGradient>
<linearGradient id="gPaperD" x1="0" y1="0" x2=".8" y2="1">
<stop offset="0" stop-color="#b2916a"/><stop offset="1" stop-color="#77582f"/>
</linearGradient>
<linearGradient id="gPaperE" x1="0" y1="0" x2=".6" y2="1">
<stop offset="0" stop-color="#ffffff"/><stop offset="1" stop-color="#f6e9d0"/>
</linearGradient>
<!-- glass -->
<radialGradient id="gGlass" cx=".38" cy=".3" r=".82">
<stop offset="0" stop-color="#ffffff" stop-opacity=".10"/>
<stop offset=".45" stop-color="#aad6ec" stop-opacity=".13"/>
<stop offset=".78" stop-color="#1b3f58" stop-opacity=".30"/>
<stop offset="1" stop-color="#06121e" stop-opacity=".62"/>
</radialGradient>
<linearGradient id="gRim" x1=".06" y1=".02" x2=".94" y2="1">
<stop offset="0" stop-color="#ffffff"/>
<stop offset=".16" stop-color="#dcf3fd"/>
<stop offset=".36" stop-color="#7fb4cf"/>
<stop offset=".55" stop-color="#2d4c63"/>
<stop offset=".72" stop-color="#132430"/>
<stop offset=".88" stop-color="#cfeeff"/>
<stop offset="1" stop-color="#ffffff"/>
</linearGradient>
<radialGradient id="gSpec">
<stop offset="0" stop-color="#ffffff" stop-opacity=".95"/>
<stop offset=".55" stop-color="#ffffff" stop-opacity=".32"/>
<stop offset="1" stop-color="#ffffff" stop-opacity="0"/>
</radialGradient>
<radialGradient id="gBounce">
<stop offset="0" stop-color="#d6f4ff" stop-opacity=".45"/>
<stop offset="1" stop-color="#d6f4ff" stop-opacity="0"/>
</radialGradient>
<radialGradient id="gHalo">
<stop offset="0" stop-color="#9fd4ee" stop-opacity=".18"/>
<stop offset=".55" stop-color="#6ba7c4" stop-opacity=".06"/>
<stop offset="1" stop-color="#6ba7c4" stop-opacity="0"/>
</radialGradient>
<radialGradient id="gFloorShadow">
<stop offset="0" stop-color="#000000" stop-opacity=".62"/>
<stop offset=".6" stop-color="#000000" stop-opacity=".26"/>
<stop offset="1" stop-color="#000000" stop-opacity="0"/>
</radialGradient>
<radialGradient id="gCaustic">
<stop offset="0" stop-color="#bfeeff" stop-opacity=".6"/>
<stop offset=".5" stop-color="#7cc6e0" stop-opacity=".2"/>
<stop offset="1" stop-color="#7cc6e0" stop-opacity="0"/>
</radialGradient>
<clipPath id="sphereClip"><circle cx="230" cy="218" r="140"/></clipPath>
<clipPath id="coreClip"><circle cx="230" cy="218" r="134"/></clipPath>
<filter id="fBlurS" x="-45%" y="-45%" width="190%" height="190%">
<feGaussianBlur stdDeviation="2.4"/>
</filter>
<filter id="fBlurM" x="-45%" y="-45%" width="190%" height="190%">
<feGaussianBlur stdDeviation="9"/>
</filter>
<filter id="fBlurL" x="-60%" y="-60%" width="220%" height="220%">
<feGaussianBlur stdDeviation="26"/>
</filter>
<filter id="fCast" x="-45%" y="-45%" width="190%" height="190%">
<feDropShadow dx="8" dy="13" stdDeviation="10" flood-color="#05101a" flood-opacity=".55"/>
</filter>
<filter id="fCastOut" x="-45%" y="-45%" width="190%" height="190%">
<feDropShadow dx="0" dy="18" stdDeviation="16" flood-color="#000000" flood-opacity=".55"/>
</filter>
<filter id="fGrain" x="0" y="0" width="100%" height="100%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="3" stitchTiles="stitch"/>
<feColorMatrix type="saturate" values="0"/>
</filter>
<!-- ================= THE ORIGAMI CRANE ================= -->
<g id="craneArt">
<!-- tail, swept up-right -->
<polygon points="80,46 150,12 96,44" fill="url(#gPaperD)"/>
<polygon points="80,46 150,12 124,31" fill="url(#gPaperC)"/>
<polygon points="80,46 124,31 96,44" fill="url(#gPaperD)"/>
<!-- neck, sweeping up-left -->
<polygon points="78,46 26,12 22,6 66,40" fill="url(#gPaperC)"/>
<polygon points="78,46 26,12 45,40" fill="url(#gPaperE)"/>
<polygon points="78,46 45,40 66,40" fill="url(#gPaperC)"/>
<!-- head and beak -->
<polygon points="30,16 22,6 15,11 25,21" fill="url(#gPaperB)"/>
<polygon points="22,6 8,9 21,12" fill="url(#gPaperD)"/>
<circle cx="24.4" cy="11.4" r="1.25" fill="#4a3722"/>
<!-- far wing -->
<polygon points="78,46 12,60 64,86" fill="url(#gPaperD)"/>
<polygon points="78,46 12,60 38,73" fill="url(#gPaperB)"/>
<polygon points="78,46 38,73 64,86" fill="url(#gPaperD)"/>
<!-- body kite -->
<polygon points="78,46 52,84 82,102 110,84" fill="url(#gPaperC)"/>
<polygon points="78,46 52,84 82,102" fill="url(#gPaperC)"/>
<polygon points="78,46 82,102 110,84" fill="url(#gPaperB)"/>
<polygon points="78,46 56,72 110,84" fill="url(#gPaperA)" opacity=".55"/>
<polygon points="78,46 52,84 70,66" fill="url(#gPaperD)" opacity=".55"/>
<!-- near wing -->
<polygon points="82,48 152,56 100,92" fill="url(#gPaperD)"/>
<polygon points="82,48 152,56 127,72" fill="url(#gPaperA)"/>
<polygon points="82,48 127,72 100,92" fill="url(#gPaperC)"/>
<polygon points="127,72 152,56 141,64" fill="url(#gPaperB)" opacity=".7"/>
<!-- creases -->
<path d="M80 46L124 31M78 46L45 40M78 46L82 102M52 84L82 102M82 102L110 84
M78 46L38 73M38 73L64 86M12 60L38 73M82 48L127 72M127 72L100 92
M152 56L127 72M82 102L96 84"
fill="none" stroke="#96693d" stroke-width=".85" stroke-linecap="round" opacity=".5"/>
<path d="M26 12L22 6M22 6L15 11M30 16L25 21M12 60L78 46M84 60L100 92"
fill="none" stroke="#a87c4d" stroke-width=".6" stroke-linecap="round" opacity=".38"/>
<!-- paper grain -->
<rect x="0" y="0" width="170" height="120" filter="url(#fGrain)" opacity=".085" style="mix-blend-mode:multiply"/>
</g>
</defs>
<!-- ================= SCENE ================= -->
<circle cx="230" cy="206" r="215" fill="url(#gHalo)"/>
<ellipse cx="230" cy="374" rx="132" ry="26" fill="url(#gFloorShadow)"/>
<ellipse class="caustic-pulse" cx="236" cy="366" rx="66" ry="12" fill="url(#gCaustic)" filter="url(#fBlurS)"/>
<g class="drift">
<g filter="url(#fCastOut)">
<circle cx="230" cy="218" r="140" fill="url(#gGlass)"/>
<g clip-path="url(#sphereClip)">
<!-- cast shadow of the crane inside the glass -->
<g transform="translate(230 206) scale(1.6) translate(-82 -54)" opacity=".55" filter="url(#fCast)">
<use href="#craneArt"/>
</g>
<!-- the crane -->
<g transform="translate(230 200) scale(1.6) translate(-82 -54)">
<g class="sway"><use href="#craneArt"/></g>
</g>
<!-- refraction: displaced, softened ghost -->
<g transform="translate(238 208) scale(1.6) translate(-82 -54)" opacity=".16" filter="url(#fBlurM)">
<use href="#craneArt"/>
</g>
<!-- refraction: compressed reflection near the base -->
<g transform="translate(230 316) scale(1.5 -.42) translate(-82 -54)" opacity=".2" filter="url(#fBlurS)">
<use href="#craneArt"/>
</g>
<!-- volumetric shading inside the glass -->
<ellipse cx="150" cy="128" rx="120" ry="90" fill="url(#gSpec)" opacity=".1" filter="url(#fBlurL)"/>
<ellipse cx="292" cy="308" rx="72" ry="46" fill="url(#gBounce)" filter="url(#fBlurM)"/>
<circle cx="230" cy="218" r="137" fill="none" stroke="#04121c" stroke-width="16" opacity=".2" filter="url(#fBlurM)"/>
<!-- chromatic edge cues -->
<path d="M98.4 170.1A140 140 0 0 1 361.6 170.1" fill="none" stroke="#6fe3ff" stroke-width="2.4" opacity=".3"/>
<path d="M101 171.5A137 137 0 0 1 359 171.5" fill="none" stroke="#ff8fd8" stroke-width="2" opacity=".26"/>
<path d="M92 280A140 140 0 0 0 176 344" fill="none" stroke="#8fd8ff" stroke-width="2.2" opacity=".22"/>
<path d="M300 344A140 140 0 0 0 374 268" fill="none" stroke="#ffd9a8" stroke-width="2" opacity=".18"/>
<!-- sparkles -->
<g transform="translate(332 126)"><g class="twinkle">
<path d="M0-9Q1.2-1.2 9 0Q1.2 1.2 0 9Q-1.2 1.2-9 0Q-1.2-1.2 0-9Z" fill="#ffffff"/>
</g></g>
<g transform="translate(122 288)"><g class="twinkle b">
<path d="M0-6Q.8-.8 6 0Q.8.8 0 6Q-.8.8-6 0Q-.8-.8 0-6Z" fill="#dff4ff"/>
</g></g>
</g>
<!-- glass shell -->
<circle cx="230" cy="218" r="139.6" fill="none" stroke="url(#gRim)" stroke-width="2.6"/>
<circle cx="230" cy="218" r="134" fill="none" stroke="#ffffff" stroke-width="1" opacity=".14"/>
<ellipse cx="172" cy="152" rx="66" ry="32" transform="rotate(-32 172 152)" fill="#ffffff" opacity=".42" filter="url(#fBlurM)"/>
<ellipse class="glint" cx="152" cy="136" rx="27" ry="12" transform="rotate(-34 152 136)" fill="#ffffff" opacity=".7" filter="url(#fBlurS)"/>
<ellipse class="glint" cx="196" cy="118" rx="10" ry="5" transform="rotate(-30 196 118)" fill="#ffffff" opacity=".8" filter="url(#fBlurS)"/>
<ellipse cx="286" cy="286" rx="44" ry="18" transform="rotate(28 286 286)" fill="#bfeaff" opacity=".2" filter="url(#fBlurM)"/>
<path d="M124 236A118 118 0 0 1 150 122" fill="none" stroke="#ffffff" stroke-width="4" opacity=".14" filter="url(#fBlurS)"/>
</g>
</g>
</svg>
<figcaption>
<span class="kicker">Study in glass & paper</span>
<span class="title"><em>Crane Suspended</em></span>
<span class="note">Pure vector — gradients, facets, creases, refraction</span>
</figcaption>
</figure>
</main>
</body>
</html>
Test 2: Procedural globe
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="dark">
<title>Procedural Globe — Three.js</title>
<style>
*,*::before,*::after{box-sizing:border-box}
[hidden]{display:none !important}
html,body{height:100%}
body{
margin:0;overflow:hidden;background:#04060d;color:#e9eefb;
font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
-webkit-font-smoothing:antialiased;
}
#scene{position:fixed;inset:0;width:100%;height:100%;display:block;touch-action:none;cursor:grab;outline:none}
#scene:active{cursor:grabbing}
#scene:focus-visible{outline:2px solid #7fb2ff;outline-offset:-4px}
.vignette{position:fixed;inset:0;pointer-events:none;z-index:1;
background:radial-gradient(circle at 50% 44%,rgba(0,0,0,0) 52%,rgba(0,0,0,.6) 100%)}
header.brand{position:fixed;top:0;left:0;z-index:2;padding:20px 24px;pointer-events:none}
.brand h1{margin:0;font-size:clamp(15px,2.1vw,21px);font-weight:600;letter-spacing:.18em;text-transform:uppercase}
.brand p{margin:7px 0 0;font-size:12.5px;letter-spacing:.03em;color:rgba(233,238,251,.58)}
.hud{
position:fixed;left:24px;bottom:24px;z-index:3;display:flex;flex-direction:column;gap:16px;
min-width:250px;padding:16px 18px;border-radius:18px;
background:rgba(11,17,33,.62);border:1px solid rgba(255,255,255,.09);
box-shadow:0 18px 50px rgba(0,0,0,.45);
backdrop-filter:blur(16px) saturate(1.25);-webkit-backdrop-filter:blur(16px) saturate(1.25);
}
.zoom-row{display:flex;gap:10px}
.btn{
width:44px;height:44px;display:grid;place-items:center;border-radius:12px;
border:1px solid rgba(255,255,255,.14);background:rgba(255,255,255,.06);color:#dbe6ff;cursor:pointer;
transition:transform .15s ease,background .15s ease,border-color .15s ease;
}
.btn:hover{background:rgba(255,255,255,.14);border-color:rgba(255,255,255,.3)}
.btn:active{transform:scale(.93)}
.btn:focus-visible{outline:2px solid #7fb2ff;outline-offset:2px}
.btn svg{width:18px;height:18px}
.slider-block{display:flex;flex-direction:column;gap:6px}
.slider-head{display:flex;justify-content:space-between;align-items:baseline;gap:12px;
font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;color:rgba(233,238,251,.72)}
.slider-head output{font-size:12px;letter-spacing:.02em;text-transform:none;color:#9fd2ff;
font-variant-numeric:tabular-nums}
input[type=range]{-webkit-appearance:none;appearance:none;width:100%;height:22px;margin:0;background:transparent;cursor:pointer}
input[type=range]::-webkit-slider-runnable-track{height:5px;border-radius:999px;
background:linear-gradient(90deg,#4f7fd0,#8fd6ff 65%,#26334f)}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:18px;height:18px;margin-top:-6.5px;
border-radius:50%;background:#eaf4ff;border:1px solid rgba(255,255,255,.75);
box-shadow:0 0 0 4px rgba(120,180,255,.2),0 2px 8px rgba(0,0,0,.5)}
input[type=range]::-moz-range-track{height:5px;border-radius:999px;
background:linear-gradient(90deg,#4f7fd0,#8fd6ff 65%,#26334f)}
input[type=range]::-moz-range-thumb{width:16px;height:16px;border-radius:50%;background:#eaf4ff;
border:1px solid rgba(255,255,255,.75)}
input[type=range]:focus-visible{outline:2px solid #7fb2ff;outline-offset:4px;border-radius:8px}
.hint{position:fixed;right:22px;bottom:24px;z-index:2;font-size:12px;color:rgba(233,238,251,.48);pointer-events:none}
.status{position:fixed;inset:0;z-index:10;display:grid;place-items:center;padding:24px;
background:radial-gradient(circle at 50% 40%,rgba(12,20,40,.88),rgba(3,5,12,.96));
backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);transition:opacity .5s ease}
.status.is-hidden{opacity:0;pointer-events:none}
.card{width:min(430px,100%);text-align:center;padding:34px 30px 30px;border-radius:22px;
background:rgba(12,18,36,.74);border:1px solid rgba(255,255,255,.1);box-shadow:0 24px 70px rgba(0,0,0,.55)}
.card h2{margin:0 0 10px;font-size:18px;font-weight:600;letter-spacing:.03em}
.card p{margin:0;font-size:13.5px;line-height:1.65;color:rgba(233,238,251,.72)}
.spinner{width:44px;height:44px;margin:0 auto 22px;border-radius:50%;
border:3px solid rgba(143,182,255,.16);border-top-color:#8fd6ff;animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.retry{margin-top:22px;padding:10px 22px;border-radius:12px;border:1px solid rgba(255,255,255,.18);
background:rgba(120,170,255,.16);color:#e8f2ff;font-size:13px;letter-spacing:.05em;cursor:pointer}
.retry:hover{background:rgba(120,170,255,.3)}
.retry:focus-visible{outline:2px solid #7fb2ff;outline-offset:2px}
noscript div{position:fixed;inset:0;display:grid;place-items:center;padding:24px;text-align:center;font-size:14px}
@media (max-width:560px){
.hud{left:14px;right:14px;bottom:14px;min-width:0}
.hint{display:none}
.brand p{max-width:230px}
}
@media (prefers-reduced-motion: reduce){
.spinner{animation:none;border-top-color:rgba(143,182,255,.5)}
.btn{transition:none}
.status{transition:none}
}
</style>
</head>
<body>
<canvas id="scene" tabindex="0"
aria-label="Interactive procedural globe. Drag, or use the arrow keys to rotate and plus and minus to zoom."></canvas>
<div class="vignette" aria-hidden="true"></div>
<header class="brand">
<h1>Procedural Globe</h1>
<p>Noise-generated continents · rendered with Three.js</p>
</header>
<section class="hud" aria-label="Globe controls">
<div class="zoom-row">
<button class="btn" id="zoomIn" type="button" aria-label="Zoom in" title="Zoom in">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true">
<circle cx="11" cy="11" r="6.5"></circle><path d="M11 8.5v5M8.5 11h5M20 20l-4.4-4.4"></path>
</svg>
</button>
<button class="btn" id="zoomOut" type="button" aria-label="Zoom out" title="Zoom out">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true">
<circle cx="11" cy="11" r="6.5"></circle><path d="M8.5 11h5M20 20l-4.4-4.4"></path>
</svg>
</button>
</div>
<div class="slider-block">
<div class="slider-head">
<label for="speed">Rotation speed</label>
<output id="speedOut" for="speed">0.36 rad/s</output>
</div>
<input id="speed" type="range" min="0" max="100" step="1" value="30" aria-describedby="speedOut">
</div>
</section>
<p class="hint">Drag to spin · scroll or use the buttons to zoom</p>
<div class="status" id="status" role="status" aria-live="polite">
<div class="card">
<div class="spinner" id="statusSpin" aria-hidden="true"></div>
<h2 id="statusTitle">Loading Three.js</h2>
<p id="statusMsg">Fetching the 3D engine from the CDN…</p>
<button class="retry" id="retry" type="button" hidden>Try again</button>
</div>
</div>
<noscript><div>This interactive globe requires JavaScript to be enabled.</div></noscript>
<script type="module">
const THREE_URL = 'https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js';
const statusEl = document.getElementById('status');
const statusSpin = document.getElementById('statusSpin');
const statusTitle= document.getElementById('statusTitle');
const statusMsg = document.getElementById('statusMsg');
const retryBtn = document.getElementById('retry');
const clamp = (v, a, b) => Math.min(b, Math.max(a, v));
const mix = (a, b, t) => a + (b - a) * t;
const nextFrame = () => new Promise(r => requestAnimationFrame(() => setTimeout(r, 0)));
function step(title, msg) { statusTitle.textContent = title; statusMsg.textContent = msg; }
function fail(msg) {
statusEl.hidden = false;
statusEl.classList.remove('is-hidden');
statusEl.removeAttribute('aria-hidden');
statusEl.setAttribute('role', 'alert');
statusSpin.hidden = true;
statusTitle.textContent = 'Unable to display the globe';
statusMsg.textContent = msg;
retryBtn.hidden = false;
retryBtn.focus();
}
function hideStatus() {
statusEl.classList.add('is-hidden');
statusEl.setAttribute('aria-hidden', 'true');
setTimeout(() => { statusEl.hidden = true; }, 600);
}
retryBtn.addEventListener('click', () => location.reload());
function mulberry32(a) {
return function () {
a |= 0; a = (a + 0x6D2B79F5) | 0;
let t = Math.imul(a ^ (a >>> 15), 1 | a);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
/* ---------- Procedural planet textures (colour / bump / specular) ---------- */
function buildPlanetTextures(THREE) {
const W = 1024, H = 512, SEA = 0.515;
const rnd = mulberry32(20261015);
const perm = new Uint8Array(512);
{
const p = new Uint8Array(256);
for (let i = 0; i < 256; i++) p[i] = i;
for (let i = 255; i > 0; i--) { const j = (rnd() * (i + 1)) | 0; const t = p[i]; p[i] = p[j]; p[j] = t; }
for (let i = 0; i < 512; i++) perm[i] = p[i & 255];
}
const fade = t => t * t * t * (t * (t * 6 - 15) + 10);
const hash = (i, j, k) => perm[(perm[(perm[i & 255] + j) & 255] + k) & 255] / 255;
function vnoise(x, y, z) {
const xi = Math.floor(x), yi = Math.floor(y), zi = Math.floor(z);
const u = fade(x - xi), v = fade(y - yi), w = fade(z - zi);
const c000 = hash(xi, yi, zi), c100 = hash(xi + 1, yi, zi);
const c010 = hash(xi, yi + 1, zi), c110 = hash(xi + 1, yi + 1, zi);
const c001 = hash(xi, yi, zi + 1), c101 = hash(xi + 1, yi, zi + 1);
const c011 = hash(xi, yi + 1, zi + 1), c111 = hash(xi + 1, yi + 1, zi + 1);
return mix(mix(mix(c000, c100, u), mix(c010, c110, u), v),
mix(mix(c001, c101, u), mix(c011, c111, u), v), w);
}
function fbm(x, y, z, oct) {
let a = 1, f = 1, s = 0, n = 0;
for (let i = 0; i < oct; i++) { s += a * vnoise(x * f, y * f, z * f); n += a; a *= 0.5; f *= 2; }
return s / n;
}
const colour = new Uint8ClampedArray(W * H * 4);
const relief = new Uint8ClampedArray(W * H * 4);
const shine = new Uint8ClampedArray(W * H * 4);
for (let y = 0; y < H; y++) {
const lat = Math.PI * 0.5 - ((y + 0.5) / H) * Math.PI;
const cl = Math.cos(lat), sl = Math.sin(lat);
for (let x = 0; x < W; x++) {
const lon = ((x + 0.5) / W) * Math.PI * 2;
const nx = cl * Math.cos(lon), ny = sl, nz = cl * Math.sin(lon);
let e = fbm(nx * 1.7 + 7.3, ny * 1.7 + 2.9, nz * 1.7 + 5.1, 5);
e += 0.16 * fbm(nx * 4.3 + 21, ny * 4.3 + 13, nz * 4.3 + 3, 3) - 0.08;
const moist = fbm(nx * 2.6 + 31, ny * 2.6 + 17, nz * 2.6 + 9, 3);
const polar = clamp((Math.abs(lat) - 1.02) / 0.3, 0, 1);
let r, g, b, sp, hv;
if (e < SEA) {
const t = clamp((SEA - e) * 4.5, 0, 1);
r = mix(30, 4, t); g = mix(96, 20, t); b = mix(150, 58, t);
sp = 235; hv = SEA;
} else {
if (moist < 0.42) { r = 176; g = 148; b = 100; }
else if (moist < 0.6) { r = 128; g = 142; b = 90; }
else { r = 62; g = 112; b = 68; }
const rock = clamp((e - SEA - 0.11) / 0.22, 0, 1);
r = mix(r, 118, rock); g = mix(g, 110, rock); b = mix(b, 102, rock);
sp = 28; hv = e;
}
const snow = clamp((e - SEA - 0.26) / 0.2, 0, 1);
const ice = clamp(Math.max(polar, snow), 0, 1);
r = mix(r, 238, ice); g = mix(g, 244, ice); b = mix(b, 250, ice);
if (ice > 0.35) sp = 120;
const i4 = (y * W + x) * 4;
colour[i4] = r; colour[i4 + 1] = g; colour[i4 + 2] = b; colour[i4 + 3] = 255;
const bv = clamp(hv, 0, 1) * 255;
relief[i4] = relief[i4 + 1] = relief[i4 + 2] = bv; relief[i4 + 3] = 255;
shine[i4] = shine[i4 + 1] = shine[i4 + 2] = sp; shine[i4 + 3] = 255;
}
}
function toTexture(data, srgb) {
const c = document.createElement('canvas');
c.width = W; c.height = H;
c.getContext('2d').putImageData(new ImageData(data, W, H), 0, 0);
const t = new THREE.CanvasTexture(c);
if (srgb) t.colorSpace = THREE.SRGBColorSpace;
return t;
}
return { colour: toTexture(colour, true), bump: toTexture(relief), spec: toTexture(shine) };
}
function buildSparkTexture(THREE) {
const c = document.createElement('canvas');
c.width = c.height = 64;
const ctx = c.getContext('2d');
const g = ctx.createRadialGradient(32, 32, 0, 32, 32, 32);
g.addColorStop(0, 'rgba(255,255,255,1)');
g.addColorStop(0.35, 'rgba(190,225,255,.75)');
g.addColorStop(1, 'rgba(120,180,255,0)');
ctx.fillStyle = g;
ctx.fillRect(0, 0, 64, 64);
return new THREE.CanvasTexture(c);
}
/* ---------- Scene ---------- */
const ATMO_VS = `
varying vec3 vNormalW; varying vec3 vViewW;
void main() {
vec4 wp = modelMatrix * vec4(position, 1.0);
vNormalW = normalize(mat3(modelMatrix) * normal);
vViewW = normalize(cameraPosition - wp.xyz);
gl_Position = projectionMatrix * viewMatrix * wp;
}`;
const ATMO_FS = `
uniform vec3 uColor; uniform vec3 uSun; uniform float uIntensity;
varying vec3 vNormalW; varying vec3 vViewW;
void main() {
vec3 n = normalize(vNormalW);
vec3 v = normalize(vViewW);
float rim = clamp(1.0 - abs(dot(n, v)), 0.0, 1.0);
float glow = pow(rim, 2.4);
float lit = 0.22 + 0.78 * max(dot(n, normalize(uSun)), 0.0);
gl_FragColor = vec4(uColor, glow * lit * uIntensity);
}`;
function init(THREE, maps) {
const canvas = document.getElementById('scene');
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true, powerPreference: 'high-performance' });
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
renderer.setSize(window.innerWidth, window.innerHeight, false);
renderer.outputColorSpace = THREE.SRGBColorSpace;
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.06;
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x04060e);
const camera = new THREE.PerspectiveCamera(42, window.innerWidth / window.innerHeight, 0.1, 400);
camera.position.set(0, 0, 3.6);
const sun = new THREE.DirectionalLight(0xfff1dd, 2.2);
sun.position.set(5, 2.2, 3.4);
scene.add(sun);
scene.add(new THREE.AmbientLight(0x2b3a5e, 0.35));
scene.add(new THREE.HemisphereLight(0x334a7a, 0x05070f, 0.28));
/* Starfield */
const starRnd = mulberry32(4242);
function starLayer(count, size, colour, radius) {
const pos = new Float32Array(count * 3);
for (let i = 0; i < count; i++) {
const u = starRnd() * 2 - 1, th = starRnd() * Math.PI * 2, s = Math.sqrt(1 - u * u);
pos[i * 3] = Math.cos(th) * s * radius;
pos[i * 3 + 1] = u * radius;
pos[i * 3 + 2] = Math.sin(th) * s * radius;
}
const geo = new THREE.BufferGeometry();
geo.setAttribute('position', new THREE.BufferAttribute(pos, 3));
return new THREE.Points(geo, new THREE.PointsMaterial({
color: colour, size, sizeAttenuation: false, transparent: true,
opacity: 0.9, depthWrite: false
}));
}
const stars = new THREE.Group();
stars.add(starLayer(1100, 1.6, 0xffffff, 90));
stars.add(starLayer(180, 2.8, 0x9fc4ff, 70));
scene.add(stars);
/* Globe */
const world = new THREE.Group();
scene.add(world);
maxAniso(renderer, maps);
maps.colour.anisotropy = renderer.capabilities.getMaxAnisotropy();
const globe = new THREE.Mesh(
new THREE.SphereGeometry(1, 96, 64),
new THREE.MeshPhongMaterial({
map: maps.colour, bumpMap: maps.bump, bumpScale: 0.022,
specularMap: maps.spec, specular: new THREE.Color(0x2a4c7a), shininess: 24
})
);
world.add(globe);
/* Atmosphere */
const atmo = new THREE.Mesh(
new THREE.SphereGeometry(1, 64, 48),
new THREE.ShaderMaterial({
uniforms: {
uColor: { value: new THREE.Color(0x5fa8ff) },
uSun: { value: sun.position.clone().normalize() },
uIntensity: { value: 1.15 }
},
vertexShader: ATMO_VS, fragmentShader: ATMO_FS,
transparent: true, blending: THREE.AdditiveBlending,
side: THREE.BackSide, depthWrite: false
})
);
atmo.scale.setScalar(1.23);
world.add(atmo);
/* Orbiting particle ring */
const RING = 560;
const ringGeo = new THREE.BufferGeometry();
const posArr = new Float32Array(RING * 3);
const ang = new Float32Array(RING), rad = new Float32Array(RING);
const yOff = new Float32Array(RING), spd = new Float32Array(RING);
const ringRnd = mulberry32(777);
for (let i = 0; i < RING; i++) {
ang[i] = ringRnd() * Math.PI * 2;
rad[i] = 1.34 + ringRnd() * 0.36;
yOff[i] = (ringRnd() - 0.5) * 0.05;
spd[i] = 0.10 + ringRnd() * 0.12;
posArr[i * 3] = Math.cos(ang[i]) * rad[i];
posArr[i * 3 + 1] = yOff[i];
posArr[i * 3 + 2] = Math.sin(ang[i]) * rad[i];
}
ringGeo.setAttribute('position', new THREE.BufferAttribute(posArr, 3));
const ring = new THREE.Points(ringGeo, new THREE.PointsMaterial({
map: buildSparkTexture(THREE), size: 0.032, sizeAttenuation: true,
color: 0xbfe4ff, transparent: true, opacity: 0.95,
blending: THREE.AdditiveBlending, depthWrite: false
}));
const ringOrbit = new THREE.Group();
ringOrbit.rotation.set(-0.22, 0, 0.44);
ringOrbit.add(ring);
world.add(ringOrbit);
function updateRing(dt) {
const arr = ringGeo.attributes.position.array;
for (let i = 0; i < RING; i++) {
ang[i] += spd[i] * dt;
const r = rad[i];
arr[i * 3] = Math.cos(ang[i]) * r;
arr[i * 3 + 1] = yOff[i] + Math.sin(ang[i] * 3) * 0.02;
arr[i * 3 + 2] = Math.sin(ang[i]) * r;
}
ringGeo.attributes.position.needsUpdate = true;
}
/* Controls */
const speedInput = document.getElementById('speed');
const speedOut = document.getElementById('speedOut');
const zoomIn = document.getElementById('zoomIn');
const zoomOut = document.getElementById('zoomOut');
const MIN_D = 1.55, MAX_D = 8;
const mq = window.matchMedia('(prefers-reduced-motion: reduce)');
let reduced = mq.matches;
let speed = 0;
function syncSpeed() {
speed = (speedInput.value / 100) * 1.2;
speedOut.textContent = speed.toFixed(2) + ' rad/s';
}
if (reduced) speedInput.value = 0;
syncSpeed();
speedInput.addEventListener('input', syncSpeed);
if (mq.addEventListener) {
mq.addEventListener('change', ev => {
reduced = ev.matches;
if (reduced) { speedInput.value = 0; spin = 0; }
syncSpeed();
});
}
let yaw = 0.9, pitch = 0.32, spin = 0;
let dist = 3.6, targetDist = 3.6;
let dragging = false, lastX = 0, lastY = 0, vel = 0;
let dirty = true;
canvas.addEventListener('pointerdown', e => {
dragging = true;
canvas.setPointerCapture(e.pointerId);
lastX = e.clientX; lastY = e.clientY; vel = 0;
canvas.focus({ preventScroll: true });
dirty = true;
});
canvas.addEventListener('pointermove', e => {
if (!dragging) return;
const dx = e.clientX - lastX, dy = e.clientY - lastY;
lastX = e.clientX; lastY = e.clientY;
yaw += dx * 0.0055;
pitch = clamp(pitch + dy * 0.0055, -1.25, 1.25);
vel = dx * 0.055;
dirty = true;
});
function endDrag() {
if (!dragging) return;
dragging = false;
spin = reduced ? 0 : vel * 0.9;
dirty = true;
}
canvas.addEventListener('pointerup', endDrag);
canvas.addEventListener('pointercancel', endDrag);
canvas.addEventListener('lostpointercapture', endDrag);
canvas.addEventListener('wheel', e => {
e.preventDefault();
targetDist = clamp(targetDist * Math.exp(e.deltaY * 0.0012), MIN_D, MAX_D);
dirty = true;
}, { passive: false });
zoomIn.addEventListener('click', () => { targetDist = clamp(targetDist * 0.78, MIN_D, MAX_D); dirty = true; });
zoomOut.addEventListener('click', () => { targetDist = clamp(targetDist * 1.28, MIN_D, MAX_D); dirty = true; });
canvas.addEventListener('keydown', e => {
switch (e.key) {
case 'ArrowLeft': yaw -= 0.09; break;
case 'ArrowRight': yaw += 0.09; break;
case 'ArrowUp': pitch = clamp(pitch - 0.07, -1.25, 1.25); break;
case 'ArrowDown': pitch = clamp(pitch + 0.07, -1.25, 1.25); break;
case '+': case '=': targetDist = clamp(targetDist * 0.82, MIN_D, MAX_D); break;
case '-': case '_': targetDist = clamp(targetDist * 1.22, MIN_D, MAX_D); break;
default: return;
}
e.preventDefault();
dirty = true;
});
function onResize() {
const w = window.innerWidth, h = window.innerHeight;
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
renderer.setSize(w, h, false);
dirty = true;
}
window.addEventListener('resize', onResize);
window.addEventListener('orientationchange', onResize);
/* Render loop */
let last = performance.now();
function tick(now) {
requestAnimationFrame(tick);
const dt = Math.min(0.05, (now - last) / 1000) || 0;
last = now;
if (!reduced && speed > 0) { yaw += speed * dt; dirty = true; }
if (Math.abs(spin) > 0.0005) { yaw += spin * dt; spin *= Math.exp(-2.2 * dt); dirty = true; }
else spin = 0;
if (!reduced && speed > 0) {
updateRing(dt);
ringOrbit.rotation.y += dt * 0.05;
stars.rotation.y -= dt * 0.004;
dirty = true;
}
if (Math.abs(dist - targetDist) > 1e-4) {
dist += (targetDist - dist) * Math.min(1, dt * 7.5);
dirty = true;
}
world.rotation.set(pitch, yaw, 0.07);
camera.position.set(0, 0, dist);
if (dirty) { dirty = false; renderer.render(scene, camera); }
}
requestAnimationFrame(tick);
}
function maxAniso() {}
/* ---------- Boot ---------- */
function hasWebGL() {
try {
const c = document.createElement('canvas');
return !!(c.getContext('webgl2') || c.getContext('webgl'));
} catch (e) { return false; }
}
if (!hasWebGL()) {
fail('WebGL is unavailable in this browser, so the globe cannot be rendered. Try an up-to-date Chrome, Edge, Firefox, or Safari with hardware acceleration enabled.');
} else {
const timer = setTimeout(() => fail('Three.js took too long to load from cdn.jsdelivr.net. Check your network connection and try again.'), 20000);
step('Loading Three.js', 'Fetching the 3D engine from the CDN…');
import(THREE_URL).then(async THREE => {
clearTimeout(timer);
try {
step('Generating terrain', 'Painting continents from procedural noise…');
await nextFrame();
const maps = buildPlanetTextures(THREE);
step('Assembling the scene', 'Building the globe, atmosphere, and orbiting light ring…');
await nextFrame();
init(THREE, maps);
hideStatus();
} catch (err) {
console.error(err);
fail('The scene failed to initialise. ' + (err && err.message ? err.message : ''));
}
}).catch(err => {
clearTimeout(timer);
console.error(err);
fail('The Three.js module could not be downloaded from cdn.jsdelivr.net. Check your connection or any content blocker, then try again.');
});
}
</script>
</body>
</html>
Test 3: Floating-island wizard game
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<title>Skybound Wizard — Floating Isles</title>
<style>
*{box-sizing:border-box}
html,body{margin:0;height:100%;overflow:hidden;background:#bfe6ff;color:#2b2547;
font-family:"Trebuchet MS",ui-rounded,system-ui,Verdana,sans-serif;
-webkit-user-select:none;user-select:none;touch-action:none}
#app{position:fixed;inset:0}
canvas{display:block}
.hud{position:fixed;inset:0;pointer-events:none;padding:12px;z-index:5}
.card{background:rgba(255,255,255,.78);border:2px solid rgba(255,255,255,.9);
border-radius:14px;padding:10px 14px;box-shadow:0 6px 18px rgba(60,50,110,.16);backdrop-filter:blur(4px)}
#topL{position:absolute;top:12px;left:12px;min-width:190px}
#topR{position:absolute;top:12px;right:12px;text-align:right;line-height:1.5}
#topR b{color:#6b3fb5;font-size:1.15em}
.hprow{display:flex;align-items:center;gap:10px}
.bar{width:140px;height:16px;background:#e7e2f5;border-radius:9px;overflow:hidden;border:1px solid #cbc3e8}
.bar>i{display:block;height:100%;width:100%;background:linear-gradient(90deg,#7ef0b0,#4fd1c5);transition:width .12s}
.hprow b{font-size:15px}
#phase{position:absolute;top:96px;left:14px;font-weight:bold;letter-spacing:.06em;color:#4a3f77;text-shadow:0 1px 0 #fff}
#hint{position:absolute;left:50%;transform:translateX(-50%);bottom:12px;font-size:13.5px;
background:rgba(255,255,255,.72);border-radius:999px;padding:7px 16px;white-space:nowrap;
border:1px solid rgba(255,255,255,.9);box-shadow:0 4px 12px rgba(60,50,110,.14)}
#flash{position:fixed;inset:0;pointer-events:none;background:#ff4d6d;opacity:0;z-index:4}
.ov{position:fixed;inset:0;display:none;align-items:center;justify-content:center;z-index:10;
background:radial-gradient(circle at 50% 30%,rgba(180,230,255,.75),rgba(70,60,120,.72));padding:18px}
.ov.show{display:flex}
.panel{max-width:520px;width:100%;background:rgba(255,255,255,.93);border-radius:22px;padding:24px 26px;
text-align:center;box-shadow:0 18px 50px rgba(30,20,70,.35);border:3px solid #fff}
.panel h1{margin:0 0 6px;font-size:34px;color:#6b3fb5;letter-spacing:.02em}
.panel h2{margin:0 0 10px;font-size:27px;color:#6b3fb5}
.panel p{margin:6px 0;font-size:15px;line-height:1.5}
.keys{display:grid;grid-template-columns:1fr 1fr;gap:6px 14px;margin:14px 0 4px;font-size:14px;text-align:left}
.keys b{color:#3d8f8a}
kbd{background:#efeafd;border:1px solid #cbc3e8;border-bottom-width:2px;border-radius:6px;padding:1px 7px;font-size:13px}
button{pointer-events:auto;margin-top:14px;font:inherit;font-weight:bold;font-size:17px;color:#fff;
background:linear-gradient(180deg,#a58bff,#7a5bf0);border:none;border-radius:14px;padding:12px 26px;cursor:pointer;
box-shadow:0 6px 0 #5b42c8,0 10px 18px rgba(60,40,140,.3);transition:transform .08s,box-shadow .08s}
button:active{transform:translateY(4px);box-shadow:0 2px 0 #5b42c8}
.tiny{font-size:13px;color:#5a5178}
#touch{position:fixed;inset:0;display:none;z-index:6;pointer-events:none}
#stick{position:absolute;left:22px;bottom:22px;width:118px;height:118px;border-radius:50%;
background:rgba(255,255,255,.28);border:2px solid rgba(255,255,255,.7);pointer-events:auto}
#knob{position:absolute;left:39px;top:39px;width:40px;height:40px;border-radius:50%;
background:rgba(255,255,255,.85);box-shadow:0 2px 8px rgba(0,0,0,.2)}
#jumpb{position:absolute;right:26px;bottom:34px;width:86px;height:86px;border-radius:50%;pointer-events:auto;
background:rgba(165,139,255,.55);border:2px solid rgba(255,255,255,.8);color:#fff;font-weight:bold;
display:flex;align-items:center;justify-content:center;font-size:15px}
@media (max-width:560px){
.panel h1{font-size:26px}.keys{grid-template-columns:1fr}#hint{font-size:11.5px;bottom:8px;padding:6px 10px}
.bar{width:96px}#topR{font-size:13px}
}
</style>
</head>
<body>
<div id="app"></div>
<div id="flash"></div>
<div class="hud">
<div class="card" id="topL">
<div class="hprow"><div class="bar"><i id="hpfill"></i></div><b id="hplbl">100</b></div>
<div class="tiny" style="margin-top:4px">Health</div>
</div>
<div class="card" id="topR">Score <b id="score">0</b><br>Crystals <b id="crys">0/11</b></div>
<div id="phase">Dawn</div>
<div id="hint">WASD move · Space jump · Drag = orbit camera · Wheel = zoom · Click / F = spell</div>
</div>
<div id="touch">
<div id="stick"><div id="knob"></div></div>
<div id="jumpb">JUMP</div>
</div>
<div class="ov" id="start">
<div class="panel">
<h1>Skybound Wizard</h1>
<p>Collect all <b>11 crystals</b> scattered across the pastel floating isles.</p>
<div class="keys">
<div><b>WASD</b> walk (relative to camera)</div><div><b>Space</b> jump / double-tap hop</div>
<div><b>Mouse drag</b> orbit camera</div><div><b>Wheel</b> zoom in / out</div>
<div><b>Click / F</b> cast bolt (stuns turrets)</div><div><b>Esc / P</b> pause</div>
</div>
<p class="tiny">Watch the elemental guardians. Fall off and you lose health — the realm drags you back to safe ground.</p>
<button id="startBtn">Begin Adventure</button>
</div>
</div>
<div class="ov" id="win">
<div class="panel">
<h2>Victory, Skybound!</h2>
<p id="winTxt">Every crystal gathered.</p>
<button id="winBtn">Play Again</button>
</div>
</div>
<div class="ov" id="lose">
<div class="panel">
<h2>The Void Took You...</h2>
<p id="loseTxt">Your robe is singed, but the islands remain.</p>
<button id="loseBtn">Try Again</button>
</div>
</div>
<div class="ov" id="pause">
<div class="panel">
<h2>Paused</h2>
<p class="tiny">Focus lost — the dream holds its breath.</p>
<button id="resumeBtn">Resume</button>
</div>
</div>
<div class="ov" id="fail">
<div class="panel">
<h2>Something went wrong</h2>
<p id="failmsg">Unable to start the experience.</p>
<p class="tiny">Please check your WebGL support and internet connection (the game needs the Three.js CDN).</p>
<button onclick="location.reload()">Reload</button>
</div>
</div>
<script type="module">
/* ============================ boot ============================ */
const $ = id => document.getElementById(id);
const show = el => el.classList.add('show');
const hide = el => el.classList.remove('show');
const fail = m => { $('failmsg').textContent = m; show($('fail')); };
function webglOK(){
try{
const c = document.createElement('canvas');
return !!(window.WebGLRenderingContext && (c.getContext('webgl') || c.getContext('experimental-webgl')));
}catch(e){ return false; }
}
let THREE = null;
try{
THREE = await Promise.race([
import('https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js'),
new Promise((_, rej) => setTimeout(() => rej(new Error('timeout')), 12000))
]);
}catch(e){
fail('Could not load Three.js from the CDN (' + e.message + ').');
}
if(THREE && !webglOK()){
fail('Your browser or GPU does not support WebGL.');
THREE = null;
}
if(THREE && !failElementShown) start(THREE);
</parameter>
</function>
</tool_call>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Skylands Wizard — Crystal Hunt</title>
<style>
:root{--ink:#2f3260}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%;overflow:hidden;background:#bfe6ff;color:var(--ink);font-family:"Trebuchet MS","Segoe UI",system-ui,sans-serif;touch-action:none;-webkit-user-select:none;user-select:none}
canvas{position:fixed;inset:0;display:block}
#hud{position:fixed;inset:0;z-index:4;pointer-events:none}
.card{background:rgba(255,255,255,.8);border:2px solid #fff;border-radius:14px;padding:7px 12px;font-weight:700;font-size:15px;box-shadow:0 6px 16px rgba(60,70,120,.2);backdrop-filter:blur(5px)}
#topbar{position:absolute;top:12px;left:12px;right:12px;display:flex;gap:10px;justify-content:space-between;align-items:flex-start}
#stats{display:flex;align-items:center;gap:14px}
#hearts{display:flex;gap:5px}
.heart{position:relative;width:16px;height:15px;transition:.2s}
.heart::before,.heart::after{content:"";position:absolute;width:10px;height:15px;background:#ff6f91;border-radius:10px 10px 0 0}
.heart::before{left:6px;transform:rotate(46deg);transform-origin:0 100%}
.heart::after{transform:rotate(-46deg);transform-origin:100% 100%}
.heart.lost::before,.heart.lost::after{background:rgba(120,130,170,.25)}
#hint{position:absolute;left:12px;bottom:12px;font-size:13.5px;max-width:min(600px,74vw);line-height:1.55;font-weight:600}
#hint b{color:#5a4fd0}
#toast{position:absolute;top:72px;left:50%;transform:translateX(-50%) translateY(-8px);font-weight:800;font-size:17px;padding:8px 16px;border-radius:12px;background:rgba(47,50,96,.85);color:#fff;opacity:0;transition:.25s}
#toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
#flash{position:fixed;inset:0;background:radial-gradient(circle,transparent 42%,rgba(255,60,80,.55));opacity:0;pointer-events:none;transition:opacity .4s;z-index:6}
#flash.on{opacity:1;transition:opacity .04s}
.gem{width:12px;height:12px;background:#8ef2ff;transform:rotate(45deg);display:inline-block;box-shadow:0 0 9px #8ef2ff}
.overlay{position:fixed;inset:0;z-index:8;display:grid;place-items:center;padding:18px;background:rgba(120,150,200,.32);backdrop-filter:blur(3px)}
.panel{width:min(580px,94vw);background:rgba(255,255,255,.94);border:3px solid #fff;border-radius:22px;box-shadow:0 22px 60px rgba(40,50,100,.35);padding:24px;text-align:center}
h1{font-size:clamp(22px,4.6vw,34px);letter-spacing:.5px;margin-bottom:6px;background:linear-gradient(90deg,#6c5ce7,#00b4d8,#ff6f91);-webkit-background-clip:text;background-clip:text;color:transparent}
h2{font-size:clamp(20px,4vw,30px);margin-bottom:6px}
p.sub{font-size:14px;opacity:.8;margin-bottom:14px}
.keys{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin:12px 0 18px}
.key{background:#f0f3ff;border:2px solid #d8ddf7;border-radius:10px;padding:6px 10px;font-size:13px;font-weight:700}
.btn{cursor:pointer;border:0;border-radius:14px;padding:13px 26px;font:inherit;font-weight:800;font-size:16px;color:#fff;background:linear-gradient(135deg,#6c5ce7,#00b4d8);box-shadow:0 10px 22px rgba(80,90,200,.35);transition:transform .12s}
.btn:hover{transform:translateY(-2px)}
.btn:active{transform:translateY(1px)}
#endStats{display:flex;flex-wrap:wrap;gap:10px;justify-content:center;margin:14px 0 18px}
#endStats div{background:#f2f5ff;border-radius:12px;padding:8px 14px;min-width:84px}
#endStats b{display:block;font-size:19px}
#endStats span{font-size:11px;opacity:.7;text-transform:uppercase;letter-spacing:.06em}
.hidden{display:none!important}
#fatal .panel{border-color:#ffb3c0;background:#fff5f7}
#fatal h2{color:#d63f5c}
#fatal .detail{font-size:12.5px;opacity:.75;margin-top:8px;word-break:break-word}
@media (max-width:560px){#hint{font-size:12px}.card{font-size:13px;padding:6px 9px}}
</style>
</head>
<body>
<canvas id="game"></canvas>
<div id="hud">
<div id="topbar">
<div class="card" id="stats">
<div id="hearts"></div>
<div>Score <b id="score">0</b></div>
<div style="display:flex;align-items:center;gap:6px"><span class="gem"></span><b id="crystalCount">0</b>/8</div>
</div>
<div class="card"><span id="phase">Day</span> · <b id="timer">0:00</b></div>
</div>
<div id="hint" class="card"><b>WASD</b> move · <b>Space</b> jump · <b>Drag</b> orbit camera · <b>Wheel</b> zoom · <b>P / Esc</b> pause<br>Crystals sit on islands and on the small floating platforms — every one is reachable. Turrets fire on sight, so break line of sight behind islands.</div>
<div id="toast"></div>
</div>
<div id="flash"></div>
<div id="overlay" class="overlay">
<div id="startPanel" class="panel">
<h1>Skylands Wizard</h1>
<p class="sub">Reclaim the 8 crystals of the floating is
Test 4: Accessible task board
tasks.length ? tasks : seedTasks(), which treats an intentional empty list as missing data. Normal nonempty changes survive the simulated reload. The original remains embedded below with this defect intact, so its result is inspectable.<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Task Board</title>
<style>
:root {
color-scheme: light dark;
--bg: #f4f6fb;
--surface: #ffffff;
--surface-alt: #eef1f8;
--text: #1a2033;
--muted: #5b6478;
--border: #d7dce8;
--accent: #2b5cff;
--accent-text: #ffffff;
--danger: #c02525;
--todo: #6b7a99;
--doing: #b06a00;
--done: #1c7a4a;
--focus: #0b3cd4;
--shadow: 0 1px 2px rgba(16, 24, 40, 0.08), 0 4px 12px rgba(16, 24, 40, 0.06);
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #101422;
--surface: #191f31;
--surface-alt: #1f263a;
--text: #eef1f8;
--muted: #a6b0c6;
--border: #2c3category;
--border: #2c3448;
--accent: #7d9bff;
--accent-text: #101422;
--danger: #ff8080;
--todo: #9fb0d0;
--doing: #f0b45c;
--done: #6fd39b;
--focus: #9db6ff;
--shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 6px 16px rgba(0, 0, 0, 0.35);
}
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
background: var(--bg);
color: var(--text);
font: 16px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
padding: 24px 16px 48px;
}
.sr-only {
position: absolute;
width: 1px; height: 1px;
margin: -1px; padding: 0;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
border: 0;
}
.shell { max-width: 1080px; margin: 0 auto; }
header.app { margin-bottom: 20px; }
header.app h1 { font-size: 1.6rem; margin: 0 0 4px; letter-spacing: -0.01em; }
header.app p { margin: 0; color: var(--muted); font-size: 0.95rem; }
.panel {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
box-shadow: var(--shadow);
padding: 16px;
}
form.add-task { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; }
.field { display: flex; flex-direction: column; gap: 6px; flex: 1 1 240px; }
.field label { font-size: 0.85rem; font-weight: 600; color: var(--muted); }
input[type="text"] {
font: inherit;
color: var(--text);
background: var(--surface-alt);
border: 1px solid var(--border);
border-radius: 8px;
padding: 10px 12px;
width: 100%;
}
input[type="text"]::placeholder { color: var(--muted); }
button {
font: inherit;
font-weight: 600;
cursor: pointer;
border-radius: 8px;
border: 1px solid transparent;
padding: 10px 14px;
}
.btn-primary {
background: var(--accent);
color: var(--accent-text);
border-color: var(--accent);
}
.btn-primary:hover { filter: brightness(1.07); }
.btn-ghost {
background: transparent;
color: var(--text);
border-color: var(--border);
}
.btn-ghost:hover { background: var(--surface-alt); }
.btn-danger {
background: transparent;
color: var(--danger);
border-color: var(--danger);
padding: 6px 10px;
font-size: 0.85rem;
}
.btn-danger:hover { background: rgba(192, 37, 37, 0.1); }
:focus-visible {
outline: 3px solid var(--focus);
outline-offset: 2px;
}
.toolbar {
display: flex;
flex-wrap: wrap;
gap: 12px;
align-items: flex-end;
margin: 16px 0;
}
.notice {
margin: 0 0 16px;
padding: 10px 12px;
border: 1px dashed var(--border);
border-radius: 8px;
background: var(--surface-alt);
color: var(--muted);
font-size: 0.9rem;
}
.notice[hidden] { display: none; }
.board {
display: grid;
gap: 16px;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
align-items: start;
}
.column {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
box-shadow: var(--shadow);
padding: 14px;
min-height: 180px;
}
.column-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
margin: 0 0 12px;
padding-bottom: 10px;
border-bottom: 1px solid var(--border);
}
.column-head h2 {
font-size: 1.05rem;
margin: 0;
display: flex;
align-items: center;
gap: 8px;
}
.dot { width: 10px; height: 10px; border-radius: 50%; background: var(--todo); flex: none; }
.column[data-column="doing"] .dot { background: var(--doing); }
.column[data-column="done"] .dot { background: var(--done); }
.count {
font-size: 0.8rem;
font-weight: 700;
color: var(--muted);
background: var(--surface-alt);
border: 1px solid var(--border);
border-radius: 999px;
padding: 2px 10px;
}
ul.tasks { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
li.card {
background: var(--surface-alt);
border: 1px solid var(--border);
border-left: 4px solid var(--todo);
border-radius: 10px;
padding: 12px;
display: grid;
gap: 10px;
}
.column[data-column="doing"] li.card { border-left-color: var(--doing); }
.column[data-column="done"] li.card { border-left-color: var(--done); }
li.card .title { font-weight: 600; overflow-wrap: anywhere; }
li.card .controls { display: flex; gap: 8px; flex-wrap: wrap; }
li.card .btn-move {
background: var(--accent);
color: var(--accent-text);
border-color: var(--accent);
padding: 6px 10px;
font-size: 0.85rem;
}
li.card .btn-move:hover { filter: brightness(1.07); }
li.card .btn-move[aria-disabled="true"] {
background: transparent;
color: var(--muted);
border-color: var(--border);
cursor: not-allowed;
}
.empty {
margin: 4px 0 0;
padding: 14px 12px;
border: 1px dashed var(--border);
border-radius: 8px;
color: var(--muted);
font-size: 0.9rem;
text-align: center;
}
@media (max-width: 520px) {
body { padding: 16px 10px 40px; }
form.add-task { flex-direction: column; align-items: stretch; }
button { width: 100%; }
.toolbar { flex-direction: column; align-items: stretch; }
li.card .controls button { width: auto; }
}
</style>
</head>
<body>
<div class="shell">
<header class="app">
<h1>Task board</h1>
<p>Organize work across three stages. Everything is saved in this browser.</p>
</header>
<p class="notice" id="storage-notice" hidden></p>
<section class="panel" aria-labelledby="add-heading">
<h2 class="sr-only" id="add-heading">Add a task</h2>
<form class="add-task" id="task-form" novalidate>
<div class="field">
<label for="task-title">Task title</label>
<input type="text" id="task-title" name="task-title" placeholder="e.g. Draft agenda" autocomplete="off" maxlength="120" required>
</div>
<button type="submit" id="add-task">Add task</button>
</form>
</section>
<div class="toolbar">
<div class="field">
<label for="task-search">Search tasks</label>
<input type="text" id="task-search" name="task-search" placeholder="Filter by title" autocomplete="off">
</div>
<button type="button" class="btn-ghost" id="reset-demo">Reset demo</button>
</div>
<main class="board" id="board" aria-label="Task board"></main>
</div>
<div class="sr-only" id="live-region" role="status" aria-live="polite" aria-atomic="true"></div>
<script>
(function () {
"use strict";
var COLUMNS = [
{ id: "todo", label: "To do" },
{ id: "doing", label: "Doing" },
{ id: "done", label: "Done" }
];
var ORDER = { todo: 0, doing: 1, done: 2 };
var SEEDS = [
{ title: "Plan launch", status: "todo" },
{ title: "Build prototype", status: "doing" },
{ title: "Write brief", status: "done" }
];
var STORAGE_KEY = "task-board.v1";
var board = document.getElementById("board");
var form = document.getElementById("task-form");
var titleInput = document.getElementById("task-title");
var searchInput = document.getElementById("task-search");
var resetButton = document.getElementById("reset-demo");
var live = document.getElementById("live-region");
var storageNotice = document.getElementById("storage-notice");
function createStore() {
try {
var probe = "__task_board_probe__";
window.localStorage.setItem(probe, "1");
window.localStorage.removeItem(probe);
return {
persistent: true,
read: function () { return window.localStorage.getItem(STORAGE_KEY); },
write: function (value) { window.localStorage.setItem(STORAGE_KEY, value); }
};
} catch (error) {
var memory = null;
return {
persistent: false,
read: function () { return memory; },
write: function (value) { memory = value; }
};
}
}
var store = createStore();
function makeId() {
return "t_" + Date.now().toString(36) + "_" + Math.random().toString(36).slice(2, 8);
}
function sanitizeTask(raw) {
if (!raw || typeof raw !== "object") { return null; }
var title = typeof raw.title === "string" ? raw.title.trim() : "";
var status = Object.prototype.hasOwnProperty.call(ORDER, raw.status) ? raw.status : "";
if (!title || !status) { return null; }
return { id: makeId(), title: title.slice(0, 200), status: status };
}
function seedTasks() {
return SEEDS.map(sanitizeTask);
}
function load() {
var raw = store.read();
if (typeof raw !== "string" || !raw) { return seedTasks(); }
try {
var parsed = JSON.parse(raw);
if (!parsed || !Array.isArray(parsed.tasks)) { return seedTasks(); }
var tasks = parsed.tasks.map(sanitizeTask).filter(Boolean);
return tasks.length ? tasks : seedTasks();
} catch (error) {
return seedTasks();
}
}
function save() {
try {
store.write(JSON.stringify({ tasks: tasks }));
} catch (error) {
store = { persistent: false, read: function () { return null; }, write: function () {} };
showStorageNotice();
}
showStorageNotice();
}
function showStorageNotice() {
if (store.persistent) {
storageNotice.hidden = true;
storageNotice.textContent = "";
} else {
storageNotice.hidden = false;
storageNotice.textContent = "Storage is unavailable, so changes are kept in memory for this session only.";
}
}
var tasks = load();
var searchTerm = "";
function announce(message) {
live.textContent = "";
window.setTimeout(function () { live.textContent = message; }, 30);
}
function matches(task) {
if (!searchTerm) { return true; }
return task.title.toLowerCase().indexOf(searchTerm) !== -1;
}
function createButton(kind, label, hiddenLabel) {
var button = document.createElement("button");
button.type = "button";
button.className = kind === "move" ? "btn-move" : "btn-danger";
button.textContent = label;
if (hiddenLabel) {
var sr = document.createElement("span");
sr.className = "sr-only";
sr.textContent = " " + hiddenLabel;
button.appendChild(sr);
}
return button;
}
function buildColumn(column) {
var section = document.createElement("section");
section.className = "column";
section.dataset.column = column.id;
section.setAttribute("aria-label", column.label);
var head = document.createElement("div");
head.className = "column-head";
var heading = document.createElement("h2");
var dot = document.createElement("span");
dot.className = "dot";
dot.setAttribute("aria-hidden", "true");
heading.appendChild(dot);
heading.appendChild(document.createTextNode(column.label));
var count = document.createElement("span");
count.className = "count";
head.appendChild(heading);
head.appendChild(count);
var list = document.createElement("ul");
list.className = "tasks";
var empty = document.createElement("p");
empty.className = "empty";
empty.hidden = true;
section.appendChild(head);
section.appendChild(list);
section.appendChild(empty);
board.appendChild(section);
return { root: section, list: list, count: count, empty: empty };
}
function render() {
board.textContent = "";
var visibleTotal = 0;
COLUMNS.forEach(function (column) {
var parts = buildColumn(column);
var inColumn = tasks.filter(function (task) {
return task.status === column.id && matches(task);
});
visibleTotal += inColumn.length;
inColumn.forEach(function (task) { parts.list.appendChild(renderCard(task, column)); });
parts.count.textContent = String(inColumn.length);
parts.count.setAttribute("aria-label", inColumn.length + (inColumn.length === 1 ? " task" : " tasks") + " in " + column.label);
if (!inColumn.length) {
parts.empty.hidden = false;
parts.empty.textContent = searchTerm
? "No tasks match \u201C" + searchTerm + "\u201D in " + column.label + "."
: "No tasks in " + column.label + " yet.";
} else {
parts.empty.hidden = true;
parts.empty.textContent = "";
}
});
return visibleTotal;
}
function renderCard(task, column) {
var item = document.createElement("li");
item.className = "card";
item.dataset.taskId = task.id;
var title = document.createElement("p");
title.className = "title";
title.textContent = task.title;
item.appendChild(title);
var controls = document.createElement("div");
controls.className = "controls";
var isLast = ORDER[task.status] === ORDER.done;
var nextColumn = COLUMNS[ORDER[task.status] + 1];
var move = createButton("move", "Move forward", "from " + column.label + (nextColumn ? " to " + nextColumn.label : ""));
if (isLast) {
move.setAttribute("aria-disabled", "true");
move.dataset.blocked = "true";
move.setAttribute("title", "Completed tasks stay in Done");
} else {
move.dataset.taskId = task.id;
move.setAttribute("title", "Move to " + nextColumn.label);
}
move.addEventListener("click", function () {
if (move.getAttribute("aria-disabled") === "true") {
announce(task.title + " is already in Done and cannot move forward.");
return;
}
moveTask(task.id);
});
controls.appendChild(move);
var del = createButton("delete", "Delete", task.title);
del.dataset.taskId = task.id;
del.setAttribute("title", "Delete task");
del.addEventListener("click", function () { deleteTask(task.id); });
controls.appendChild(del);
item.appendChild(controls);
return item;
}
function findTask(id) {
for (var i = 0; i < tasks.length; i++) {
if (tasks[i].id === id) { return tasks[i]; }
}
return null;
}
function moveTask(id) {
var task = findTask(id);
if (!task) { return; }
var next = COLUMNS[ORDER[task.status] + 1];
if (!next) {
announce(task.title + " is already in Done.");
return;
}
var from = COLUMNS[ORDER[task.status]].label;
task.status = next.id;
save();
var total = render();
var target = board.querySelector('[data-task-id="' + id + '"]');
if (target) {
var focusable = target.querySelector("button:not([aria-disabled='true'])");
if (focusable) { focusable.focus(); }
}
announce("Moved " + task.title + " from " + from + " to " + next.label + ". " + total + " tasks shown.");
}
function deleteTask(id) {
var task = findTask(id);
if (!task) { return; }
tasks = tasks.filter(function (item) { return item.id !== id; });
save();
var total = render();
announce("Deleted " + task.title + ". " + tasks.length + " tasks remaining.");
if (total === 0) { searchInput.focus(); }
}
form.addEventListener("submit", function (event) {
event.preventDefault();
var title = titleInput.value.trim();
if (!title) {
announce("Enter a task title before adding.");
titleInput.focus();
return;
}
tasks.push({ id: makeId(), title: title, status: "todo" });
titleInput.value = "";
save();
var total = render();
var first = board.querySelector('.column[data-column="todo"] li.card:last-child');
if (first) {
var focusable = first.querySelector("button:not([aria-disabled='true'])");
if (focusable) { focusable.focus(); }
}
announce("Added " + title + " to To do. " + total + " tasks shown.");
});
searchInput.addEventListener("input", function () {
searchTerm = searchInput.value.trim().toLowerCase();
var total = render();
if (searchTerm) {
announce(total === 0
? "No tasks match " + searchInput.value.trim() + "."
: total + (total === 1 ? " task matches " : " tasks match ") + searchInput.value.trim() + ".");
}
});
resetButton.addEventListener("click", function () {
var ok = window.confirm("Reset the demo board? This removes your current tasks and restores the three seed cards.");
if (!ok) { return; }
tasks = seedTasks();
searchTerm = "";
searchInput.value = "";
titleInput.value = "";
save();
render();
announce("Demo reset. 3 seed tasks restored.");
});
render();
showStorageNotice();
})();
</script>
</body>
</html>
What we checked, and what remains unverified
scripts/check-step5-benchmark.mjs reproduces these checks and the 16 task-board cases using esbuild and jsdom. The task-board checks were written after inspecting its output; they are diagnostic cases, not a preregistered benchmark suite. A failed artifact case is recorded as a benchmark finding; it is not hidden by editing the submission.What this session tells us
Read Next
Ling 3.1 Flash: Free HTML Benchmark and Availability Results
OpenRouter chat produced a detailed glass-crane SVG, while globe requests hit provider rate limits and the game retry returned no visible HTML.
Pareto 26.10 Preview: Pricing, Context, and Vendor Benchmarks
A source-based look at Unbiased’s composite-model preview, its lower token rates, preliminary evaluations, and the implications of a changing serving stack.
DeepSeek V4.1 Flash Review: Three Hands-On Coding Benchmarks
A hands-on DeepSeek V4.1 Flash review covering its 552B MoE architecture, compressed KV cache, official agent benchmarks, and three interactive creative-coding tests.