Same jet.
Two briefs.
Four models.
Four Claude models built the same 3D landing page, blind and one shot each. In one round they got a one paragraph brief. In the other they got a 16KB spec. Fly each build, guess which model made it, then lock in for your score.
- Fly each buildOpen it full screen, then scroll inside the page to fly the jet to the end.
- Name the pilotTag each build with the model you think made it. Each model flies once per round.
- Lock inSee who flew what, your score, and a receipt for every build.
Round 1: The one paragraph brief
Same jet, same clouds, same video. No spec. Just "make it premium, cinematic and memorable, the jet is the star." Every design choice here is the model's own.
What to look for: the story each page tells as you scroll, how it handles type, and how it ends. Fly all four before you tag them.
Round 2: The 16KB spec
The control group. Every hex code, camera keyframe, shader line and easing curve was written out. The test: can each model follow it to the letter, and can you tell them apart?
What to look for: the camera orbit, the radar rings and the caption swap near the bottom. Spot a difference and you're doing better than the test rig.
Four models. One family.
Round 1 gave them total freedom. Nobody told them what to write. Here's what they wrote anyway.
See the sky before you fly it.
Opening headline, word for wordSense. Predict. Advise.
Same three verbs, same sectionTurbulence, called twenty minutes out.
The second one said "fourteen minutes early"Fly ahead of the weather.
Closing line, word for word
Same font, too. All four picked Instrument Serif with an italic accent word. Same mood. All four dropped the bright peach clouds for a dark dusk grade. Unprompted.
Letters are Round 1 builds. Lock in Round 1 to see which models said it.
Fly your own
Run either round yourself and see whose page yours looks like. The Round 1 brief and full Round 2 spec are below.
# Skyra AI Build a single self-contained file, index.html (all HTML, CSS and JS inline, no build step), for a scroll-driven 3D landing page for Skyra AI, a startup that gives pilots predictive AI for safer, more efficient flight. Assets you can use: - Cloud background video (MP4, 1920x1080, 10 s, muted loop): https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20261016_130129_cfe21363-8606-4dd9-a8cc-d19b6c24d2d7.mp4 - Poster still of the same clouds (PNG): https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20261016_130037_46341e32-6cd0-4fac-ad09-00d747e2f806.png - 3D jet model (GLB, white glossy business jet with orange accents, Y-up): https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20261017_132803_66d7da07-a6ef-4081-976a-8cd35f92833c.glb - External libraries may load from cdn.jsdelivr.net. Fonts may load from Google Fonts. Make it feel premium, cinematic and memorable. The jet is the star. Everything else (sections, copy, layout, motion, color, interaction) is your call.
Build a single self-contained file, index.html (all HTML, CSS and JS inline, no build step), for a two-section, scroll-driven 3D landing page called "Skyra AI". Recreate it EXACTLY as specified below — same copy, colors, sizes, timings and math. Do not add sections, copy or libraries beyond what is listed.
========================================
1. ASSETS (use these exact URLs, loaded directly)
========================================
- Cloud background video (MP4, 1920x1080, 10 s, 16:9, muted loop):
https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20261016_130129_cfe21363-8606-4dd9-a8cc-d19b6c24d2d7.mp4
- Poster / fallback still of the same clouds (PNG):
https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20261016_130037_46341e32-6cd0-4fac-ad09-00d747e2f806.png
- 3D jet model (GLB, white glossy business jet with orange T-tail, orange rear twin engines, orange fuselage stripe, orange winglets, Y-up, single mesh):
https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20261017_132803_66d7da07-a6ef-4081-976a-8cd35f92833c.glb
- Three.js r160 via import map (ES modules):
"three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js"
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
Import THREE, GLTFLoader (three/addons/loaders/GLTFLoader.js) and RoomEnvironment (three/addons/environments/RoomEnvironment.js).
- Font: Google Fonts "Manrope" weights 300;400;500;600, display=swap, with preconnect to fonts.googleapis.com and fonts.gstatic.com (crossorigin).
========================================
2. HEAD
========================================
<html lang="en">, meta charset utf-8, meta viewport "width=device-width, initial-scale=1".
<title>Skyra AI — Airborne Safety</title>
========================================
3. CSS (exact)
========================================
:root tokens:
--ink: #1c1a18;
--ink-soft: rgba(28,26,24,0.72);
--orange: #ff7a1f;
--orange-deep: #f2650b;
--sky: #f3e3d0;
--glass: rgba(255,255,255,0.28);
--glass-line: rgba(255,255,255,0.55);
* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body { font-family: "Manrope", system-ui, sans-serif; color: var(--ink); background: var(--sky); overflow-x: hidden; -webkit-font-smoothing: antialiased; }
Fixed stage (sits behind everything):
.stage { position: fixed; inset: 0; z-index: 0; pointer-events: none; }
.stage video, .stage .poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.stage .poster { background: center / cover no-repeat; }
.stage canvas { position: absolute; inset: 0; width: 100% !important; height: 100% !important; }
.stage .tint { position: absolute; inset: 0; background: radial-gradient(120% 80% at 50% 45%, rgba(255,240,225,0) 40%, rgba(240,214,190,0.35) 100%); }
Stacking inside .stage, bottom to top: .poster div, <video>, WebGL canvas, .tint.
Nav:
nav { position: fixed; top: 0; left: 0; right: 0; z-index: 20; display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; padding: 14px 30px; }
nav .links { display: flex; gap: 30px; }
nav .links.right { justify-content: flex-end; align-items: center; }
nav a { color: var(--ink); text-decoration: none; font-size: 16px; font-weight: 400; transition: opacity .25s; }
nav a:hover { opacity: .6; }
.logo { display: block; width: 42px; height: 42px; }
.btn { display: inline-flex; align-items: center; justify-content: center; height: 50px; padding: 0 37px; border-radius: 999px; background: var(--orange); color: #fff !important; font-size: 16px; box-shadow: 0 8px 24px rgba(255,122,31,0.28), inset 0 1px 0 rgba(255,255,255,.35); transition: background .25s, transform .25s, opacity .25s !important; }
.btn:hover { background: var(--orange-deep); transform: translateY(-1px); opacity: 1 !important; }
Scroll track:
main { position: relative; z-index: 10; }
section { position: relative; height: 150vh; } (#hero and #tracking are both 150vh → total page 300vh)
.headline { position: absolute; top: 17vh; left: 0; right: 0; text-align: center; font-weight: 400; font-size: clamp(34px, 3.6vw, 48px); line-height: 1.12; letter-spacing: -0.035em; will-change: transform, opacity; }
Section-2 header (fixed, fades in by JS):
.s2-head { position: fixed; top: 92px; left: 0; right: 0; z-index: 15; text-align: center; opacity: 0; transform: translateY(12px); pointer-events: none; will-change: opacity, transform; }
.s2-head small { display: block; font-size: 11px; letter-spacing: .02em; color: var(--ink-soft); }
.s2-head h2 { font-size: 19px; font-weight: 500; letter-spacing: -0.02em; margin: 2px 0 8px; }
.s2-head p { font-size: 11px; color: var(--ink-soft); margin-bottom: 8px; }
.s2-head .icons { display: flex; justify-content: center; gap: 7px; }
.s2-head .icons span { width: 18px; height: 18px; border-radius: 5px; display: grid; place-items: center; background: rgba(28,26,24,.72); color: #fff; font-size: 9px; font-weight: 600; }
.s2-head.on { pointer-events: auto; }
Glass caption pill (fixed, two stacked texts that crossfade):
.pill { position: fixed; z-index: 15; left: 50%; bottom: 80px; transform: translateX(-50%); width: min(494px, calc(100vw - 32px)); height: 100px; border-radius: 999px; background: var(--glass); border: 1px solid var(--glass-line); backdrop-filter: blur(14px) saturate(1.2); -webkit-backdrop-filter: blur(14px) saturate(1.2); box-shadow: 0 10px 40px rgba(170,120,80,.12), inset 0 1px 0 rgba(255,255,255,.6); display: grid; place-items: center; text-align: center; }
.pill p { grid-area: 1 / 1; font-size: 19px; line-height: 1.42; letter-spacing: -0.015em; color: #2c2925; padding: 0 40px; will-change: opacity, filter; }
.pill p.b { opacity: 0; }
Mobile (max-width: 760px):
nav { padding: 12px 16px; }
hide every left nav link except the first ("Craft"), and hide right-side links that are not .btn ("Story")
.btn { height: 42px; padding: 0 22px; font-size: 14px; }
.pill { height: 84px; bottom: 40px; }
.pill p { font-size: 15px; padding: 0 24px; }
.headline { top: 15vh; padding: 0 16px; }
========================================
4. HTML (exact structure and copy)
========================================
<div class="stage" id="stage">
<div class="poster" id="poster"></div>
<video id="bg" autoplay muted loop playsinline preload="auto"></video>
<div class="tint"></div>
</div>
<nav>
<div class="links left">
<a href="#hero">Craft</a>
<a href="#tracking">Highlights</a>
<a href="#tracking">Connect</a>
</div>
<a href="#hero" aria-label="Skyra AI home">
<svg class="logo" viewBox="0 0 48 48" fill="none" aria-hidden="true">
<path d="M17 13c-6 4-9.5 11-8 17.5 1.3 5.7 6.4 8.4 11.6 6.8 6.8-2.1 11.4-9.6 12.6-17.6" stroke="#1c1a18" stroke-width="4.2" stroke-linecap="round"/>
<path d="M26.5 21.5 34 8l5.5 14.5-6.7-3.3-6.3 2.3Z" fill="#1c1a18"/>
<path d="M22 16.5c-2.6 3.8-3.7 8.5-3 13" stroke="#1c1a18" stroke-width="3" stroke-linecap="round"/>
</svg>
</a>
<div class="links right">
<a href="#tracking">Story</a>
<a class="btn" href="#tracking">Request</a>
</div>
</nav>
<main>
<section id="hero">
<h1 class="headline" id="headline">The next era of flight safety<br />enabled by Skyra AI</h1>
</section>
<section id="tracking"></section>
</main>
<div class="s2-head" id="s2head">
<small>Live intel from</small>
<h2>Skyra Predictive Avionics</h2>
<p>Join us in the sky</p>
<div class="icons"><span>in</span><span>X</span><span>◎</span></div>
</div>
<div class="pill" id="pill">
<p class="a">Equipping pilots with intelligent AI for safer, more efficient flight</p>
<p class="b">Live aircraft monitoring and forward-looking insights</p>
</div>
========================================
5. BACKGROUND JS
========================================
Set #poster backgroundImage to the poster PNG URL. Set video.src to the MP4 URL and video.poster to the PNG URL.
========================================
6. THREE.JS SCENE
========================================
Renderer: WebGLRenderer({ antialias: true, alpha: true }); pixelRatio = min(devicePixelRatio, 2); size = window; outputColorSpace = SRGBColorSpace; toneMapping = ACESFilmicToneMapping; toneMappingExposure = 1.05. Insert the canvas inside .stage directly before .tint.
Environment: PMREMGenerator(renderer).fromScene(new RoomEnvironment(), 0.04).texture → scene.environment. No scene background (transparent, so the video shows through).
Camera: PerspectiveCamera(fov 30, aspect window, near 0.1, far 200).
Lights:
HemisphereLight(0xfff3e6, 0xf0c8a0, 1.3)
DirectionalLight "sun" (0xffe8d2, 2.4) at (-4, 8, 6)
DirectionalLight "rim" (0xffb27a, 1.2) at (6, 2, -6)
Jet hierarchy: scene → jetPivot (scroll-driven yaw/bank) → jetBob (idle float) → holder → GLB scene.
Convention: jet nose points along local +X, up = +Y.
GLB load (GLTFLoader):
model.rotation = Euler(0, Math.PI, 0) // makes the GLB nose point +X
put model in a "holder" Group; compute Box3 of holder → size, center
s = 4.6 / max(size.x, size.z) (jetLength = 4.6)
model.position.sub(center); holder.scale.setScalar(s)
for every mesh material: envMapIntensity = 1.1; roughness = min(roughness, 0.45)
engine points (for contrails): L = size.x*s, Hh = size.y*s, Wd = size.z*s →
(-L*0.2, Hh*0.04, Wd*0.1) and (-L*0.2, Hh*0.04, -Wd*0.1)
rebuild contrails at those points, then add holder to jetBob.
Contrails (one per engine point, children of jetBob):
ShaderMaterial { transparent: true, depthWrite: false, side: DoubleSide, uniforms { uTime: 0, uOpacity: 0.75 } }
vertex: pass uv as vUv; standard projection.
fragment:
along = vUv.x (0 at engine, 1 at the far end); across = abs(vUv.y - .5) * 2.
width = mix(.25, 1., along)
core = 1. - smoothstep(0., width, across); core *= core
fade = pow(1. - along, 1.4) * smoothstep(0., .05, along)
flicker = .9 + .1 * sin(along * 40. - uTime * 18.)
col = mix(vec3(1., .93, .84), vec3(1.), along)
gl_FragColor = vec4(col * 1.25, min(1., core * fade * flicker * uOpacity * 1.6))
Geometry: PlaneGeometry(9, 0.55); translate(-4.5, 0, 0) so it extends backwards (-X); flip the UV x (u = 1 - u) so u=0 sits at the engine. Make a second copy rotated rotation.x = PI/2 (crossed planes). Group both, position = enginePoint + (-0.42, 0, 0).
Glow ring under the jet (hero):
ShaderMaterial { transparent: true, depthWrite: false, NormalBlending, uniforms { uOpacity: 1, uFill: 0.35, uColor: Color(0xff7a2a) } }
fragment:
r = length(vUv - .5) * 2.
rimLine = 1. - smoothstep(0., .06, abs(r - .9))
halo = (1. - smoothstep(0., .35, abs(r - .9))) * .55
fill = (1. - smoothstep(.2, 1., r)) * uFill
col = mix(uColor, vec3(1., .97, .92), rimLine * .55)
a = (rimLine + halo + fill) * (1. - smoothstep(.93, 1., r))
gl_FragColor = vec4(col, a * uOpacity)
Mesh PlaneGeometry(3.6, 3.6), rotation.x = -PI/2, position.y = -0.85, added to scene (not to the jet).
Radar group (section 2): Group at y = -0.85, added to scene.
4 thin white rings: RingGeometry(r - w, r + w, 160), rotation.x = -PI/2, MeshBasicMaterial white, transparent, opacity 0, depthWrite false.
(r, w) = (2.6, 0.035), (4.3, 0.03), (6.4, 0.025), (9.0, 0.02); max opacities = 0.85, 0.7, 0.55, 0.4.
Pulse: clone of the glow-ring material with its own cloned uniforms, uColor = white, uFill = 0.55; PlaneGeometry(1,1), rotation.x = -PI/2.
16 tiny aircraft markers: PlaneGeometry(0.32, 0.32) lying flat (rotation.x = -PI/2), MeshBasicMaterial with a canvas texture, transparent, opacity 0, depthWrite false; tint 0xff7a2a for every 4th marker (i % 4 === 0), else white.
Marker texture: 128x128 canvas, translate(64,64), white fill, path:
moveTo(0,-50) quadraticCurveTo(7,-40,7,-18) lineTo(48,6) lineTo(48,14) lineTo(7,4) lineTo(6,32) lineTo(18,42) lineTo(18,48) lineTo(0,42) lineTo(-18,48) lineTo(-18,42) lineTo(-6,32) lineTo(-7,4) lineTo(-48,14) lineTo(-48,6) lineTo(-7,-18) quadraticCurveTo(-7,-40,0,-50) fill.
CanvasTexture with SRGBColorSpace.
Placement uses a seeded PRNG (mulberry32, seed 7):
function mulberry(a){return()=>{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;};}
per marker, in this order: ring = 1 + floor(rand()*3); r = [2.6,4.3,6.4,9.0][ring] + (rand()-0.5)*0.5; a = rand()*2PI; speed = (0.02 + rand()*0.05) * (rand() > 0.5 ? 1 : -1); delay = rand()*0.25.
========================================
7. SCROLL + ANIMATION LOGIC (per frame, requestAnimationFrame)
========================================
Helpers:
ease(t) = t < .5 ? 4t³ : 1 - (-2t+2)³/2 (easeInOutCubic)
clamp01, range(p,a,b) = clamp01((p-a)/(b-a)), lerp
Scroll progress: target = clamp01(scrollY / (document.documentElement.scrollHeight - innerHeight)), updated on passive scroll and on resize.
Smoothing: dt = min(clock delta, 0.05); prog += (target - prog) * (1 - 0.0015^dt). p = prog.
Mouse: normalized -1..1 from pointermove; mouseS lerps toward it by (1 - 0.02^dt).
Camera keyframes:
A (hero): pos (0.3, 1.05, 11.2), lookAt (0, 0.25, 0)
B (tracking): pos (0.0, 12.8, 9.6), lookAt (0, -0.9, -0.2)
k = ease(range(p, 0.08, 0.92))
fit = aspect < 1 ? 1 + (1 - aspect) * 1.1 : 1 (pulls back on portrait/mobile)
camPos = lerp(A.pos, B.pos, k) * fit; camLook = lerp(A.look, B.look, k)
camPos.x += mouseS.x * 0.35; camPos.y += -mouseS.y * 0.2; camera.lookAt(camLook)
Jet:
jetPivot.rotation.y = lerp(3.42, 2.42, k) (hero: nose to lower-left toward viewer → section 2: nose to upper-left)
jetPivot.rotation.x = lerp(0.12, -0.04, k) (bank)
jetPivot.rotation.z = lerp(0.06, 0.0, k) (pitch)
jetBob.position.y = sin(t*0.9)*0.06; jetBob.rotation.x = sin(t*0.7)*0.025; jetBob.rotation.z = sin(t*0.55+1)*0.015
contrail uTime = t
Glow ring (leaves the hero):
r1 = range(p, 0, 0.3); scale = 1 + ease(r1)*2.6
opacity = (1 - ease(r1)) * (0.9 + sin(t*2.2)*0.1)
position.y = -0.85 + jetBob.position.y * 0.4
Radar (enters section 2):
r2 = ease(range(p, 0.5, 0.95)); radar.scale = lerp(0.35, 1, r2)
ring i opacity = ease(range(p, 0.5 + i*0.07, 0.75 + i*0.07)) * maxOpacity[i]
pulse: cycle = (t*0.35) % 1; scale = lerp(2.2, 11, cycle); opacity = range(p, 0.55, 0.75) * (1 - cycle) * 0.75
markers: vis = ease(range(p, 0.62 + delay, 0.82 + delay)); angle = a + t*speed;
position (cos(angle)*r, 0.01, sin(angle)*r); rotation.z = -angle + (speed > 0 ? 0 : PI); opacity = vis * 0.9
DOM:
headline opacity = 1 - range(p, 0, 0.22) (it also scrolls up naturally)
pill text A: outA = range(p, 0.3, 0.42) → opacity 1 - outA, filter blur(outA*6 px)
pill text B: inB = range(p, 0.48, 0.6) → opacity inB, filter blur((1 - inB)*6 px)
section-2 header: sIn = ease(range(p, 0.72, 0.9)) → opacity sIn, transform translateY((1 - sIn)*12 px); toggle class "on" when sIn > 0.5
Render scene every frame. On resize: update camera aspect + projection, renderer size, re-read scroll.
========================================
8. EXPECTED RESULT
========================================
Section 1 (top): warm peach cloud video full-bleed; fixed nav (Craft · Highlights · Connect | black swoosh-arrow logo centered | Story + orange "Request" pill button); centered two-line headline; the white/orange jet hovers in the center, nose pointing left toward the viewer, with soft white contrails streaming to the right from the engines and an orange glowing ellipse ring beneath it; frosted glass caption pill at the bottom.
While scrolling: the headline fades out, the orange ring expands and dissolves, the camera smoothly orbits up to a high top-down view while the jet turns so its nose points up-left, the pill text blurs out and the new caption blurs in.
Section 2 (bottom): concentric white radar rings grow in under the jet with a repeating white pulse wave and small orange/white plane icons slowly orbiting on the rings; a small centered header ("Live intel from / Skyra Predictive Avionics / Join us in the sky" + three tiny dark icon squares) fades in under the nav.
The jet always floats gently and the camera shifts slightly with the mouse. Mobile: compact nav (Craft, logo, Request), smaller pill and button, camera pulls back so the wings fit.
House rules
- Identical inputEvery model read the same brief file, checked by fingerprint below.
- One shotWrite the page once. No browser preview, no testing, no second pass.
- IsolatedEach model ran as its own agent with the same tools and couldn't see the others' work.
- Blind judgingThe test rig ran on Opus 5.5, which is also an entrant. So this page names no winner. You do.
- What's measuredBuild time is wall clock from first read to file written. Page size is the single HTML file. Token counts are left out because about 115k of every run was fixed agent overhead.
- Brief fingerprintsRound 1 briefsha256 c0ddfb15f5237a341a14299bb63e7b86dedf9966ee70fe12aef03cf9595d27c8Round 2 specsha256 cf03a3e9a48878922a852c8296aaacf490dc835538a33e865277d3dad5c70f5a