Skip to content
LandingPagePrompts
Landing Pagexiaomi/mimo-v2.6-proverified 20/20partial cross-check

Lattice

A slowly rotating gyroid wireframe lattice projected to depth-faded hairlines over a thin horizon glow

The exact prompt

Build one complete, self-contained `index.html` for **Lattice** — a materials-science company that architects gyroid-phase ceramics. Document title: `Lattice — Matter, Architected`. `<html lang="en">`. ONE file only: plain HTML + CSS + JS in `<style>` and one `<script>` at end of body. No build step, no framework, no bundler, no React, Tailwind, GSAP, Three.js, Lottie, jQuery, or external scripts. NO EXTERNAL MEDIA: no mp4/webm/gif, no remote images, no base64 blobs, no third-party CDN URLs. Google Fonts is the ONLY permitted network request (Inter + IBM Plex Mono) with system fallback stacks. Every visible pixel comes from CSS gradients, inline SVG, text, or canvas.

**Viewport rule:** at widths `>= 901px` the page is one frame: `html, body { height:100%; overflow:hidden }` and `.page { height:100dvh; overflow:hidden }`. NO SCROLL on desktop. At widths `<= 900px` the page may scroll vertically. No horizontal overflow at 390x844, 768x1024, 1440x900, or 1920x1080, ever.

**Do NOT build:** no WebGL, no video, no audio, no images, no forms, no newsletter capture, no pricing table, no testimonials, no logos wall, no case-study carousel, no blog feed, no dashboard, no cookie banner, no scroll indicator, no hamburger on desktop (burger only at `<=900px`), no sections beyond the specified header / hero / footer, no footer links beyond the three specified, no second `<h1>`, no `console.log` in the shipped file.

---

## A. WHAT IS BEING BUILT

A single-viewport landing page for **Lattice**, a materials-science company. A full-bleed `<canvas>` renders a slowly rotating 3D wireframe lattice — a cubic node grid whose vertices are Newton-projected onto the gyroid isosurface `F = 0`, so the wireframe reads as an architected minimal surface, not a plain cube. A pinhole camera projects it to 2D; hairline edges are depth-bucketed and alpha-faded so far geometry dissolves and near geometry stays crisp. Behind it a thin horizon glow: a soft band plus a 1px core line dying at both ends. Everything is monochrome — one cold near-white on near-black — precise and technical. Over the field: a compact left-aligned type block (eyebrow, one H1 of two masked lines, one lead sentence, one mono spec readout, two buttons) and a hairline footer with batch status. Composition is asymmetric: type in the left 44%, lattice right-of-centre, never covered by text on desktop.

---

## B. THE BACKDROP — procedural gyroid lattice on canvas (the ONLY visual effect besides the grain)

A single `<canvas id="lattice">` fills the viewport: `position:fixed; inset:0; width:100%; height:100%; z-index:0; display:block; pointer-events:none`. Repainted every animation frame; NEVER a static image.

**Geometry, built ONCE at startup:**

- Node grid: `i, j, k ∈ 0..8` at `(x,y,z) = ((i-4)*0.62, (j-4)*0.62, (k-4)*0.62)`. Spacing 0.62, cube half-extent 2.48, exactly 729 nodes.
- Gyroid field with `a = 0.9`: `F(p) = sin(a x)cos(a y) + sin(a y)cos(a z) + sin(a z)cos(a x)`.
- Analytic gradient: `dF/dx = a cos(a x)cos(a y) - a sin(a z)sin(a x)`; `dF/dy = -a sin(a x)sin(a y) + a cos(a y)cos(a z)`; `dF/dz = -a sin(a y)sin(a z) + a cos(a z)cos(a x)`.
- Newton projection onto `F = 0`: `p' = p - 0.9 * F(p) * grad / |grad|^2`, once per node; skip when `|grad|^2 < 0.05`; clamp displacement length to 0.34. This bends the cubic grid into a gyroid-like saddle mesh.
- Edges: `+x`, `+y`, `+z` neighbours where they exist: `3 * 8 * 9 * 9 = 1944` edges. Nodes in `Float32Array(2187)`, edge pairs in `Uint16Array(3888)`. Nothing is allocated during animation.

