Skip to content

feat(site): a tilted table of the examples as the home page hero - #45

Merged
Zach Dunn (zachdunn) merged 3 commits into
mainfrom
feat/site-hero-table
Oct 16, 2026
Merged

Zach Dunn (zachdunn) merged 3 commits into
mainfrom
feat/site-hero-table

Conversation

@zachdunn

@zachdunn Zach Dunn (zachdunn) commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

The home page hero now shows what the skill makes. Under the headline, each example is laid out as a cluster on a tilted table:

  • The post: a tall page.
  • Two of its figures: pulled out beside the post, each with a leader line to where it sits.
  • The deck and the video.
  • The room (Sunny's cluster only): the room from Sunny's post, as a 3D model, with a camera orbiting it.

The camera settles on one cluster, glides to the next, and wraps back to the first. A chip types out the request that made the cluster in view, and a pager under it (a bar per cluster, named only for screen readers) jumps to any cluster. Pointing at an object lifts it off the table.

How it's built

  • One three.js scene. site/assets/hero/hero.js draws everything; the positions live in layout.js. The chip and pager are plain HTML over the canvas.
  • Usage line: the /buildnotes [post | video | deck] what to explain template sits in a code box like the install command. On a narrow screen it breaks only before the brief, which hangs under the output word, so it still reads as one command.
  • Rendering: the scene renders only when something changes. That's every frame during a glide or lift, 30 fps while the hero is on screen, and nothing when it's scrolled away or the tab is hidden. It renders at up to 1.25× the screen's density, into a 2× multisampled target.
  • Images: each image is cut to the width it's drawn at, in a desktop size and a phone size. The GPU holds images decoded whatever their file format, so pixel count is what costs memory.
  • Poster: a baked poster of the Sunny view shows until the scene is ready. It stays, with the pager hidden, under reduced motion or without WebGL.
  • site/hero.mjs: cuts the images from site/hero/src/ and bakes the posters with Chrome, the same way card.mjs renders its link-preview cards. Its output is committed, so the site build still needs nothing installed.
  • three.js r160: served from the site itself, like the fonts, through an import map. Its LICENSE file sits next to it.
  • room.glb: exported from site/hero/room.blend.
  • Build: site/build.mjs copies site/assets/hero/ whole, because the script loads its own files.
  • Worker: wrangler.jsonc now routes the hero's videos through the Worker too, for HTTP Range responses. Safari won't play an MP4 without them.

What it costs

These are from headless Chrome on an M3 Max GPU, with three runs each, measured on prototypes of this design before the port.

  • Glide: the hero holds 60 fps on desktop. A CSS 3D version of the same design dropped to about 30 fps in two of three runs.
  • GPU memory: at rest, the hero roughly doubles the home page's GPU memory over a blank page. On desktop it's about 125 MB before and about 275 MB after; on phones (390 px) about 63 MB before and about 170 MB after.
  • Compared with other sites: on desktop, stripe.com and linear.app each use about 470–525 MB over a blank page.
  • Downloads: about 160 KB compressed for three.js, 350 KB for the model, 0.9 MB of video in total (only the video in view loads), and 0.5 MB of images and posters.

Screenshots

Before After
Home page before: the headline, install command and usage line, then the Sunny example section Home page after: the same headline, with the tilted table of examples starting under the usage line

The table at 1440 px, with Sunny's cluster in view:

The hero's table at 1440 px: Sunny's cluster with its video, deck, 3D room, post and figures, and the chip and pager below

390 px 390 px, reduced motion (the poster)
The hero's table at 390 px With reduced motion at 390 px: the baked poster, and no pager

Checks

  • npm test passes. One new test checks that the import map, the scene, the model, the videos, both image sizes and the posters all reach the build.
  • Checked in Chrome at 1440 px and 390 px:
    • the scene renders, glides and wraps back to the first cluster;
    • hovering lifts objects;
    • there's no horizontal scroll;
    • the reduced-motion and no-WebGL posters line up with the live scene.
  • Not checked on a real phone or in Safari.

The hero now shows each example as a cluster on a tilted table: the post as a
tall page, two of its figures pulled out with leaders, its deck, its video,
and for Sunny the room from its post as a 3D model, with the camera orbiting
it. The camera settles on a cluster, glides to the next and wraps; a chip
types the request that made the cluster in view, and a pager picks one.

It's one three.js scene (site/assets/hero/hero.js, layout in layout.js),
rendered on demand and only while the hero is on screen, at most 1.25x the
screen's density into a 2x multisampled target. Images are cut to the width
they're drawn at, in a desktop and a phone size, since the GPU holds them
decoded whatever their format. A baked poster shows until the scene is ready,
and for good under reduced motion or without WebGL.

- site/hero.mjs cuts the images (from site/hero/src) and bakes the posters
  with Chrome, like card.mjs; its output is committed.
- three.js r160 is served from the site, named by an import map.
- The build copies site/assets/hero whole; the Worker answers Range requests
  for the hero's videos too, which Safari needs to play them.
@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one): 2
  • coderabbit:review
  • review
🚫 Excluded labels (none allowed): 1
  • wip

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 779d2dc4-3d02-40f4-95f0-3dd2e7727cfe

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@uploads-sh

uploads-sh Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

5 files · View all on uploads.sh →

Before
hero-before-1440.webp
before
After
hero-after-1440.webp
after

hero-poster-reduced-390.webp
after

hero-table-1440.webp
after

hero-table-390.webp
after

Maintained by uploads.sh · add media: uploads put <file> --pr 45 · docs

@zachdunn
Zach Dunn (zachdunn) merged commit 9fc8bdf into main Oct 16, 2026
3 checks passed
@zachdunn
Zach Dunn (zachdunn) deleted the feat/site-hero-table branch October 16, 2026 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant