feat(site): landing redesign — product-led - #527
Draft
omridevk wants to merge 65 commits into
Draft
Conversation
… assets Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ures, alignment pass Framework tabs get back an interaction-triggered animated indicator (smoothui animated-tabs pattern), the how-it-works pnpm-dev block becomes a filename-bar + copy terminal block (21st code-block layout, no react-syntax-highlighter — a single plain command line has nothing to highlight), capability figures wrap in shadcn Card stripped back to a plain 1px border frame per the tile rule, ProductFrame's chrome bar gets a centered url field and its 40px top margin restored, and the principles/capability/how-it-works/open-source sections share one py-16 vertical rhythm.
…blic/ module imports
Vite's dev server hard-errors on importing a JSON module from public/
("Assets in public directory cannot be imported from JavaScript") --
capability-section.tsx and how-it-works.tsx were doing exactly that
since Task 4/5 and it only surfaced now under real browser testing.
public/screenshots/index.json stays as the spec's documented
reproducibility record; src/data/screenshots-index.json is now the
single importable copy the two components actually read from.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…component sourcing rules Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nks; rigid zoom/rotate motion full-bleed under the rules Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…delayed count bump and +1 float; CSS transitions on the link group, reserved count width Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…m) on one baseline, mark centred on x-height, subtle group hover; used in nav, footer, docs header Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ain h2s, ≤14-word captions, no em-dashes, footer blurb no longer repeats the hero, symmetric hero padding, reserved-width ledger count Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ator 200ms ease-out, magic-move 250ms/no stagger, tile hover bar 160ms, per-theme shader alpha (0.10 light / 0.16 dark) with a wider quiet zone, 60ch balanced hero lede, CSS comments removed Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…single lightbox affordance, active links, touch targets Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…count skeleton Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… delays focus like hover), reachable and labelled Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tions and contrast table Spec: rewrite the provenance table against the files as they now stand (every hand-written row carries its justification), update the Components lists, and re-cut the page-structure copy to what the components actually render. Critique: append the skills applied by all three agents, the fixes since the critique with commit hashes, the compare iterations with remaining differences versus zed.dev, and a line-by-line disposition of both Codex reviews. Plan: tasks 0-6 done, 7-9 in progress with the exact commands. DESIGN.md: Hallmark exceptions with their reasons, the measured accent contrast table, the hero padding decision, the motion token ladder, the touch-target rule, and the serif boundary. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… centre on them The page and column rules are borders, so their 1px width shifted every coordinate: the column ruled 161/1278 instead of 160/1279 and inset text started at 210 instead of 208. The gutter and inset now subtract the rule they sit behind, and the node squares move to -3px so their centre falls on the rule centre instead of 1px outside it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…the type scale A divide rule takes its pixel out of the cell that carries it, so the last cell in every row was 1px wider: the two screenshots in a row rendered at different scales and their captions sat 0.63px apart. The last cell now carries a transparent rule of its own, so every cell in a row is exactly as wide as its neighbours. The ledger inherited a 19.5px line box from the table's own text size; it now takes the 13/20 caption slot, which also squares its rows at 36px. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rift too slow to register at 24fps 0fa119a kept the figure in place but left only a 30s brightness wave (floor 0.45, phase 0.7/iteration) and one contour band per 45s: over 3s that changed 0.06% (light) to 0.4% (dark) of the hero band pixels at threshold 8, below what a viewer notices. The wave now runs a 10s period with a 1.1/iteration phase gradient and a 0.3 floor, and the contour levels drift one band per 20s. Motion stays inside the figure (no rotation, zoom or drift of the set). Measured over the hero band at 1440x900: 4.7% (dark) / 1.9% (light) of pixels changed in 3s, 5.7% / 3.1% in 5s in both Chromium and Firefox, ~106-111 draws per 5s, reduced motion 0 draws and 0% change. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…henticated on every request and hit the 60/hour IP limit
The route had no server-side cache (the cache-control header only steered browsers), so dev reloads, tests and captures
exhausted GitHub's shared 60 requests/hour per IP, the API answered 403, the route returned `stars: null`, and the
three-state count rendered its "unavailable → blank slot" branch. The count element itself was fine: stubbing the
route to `{"stars":4}` rendered "4" in the same build.
The worker now keeps the upstream count in the Cache API (`caches.open('github-stars')`, fresh for an hour, kept for a
week) and refreshes it at most once an hour per data centre; when GitHub fails it serves the last known count instead of
null. Verified on the dev server: first call 648 ms and one GitHub request, the next four 5-9 ms with `used` still 1;
Chromium and Firefox render "GitHub 4" + "4 stars on GitHub". IT: the nav button shows the count /api/stars reports.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…en unavailable Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ied by eye Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…demo hint contrast, hover docs wrap, accent-text token - package-installer tabs: the active trigger's aria-controls pointed at a content id that never rendered (axe aria-valid-attr-value, critical); the command row is now the TabsPrimitive.Content panel - shiki light theme github-light → github-light-high-contrast for the landing snippets and the docs (github-light keywords/comments/parameters fail 4.5:1 on the docs code background and parameters fail on panel) - fumadocs --color-fd-muted-foreground overridden to hsl(0 0% 40%): the neutral default measures 4.35 on its own background - demo transcript hint drops the /60 and /70 alpha (2.97 / 3.48 → pass) - twoslash hover code wraps instead of scrolling (scrollable-region-focusable) - new --od-accent-text token (= --od-accent today) used for accent-as-type, so the brand accent can return for fills without failing AA on text; DESIGN.md carries the measured table and the flip recipe Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@axe-core/playwright 4.13.0 (exact) scans / at 1440×900 and 390×844, light and dark via the real theme toggle, in five states (initial, footer in view, capability tile hovered, lightbox open, framework twoslash hover card open) plus /docs once. Serious/critical violations and any color-contrast violation fail the test; the message lists rule, impact, target, html and failure summary per node. Legacy axe mode because the fixture's browser.newPage() context cannot spawn axe's blank finish page. A keyboard order test tabs through the whole landing page and asserts every stop is visible, in the viewport and shows a focus ring, and that the nav, theme toggle and capability tiles are reachable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The headline test now records console.error text with its source location and page errors with their stack, and prints the list in the assertion message. Flake RCA (5 green e2e runs, no repro) in scratchpad/flake-rca.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
try-live-button takes main's event-bus client (PR #521) with the landing action-row styling; hero keeps the redesign layout and gains main's mobile desktop-only hint; mobile-gating and live-connect tests merged (exact button name, hydration wait before the pre-mount click). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Variant A of the Codex-1 restructure, owner-approved from the mock: two mirrored 7/5 stories (grab-element, edit-live) with a serif h3, one-line body and three code-verified numbered facts, then a four-up evidence strip with equal-height MediaFrame tiles. Spec v5 and critique doc updated; landing-sections IT asserts the new structure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Redesigns the landing site around product demonstrations, structured editorial styling, responsive navigation, and server-rendered GitHub metrics.
Changes:
- Rebuilds landing content, navigation, screenshots, demo framing, and visual system.
- Adds accessible UI primitives, responsive interactions, and browser-based coverage.
- Introduces cached GitHub star resolution and removes legacy effects.
Reviewed changes
Copilot reviewed 99 out of 113 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
pnpm-lock.yaml |
Updates fonts, accessibility tooling, and removed dependencies. |
docs/superpowers/plans/2026-08-15-landing-redesign-plan.md |
Adds implementation plan and status. |
apps/site/package.json |
Updates site dependencies. |
apps/site/README.md |
Documents star-count caching. |
apps/site/source.config.ts |
Uses high-contrast code themes. |
apps/site/vitest.e2e.config.ts |
Enables TypeScript path resolution. |
apps/site/scripts/highlight-snippets.ts |
Generates highlighted install and framework snippets. |
apps/site/test/a11y.it.test.ts |
Adds accessibility and keyboard tests. |
apps/site/test/landing-install-command.it.test.ts |
Tests installer interactions. |
apps/site/test/landing-page.ts |
Adds landing hydration helpers. |
apps/site/test/live-connect.it.test.ts |
Updates live-connect interaction waits. |
apps/site/test/mobile-gating.it.test.ts |
Tests mobile demo gating. |
apps/site/test/seo-metadata.it.test.ts |
Updates star-link SSR assertion. |
apps/site/test/site-fixture.ts |
Supports configurable Wrangler variables. |
apps/site/test/star-count-unavailable.it.test.ts |
Tests unavailable star counts. |
apps/site/test/wrangler-dev.ts |
Passes variables to Wrangler. |
apps/site/src/routes/__root.tsx |
Adds star loader and site-wide motion. |
apps/site/src/routes/api/stars.ts |
Uses cached star resolver. |
apps/site/src/routes/docs/$.tsx |
Uses redesigned GitHub button. |
apps/site/src/lib/layout.shared.tsx |
Uses the shared brand mark. |
apps/site/src/lib/motion-features.ts |
Exposes Motion features. |
apps/site/src/lib/motion-tokens.ts |
Removes obsolete motion tokens. |
apps/site/src/lib/package-installer-store.ts |
Stores package-manager selection. |
apps/site/src/lib/screenshots.ts |
Adds screenshot-manifest lookup. |
apps/site/src/lib/star-count-resolver.server.ts |
Adds upstream star caching. |
apps/site/src/lib/star-count-store.ts |
Adds client star refresh state. |
apps/site/src/lib/star-count.functions.ts |
Exposes star-count server function. |
apps/site/src/lib/use-is-mobile.ts |
Makes mobile detection hydration-safe. |
apps/site/src/lib/use-media-query.ts |
Adds tri-state media queries. |
apps/site/src/lib/use-star-count.ts |
Combines loaded and refreshed counts. |
apps/site/src/data/screenshots-index.json |
Adds screenshot metadata. |
apps/site/src/components/brand-mark.tsx |
Adds shared product branding. |
apps/site/src/components/github-stars-button.tsx |
Adds the GitHub star action. |
apps/site/src/components/not-found.tsx |
Uses redesigned GitHub action. |
apps/site/src/components/site-motion.tsx |
Promotes motion provider site-wide. |
apps/site/src/components/AnimatedContent.tsx |
Removes legacy entrance effects. |
apps/site/src/components/ClickSpark.tsx |
Removes click-particle effects. |
apps/site/src/components/Magnet.tsx |
Removes magnetic hover effects. |
apps/site/src/components/SplitText.tsx |
Removes animated text splitting. |
apps/site/src/components/VariableProximity.tsx |
Removes proximity typography. |
apps/site/src/components/ui/animated-tabs.tsx |
Adds shared animated tabs. |
apps/site/src/components/ui/browser-frame.tsx |
Adds browser-style demo framing. |
apps/site/src/components/ui/card.tsx |
Removes unused card subcomponents. |
apps/site/src/components/ui/code-block.tsx |
Adds reusable code chrome. |
apps/site/src/components/ui/copy-button.tsx |
Adds copy success and failure states. |
apps/site/src/components/ui/dialog.tsx |
Adds lightbox dialog primitives. |
apps/site/src/components/ui/github-mark.tsx |
Adds the GitHub logo. |
apps/site/src/components/ui/github-stars.tsx |
Adds star presentation and hover effects. |
apps/site/src/components/ui/media-frame.tsx |
Adds screenshot mats and lightboxes. |
apps/site/src/components/ui/message-circle-icon.tsx |
Removes legacy animated icon. |
apps/site/src/components/ui/mouse-pointer-2-icon.tsx |
Removes legacy animated icon. |
apps/site/src/components/ui/package-installer-tabs.tsx |
Adds installer tabs and command display. |
apps/site/src/components/ui/pen-icon.tsx |
Removes legacy animated icon. |
apps/site/src/components/ui/plug-connected-icon.tsx |
Removes legacy animated icon. |
apps/site/src/components/ui/separator.tsx |
Adds separator primitive. |
apps/site/src/components/ui/sheet.tsx |
Adds mobile navigation sheet. |
apps/site/src/components/ui/shield-check.tsx |
Removes legacy animated icon. |
apps/site/src/components/ui/site-header.tsx |
Adds responsive header structure. |
apps/site/src/components/ui/table.tsx |
Adds ledger table primitives. |
apps/site/src/components/ui/terminal-icon.tsx |
Removes legacy animated icon. |
apps/site/src/components/ui/theme-switch.tsx |
Adds redesigned theme control. |
apps/site/src/components/ui/types.ts |
Removes obsolete icon types. |
apps/site/src/components/landing/bundler-band.tsx |
Removes the legacy bundler carousel. |
apps/site/src/components/landing/capability-section.tsx |
Adds screenshot-led product stories. |
apps/site/src/components/landing/copy-button.tsx |
Removes duplicate copy implementation. |
apps/site/src/components/landing/demo/app-preview.tsx |
Restyles the demo preview. |
apps/site/src/components/landing/demo/composer.tsx |
Aligns demo composer typography. |
apps/site/src/components/landing/demo/demo.tsx |
Reframes the live demo and readiness handoff. |
apps/site/src/components/landing/demo/grab-reference.tsx |
Updates demo reference typography. |
apps/site/src/components/landing/demo/message-row.tsx |
Updates transcript typography. |
apps/site/src/components/landing/demo/transcript.tsx |
Updates demo guidance styling. |
apps/site/src/components/landing/features-section.tsx |
Removes the legacy feature cards. |
apps/site/src/components/landing/github-star-link.tsx |
Removes the old star link. |
apps/site/src/components/landing/hero-backdrop.tsx |
Lazily mounts the hero shader. |
apps/site/src/components/landing/hero-shader-sources.ts |
Adds hero GLSL programs. |
apps/site/src/components/landing/hero-shader.tsx |
Adds managed WebGL rendering. |
apps/site/src/components/landing/hero.tsx |
Rebuilds hero copy and actions. |
apps/site/src/components/landing/how-it-works.tsx |
Rebuilds the installation steps. |
apps/site/src/components/landing/install-chip.tsx |
Removes the old installer chip. |
apps/site/src/components/landing/install-command.tsx |
Adds animated installer commands. |
apps/site/src/components/landing/landing-page.tsx |
Composes the redesigned landing page. |
apps/site/src/components/landing/magic-move-options.ts |
Centralizes snippet motion options. |
apps/site/src/components/landing/open-source-strip.tsx |
Adds open-source metrics ledger. |
apps/site/src/components/landing/principles-strip.tsx |
Adds product principles. |
apps/site/src/components/landing/product-frame.tsx |
Adds poster-gated live demo. |
apps/site/src/components/landing/robot-fab.tsx |
Removes the legacy interactive mascot. |
apps/site/src/components/landing/site-footer.tsx |
Rebuilds the footer index. |
apps/site/src/components/landing/site-nav.tsx |
Rebuilds responsive navigation. |
apps/site/src/components/landing/smooth-scroll.tsx |
Removes custom smooth scrolling. |
apps/site/src/components/landing/spark-mark.tsx |
Simplifies brand-mark motion. |
apps/site/src/components/landing/theme-toggle.tsx |
Removes the old theme toggle. |
apps/site/src/components/landing/try-live-button.tsx |
Restyles the live-demo action. |
apps/site/public/screenshots/index.json |
Publishes screenshot metadata. |
apps/site/public/icons/bun.svg |
Adds Bun branding. |
apps/site/public/icons/npm.svg |
Adds npm branding. |
apps/site/public/icons/pnpm.svg |
Adds pnpm branding. |
apps/site/public/icons/yarn.svg |
Adds Yarn branding. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| tabIndex={0} | ||
| role="button" | ||
| aria-label={anchor.hover ? `Type of ${anchor.hover.target}` : 'Completions'} | ||
| onFocus={() => setOpen(true)} |
Comment on lines
+3
to
5
| let refreshed: number | null = null | ||
| let started = false | ||
| const listeners = new Set<() => void>() |
Comment on lines
+56
to
+66
| async function refreshStarCount(stale: CachedStars | null): Promise<number | null> { | ||
| const stars = await fetchStarCount() | ||
| if (stars === null) return stale === null ? null : stale.stars | ||
| await writeCachedStars(stars) | ||
| return stars | ||
| } | ||
|
|
||
| export async function resolveStarCount(): Promise<number | null> { | ||
| const cached = await readCachedStars() | ||
| return isFresh(cached) ? cached.stars : refreshStarCount(cached) | ||
| } |
Comment on lines
+27
to
+47
| function readStored(): PackageInstaller { | ||
| const stored = window.localStorage.getItem(STORAGE_KEY) | ||
| return isPackageInstaller(stored) ? stored : DEFAULT_INSTALLER | ||
| } | ||
|
|
||
| function getSnapshot(): PackageInstaller { | ||
| if (current === null) current = readStored() | ||
| return current | ||
| } | ||
|
|
||
| function subscribe(onChange: () => void): () => void { | ||
| listeners.add(onChange) | ||
| return () => listeners.delete(onChange) | ||
| } | ||
|
|
||
| export function selectPackageInstaller(value: string): void { | ||
| if (!isPackageInstaller(value)) return | ||
| current = value | ||
| window.localStorage.setItem(STORAGE_KEY, value) | ||
| for (const listener of listeners) listener() | ||
| } |
Comment on lines
+37
to
+38
| <TableCell className="px-0 text-muted-foreground">stars</TableCell> | ||
| <TableCell className="px-0 text-right tabular-nums">{formatStarCount(stars)}</TableCell> |
Comment on lines
+7
to
+8
| const TILT_DEGREES = -8 | ||
| const GROW = 0.06 |
Comment on lines
+11
to
+12
| Tasks 0 to 6 are done and committed on `feat/landing-redesign`. Nothing is pushed. Tasks 7, 8 and 9 | ||
| are in progress in the current pass, split across three agents working on the same worktree. |
Comment on lines
+60
to
+61
| const STRIP_GRID = | ||
| 'grid grid-cols-1 divide-y border-t lg:grid-cols-4 lg:divide-x lg:divide-y-0 lg:[&>*:last-child]:border-r lg:[&>*:last-child]:border-r-transparent' |
Comment on lines
+21
to
+22
| <p className="od-caption mt-4 text-muted-foreground md:hidden"> | ||
| The live try-it flow needs a terminal, so it's desktop-only.{' '} |
| {tryButtonLabel({connected: isConnected, pending: busState === 'connecting'})} | ||
| </Button> | ||
| </div> | ||
| <Button variant="outline" size="lg" onClick={open} aria-busy={busState === 'connecting'} className="max-md:hidden"> |
…orph motion The hero backdrop rendered its backing store at DPR 1 and upscaled it on retina, and computed isoline width with a widen*1.5 heuristic, so the filigree read as pixelated mush. It now renders at device DPR (capped at 2) with analytic anti-aliasing: the distance to the nearest isoline is measured in device pixels through fwidth, giving a ~1.4 device-px line, and a second fwidth gate fades a band out once its neighbours fall below ~2 device px, which removes the moire. The budget for 4x the pixels comes from a zoom-adaptive iteration cap (clamp(64 + 12*log2(zoom), 32, 96) against a 96 loop bound), an early return in the headline quiet zone, mediump defaults with highp only on the iteration coordinates, a 12 fps cap, and per-frame allocation-free uniform updates. Net GPU cost at DPR 2 is 0.80 ms/draw versus 1.09 ms/draw for the old shader at the same resolution. Motion is rebuilt around three variants: morph (default) walks the Julia parameter along an arc of the cardioid so the figure continuously changes shape, morph-dive adds a slow zoom, dive keeps a fixed parameter and zooms only. The travelling luminance pulse and the breathing are gone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s (rings default) Replace the animated WebGL fractal with a static inline SVG engraving: no GL context, no rAF, no per-frame work. Three seeded variants behind HERO_ENGRAVING_VARIANT — rings (nested rotated rounded polygons, default), rosette (guilloche bands) and contours (frozen topographic isolines). Lines are currentColor hairlines (non-scaling-stroke, crisp at DPR2) faded out behind the headline by a radial mask. Line alpha drops to 0.05 light / 0.08 dark so the figure is visible when looked for and invisible when reading. The shader IT becomes a stillness contract: the engraving renders and a backdrop-only strip is pixel-identical across a 2s window, with and without reduced motion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Raise the default ring figure from 18 to 30 nested pentagons and tighten the radial growth from 1.168 to 1.10 so the extra rings land inside the band instead of extending it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 7px markers were offset 1px inward from the rule they mark, because the -3px inset ignored the 1px rule the marker straddles. Derive the inset from the marker size and rule width so the marker centre lands on the rule centre at every DPR. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add a 14px full-width strip between the principles, capability, how-it-works and open-source sections: hairline rules top and bottom, a faint 14px cell grid in between and the existing node diamonds on the page and column rule crossings. CSS background only, no motion, no JS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ngraving Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pads the demo frame inside its band so the band reads around it, and puts a luminous-silt flow-field field behind it, bounded by the column rules. The backdrop is a small port of Radiant's luminous-silt technique (MIT, github.com/pbakaus/radiant): seeded Perlin flow field, particles advected along it, trails accumulated with a destination-out fade so the canvas stays transparent. Recoloured to the accent via --od-silt-tint/--od-silt-alpha, with multiply in light and screen in dark. Renders at 0.4x and drifts at 30fps, pausing offscreen and on a hidden tab; reduced motion gets a settled still frame. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The product-frame backdrop now picks its effect from a typed variant map instead of a bare alias, and the active variant is a compact port of Paper Shaders' Dithering / Warp: a warped noise ridge field quantised into 2.5px blocks and ordered-dithered through a 4x4 Bayer matrix, recoloured to the accent tokens so the wrapper's multiply/screen blend carries both themes. Silt stays in the map for A/B. Because the pattern is block-quantised, the fragment shader renders one pixel per block and the canvas is upscaled with image-rendering: pixelated — 1.04ms per draw under software GL instead of 18.5ms at device resolution, capped at 12 fps, paused offscreen and on a hidden tab, static under prefers-reduced-motion, with no per-frame allocation. Time is wrapped to the shader's own 4pi period so highp never drifts. The demo frame padding drops to a flat 0.5rem on every side and breakpoint. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port React Bits Ferrofluid (MIT) to the site's raw-WebGL runtime shape: no ogl dependency, the original GLSL with the picker's parameters baked in, and the picker's palette mapped onto the accent/ink frame tokens. Pointer input is replaced by a slow lissajous attractor so the field drifts on its own. Shared canvas plumbing (guards, program helpers) moves into frame-canvas and shader-program, so the ribbon and dithering variants stop repeating it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port the grain term of Paper Shaders' GrainGradient (grain-gradient fragment, @paper-design/shaders@0.0.80, Apache-2.0) with the shape/blob machinery dropped: simplex base noise, the fbm-modulated speckle and the Blob preset's intensity/noise weights, tinted ink and drawn once into a WebGL layer. No rAF loop — the field is static, exactly as in the source where only the shape term reads u_time. The layer covers the page from the top edge through the principles strip and its spacer and stops at the product frame's top rule, hidden under 768px with the rest of the decor. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rule Paint the grain above the section backgrounds instead of behind them so it reads across the outer gutters and through the principles strip, and derive the band bottom from the spacer element that opens the hatch strip. The band now tracks layout: the resize observer watches the container, the spacer, and main, so late font and demo reflows move the edge instead of leaving a stale one. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The band is a fixed, viewport-sized overlay from nav to footer with no stop element, and its horizontal extent comes from an .od-page wrapper, so the grain lands exactly between the two outer vertical page rules and never bleeds into the margins outside them. Drops the grainStop marker and the spacer ref along with it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The band drops to z-index -1 so it reads as paper the page is printed on rather than a film over it. Section backgrounds are already translucent tints, so every band from nav to footer still shows the grain through. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A live WebGL canvas composited under translucent sections cost around 8ms a frame while scrolling in Firefox. The shader now draws once into a detached canvas, that canvas is encoded to a blob the band shows through an img, and the GL context is lost right after the encode, so scrolling composites a static bitmap. Re-rasterizes on the same size changes as before and revokes the previous object url each time. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
product-led system: 1120px column with 112px ruled gutters and node markers, six-size type scale (13/14/16/17/26/48), Newsreader italic h1 + Geist + JetBrains Mono, paper/ink/red tokens with measured AA contrast, real product screenshots on hairline mats, and a live in-browser demo behind an SSR poster that only hands over once the demo reports ready. Every visible element is sourced from a registry component or listed as hand-written with a justification (provenance table below).
Docs:
docs/superpowers/specs/2026-08-15-landing-redesign-design.md(spec v5 + provenance),docs/superpowers/specs/2026-08-16-landing-critique.md(critique, skills applied, fixes, compare iterations, codex review #1/#2 dispositions),docs/superpowers/plans/2026-08-15-landing-redesign-plan.md,apps/site/DESIGN.md(tokens, layout, Hallmark exceptions, contrast table, motion tokens).Before / after
scratchpad/landing-full.png(attached separately by the owner lane)scratchpad/landing-evidence/{1440,390}-{light,dark}-{viewport,full}.png(zero page errors; the only console noise at 1440 isERR_CONNECTION_REFUSEDfrom the try-live local-server discovery probe, pre-existing and on hold in another lane)scratchpad/compare-01.png,compare-02.png,copy-hero-2up.png,hero-shader-2-2up.pngscratchpad/pixel-audit.md(25 checks: 19 ok, 6 fixed, 0 open; light/dark geometry identical)Provenance
navbar)ui/site-header.tsx,landing/site-nav.tsxSparklefill-currentin accent, nudgedtranslate-y-[0.09em]onto the x-height centre, "conciv" in Geist 16/700 tracking -0.02em; CSS hover rotates 4deg and scales 1.04 over 200ms on the whole linkcomponents/brand-mark.tsx,landing/spark-mark.tsxgithub-stars-animation/api/starsviauseStarCount); theuseSpringcount is kept; tokensui/github-stars.tsx,components/github-stars-button.tsx--od-ease-out, count bump and "+1" delayed 100ms, reduced-motion drops all of it. Owner keeps the fill, tilt and +1ui/github-stars.tsxui/count-skeleton.tsxswitch-buttonwas adopted then gutted: its gradient surface, shine hover and 360deg icon spin all failed the Hallmark gates, so what remains is a flat outline button with a 160ms colour transition. Listed as shadcn, not kokonutuiui/theme-switch.tsxui/site-header.tsx,ui/sheet.tsxLinkactiveProps/inactiveProps/activeOptions; the router suppliesaria-currentitself, so no hand-rolled active statelanding/site-nav.tsx,landing/site-footer.tsxBeta · Open sourcelanding/hero.tsxlanding/hero.tsx,app.css .od-h1/.od-ledearia-hidden, hidden below 768pxlanding/hero-backdrop.tsx,landing/hero-shader.tsx,landing/hero-shader-sources.tsui/animated-tabs.tsxwith pm icons; command box has a min-width set from the widest command so the buttons never shift; persisted choice store; tokensui/package-installer-tabs.tsx,landing/install-command.tsx,lib/package-installer-store.tsanimated-tabson Radix TabslayoutIdindicator retimed to 200mscubic-bezier(0.23, 1, 0.32, 1)with no spring and nooriginY; underline / pill / segment variants; reduced motion sets duration 0ui/animated-tabs.tsx@shikijs/magic-moveShikiMagicMovePrecompiledscripts/highlight-snippets.ts; 250ms, stagger 0, instant under reduced motionlanding/install-command.tsx,landing/magic-move-options.ts,landing/framework-snippets.gen.tsbutton-copyfailedstate with an X icon and live-region text added; tokensui/copy-button.tsxmd, label changes once the widget reports connectedlanding/try-live-button.tsxnext/imagedropped, square corners flush to the rules), so it is listed as hand-written layout rather than as an adopted componentui/browser-frame.tsxopacity-0overlay crosses in only when the demo callsonReady, 500ms opacity on--od-ease-out,motion-reduce:transition-none, poster keepsaria-hiddenoff until readylanding/product-frame.tsx,landing/demo/demo.tsxlanding/product-frame.tsxululof ruled cells with a realh3and a one-line 13/20 fact, 24px vertical padding, no wrapper componentlanding/principles-strip.tsxfiguredivwhere a heading belonged; the cell is now a plainfigurewithh3+ caption insidefigcaptionlanding/capability-section.tsxlineoutside a 1px solid frame at 2px radius (2026-08-16, 1440x900); ours reproduces it. One button per tile carries the image and a decorative slide-up label (160ms, hover-capable pointers only, none under reduced motion); the lightbox is a shadcn Dialogui/media-frame.tsx,ui/dialog.tsxlanding/capability-section.tsx<ol>rows, 96px numeral column, step 3 on a measured 2:1 grid with equal heightslanding/how-it-works.tsxui/animated-tabs.tsx+ shadcn Select (belowsm) + shadcn Badge (soon/alpha)soonentrieslanding/framework-tabs.tsxopenDelay700ms /closeDelay250ms, but controlledopenso keyboard focus opens instantly; anchors are focusable and labelled; hover markup renders from aSnippetToken[][]structure, neverdangerouslySetInnerHTMLui/hover-card.tsx,landing/framework-tabs.tsxreact-syntax-highlighterdropped for the precompiled shiki magic-move and twoslash hovers already in the repo; tokensui/code-block.tsx,landing/framework-tabs.tsxpnpm dev)ui/code-block.tsx,landing/how-it-works.tsxui/media-frame.tsxinfillmodelanding/how-it-works.tsxui/table.tsx,landing/open-source-strip.tsxlanding/open-source-strip.tsxfooter-3was adopted and then gutted (newsletter, socials, entrance and the whole three-column grid removed), which left no registry structure to claim. Both Codex reviews called the column grid a link farm, so the footer is now brand + sentence + seven nowrap links in one rowlanding/site-footer.tsxlanding/site-footer.tsxapp.css .od-page/.od-col/.od-inset/.od-ruled.od-hitgrows the hit area to 44px on coarse pointers with a pseudo-element, so visible chrome keeps its Zed proportionsapp.css .od-hitTests
pnpm exec turbo run test --filter=site --force: 10 files, 47 tests passedpnpm exec turbo run test:e2e --filter=site --concurrency=1: 6 files, 42 tests passed (real Chromium against the built site viawrangler dev): overflow ladder 320/375/414/768/1024/1280/1440, reduced-motion shader static, poster persistence until demo-ready (desktop + reduced motion + iPhone gating), lightbox keyboard flow (Enter/Escape/focus return), rapid tab interrupt (pm tabs + framework tabs), install command copy/persist, widget mount/gating, live connectGates
pnpm --filter site typecheckclean;pnpm --filter site lintclean;pnpm formatcleanpnpm exec fallow audit --changed-since main --format json: verdict pass, 0 introduced (dead code / complexity / duplication)21st review apps/site/src/components/landing: 4 findings, all reviewed and kept (2 false positives onmax-w-*, hardcoded white/CLI: real verb descriptions from one catalog, guarded by a registry test #222 on the demo ghost cursor glyph, owner-approved 1.04 spark hover)pnpm exec conciv-publish check-changesets --require-coverage --base origin/main: exit 0 (site is private, no changeset required)Follow-ups
scratchpad/capability-mock-a.png, waiting for the owner's go; current 2/3/1 grid keptdata-conciv-sourceline numbers from a stale SSR module) is dev-server only; the built site has none🤖 Generated with Claude Code