**Camera and projection (per frame):**

- Rotation per node, in order: yaw about Y `theta = t * (2*PI/48)` (48s per revolution), pitch about X `phi = 0.42 + 0.10 * sin(t * 2*PI/74)`, roll about Z `psi = 0.06 * sin(t * 2*PI/90)`; `t` = seconds since start.
- Pinhole projection: camera at `z = CAM_Z = 9.0` on the origin; `depth = 9.0 - zRot`; `sx = cx + xRot * f / depth`, `sy = cy - yRot * f / depth`. Focal `f = min(h, w * 1.35) * zoom` with `zoom = 1.0`, or `0.88` at desktop max-height 850px, `0.78` at max-height 720px. Centre: desktop `cx = w * 0.635, cy = h * 0.54`; `<=900px` `cx = w * 0.5, cy = h * 0.42`. At 1440x900 with `f = h` the structure spans `5.56 * 900 / 9 = 556px` = 62% of viewport height, the designed size.

**Depth sorting and fade (the core look):**

- Per node store `sx`, `sy`, `depth`, validity in preallocated `Float32Array(729)` x3 + `Uint8Array(729)`; invalid when `depth < 5.8` or `depth > 12.4` (near cull + fog cutoff).
- Per edge mean depth `dm = (d0 + d1) / 2`; drop the edge if either endpoint is invalid. Bucket `b = floor((dm - 5.8) / (12.4 - 5.8) * 12)` clamped `0..11` (b0 = nearest); push the edge index into one of 12 preallocated `Uint16Array(1944)` buffers with an integer count each — zero allocation per frame.
- Paint buckets 11 (far) → 0 (near): one `beginPath()`, the bucket's `moveTo/lineTo` pairs, one `stroke()`. Exactly 12 stroke calls per frame.
- Stroke: `lineWidth = 1`, `lineCap = 'butt'`, colour `rgba(223, 233, 243, alpha)` where `alpha[b] = 0.03 + 0.29 * pow(1 - b / 11, 1.25)` (near ≈ 0.32, far ≈ 0.03). Cache the 12 `strokeStyle` strings at startup.

**Horizon glow (2 fill primitives, gradients cached on resize):**

- Band: `fillRect(0, cy - h*0.13, w, h*0.26)` with vertical gradient stops `rgba(223,233,243,0) 0%`, `rgba(223,233,243,0.11) 50%`, `rgba(223,233,243,0) 100%`.
- Core line: `fillRect(cx - w*0.36, cy - 0.5, w*0.72, 1)` with a horizontal linear gradient stopped `rgba(223,233,243,0) 0%`, `rgba(223,233,243,0.26) 50%`, `rgba(223,233,243,0) 100%`.
- Both draw BEFORE the wireframe and are built once in `resizeCanvas()` — `createLinearGradient` is never called inside the loop.

**Vignette (1 fill primitive, gradient cached on resize):** full-canvas radial gradient centred `(w/2, h/2)`, radius `max(w,h) * 0.78`, stops `rgba(3,5,8,0) 0%`, `rgba(3,5,8,0.18) 55%`, `rgba(3,5,8,0.62) 100%`, drawn last.

**Per-frame cost budget:** 729 node rotations (~18 flops each) + 729 perspective divides + up to 1944 moveTo/lineTo pairs + 12 strokes + 3 gradient fills = **15 draw calls, ≈ 45k flops per frame**, far under the 20-frames-per-1.2s bar. NEVER call `getBoundingClientRect` in the loop; cache `document.hidden`, canvas and context handles outside it. NEVER set `ctx.filter` or `ctx.shadowBlur`. The glow's softness comes from gradient stops alone.

**Resolution trick:** `canvas.width = cssW * dpr`, `canvas.height = cssH * dpr`, then `ctx.setTransform(dpr,0,0,dpr,0,0)`, with `dpr = Math.min(devicePixelRatio, 2)` at `>=901px`, `Math.min(devicePixelRatio, 1.5)` at `<=900px`. Resize is scheduled by one boolean + rAF flag, never a timer.

**Grain (CSS element):** `.grain` fixed, `inset:-50%; width:200%; height:200%; opacity:0.04`, data-URI inline-SVG `feTurbulence` (`type="fractalNoise" baseFrequency="0.85" numOctaves="2" stitchTiles="stitch"` + `feColorMatrix saturate 0`), tile 180px, `animation: grain 0.95s steps(4) infinite` among offsets `(0,0) (-2%,1%) (1%,-2%) (-1%,2%)`.

---

## C. LAYER STACK (back → front)

1. `html, body` — `#05070a`, with a base gradient `linear-gradient(180deg, #070a0e 0%, #05070a 46%, #030508 100%)` forced twice (see Failure Guards).
2. `canvas#lattice` — z-index 0: horizon glow, 12 depth-sorted wire batches, vignette.
3. `.scrim` — z-index 1, fixed: desktop `linear-gradient(90deg, rgba(5,7,10,0.88) 0%, rgba(5,7,10,0.66) 32%, rgba(5,7,10,0.10) 60%, rgba(5,7,10,0.34) 100%)` (text-protection left, structure breathing right); at `<=900px` `linear-gradient(180deg, rgba(5,7,10,0.55) 0%, rgba(5,7,10,0.20) 40%, rgba(5,7,10,0.80) 100%)`.
4. `.page` — z-index 2, `position:relative; display:grid; grid-template-rows:auto 1fr auto; min-height:100dvh`.
5. `.grain` — z-index 5, pointer-events none.
6. `.menu` — z-index 80 when open (`<=900px` only).
Focus rings stay above local stacking contexts.

---

## D. TOKEN TABLE (defaults at ~1440px)

```
--bg:            #05070a
--bg-deep:       #030508
--bg-top:        #070a0e
--text:          #eef3f8
--muted:         #97a4b0
--dim:           #616e7a
--accent:        #dfe9f3
--accent-dim:    rgba(223,233,243,0.55)
--accent-line:   rgba(223,233,243,0.30)
--accent-fill:   rgba(223,233,243,0.06)
--wire:          rgba(223,233,243,1)
--border:        rgba(255,255,255,0.14)
--border-soft:   rgba(255,255,255,0.08)
--logo:          15px
--logo-mark:     22px
--nav:           13px
--nav-h:         38px
--eyebrow:       11.5px
--h1:            62px
--lead:          16px
--spec:          12.5px
--btn:           13px
--btn-h:         42px
--foot:          12px
--header-y:      26px
--header-x:      44px
--hero-x:        44px
--hero-y:        40px
--hero-max:      640px
--hero-gap:      24px
--copy-gap-h1:   22px
--copy-gap-lead: 24px
--radius-btn:    4px
--focus-w:       2px
--focus-off:     3px
--mono:  "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace
--sans:  "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif
--ease-out:      cubic-bezier(0.16,1,0.3,1)
--enter-dur:     0.95s
--grain-dur:     0.95s
```

Canvas constants mirror the tokens in JS: `NODES_N 9`, `SPACING 0.62`, `GYROID_A 0.9`, `NEWTON 0.9`, `DISPLACE_MAX 0.34`, `CAM_Z 9.0`, `DEPTH_NEAR 5.8`, `DEPTH_FAR 12.4`, `BUCKETS 12`, `YAW_PERIOD 48`, `PITCH_PERIOD 74`, `ROLL_PERIOD 90`, `DPR_MAX 2`, `DPR_MAX_MOBILE 1.5`.

Fonts (Google Fonts ONLY): `Inter:wght@400;500;600` and `IBM+Plex+Mono:wght@400;500`, one `<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>` plus one stylesheet link with `display=swap`.

---

## E. THE COMPOSITION — exact build order

**.page** is the grid container with three rows: `<header>`, `<main>`, `<footer>`.

**HEADER** — `padding: var(--header-y) var(--header-x); display:flex; align-items:center; justify-content:space-between; gap:24px`.

