# husky-bench — a recreate-the-website benchmark A benchmark for coding LLMs that produces a **visually and physically judged** artifact, not a unit- testable one. The task: rebuild `husky-walk`, an animated walking Siberian husky in a scrolling park, as a single static web page. Anatomy, gait direction, layering and secondary motion are the hard parts; they are also the parts a model gets plausibly, silently wrong. Run label: `husky-walk-recreate` --- ## 1. What the model must produce A directory containing exactly: ``` index.html the whole scene as INLINE SVG (no , no canvas, no WebGL, no build step) styles.css theming + all animation app.js state, counters, persistence, particle spawning favicon.svg day icon (explicit width AND height attributes) favicon-night.svg favicon.ico binary fallback README.md user-facing description tools/audit.js headless regression guards (Playwright) tools/poses.js frozen-phase screenshots of every gait tools/responsive.js viewport screenshots, day and night ``` Hard constraints: - **No runtime dependencies, no build step.** `index.html` opened directly (`file://`) must work. - Playwright is allowed **only** under `tools/` (`tools/package.json`, local `node_modules`). - The only image files in the project are the three favicons. - No screenshots or PNGs committed as scene assets. - Runs offline. No fonts, CDNs, or network calls. The benchmark is run by a human or a script that opens the page and reads screenshots. A submission without working verification tooling is scored down even if it looks right, because it cannot be re-checked later. --- ## 2. Required behaviour (the contract) ### 2.1 Scene and coordinate system | Contract | Value | |---|---| | SVG viewBox | `0 0 900 460` — never change it | | Scenery strips | each exactly **900 units** wide, cloned seamlessly with `` | | Background motion | one keyframe per strip: `translateX(0 → -900px)`; speed is a dial, never a re-authored path | | Ground / paw line | `y ≈ 340`; paws land **336–344** | | Dog footprint | `x ≈ 300–620`, head centred near `(560, 180)` | | Contact shadow | ellipse at `(426, 352)` | | Lamppost | post at `x = 664`, glass centred `(667.5, 166)` | | Parallax | four strips (far hills / mid trees / near bushes / dirt), four dials `--glide-far`, `--glide-mid`, `--glide-near`, `--glide-dirt`; **ratio between them is the depth cue and must be preserved when the pace changes** | ### 2.2 Controls - **Four paces**: `stroll`, `walk`, `hop`, `zoomies` (in that order). Buttons and ← / → key cycling must both derive from one ordered list, so they can never drift apart. - **Pause** — stops the gait but **not** the animal: head still looks around, ear still flicks. - **Day / night** — themes the *entire page*, not just the SVG: `` is the single source of truth for chrome and scene. - **Reduced motion** — the scene renders as a correct still frame; an opt-in button (labelled `Start the walk`) is appended to the existing `.controls` container. - **Counters** (distance walked, steps, elapsed, …) driven from the same pace table, and they must keep counting at a rate consistent with the stride frequency. One dial per gait: `--cycle`. Every limb, bob, nod, wag and shadow derives from it. Stroll `1.06s`, walk `0.78s`, hop `0.62s`, zoomies `0.38s`. When a pace changes speed, the four parallax durations are divided by the **same ratio**. ### 2.3 Anatomy (profile view) - The dog faces **right**, so the flank we see is his **right** side. `*-near-*` = right legs, `*-far-*` = left legs. Getting this backwards breaks the hop gag later. - **One eye, one ear, one brow** visible. The near ear must be painted **after** the skull and the white face mask — an ear drawn behind the skull collapses into a horn. - Ear: a broad-based triangle, base ≈42 units, height ≈53, leaning back ≈20°, pivoting at its base. Resize by scaling the whole group about that pivot, never by re-authoring points. - **A foreleg is a chain hinged at the shoulder on the side of the body** — blade (scapula lying on the ribcage) → upper arm → **elbow** → forearm → wrist → paw. The elbow is the *second* joint, not the attachment point. Reference pivots, near leg: `498,214` → `482,252` → `485,340`; far leg `478,212` → `464,250` → `466,340`. - The near foreleg is painted **last, over the head/neck/chest fur**. Overlap is the only depth cue a flat profile drawing gets; a leg painted under the neck coat has its shoulder sheared off. - The scapula is a **filled plane on the body** (low-opacity fill), not a stroked outline or a hollow. A path with no matching fill rule renders **black**. - Upper arm thicker than forearm: `stroke-width` 21 vs 14.5. - The **hind limb is not a mirrored foreleg**: femur leans back, shank leans forward, so it needs its own fold numbers. - Collar encircles **neck + throat** at the base of the neck, tilted ~17° forward, width ≈1/8 of skull width, ends flush with the body outline, front edge disappearing behind the skull. - Underside is **one continuous white bib** from chest to belly (one visual piece from two paths that must overlap), deep enough to have area (~19 units of white above the underside), not a stripe. ### 2.4 Gait physics — the part most models fail - **A paw that is on the ground must travel backward** (leftward, opposite the scroll). Foot lands *in front* of the shoulder, body passes over it, it leaves the ground *behind* him. Sign trap: in a y-down SVG/CSS space a **positive rotation swings a downward-pointing limb backward**, toward the tail. Flip the sign and the dog moonwalks — which looks finished and is wrong. - Stance stops use `linear` timing (a planted foot cannot accelerate). Free-swing stops use `cubic-bezier` so the limb whips and the body dwells at the top of its arc — the dwell is what reads as suspension. - Reference walk: strike at `0%` (limb protracted, elbow near straight), toe-off at `46%` (limb retracted, still straight), swing `46→100%` with the **elbow folded ~60°**, and the limb only straightening in the last few percent so the reach finishes *in the air* and the descent is last. - The paw is a third animated part (`.pawgrp` hinged at the wrist): flexed reaching, flat loaded, extended at toe-off, tucked through the swing. If a rig has three animated leg parts, **all three must appear in every `animation-delay` rule** or a paw runs on a different phase from its shin. - Four contact-shadow dots on the path, one per paw, each with the **exact** computed `animation-delay` of its own leg, and declared **outside** the dog group so they never inherit its bob. - Tail length must be identical across gaits: reach the low streamed tail with **rotation only**. A bounding-box diagonal is not rotation invariant; measure base-to-tip distance through the transform. - Secondary action: tail tip lags the tail, collar tag swings, ears flick, eyes blink, body absorbs the landing. ### 2.5 Gaits, in detail - **stroll / walk** — four-beat walk, diagonal pairs offset by half a cycle, far pair offset ~4% from the near pair to break mechanical lockstep. - **hop** — a *tripod*: the dog's **right foreleg** (the near one) detaches, arcs backwards, lands once on the path behind him and stays gone while hop is selected. One-shot (`fill-mode: both`, never repeating). The detached group must pass far enough left that it clearly reads as separated, and the remaining three limbs beat together while the whole dog springs (peak ≈ −27 units, touchdown ≈ +2, paws still inside the path band). In **still / reduced-motion mode the missing leg must be hidden by CSS, not only by the animation** — a one-shot gag cannot be the only thing hiding a limb. - **zoomies** — a **gallop, not a fast trot**: legs beat in *pairs* (near-front `0`, far-front `−0.1`, near-rear `−0.5`, far-rear `−0.6` of a cycle), knees fold in the air and limbs straighten at the ground beats, body bounce and shadow run at `calc(var(--cycle) * .5)` because full extension happens twice per stride. Tail streamed out low. Tongue blown back. ### 2.6 Extras that are part of the spec - **Shedding**: at hop and zoomies only, clumps of undercoat come loose and tumble behind him (randomised anchor, size, spin, flight time, capped). Never while paused, never in a still scene. - **Hearts** when the dog is happy: transform via custom properties (`--x`, `--y`, `--s`) inside the keyframes, because a CSS animation overrides an SVG `transform` attribute and the hearts then render off-canvas. All hearts must be inside the viewBox. - **Night**: the animal's white underside stays **high-value white**. Do not dim the belly with the rest of the scene; lift/darken coat and trail instead. Reference: `--fur-white:#f4f7fc`, `--coat-dark:#333d52`, `--coat-mid:#48556d`, `--trail:#464e66`. - **Persistence**: day/night remembered across reloads. Cookie `husky-sky` as primary, mirrored to `localStorage` because `file://` rejects cookies and private modes can throw. A synchronous `