Skip to content

feat(sites): FRDM Circle landing page — a sunlit ring garden where the hero is the counter - #5

Draft
Gerstep wants to merge 12 commits into
mainfrom
cursor/frdm-circle-landing-189e
Draft

feat(sites): FRDM Circle landing page — a sunlit ring garden where the hero is the counter#5
Gerstep wants to merge 12 commits into
mainfrom
cursor/frdm-circle-landing-189e

Conversation

@Gerstep

@Gerstep Gerstep commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Live: frdm-circle.vercel.app

Deployed to production from this branch with the Vercel CLI, so the page is up without waiting on a merge to main. Dashboard: gersteps-projects/frdm-circle.

A static, zero-build landing page for The Freedom Circle at sites/frdm-circle/. Serve the folder over HTTP and it runs — no bundler, no server, nothing external at runtime.

Deploying

vercel.json at the repository root configures the whole deploy: no install step, no framework, a build that stages index.html, assets/ and licenses/ into dist/, and cache headers. The acceptance harness is deliberately not published.

Vercel Git production still follows main. This production URL came from a CLI upload of this branch (npx vercel deploy --prod --yes). An ignore-build command skips Git deploys that lack sites/frdm-circle, so a push to main cannot overwrite the live page with an empty tree. After this merges, Git deploys to main will publish as usual.

Locally, one command:

cd sites/frdm-circle && ./serve.sh

It has to be served over HTTP rather than opened as a file: the scene is an ES module, and a file:// origin is opaque, so the browser refuses the import and the static fallback ring takes over. serve.sh handles that and waits for the port to answer before opening the browser.

The idea

The hero is not a picture of the product. It is the product's number.

Ten thousand stems stand planted in a circle of daylight around a reflecting pool. Every stem is planted and none has flowered, because the real membership count is zero and this fund is built on not pretending otherwise. Light travels around the inside of the ring rather than down through it — which is the argument the copy makes a few sections later: in charity money moves down; here it moves around. The pool in the middle is the fund, the one thing in the circle that belongs to nobody in particular.

When somebody joins, one stem flowers. That is the only way gold enters this garden.

Nothing in the scene is a photograph or a model file. The stems, the water, the sky, the ground and the light are grown from a fixed seed on load, so the same garden appears every time.

The same world, twice

One canvas serves the hero and the loop section. The camera holds two framings, each fitted to a measured DOM box rather than to viewport fractions, so the garden is the same size at 320 as it is at 1920. For the loop the ring turns to face the reader and its four stages are labelled from projected 3D coordinates.

What is here

  • Content — every sentence of frdmcircle.org, verbatim. Layout and world are new.
  • Scene — instanced grass with two-frequency wind and pointer parting scaled by each stem's own length; a Fresnel water surface with pointer ripples; billboarded procedural flowers; drifting pollen; a sky dome with a low sun; a plain that dissolves into its own haze.
  • Motion — GSAP with ScrollTrigger, and Lenis as the single smooth-scroll engine, both bypassed entirely under prefers-reduced-motion.
  • Theme — bone paper, deep leaf green, one gold reserved for members, on Fraunces and Outfit. The footer is the single dark surface so the page lands on solid ground.
  • Layout — a ruled editorial system: a three-item ladder instead of three equal cards, a 2+3 matrix instead of a five-across grid, a six-step rail that draws itself.

Performance

Cost here is fill rate and vertex count, so three quality tiers trade pixel ratio, blade detail and the ambient extras. The stem count never moves — ten thousand is the argument, not a decoration. A weak GPU still counts every woman; it just draws her smaller.

A governor watches frame time and demotes one tier at a time, one-way. A single long frame is read as a main-thread stall rather than a slow GPU, so a layout or a collection cannot permanently downgrade the page. The render loop runs only while the hero or the loop is on screen, and data-animation-active on the canvas reports its state so that is checkable from outside.

Verification

verify/verify.mjs runs nineteen gates across nine viewports from 1920 down to 320. Eighteen pass, zero fail, one is blocked honestly.

Gate Result
Load, console, network pass — zero errors or warnings at any viewport
Horizontal overflow pass
Touch targets ≥ 44×44 pass
axe, WCAG 2.1 AA pass — zero violations
Scene paints; render loop parks offscreen pass
Dock navigation, FAQ, form validation and submission pass — the client's live Formspree endpoint is stubbed throughout
Reduced motion · no JavaScript · no WebGL 2 pass — each renders complete, readable content
Keyboard order and visible focus pass
Copy fidelity vs frdmcircle.org pass — 153 of 153 sentences
Originality vs Sylva clear in checked scope
Sustained frame rate blocked — headless Chromium here rasterises in software and no GPU is available, so the number says nothing about real hardware