- Left: `a.brand` (href `#`, accessible name "Lattice home"): inline SVG mark 22x22 — a wireframe unit cell: `<path d="M11 2 L20 7 L20 16 L11 21 L2 16 L2 7 Z M11 2 L11 11.5 M11 11.5 L20 7 M11 11.5 L2 7" fill="none" stroke="#dfe9f3" stroke-width="1.3" stroke-linejoin="miter"/>` — then the wordmark `lattice`, `var(--sans); font-size:var(--logo); font-weight:600; letter-spacing:0.14em; text-transform:lowercase; color:var(--text)`, then a blinking underscore `_` in `var(--accent)` (`blink` keyframes, `animation: blink 1.06s steps(1) infinite`).
- Centre: `nav` with exactly 4 links — `01 materials`, `02 process`, `03 research`, `04 index` — all `href="#"`, mono, `font-size:var(--nav)`; container `height:var(--nav-h); display:flex; align-items:center; gap:28px`. Numerals sit in `<span class="num">` at `color:var(--dim)`, words at `color:var(--muted)`. Hover over 0.18s ease: word → `var(--text)`, numeral → `var(--accent)`.
- Right: `a.cta` (href `#`), text `Request data sheet` — mono, `font-size:var(--btn); height:var(--btn-h); padding:0 18px; display:inline-flex; align-items:center; border:1px solid var(--accent-line); border-radius:var(--radius-btn); color:var(--text); background:var(--accent-fill)`. Hover 0.2s ease: `background:rgba(223,233,243,0.13); border-color:var(--accent-dim); box-shadow:0 0 18px rgba(223,233,243,0.14); transform:translateY(-1px)`.

**MAIN (hero)** — `display:flex; flex-direction:column; justify-content:center; align-items:flex-start; padding:var(--hero-y) var(--hero-x); width:100%`; inner `.hero-copy { width:100%; max-width:var(--hero-max) }`. Left-aligned, vertically centred in the 1fr row; on desktop it never exceeds 44vw so it cannot collide with the lattice at `cx = w*0.635`.

1. `.eyebrow` — mono, `font-size:var(--eyebrow); letter-spacing:0.18em; color:var(--dim); text-transform:uppercase`. Exact copy: `LATTICE MATERIALS · ARCHITECTED SOLIDS · EST. 2021`.
2. `h1` — EXACTLY ONE `<h1>`, `var(--sans); font-weight:600; font-size:var(--h1); letter-spacing:-0.045em; line-height:1.04; color:var(--text); margin:var(--copy-gap-h1) 0 0`. Two masked lines (see Motion), exact copy:
   Line 1: `Matter, architected.`
   Line 2: `Down to the unit cell.`
   Line 2 wraps `<em>unit cell</em>` styled `font-family:var(--mono); font-style:normal; font-weight:400; font-size:0.86em; letter-spacing:-0.02em; color:var(--accent)`.
3. `p.lead` — `var(--sans); font-size:var(--lead); line-height:1.6; letter-spacing:-0.012em; color:var(--muted); margin:var(--copy-gap-lead) 0 0; max-width:520px`. Exact copy: `Lattice grows gyroid-phase ceramics whose stiffness is programmed by geometry, then verified one unit cell at a time.`
4. `.spec` — mono, `font-size:var(--spec); color:var(--dim); margin-top:18px; white-space:nowrap`. Exact copy: `G-surface · Si–O system · ρ* 0.42 g/cm³ · E*/E_s 3.1`. The `G-surface` token is `color:var(--accent)`. At `<=560px` the `· E*/E_s 3.1` tail sits in `<span class="opt">` and is hidden so the line never wraps.
5. `.actions` — `display:flex; gap:12px; flex-wrap:wrap; margin-top:30px`. `a.btn.btn--primary` text `Request the data sheet`; `a.btn.btn--ghost` text `Read the method`. Both `href="#"`; treatments in section F.

**FOOTER** — `padding:22px var(--header-x); display:flex; align-items:center; justify-content:space-between; gap:20px; border-top:1px solid var(--border-soft)`.

- Left: mono `var(--foot)`, `color:var(--dim)`: `© 2026 Lattice Materials`.
- Centre: mono `var(--foot)`, `color:var(--dim)`: `SEM batch 07 · released 12 MAR`, preceded by a 7px square status pixel `display:inline-block; margin-right:8px; background:var(--accent); box-shadow:0 0 8px var(--accent-dim)`.
- Right: exactly 3 links `papers`, `patents`, `contact` — mono `var(--foot)`, `color:var(--muted)`, `gap:22px`, `href="#"`, hover `color:var(--text)` over 0.18s.

---

## F. THE UI LANGUAGE

Two button treatments, both squared and instrument-like. `.btn` is `display:inline-flex; align-items:center; justify-content:center; height:var(--btn-h); padding:0 20px; border-radius:var(--radius-btn); font-family:var(--mono); font-size:var(--btn); letter-spacing:0.01em; text-decoration:none; transition: transform 200ms var(--ease-out), background 200ms var(--ease-out), border-color 200ms var(--ease-out), color 200ms var(--ease-out), box-shadow 200ms var(--ease-out)`.

- `.btn--primary`: `color:#05070a; font-weight:500; border:1px solid rgba(255,255,255,0.55); background:linear-gradient(180deg, #f4f8fc 0%, #dfe9f3 55%, #c3cfdb 100%); box-shadow:0 12px 30px rgba(223,233,243,0.12), inset 0 1px 0 rgba(255,255,255,0.7)`. Hover: `background:linear-gradient(180deg, #ffffff 0%, #eaf1f8 52%, #d0dbe6 100%); transform:translateY(-1px); box-shadow:0 16px 38px rgba(223,233,243,0.20), inset 0 1px 0 rgba(255,255,255,0.8)`. Active: `transform:translateY(0)`.
- `.btn--ghost`: `color:var(--text); border:1px solid var(--border); background:rgba(255,255,255,0.03)`. Hover: `border-color:var(--accent-line); background:rgba(223,233,243,0.07); transform:translateY(-1px)`. Active: `transform:translateY(0)`.

The header CTA reuses the ghost family with `background:var(--accent-fill)`. Nav and footer links are plain mono text with numeral prefixes — no pills, no backgrounds, no underlines. Focus: every `a`/`button` gets `:focus-visible { outline:var(--focus-w) solid var(--accent); outline-offset:var(--focus-off); border-radius:2px }`; `::selection { background:rgba(223,233,243,0.22); color:#ffffff }`.

---

## G. MOTION — entrance stagger + named keyframes

All entrance animations: `animation-duration:var(--enter-dur); animation-fill-mode:both; animation-timing-function:var(--ease-out); animation-delay:var(--d, 0.08s)`. Each animated element carries `.appear`, one modifier selecting keyframes, and inline `--d`.

Stagger table (element → modifier → --d):
```
brand            appear--fade   0.08s
nav link 1       appear--fade   0.16s
nav link 2       appear--fade   0.23s
nav link 3       appear--fade   0.30s
nav link 4       appear--fade   0.37s
header cta       appear--chip   0.44s
eyebrow          appear--type   0.52s
h1 line 1        appear--mask   0.66s
h1 line 2        appear--mask   0.80s
lead             appear--soft   0.98s   (duration 1.15s)
spec line        appear--soft   1.12s
primary button   appear--chip   1.24s
ghost button     appear--chip   1.32s
footer left      appear--fade   1.44s
footer centre    appear--fade   1.52s
footer right     appear--fade   1.60s
```

Named keyframes (all end at opacity 1 / identity transform):
```
in-fade   from { opacity: 0 }                                          to { opacity: 1 }
in-soft   from { opacity: 0; transform: translateY(12px) }             to { opacity: 1; transform: none }
in-mask   from { opacity: 0; transform: translateY(104%) }             to { opacity: 1; transform: none }
in-chip   from { opacity: 0; transform: translateY(8px) scale(0.97) }  to { opacity: 1; transform: none }
in-type   from { opacity: 0; clip-path: inset(0 100% 0 0) }            to { opacity: 1; clip-path: inset(0 -4% 0 0) }
blink     0%,49% { opacity: 1 }  50%,100% { opacity: 0 }
grain     0% { transform: translate(0,0) }  25% { transform: translate(-2%,1%) }
          50% { transform: translate(1%,-2%) }  75% { transform: translate(-1%,2%) }
```

H1 masking: each line is `<span class="line"><span class="line-inner appear appear--mask">…</span></span>` with `.line { display:block; overflow:hidden; padding:0.03em 0.06em 0.09em }`, `.line-inner { display:inline-block }`. `in-mask` rises out of that hard edge; `in-type` reveals the eyebrow left-to-right like a typed label. Canvas rotation and grain jitter run continuously, independent of the stagger.