That last row is the one thing this environment cannot answer, and it is reported as blocked rather than dressed up as a pass.

The configured Vercel build was also run and its output served: renders with all 10,000 stems, zero console issues, zero failed requests. Production (https://frdm-circle.vercel.app) returns 200 for the page, scene scripts, fonts, and brand marks.

Sylva, and why there is an audit

Sylva's README grants no licence for reuse of its code, design or artwork. So it informed technique and nothing else — and that claim is audited rather than asserted. verify/ORIGINALITY.md runs MengTo's own evidence-inventory script and reports the load-bearing result: the three files containing all of this page's authored markup, styling, shaders and behaviour share no eight-word sequence with any Sylva file. Every text lead is either the vendored Three.js runtime or licence boilerplate.

Built following MengTo/Skills (MIT). build-awwwards-quality-sites governs; editorial-tech, container-lines and number-details set the layout; threejs-landscape, globe-particles and build-interactive-particle-trail inform the garden; iterate-until-verified and audit-reference-originality shape the harness and the audit. Skills deliberately not combined are named in docs/frdm-circle-landing.md.

This page makes no claim to any award. "Awwwards quality" was an acceptance bar during the build, nothing more.

Bugs worth knowing about

Each was found by measurement, not inspection. Full list in docs/frdm-circle-landing.md.

  • A point-size formula multiplied by screen height produced ~950px sprites and 0.2fps. One expression accounted for the entire performance problem.
  • A percentage translate in a stylesheet reached GSAP as a resolved pixel offset, which it kept underneath the yPercent it was animating — so every headline finished its reveal still 112% low and the page had no visible headings at all.
  • Percentage gradient stops on a taller-than-viewport element put the mobile scrim hundreds of pixels below the type it was meant to protect. Body copy sat on grass at 2.2:1.
  • A background on the canvas parent paints after negative-z descendants and buried the whole scene.
  • Playwright consults the most recently registered route first, so a catch-all abort swallowed the stubbed request and the form gate failed for a reason unrelated to the form.

Mobile

Designed rather than reflowed: a window onto the garden at the top of the frame with the dock floating over it, then the whole argument on paper.

Known gaps

  • Frame rate is unmeasured on real hardware.
  • Under prefers-reduced-motion the canvas is replaced entirely rather than rendering one static frame of the garden. This follows build-awwwards-quality-sites to the letter, but a static render would arguably serve those readers better and is the obvious next improvement.
  • og:image still points at the client's existing og.jpg, which does not depict this design.
Open in Web Open in Cursor 

cursoragent and others added 12 commits August 19, 2026 18:30
Static, zero-build landing page carrying frdmcircle.org's content verbatim,
with a Three.js hero where the visual is the counter: 10,000 instanced
seats on a ring, all unlit because the real count is zero, chords carrying
light one way around the interior, and risers crossing the middle.

One canvas serves the hero and the loop section; the ring turns to face the
reader for the loop and its four labels are placed from projected 3D
coordinates. Rendering is parked whenever neither section is on screen.

Built following MengTo/Skills (MIT): build-awwwards-quality-sites governs,
editorial-tech sets the layout system, threejs-landscape and globe-particles
inform the ring, and iterate-until-verified shapes the acceptance harness.
No Sylva code or assets are reused; the reference informed technique only.

Motion: GSAP with ScrollTrigger, Lenis as the single smooth-scroll engine,
both bypassed entirely under prefers-reduced-motion.

Co-authored-by: stepan <gershuni.stepan@gmail.com>
…bustness

- Dock: labels need ~1000px, so glyph-only starts at 1039px rather than 760px,
  and the dock stays at the top on phones. Docking it to the bottom put a
  fixed bar over the hero's own call to action.
- Loop labels: the node is now a dimensionless anchor with the dot centred on
  the rim and the label hanging outboard, so no label sits on its own seats.
  Scoped the sub-label rule to a direct child; .node-txt is itself a span and
  was inheriting uppercase for the whole label.
- Mobile hero: the ring becomes a shallow horizon high in the frame with a
  graduated veil, instead of a haze behind the body copy.
- Quality governor: a single long frame is a main-thread stall, not a slow
  GPU. It no longer demotes on one spike, resets whenever the loop resumes,
  and needs sustained failure at the cheapest tier before standing down.
- Requests WebGL 2 by name so three never takes its deprecated WebGL 1 path.
- Touch targets: dock items and footer links now clear 44px.
- Heading reveal: a percentage translate in the stylesheet reached GSAP as a
  pixel offset it kept underneath the yPercent it was animating, so every
  headline stayed hidden. The start state is set in script now.
- Point-size attenuation multiplied by screen height, producing ~950px
  sprites and 0.2fps. Sizes are now CSS pixels at a reference distance.

Co-authored-by: stepan <gershuni.stepan@gmail.com>
Replaces the dark editorial treatment entirely. The hero is now a garden in
daylight: ten thousand instanced stems planted in a ring around a reflecting
pool, wind crossing the whole meadow in slow gusts, golden light travelling
one way around the interior, seed drifting in the sun. Nothing has flowered,
because the real count is zero — gold only ever enters this garden when
somebody joins, and then one stem blooms.

The pool is the fund: the one thing in the circle that belongs to nobody in
particular, which is the argument the loop section goes on to make.

- New scene: sky dome with a low sun, a plain that dissolves into its own
  haze, instanced grass with two-frequency wind and pointer parting scaled by
  each stem's own length, a fresnel water surface with pointer ripples,
  billboarded procedural flowers, and drifting pollen.
- New theme: bone paper, deep leaf green, one gold reserved for members, on
  Fraunces and Outfit. The footer is the single dark surface so the page
  lands on solid ground.
- Grass is opaque: ten thousand alpha-blended blades cannot be depth-sorted,
  and the canvas already fades in through its own opacity transition.
- The context now requests a depth buffer, which real geometry needs.

Co-authored-by: stepan <gershuni.stepan@gmail.com>
- Raised the faint and soft ink tokens and the form label size: at 10.9px
  and 54% opacity the labels sat at 3.4:1 against the panel. Now 5.1-8.3:1
  everywhere, and axe reports zero violations at WCAG 2.1 AA.
- Underlined links inside running text; colour alone was not distinguishing
  them from the surrounding sentence.
- Footer links were 44 tall but 26 wide, so they now carry a min-width too.
- Every loop label stacks with its dot instead of reaching out sideways. A
  label that hangs off the flank of the ring will always find a viewport
  narrow enough to fall off the edge of.
- Darkened the required-field marker, which was 4.42:1.

Verified clean on overflow and 44px targets across nine viewports from
1920 down to 320.

Co-authored-by: stepan <gershuni.stepan@gmail.com>
Also removes the retired Cormorant Garamond and Jost font files and their
licences, and the standalone icon sprite now that it is inlined.

Co-authored-by: stepan <gershuni.stepan@gmail.com>
Co-authored-by: stepan <gershuni.stepan@gmail.com>
Stages sites/frdm-circle/ (without the acceptance harness) and deploys it.
The page uses only relative asset paths, so it works unchanged under the
/<repo>/ prefix that project Pages adds — verified by serving it from a
subdirectory locally.

Includes a guard that fails the build if the markup or the scene module
references an asset that was not staged, so a renamed file cannot ship a
broken page.

One-time setup: Settings -> Pages -> Source -> GitHub Actions.

Co-authored-by: stepan <gershuni.stepan@gmail.com>
configure-pages can create the Pages site with the workflow's own pages:write
token, so the first deploy no longer waits on a repository setting being
changed by hand.

Co-authored-by: stepan <gershuni.stepan@gmail.com>
Co-authored-by: stepan <gershuni.stepan@gmail.com>
serve.sh waits for the port to answer before opening the browser rather than
sleeping a fixed interval, and explains why the page cannot be opened as a
file: the scene is an ES module and a file:// origin is opaque, so the import
is refused and the static ring takes over.

Co-authored-by: stepan <gershuni.stepan@gmail.com>
vercel.json at the repository root configures the whole deploy, so importing
the repo needs no dashboard settings: no install step, no framework, a build
that stages index.html, assets/ and licenses/ into dist/, and cache headers.
The acceptance harness is deliberately not published.

Removes the Pages workflow. GITHUB_TOKEN is refused permission to create a
Pages site on this repository, so it failed on every push and would have kept
failing until somebody changed a repository setting.

Verified by running the configured build and serving its output: renders with
all 10,000 stems, zero console issues and zero failed requests.

Co-authored-by: stepan <gershuni.stepan@gmail.com>
The page is up at https://frdm-circle.vercel.app from a CLI production
deploy of this branch. Git production still follows main, so the live
URL is the thing to use until this merges.

Co-authored-by: stepan <gershuni.stepan@gmail.com>
@vercel

vercel Bot commented Aug 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
frdm-circle Ready Ready Preview Aug 19, 2026 10:49pm

@cursor
cursor Bot deleted the cursor/frdm-circle-landing-189e branch August 20, 2026 08:56
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.

2 participants