---

## H. RESPONSIVE TABLE — token overrides per breakpoint (exact)

```
>= 1600px:
  --h1: 74px  --logo: 16px  --nav: 13.5px  --btn: 13.5px  --btn-h: 44px
  --lead: 17px  --spec: 13px  --foot: 12.5px
  --header-y: 30px  --header-x: 60px  --hero-x: 60px  --hero-max: 700px

>= 1920px:
  --h1: 86px  --header-x: 76px  --hero-x: 76px  --hero-max: 780px
  --lead: 18px  --nav-h: 42px  --btn-h: 46px

1280px – 1599px:
  --h1: 56px  --header-x: 40px  --hero-x: 40px  --hero-max: 600px

901px – 1279px:
  --h1: 44px  --nav-h: 34px  --header-x: 30px  --hero-x: 30px
  --hero-max: 520px  --lead: 15px  --spec: 12px

>= 901px AND max-height 850px:
  --h1: 46px  --hero-y: 24px  --header-y: 18px  --lead: 15px
  --copy-gap-h1: 16px  --copy-gap-lead: 18px   (spec margin-top 14px, actions margin-top 22px)
  canvas zoom: 0.88

>= 901px AND max-height 720px:
  --h1: 38px  --hero-y: 14px  --header-y: 12px  --eyebrow: 11px
  --lead: 13.5px  --spec: 11.5px  --btn-h: 36px  --foot: 11px
  canvas zoom: 0.78

>= 901px (desktop lock, all heights):
  html, body { height:100%; overflow:hidden }   .page { height:100dvh; overflow:hidden }
  .scrim uses the 90deg gradient; hero-copy max-width never exceeds 44vw

<= 900px:
  no height lock; page may scroll; nav becomes a full-viewport overlay menu:
  - header keeps brand + burger <button class="burger" aria-label="Menu" aria-expanded="false">
    (three 18x1.5px bars in var(--text), gap 5px); the header CTA hides here
  - .menu { position:fixed; inset:0; z-index:80; background:rgba(5,7,10,0.94); backdrop-filter:blur(12px);
    display:flex; flex-direction:column; align-items:flex-start; justify-content:center; padding:0 32px;
    gap:24px; transform:translateY(-100%); transition:transform 0.45s var(--ease-out) }
  - .menu.open { transform:none }; links at --nav: 22px + the CTA chip; Escape, link click, or resize >900px all close it
  canvas: cx = w*0.5, cy = h*0.42, dpr cap 1.5
  --h1: 40px  --header-x: 24px  --hero-x: 24px  --hero-max: 100%  --hero-y: 64px

<= 560px:
  --h1: 32px  --lead: 14.5px  --spec: 11px  --eyebrow: 10.5px  --header-x: 20px  --hero-x: 20px
  .spec .opt { display:none }
  footer becomes flex-direction:column; align-items:flex-start; gap:10px
```

The `min-height:100dvh` stays at every breakpoint; only the `901px+` lock adds `overflow:hidden`. No element exceeds `100vw` at the four required viewports.

---

## I. FAILURE GUARDS — the page is never blank, never broken

1. **Black-first:** the FIRST CSS rule is `html, body { background:#05070a !important; color:#eef3f8 }`; the body tag carries `style="background:#05070a;color:#eef3f8"`; a later rule restates `html, body { background:#05070a; background-image:linear-gradient(180deg,#070a0e 0%,#05070a 46%,#030508 100%) }`.
2. **Resting opacity is 1:** every `.appear` element's un-animated computed style is its final state (opacity 1, no transform, no clip-path). `fill-mode: both` only holds the FROM state during the delay. If animations fail or JS never runs, the page renders complete.
3. **Two-rAF entrance fallback:** after two nested rAF ticks, for every `.appear` run `el.getAnimations({subtree:false})`; if none reports `playState` "running" or "finished", add `.is-in` to ALL `.appear`. If `getAnimations` is missing, apply `.is-in` after the two rAFs. `.is-in { animation:none !important; opacity:1 !important; transform:none !important; clip-path:none !important; filter:none !important }`.
4. **Canvas fallback:** if `canvas.getContext('2d')` returns null or throws, add `.no-canvas` to `<html>`, push the string `'canvas-unavailable'` into `window.__DEMO__.errors`, and CSS paints a static wire substitute: `.no-canvas body { background-image: linear-gradient(rgba(255,255,255,0.06) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.06) 1px, transparent 1px); background-size: 56px 56px; background-position: center; }` plus `.no-canvas .scrim::after` a static 1px horizon `linear-gradient(90deg, transparent, rgba(223,233,243,0.22), transparent)` at `top:54%; height:1px`.
5. **Reduced motion:** inside `@media (prefers-reduced-motion: reduce)`: `*, *::before, *::after { transition:none !important; animation:none !important }`; force `.appear, .line-inner, .eyebrow` to `opacity:1 !important; transform:none !important; clip-path:none !important`; hide `.grain` and the cursor blink; the rAF loop keeps running (`frames` increments) with `t` frozen at 7.5s, painting one identical static frame per tick — readable, static, never blank.
6. **Zero console output:** no `console.*` calls, no thrown exceptions, every canvas call guarded, the geometry builder wrapped so a maths failure degrades to the raw cubic grid.

---

## J. THE EXACT JS (only this, vanilla, one IIFE at end of body)

1. **Telemetry first, before anything else:**
   `window.__DEMO__ = { name: 'lattice', ready: false, frames: 0, effects: [], errors: [] };`
   Push `'gyroid-lattice'`, `'horizon-glow'`, `'grain-texture'` into `effects` in that order, exactly once. Then `window.addEventListener('error', e => window.__DEMO__.errors.push(String(e.message || e)))`.
2. **Build geometry once:** `pts = new Float32Array(2187)`, `idx = new Uint16Array(3888)`, working `rx/ry/rz` and `sx/sy/dd` `Float32Array(729)`, `ok = new Uint8Array(729)`. Fill the 9x9x9 grid at spacing 0.62, Newton-project per section B inside try/catch (on failure keep raw grid points), build the 1944 edge pairs (`+x/+y/+z` neighbours). Allocate 12 `Uint16Array(1944)` bucket buffers + counts and 12 cached `'rgba(223,233,243,' + alpha[b] + ')'` strings with `alpha[b] = 0.03 + 0.29 * Math.pow(1 - b/11, 1.25)`.
3. **Canvas setup:** grab `#lattice`, guard the 2d context (null → `.no-canvas` + one errors push). `resizeCanvas()`: read `innerWidth/innerHeight` (never getBoundingClientRect), `dpr = Math.min(devicePixelRatio, innerWidth <= 900 ? 1.5 : 2)`, set the backing store, `ctx.setTransform(dpr,0,0,dpr,0,0)`, rebuild the three cached gradients and `cx, cy, f` per section B. Resize queues via a boolean + rAF only.
4. **Render loop:** one `requestAnimationFrame` callback. Each tick: `window.__DEMO__.frames++` once; if `document.hidden`, skip paint but keep the loop alive; `t = reduced ? 7.5 : ms/1000`; compute `theta, phi, psi` per section B (sin/cos computed 3 times per frame, not per node); rotate all 729 nodes into `rx/ry/rz`; project to `sx/sy/dd`; validity `5.8 < depth < 12.4`; reset bucket counts, bucket every edge by mean depth; `clearRect(0,0,w,h)`; paint horizon band, horizon core; for `b = 11..0`: `beginPath()`, `moveTo/lineTo` the bucket, `stroke()` at `lineWidth 1`; paint the vignette. On the FIRST completed paint set `window.__DEMO__.ready = true`. NO allocation, NO getBoundingClientRect, NO ctx.filter, NO ctx.shadowBlur, NO gradient recreation in the loop.
5. **Entrance fallback:** two nested rAFs after DOMContentLoaded, then the `.appear` `getAnimations` check and `.is-in` sweep per I.3.
6. **Mobile menu (`<=900px` only):** burger toggles `.menu.open` + `aria-expanded`; Escape, any link click, or resize to `>900px` closes.
7. **Reduced motion:** read `matchMedia('(prefers-reduced-motion: reduce)')` once at startup; when true freeze `t` at 7.5 (loop and `frames` keep running) and hide `.grain` via CSS.

No other JS. No libraries. No timers. No console calls.

---

TECHNICAL CONTRACT (non-negotiable):

1. Deliver ONE single file: a complete, valid `index.html`. No build step, no bundler,
   no framework, no package install. It must open correctly by double-clicking the file
   and also over http://.
2. Vanilla only. No React, no Tailwind CDN, no GSAP, no Three.js, no jQuery, no Lottie.
   Plain HTML + CSS + modern JavaScript in <style> and <script> tags.
3. NO external media. No .mp4, no .webm, no .gif, no remote images, no base64 blobs of
   photos. Every visual must be generated procedurally with CSS gradients, SVG, or
   <canvas>. This keeps the page free to host and impossible to break with a dead link.
4. Google Fonts is the ONLY permitted network request, and it must be declared with a
   <link rel="preconnect"> plus a system-font fallback stack so the page still looks
   intentional offline. If you prefer, skip it and use a pure system stack.
5. Responsive and correct at 390x844 (phone), 768x1024 (tablet) and 1440x900 (desktop).
   No horizontal scrollbar at any of those widths. Nothing may overflow its container.
6. Accessibility: exactly one <h1>; real <header>/<main>/<footer>/<nav> landmarks; every
   interactive element is a <button> or <a> with an accessible name; visible :focus-visible
   ring; body text contrast ratio >= 4.5:1 against its background.
7. Motion safety: wrap all continuous motion in
   `@media (prefers-reduced-motion: reduce)` rules that reduce it to a static or
   near-static state. The page must remain fully readable and usable with motion off.
8. Performance: no layout thrash. Cache DOM reads, batch writes inside a single
   requestAnimationFrame loop, use transform/opacity for animation, and never allocate
   inside the hot loop. Target 60fps on a 2019 laptop. Total file under 90 KB.
9. Runtime telemetry hook (used by the automated verifier — implement it exactly):
   at the top of your script define
     window.__DEMO__ = { name: '<slug>', ready: false, frames: 0, effects: [], errors: [] };
   then set `ready = true` after the first paint of your main effect, increment
   `frames` once per animation frame inside your rAF loop, and push the name of each
   implemented effect into `effects`. Add a `window.addEventListener('error', ...)`
   handler that pushes messages into `errors`. Do not rename these fields.
10. Zero console output in the happy path. No console.log left behind. No uncaught
    exceptions, no failed network requests.

RESPONSE FORMAT:
Return ONLY the raw HTML inside a single ```html fenced code block. No explanation, no
preamble, no commentary before or after the fence. The file must be complete and
immediately runnable — never truncate, never write "// rest of code here".

Acceptance criteria (15)

  1. the document contains exactly one h1 with the text 'Matter, architected. Down to the unit cell.' and uses semantic header, nav, main, and footer landmarks with every anchor and button carrying an accessible name
  2. canvas#lattice paints non-blank 3D wireframe content at 1440x900, its pixels change across consecutive frames, and window.__DEMO__.frames increments exactly once per requestAnimationFrame tick
  3. window.__DEMO__ is initialized with name 'lattice', ready becomes true after the first painted lattice frame, effects contains 'gyroid-lattice' and 'horizon-glow', and errors stays empty in the happy path
  4. the rAF loop sustains at least 20 painted frames within a 1.2s window at 1440x900 headless, and the render loop body never calls getBoundingClientRect, ctx.filter, or ctx.shadowBlur
  5. no horizontal overflow at 390px, 768px, 1440px, or 1920px; at >=901px body has overflow:hidden and .page is 100dvh; a prefers-reduced-motion reduce block forces all entrance elements to opacity 1 and freezes the lattice to a static frame
  6. window.__DEMO__.ready becomes true within 5s
  7. window.__DEMO__.frames advances (>= 20 frames in 1.2s)
  8. window.__DEMO__.errors is empty
  9. zero console errors and zero page errors
  10. zero failed network requests
  11. exactly one <h1> with non-empty text
  12. header, main, footer landmarks present
  13. no horizontal overflow at 390 / 768 / 1440 widths
  14. no horizontal overflow after 2s of animation
  15. prefers-reduced-motion: reduce leaves the page usable and errors empty

More landing page prompts