
Coollanding
- 2 installs
- 7 repo stars
- Updated June 12, 2026
- veithly/coollanding-skill
Compose a unique cinematic landing page by picking one of 8 style worlds and mixing 2-4 interaction mechanics, producing a different combination each time.
About
An anti-template landing-page skill that forces a distinct result each run by selecting a style world, composing mechanics, and inventing a signature interaction, with WebGL and asset-isolation tooling. A developer uses it to build reference-grade, immersive launch or portfolio sites.
- 8 style worlds plus a mechanics library composed into a non-repeating combo
- Reference-harvesting, WebGL/particle, and chroma-cutout asset scripts for parity
Coollanding by the numbers
- 2 all-time installs (skills.sh)
- Ranked #1,564 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
- Data as of Jul 27, 2026 (Skillselion catalog sync)
npx skills add https://github.com/veithly/coollanding-skill --skill coollandingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 7 |
| Last updated | June 12, 2026 |
| Repository | veithly/coollanding-skill ↗ |
What it does
Compose a unique cinematic landing page by picking one of 8 style worlds and mixing 2-4 interaction mechanics, producing a different combination each time.
Files
CoolLanding
Premise
This skill does not produce one look. It produces a different look every time, by forcing the agent to:
1. Diagnose the brand, audience, and emotional target. 2. Pick one Style World from references/style-worlds.md (cinematic-dark, editorial-interference, ritual-craft, spatial-architecture, festival-kinetic, papercraft-tactile, luxury-alcove, generative-system). 3. Compose 2–4 Mechanics from references/mechanics-library.md that fit that world (not the same combo used last time). 4. Invent one Signature Mechanic that nobody else has — the one thing this brand owns. 5. Verify the result is unique, readable, and on-brand.
The output is never "the CoolLanding style". The output is a page only that brand could ship.
Readreferences/style-worlds.md,references/mechanics-library.md,references/composition-strategy.md, andreferences/anti-template-rules.mdbefore composing. When the user asks for reference-grade parity or "as close as possible" animation, also readreferences/kinetic-parity.md(the entrance + pointer + scroll + local-state + renderer proof ladder). When you generate illustrations, also readreferences/asset-isolation.mdand use the bundled asset scripts (scripts/asset_prompt.py,scripts/chroma_cut.py,scripts/preview_cutouts.py) for chroma-backdrop prompting, keying, autocrop, and halo review. When you build a WebGL/3D/particle hero, readreferences/webgl-animation.md(the GPU-particle + bloom + smooth-scroll recipe distilled from the reference sites' shipped code).
Workflow
1. Ground the brief
- Read local repo instructions,
AGENTS.md,README.md, nearby docs. - Inspect current stack, file structure, existing UI patterns.
- If the user provides reference sites, capture real screenshots or DOM/style signals before designing.
- If external libraries are needed, verify current official docs.
1.5 Harvest the reference websites before designing
When the user asks for reference-grade parity, do not design from memory. Build an evidence folder first.
- Download what is publicly shipped: HTML, JS, CSS, visible images, screenshots, and bundle scans. In this repo the proven harvester is
tools/research_refs.py, which writesresearch/refs/<site>/_page.html,_libs.json,_scan.json,_shaders.txt, screenshots, and saved bundles. - Scan bundles for rendering and choreography signals:
THREE,WebGLRenderTarget,UnrealBloomPass,curlNoise,DataTexture,FBO,InstancedMesh,GLTFLoader,DRACO,Reflector,Lenis,ScrollTrigger,barba,Howler,AudioContext,Rive,Framer, and inline GLSL markers. - Probe behavior, not just files: screenshot at load, after pointer movement, after 5s, and after scroll. Record whether motion changes, scroll changes, canvas count, video count, fixed layers, font stack, and dominant layout grammar.
- If a site blocks or serves no public assets (for example a gated luxury page), mark that as
visual-only evidence; do not invent a tech stack. - Convert evidence into a mechanism inventory: hero anchor object, renderer, scroll clock, post-FX, typography scale, cursor behavior, asset strategy, and mobile fallback.
- Use the inventory as source material only. Do not copy proprietary markup, minified code, branded copy, product objects, or trademarked visual signatures.
The implementation target is 90% perceived effect parity, not code parity. Judge against:
- first-viewport impact and single anchor object,
- actual render layer parity (WebGL/canvas/DOM/SVG as appropriate),
- scroll and pointer cause/effect,
- typography scale and crop behavior,
- material/texture quality,
- entrance ritual,
- mobile fallback,
- console cleanliness and nonblank canvas checks.
2. Diagnose the brand
Answer these out loud before touching code (use AskQuestion if any are unclear):
- Product category: physical product, SaaS, event, portfolio, real estate, agency, service, manifesto, etc.
- Brand archetype: heritage / challenger / playful / operational / luxury / artisan / system / studio.
- Audience temperature: cold/skeptical, warm/curious, hot/converted, technical, mainstream.
- Emotion target: awe, intrigue, joy, exclusivity, trust, energy, calm, momentum.
- One-sentence promise: what the first viewport must communicate before the user scrolls.
- Performance ceiling: heavy WebGL OK, or must stay lean?
- Reference vibe: which 1–2 worlds from the catalog feel closest? (Do not pick more than 2.)
3. Pick exactly one Style World
From references/style-worlds.md, pick the lead world. The lead world controls color logic, type system, layout grammar, motion grammar, asset strategy, and the dominant feeling. You may borrow at most one minor accent from a second world, but the page must read as one world.
If two worlds tie, run the uniqueness check:
- Which world has the agent used least recently in this codebase / chat?
- Which world creates the strongest contrast with what competitors do?
- Which world rewards the brand's one-sentence promise best?
Then commit. Do not blend three worlds into a "safe average".
4. Compose 2–4 Mechanics
From references/mechanics-library.md, pick 2–4 mechanics that amplify the world.
- Worlds suggest a default mechanic shortlist — read them.
- One mechanic must be the hero mechanic (carries the first viewport).
- The others are supporting mechanics (used in 2nd / 3rd / footer sections).
- Never copy the exact combination listed as a reference site's signature. Re-arrange. Re-time. Re-color.
5. Invent one Signature Mechanic
The page must have one thing no reference has. Examples:
- A custom cursor that becomes the product's icon when hovered.
- A scroll bar that is the product itself (e.g., a knife blade, a bracelet link).
- A loader that types out the user's location/IP city.
- A 3D hero where the camera follows the actual time of day at the user's locale.
- A footer that prints a generated postcard the user can save.
Write the Signature Mechanic in one sentence before implementing.
6. Generate or create assets
- Bitmap visuals: use image generation, copy final assets into the project, never leave them in the generator's output folder.
- Isolate every illustration. A subject inside a visible rectangle, a halo, or a fake "transparency checkerboard" reads as a cheap template. Floating, shadowed, separated elements are what make reference sites feel premium.
- Never matte a subject out of a busy scene (rembg/SAM on a full studio shot halos and eats into the subject — 误伤). Instead, generate the asset on a uniform high-contrast chroma backdrop, then key that one color out. Pick the backdrop hue to be absent from the subject (green by default; magenta/violet when the subject contains green or many bright colors). Follow
references/asset-isolation.mdfor the backdrop table, prompt template, the color-distance + gated-despill keyer, and the CSS to present cutouts as floating objects. - Use
scripts/asset_prompt.pyto produce the image-generation prompt,scripts/chroma_cut.pyto key and autocrop the generated source, andscripts/preview_cutouts.pyto review the cutout over dark/cream/kraft backgrounds before placing it in the page. - 3D assets: use Blender exports (.glb), keep file size low (texture atlas, draco compression).
- Avoid external stock unless the user explicitly allows them.
- Prefer 1–3 strong assets over many weak decorations.
7. Build the first screen as the experience
- Make the first viewport the actual product/brand signal, not a marketing preamble.
- Full-bleed or unframed layouts; do not put the hero inside a decorative card.
- Let a hint of the next section appear on common desktop and mobile viewports.
- Keep nav and CTAs usable even when the visual layer is intense.
8. Implement kinetic systems
- Use CSS variables for color, spacing, type scale, motion timings — switching worlds should be possible by swapping a
data-worldattribute and a variable bundle. - For reference-grade work, install a kinetic director before polishing visuals: one scoped loop that writes normalized pointer, local scroll, chapter, and entry values into each world. Follow
references/kinetic-parity.md; a static lookalike is not enough. - Add canvas/WebGL/procedural layer only when the world demands it. If you add one, it must carry data via uniforms (mouse, scroll, time, pulse).
- A flat full-screen fragment-shader gradient is not a hero. The reference sites get their "wow" from a known recipe: GPU particles (curl-noise FBO ping-pong) → HDR multi-pass bloom → filmic composite, clocked by Lenis smooth scroll driving GSAP/camera, with motion made frame-rate-independent, rendered off the main thread where possible, and gated by a feature-detect → fallback. Implement from
references/webgl-animation.md(verified stacks + real GLSL) and thegpgpu-curl-particles/hdr-bloom-postfx/offscreen-worker-rendermechanics. - Custom cursor, magnetic buttons, parallax, scroll progress, ticker text, hover distortion: each must have a purpose tied to the world's grammar.
- Respect
prefers-reduced-motion; always cap DPR and pause the loop when offscreen.
9. Verify visually
- Run the app in a browser.
- Capture desktop and mobile screenshots for every section.
- Check that generated images load, canvas pixels are nonblank, text does not overlap, buttons fit, scrolling works, no console errors.
- For isolated assets, composite each cutout over its real world background (dark/cream/kraft) and render in real headless Chromium — the IDE preview caches images and hides fringes. Target ≥90% of the reference's separation quality. See
references/asset-isolation.md§5. - Inspect the output yourself before claiming success.
- Run the anti-template audit in
references/anti-template-rules.md. - If the brief compared the page to reference sites, run a motion proof: screenshot before/after pointer, before/after scroll, active-state DOM assertions, nonblank canvas checks, and console capture. In the CoolFE demo this is
python tools/verify_motion.py; in other repos, build the same checks locally. Do not claim "reference-grade" from static screenshots alone.
Reference Sites the Skill Was Trained On
The catalog is informed by these eight reference sites. The agent must not copy any of them — only inherit their mechanisms.
| # | Site | World | Signature mechanism |
|---|---|---|---|
| 1 | Sidewave | cinematic-dark | WebGL2 black void, single luminous origin, loading ritual |
| 2 | Active Theory | cinematic-dark | Sparse DOM, ASCII/data texture, runtime asset stage |
| 3 | Blit Studio | editorial-interference | Huge cropped wordmark, white field, custom cursor, media collisions |
| 4 | Remote Rituals | ritual-craft | Saturated panels, sticker UI, calendar/desktop metaphors |
| 5 | AIR Center | spatial-architecture | 2D↔3D↔2D RenderTarget transitions, water reflector, panoramic glass |
| 6 | Razorpay Sprint 26 | festival-kinetic | 100+ scroll/click triggers, chapter index (01/A…), B2B-as-consumer storytelling |
| 7 | Aimee's Papercraft | papercraft-tactile | Character-led scrollytelling, baked 2D illustrations on 3D geometry |
| 8 | Cartier Watches & Wonders | luxury-alcove | Six dreamlike 3D rooms per product, hidden gestures, Web Audio score |
Each row maps to a chapter in references/style-worlds.md and a tested mechanism in references/mechanics-library.md. Their real, verified front-end stacks (captured by downloading and scanning the shipped bundles) are tabulated in references/webgl-animation.md §1 — e.g. Sidewave is a Unity→WebGL export, Blit Studio runs Three.js + Lenis + Howler, Active Theory uses GPGPU curl-noise particles + UnrealBloom in an OffscreenCanvas worker, and Remote Rituals is no-code Framer with zero custom WebGL. Inherit mechanisms, not markup.
Quality Bar
- Every visual asset must have a job.
- Motion must clarify state, depth, or rhythm — never decoration alone.
- The page must remain readable at mobile widths.
- Avoid generic AI aesthetics: stock gradients, vague glassmorphism, repeated rounded cards, filler badges, decorative purple/blue blobs.
- Report generated asset paths, implementation files, and verification commands.
- The result must pass the uniqueness test: a critic should not be able to say "this is the CoolLanding skill output". They should say "this is the brand".
interface:
display_name: "CoolLanding"
short_description: "Anti-template framework: compose a unique cinematic landing page from 8 style worlds + 40 mechanics."
default_prompt: "Use $coollanding to build a landing page: diagnose the brand, pick one Style World, compose mechanics, generate isolated project-bound visuals, implement the page, and verify it against the audit."
Anti-Template Rules
The skill must produce different pages every time. Use this file as a final audit before shipping. If any check fails, fix it before claiming done.
The Templated-Output Audit
Run through every line. A "no" anywhere means rework needed.
1. Originality
- [ ] Could a reviewer name this page after 5 seconds without the word "CoolLanding" or any of the 8 reference site names?
- [ ] Does the page have a Signature Mechanic documented in 1 sentence in the project README?
- [ ] Does the signature mechanic appear in 2+ moments of the page?
- [ ] Have you removed any direct copy of a reference's exact combo (see forbidden combinations in
composition-strategy.md)?
2. World purity
- [ ] Is there exactly one lead Style World? (No 3-way blends.)
- [ ] Does the color palette match the world's color logic (restraint vs. saturation, not "safe average")?
- [ ] Does the type system match (mono+display, or refined serif, or notebook, etc.)?
- [ ] Does the motion grammar match (slow+ceremonial, or snappy+festival, or spring+tactile)?
3. Mechanic discipline
- [ ] Are there 2–4 mechanics? (Not 1, not 7.)
- [ ] Is there one hero mechanic that carries the first viewport?
- [ ] Does every mechanic serve the world? (No sticker stack in luxury, no shader in papercraft hero, etc.)
- [ ] Have you avoided every combination in the "forbidden" list?
4. Reference avoidance
- [ ] First viewport is not a 1:1 reskin of Sidewave / Active Theory / Blit / Remote Rituals / AIR / Razorpay Sprint / Aimee's / Cartier.
- [ ] Loader (if any) is not identical to Sidewave's count + line.
- [ ] Chapter index (if any) is not identical to Razorpay's 01/A format.
- [ ] Sticker stack (if any) is not identical to Remote Rituals' rotation pattern.
5. Anti-AI-slop checks
- [ ] No "gradient blob" decorations.
- [ ] No purple-to-blue brand gradient as hero background.
- [ ] No glassmorphism cards over a generic bg.
- [ ] No 3-card "Features" grid with identical icons.
- [ ] No generic CTA pair ("Get started for free" / "Book a demo") unless intentionally retro/ironic.
- [ ] No "Trusted by [logos]" strip with grayscale clip-art.
- [ ] No "How it works" 1-2-3 numbered explainer that could be on any SaaS site.
- [ ] No filler badge ("AI-powered ✨", "New") unless the badge says something specific.
6. Specificity test
- [ ] Every visual asset has a job (not decoration).
- [ ] Every motion serves state, depth, rhythm, or surprise — never decoration alone.
- [ ] Every section heading is specific to the brand, not template phrasing ("Built for teams").
- [ ] CTA labels are specific (e.g., "Hold the ledger", "Open the alcove") not generic ("Get started").
7. Readability + accessibility
- [ ] Mobile width keeps the lead mechanic visible (even if downgraded).
- [ ]
prefers-reduced-motiondisables heavy motion, keeps the page navigable. - [ ] Color contrast on body text passes WCAG AA in the chosen palette.
- [ ] Custom cursor falls back to native on touch.
- [ ] Page is usable with keyboard (focus rings visible).
8. Performance
- [ ] First contentful paint ≤ 2s on a mid-tier laptop.
- [ ] 3D assets ≤ 5MB combined (Draco / KTX2 / GLB compression used).
- [ ] Shaders render at ≥ 50fps on a mid-tier laptop.
- [ ] No layout shift after load.
- [ ] No console errors.
9. The "show a screenshot" test
Show the desktop hero screenshot to a designer who has not seen the brand. They must be able to answer:
- What is the brand selling?
- What is the brand's mood?
- What is the one weird/cool thing on this page?
If they can't answer all 3, the page is too generic.
10. The "skill output diff" test
If you have built another landing page with this skill before, place the two side by side. They must differ on:
- World (different world entirely, or same world with totally different mechanics)
- Palette
- Type system
- Hero mechanic
- Signature mechanic
- At least 50% of the section structure
If two outputs of the skill look 80% similar, the skill failed.
Forbidden Phrases (in copy)
These are AI tells. Replace with brand-specific copy:
- "Welcome to the future of X"
- "Built for the way you work"
- "Powered by AI"
- "Get started for free"
- "Trusted by the world's best companies"
- "Everything you need to X"
- "Built for scale"
- "From idea to launch"
- "The all-in-one platform for X"
- Any sentence starting with "Welcome to" unless the brand is literally a foyer
Forbidden Visuals
- Gradient mesh blobs (3D-rendered or CSS) as hero bg.
- Multi-colored neon laser lines as decoration.
- Floating UI screenshots in 3D perspective with no purpose.
- "App preview" iPhone mockups with screenshots inside.
- Glass-card stacked feature grids.
- AI-rendered pastel illustrations of vague tech concepts (cogs, brains, clouds).
Composition diary
Recommendation: keep a compositions.log in the user's projects directory listing each project's:
date | project | world | hero-mech | supports | signatureBefore composing the next page, read the last 3 entries and pick a different combination.
This file is the spine of anti-templating. Audit before shipping.
Asset Isolation — generate on a chroma backdrop, then key
Floating, layered, shadowed illustrations are what separate a reference-grade page (Cartier, Aimee's Papercraft, Blit) from an AI template. A subject sitting inside a visible rectangle, a halo, or a fake "transparency checkerboard" reads as cheap instantly.
Do not try to matte a subject out of a busy generated scene. Running a segmentation model (rembg/SAM) on a full studio shot leaves halos and eats into the subject (误伤: it deletes fingers, hair, gem facets, thin metal). It is unreliable and you cannot tune it per pixel.
Instead, regenerate the asset on a single uniform high-contrast backdrop, then key that one known color out. This is the green-screen workflow from VFX, and it is the most reliable way to hit a clean, fully-separated cutout.
---
Step 1 — Pick the backdrop color (avoid 误伤)
Choose a backdrop whose hue is absent from the subject. If the backdrop hue also appears in the subject, the key erases part of the subject.
| Subject contains… | Use backdrop | Why |
|---|---|---|
| warm metals, glass, skin, B&W | chroma green #00B140 | green is far from gold/amber/neutral |
| green (emerald, foliage) | magenta #E5007E | never green-screen a green subject |
| many bright colors incl. green | violet #7A1FA2 | violet is absent from typical sticker/pop palettes |
| pure red marks / red ink | green #00B140 | red↔green are complementary, cleanest key |
Rule of thumb: green first; switch to magenta/violet only when green collides. You control the prompt, so you can also steer the subject palette away from the backdrop (e.g. "doodles in blue/red/orange/pink/black, no green").
Step 2 — Generate on that backdrop
Prompt template (fill the brackets):
[detailed subject], centered and fully visible with generous empty margin,
sharp focus, soft even studio lighting. CRITICAL: the ENTIRE background is one
perfectly uniform, flat, saturated [BACKDROP NAME] ([HEX]), seamless edge to
edge — no gradient, no vignette, no surface, and NO shadow cast onto the
backdrop. The subject floats on solid [color].
Notes:
- Demand "no shadow on the backdrop" — cast shadows key as holes or grey fringe.
- Demand "full subject, margin on all sides" — autocrop needs breathing room.
- For glass/translucent subjects, ask for frosted glass so edges are keyable.
- Forbid baked-in trademarks ("plain dial, NO brand name, NO text, NO logo").
Bundled helper:
python scripts/asset_prompt.py "gold watch macro with faceted crown" --world luxury-alcove
python scripts/asset_prompt.py "paper sticker pack for a remote-work ritual" --world ritual-craft --many-bright-colors
python scripts/asset_prompt.py "emerald glass ornament" --world luxury-alcove --contains-greenUse the printed prompt in the image generator. Copy the final source image into the project assets folder as name.png before cutting it.
Step 3 — Key it (color-distance matte + gated despill)
A two-threshold color-distance matte beats a single saturation/luminance key, and despill must be gated to the edge ring or it desaturates genuinely colored subjects (a pink sticker turns brown). The reference implementation (scripts/chroma_cut.py) is bundled with this skill:
python scripts/chroma_cut.py assets/watch.png --bg green --out-dir assets
python scripts/chroma_cut.py assets/stickers.png --bg violet --t-low 85 --t-high 150 --feather 0.6 --pad 10
python scripts/chroma_cut.py assets/generated.png --bg auto --suffix -cutDefaults are tuned for #00B140 green. Use --bg magenta when the subject contains green and --bg violet for bright sticker/pop palettes. Use --bg auto only when all four image corners are the same key color.
The core algorithm is small enough to audit:
import numpy as np
from PIL import Image, ImageFilter
GREEN, MAGENTA, VIOLET = (0,177,64), (229,0,126), (122,31,162)
def smoothstep(x, lo, hi):
t = np.clip((x-lo)/max(hi-lo,1e-6), 0, 1); return t*t*(3-2*t)
def despill(rgb, bg, alpha):
r,g,b = rgb[...,0], rgb[...,1], rgb[...,2]
w = np.clip(1.0-alpha, 0, 1) # edge ring only; interior untouched
out = rgb.copy()
if bg[1] >= bg[0] and bg[1] >= bg[2]: # green key
cap = np.maximum(r,b); out[...,1] = g + (np.minimum(g,cap)-g)*w
else: # magenta / violet key
ex = np.clip(0.5*(r+b)-g, 0, None)
out[...,0] = r-ex*0.9*w; out[...,2] = b-ex*0.9*w
return np.clip(out,0,255)
def chroma_cut(path, out, bg, t_low=70, t_high=135, erode=1, feather=0.7, pad=10):
arr = np.asarray(Image.open(path).convert("RGB")).astype(np.float32)
dist = np.sqrt(((arr-np.array(bg))**2).sum(-1))
alpha = smoothstep(dist, t_low, t_high) # near backdrop -> 0
rgb = despill(arr, bg, alpha)
a = Image.fromarray((alpha*255).astype(np.uint8), "L")
for _ in range(erode): a = a.filter(ImageFilter.MinFilter(3)) # bite 1px fringe
if feather: a = a.filter(ImageFilter.GaussianBlur(feather))
im = Image.fromarray(rgb.astype(np.uint8)).convert("RGBA"); im.putalpha(a)
# autocrop to opaque bbox + pad, then save
m = np.array(a) > 8; ys, xs = np.where(m)
im = im.crop((max(xs.min()-pad,0), max(ys.min()-pad,0),
min(xs.max()+pad+1, im.width), min(ys.max()+pad+1, im.height)))
im.save(out)Tuning:
- Raise
t_low/t_highif a colored fringe survives; lower them if edges erode. erode=1removes the last hard pixel;feather≈0.6–0.8makes edges composite
smoothly. Keep feather low for crisp line-art (marks/doodles).
- Keep the opaque chroma source on disk (
name.png) and write the cutout to
name-cut.png — non-destructive and re-runnable.
Step 4 — Present as a floating element (CSS)
The cutout is only half the effect; layer it like a print object:
.cut {
filter: drop-shadow(0 24px 40px rgba(0,0,0,.45)); /* shadow follows the alpha */
object-fit: contain;
}
/* dark "museum" rooms: add a spotlight behind the subject */
.cut-wrap::before {
content:""; position:absolute; inset:-15% ; z-index:-1;
background: radial-gradient(closest-side, rgba(255,220,150,.18), transparent 70%);
}For a gold-relief ornament on black, skip keying entirely: use the original gold-on-black art with mix-blend-mode: screen + a mask-image: radial-gradient so the black dissolves and only the gold survives.
Step 5 — Verify in a REAL browser
- Composite each cutout over its actual world background (black / cream /
kraft) and eyeball for halo, holes, spill, and 误伤. Transparent-over-white hides green fringe; transparent-over-dark hides nothing.
- Use the bundled previewer for a quick contact sheet:
python scripts/preview_cutouts.py assets/*-cut.png --out assets/_cutout-preview.png
python scripts/preview_cutouts.py assets/watch-cut.png --bg luxury=#0e0b0d --bg paper=#f3f0e8- Render in real headless Chromium (Playwright), not only the IDE preview.
- Target ≥90% of the reference's separation quality before shipping.
Pitfalls (all seen in practice)
- Baked-in checkerboard. Some generators paint a grey/white "transparency"
checker into the pixels (an opaque RGB image). It is not transparent — key it like any other backdrop (saturation or color-distance).
- IDE image cache. After re-cutting, the in-IDE browser may keep serving the
old file. Force a refetch (cache-bust the src, e.g. ?cb=Date.now()) before trusting the preview.
- Despill desaturation. Ungated despill on a magenta/violet key turns pink/red
subjects brown. Always gate despill by (1-alpha) so only the edge ring is corrected.
- Cast shadows. A shadow on the backdrop keys as a grey halo or a hole. Forbid
it in the prompt.
Composition Strategy
How to turn a brief into a unique page by composing one Style World + 2–4 Mechanics + 1 Signature Mechanic. Use this when you have read style-worlds.md and mechanics-library.md.
Step 1 — Diagnose
Answer in ≤ 5 lines:
Brand: <one line>
Product: <category + format>
Audience: <temperature, technical level>
Emotion: <one feeling>
Promise: <what the first viewport must say>
Constraints: <perf ceiling, brand colors, fonts>If any line is unclear, ask the user with AskQuestion — do not guess on the emotion or promise.
Step 2 — Match worlds
For each candidate world, score 1–5 on:
- Fit: does the world serve the emotion target?
- Differentiation: do competitors look like this world? (Lower = better.)
- Feasibility: can we ship this world with current constraints?
Drop the world with the lowest fit. Of the remaining, pick the one with the highest differentiation × fit product.
Brand → World hints
| Brand archetype | Default world | Alt worlds |
|---|---|---|
| AI / agents / infra | cinematic-dark | generative-system |
| Design studio / agency / fashion | editorial-interference | luxury-alcove |
| Community / remote work / kids / education | ritual-craft | papercraft-tactile |
| Real estate / hotel / hardware | spatial-architecture | luxury-alcove |
| Annual recap / product launch / event | festival-kinetic | ritual-craft |
| Personal portfolio / storyteller / charity | papercraft-tactile | editorial-interference |
| Watches / jewelry / perfume / luxury auto | luxury-alcove | spatial-architecture |
| Generative tool / music / data viz | generative-system | cinematic-dark |
These are starting points, not rules. A perfume brand might be brilliant in editorial-interference; a SaaS might be brilliant in ritual-craft. Use the differentiation score to break ties.
Step 3 — Compose mechanics
From the world's Recommended mechanics, pick:
- 1 hero mechanic — carries the first viewport
- 1–2 support mechanics — used in 2nd / 3rd sections
- 1 mechanic from outside the world's list — borrowed for a single moment (must justify why)
Anti-pattern combinations (forbidden)
loader-ritual + scramble-text + ascii-data-overlay + custom-cursor-difference + system-status-stripin cinematic-dark → this is the exact CoolLanding default and now reads as a template. Drop at least one and replace with a fresh mechanic.sticker-stack + pinned-horizontal-track + magnetic-buttons + chapter-index-navin ritual-craft → identical to the Remote Rituals + Razorpay mash-up; vary by addingaudio-ambient-looporhover-image-trail.webgl-3d-scene + water-reflector + scroll-camera-dollyin spatial-architecture without2d-3d-2d-transition→ close to AIR Center but missing the signature transition; either add it or pick a non-AIR direction (e.g.,pbr-product-renderinstead).- Anything +
cropped-mega-type+marquee-tickerin editorial-interference → near-identical to every studio site on Awwwards 2024–2025. Add a fresh mechanic.
Step 4 — Define the Signature Mechanic
One sentence. The format is:
"A [where] that [does something nobody else does] because [brand reason]."
Examples:
- "A scroll bar shaped like the actual product knife blade that 'cuts' the page sections open as you drag because the brand makes folding knives."
- "A custom cursor that becomes the seed of the day, downloadable as a poster at the footer, because the product is a daily generative art newsletter."
- "A loader that types out the user's local time + weather as the first hero copy because the product is a real-world dashboard."
If the signature mechanic doesn't pass the 3 tests:
1. Could only this brand have built it? 2. Does it appear in 2+ moments of the page (not just one)? 3. Would a screenshot of it be shareable?
…iterate until yes on all three.
Step 5 — Lock the system
Before writing code, write a 1-page composition brief:
WORLD: <one>
HERO MECH: <name>
SUPPORT 1: <name>
SUPPORT 2: <name>
BORROWED: <name> (from <other world>)
SIGNATURE: <one sentence>
PALETTE: <3–5 hex values>
TYPE: <display + chrome + body>
ASSETS: <list of generated/loaded assets>
SECTIONS: <ordered list of 4–7 sections>This brief is the single source of truth for the build. If a code change is not justified by it, do not ship it.
Step 6 — Build & verify
- Build in order: chrome (nav, cursor, loader) → hero → signature mechanic → supporting sections → footer.
- For a demo, catalog, or multi-world reference page, place a world-scoped skill + design primitives block immediately after each hero or lead mechanism. It must explain the skill use case, list exactly 3–4 design primitives, and name the proof channel (pointer, scroll, renderer, local state, or asset isolation) that makes the page feel alive. Keep it inside the world/page section and mark it with
data-skill-primitivesso browser verification can assert one visible block per world. - After each section, screenshot and confirm it matches the brief.
- After full build, run the audit in
anti-template-rules.md. - Capture desktop and mobile screenshots, save with descriptive names.
Reusing the skill on a new project
Every new project must:
1. Pick a different world from the previous one or justify reusing the same world with a totally different mechanic combination and signature. 2. Run the differentiation check against the previous 2 outputs. 3. Output the composition brief in the README of the project so future agents can audit.
The skill remembers nothing. The discipline lives in this file.
Kinetic Parity Methodology
Use this when the user asks for a landing page to match reference-site animation, not just visual style. The goal is 90% perceived effect parity: the same motion grammar and cause/effect, without copying proprietary markup, bundles, branded assets, or exact art direction.
The parity ladder
Every reference-grade world needs these channels. If a channel is missing, the page will feel like a static poster.
1. Entrance ritual — the first 800-1600ms should stage the hero title, anchor object, and chrome. Re-run it when switching worlds or re-entering the section. 2. Pointer channel — pointer data must drive something legible: WebGL attractor, cursor lens, product glow, pass tilt, paper parallax, or control-panel drift. Raw mouse coordinates should be smoothed or normalized. 3. Scroll channel — local section progress must change the scene: camera dolly, horizontal track, waterline, path traveler, chapter index, card assembly, or material parallax. Prefer local section progress over global page progress for scene-specific effects. 4. Chapter/local state — active rows, panels, rooms, cards, strata, steps, and indexes must react as the user passes through sections. This is what makes scroll feel choreographed instead of decorative. 5. Renderer channel — if a world uses canvas/WebGL, prove pixels change on time, pointer, scroll, and click. If a world is DOM-only, replace renderer proof with multiple DOM transforms and state changes.
Reference-to-mechanism map
| Reference family | What to inherit | Minimum parity signal |
|---|---|---|
| Sidewave / Active Theory | black stage, luminous origin, GPU particles, bloom, technical HUD, pointer/click shock | nonblank WebGL/canvas, pointer delta, scroll-fed camera/uniform, no shader errors |
| Blit Studio | oversized cropped type, white editorial field, custom cursor/lens, media collision | pointer changes type/image transforms; scroll changes contents/current row |
| Remote Rituals | saturated panels, sticker UI, desktop-window metaphors, pinned horizontal narrative | horizontal track progress, active panel, persistent/tactile interaction |
| Cartier W&W | slow rooms, one material per room, reflection, audio/gesture restraint | pointer drift, slow room activation, product glow/reflection, optional score toggle |
| AIR Center | spatial stage, waterline/reflection, 2D-to-3D feeling, proximity index | scroll-fed stage/waterline, active stratum/index, pointer tilt/orbit |
| Razorpay Sprint | chapter index, loud kinetic typography, object-as-ticket/pass, many scroll beats | active chapter, anchor object tilt/breathe, cards assemble on scroll |
| Aimee Papercraft | character-led path, baked 2D-on-3D illusion, paper folds and props | SVG/3D path traveler moves, path draws, fold sheets react to path progress |
| Generative systems | live parameter UI, seeded field, pointer vortex, technical readout | pixel delta after pointer/click, fps/particle readout, URL/seed state |
Implementation pattern
Build one kinetic director instead of scattering unrelated animation snippets:
function localProgress(el) {
const rect = el.getBoundingClientRect();
const travel = Math.max(1, el.offsetHeight - innerHeight);
return Math.min(1, Math.max(0, -rect.top / travel));
}
function updateKineticDirector(time) {
const world = document.getElementById(currentWorld);
const mx = pointer.x / width - 0.5;
const my = pointer.y / height - 0.5;
const p = localProgress(world);
world.style.setProperty("--world-p", p.toFixed(4));
world.style.setProperty("--mx", mx.toFixed(4));
world.style.setProperty("--my", my.toFixed(4));
// Then call one scoped updater per active world.
}Call the director from:
- the main
requestAnimationFrameloop, scrollhandlers,- pointer move/click handlers,
- world/route changes, so the new world gets an entrance state immediately.
Scope selectors to the active world. Hidden worlds may keep stale classes; verification should not count them.
World-specific motion checklist
- cinematic-dark: GPU particles or procedural field; pointer attractor; click shock; scroll-fed bloom/camera; HUD values from real state.
- editorial-interference: cropped wordmark drift; portrait/media collision; cursor lens; active table-of-contents row; marquee or draw-on rule.
- ritual-craft: idle sticker wobble; click-to-stamp or checklist persistence; pinned horizontal panels; active panel saturation/position.
- luxury-alcove: slow room activation; product glow follows pointer; material image parallax; reflection or audio score kept restrained.
- spatial-architecture: stage dolly; waterline/reflection shift; active stratum/proximity row; pointer tilt or orbit toggle.
- festival-kinetic: chapter index; pass/ticket anchor object; repeated scroll beats; card assembly with stagger.
- papercraft-tactile: character/traveler along path; path draw; paper fold transforms; prop parallax; sticky scene that does not clip the traveler.
- generative-system: seeded canvas; pointer vortex/lens; click pulse; live parameter and fps readouts; export/share state.
Verification gate
Do not claim reference-grade animation until a browser test proves motion. A valid proof includes:
- screenshot before/after pointer movement or click, with pixel delta for canvas/WebGL worlds,
- scroll before/after with changed CSS vars or transforms,
- active-state assertions for chapter indexes, panels, rooms, strata, cards, or path steps,
- for demo/catalog pages, assert each active world has exactly one visible
data-skill-primitivesblock with at least three primitive cards, so the page explains the skill method and the design primitives it demonstrates, - for sticky scrollytelling worlds, assert the sticky container is actually pinned in the viewport and the hero object/traveler has a visible bounding rect; checking changed
left/topalone is not enough, - console/pageerror capture,
- nonblank canvas/WebGL checks where relevant,
- mobile or narrow viewport smoke check for clipping and overlap.
For the CoolFE demo, run:
python tools/verify_worlds.py
python tools/verify_webgl.py
python tools/verify_motion.pyWhen writing a new repo, recreate the same verifier with selectors from that project. Disable smooth scrolling inside tests (scrollBehavior = "auto" and instant scrollTo) so animated browser scrolling does not create false negatives.
Common failure modes
- Static clone: colors/type are close, but pointer and scroll do not change the scene.
- Global progress misuse: every scene reads total page scroll, so local beats happen too early or too late.
- Decorative motion: blobs, marquees, and float animations move, but they do not encode state or depth.
- Unscoped verification: hidden sections retain active classes and make tests pass for the wrong world.
- Untested smooth scroll: tests sample before scrolling finishes and report false failures.
- Canvas wallpaper: renderer loops, but pointer/scroll/click do not affect pixels.
- Broken sticky path: an ancestor uses
overflow: hidden/auto, disablingposition: sticky; the path/traveler coordinates update offscreen, so DOM assertions pass while the animation is invisible.
Mechanics Library
Reusable interaction recipes. Each mechanic is small, world-agnostic in code, but only fits a few worlds creatively. Pick 2–4 mechanics that match the lead world from style-worlds.md. One must be the hero mechanic.
Each entry includes: what it does, when to use, tech ingredients, how to instrument, how to fail (anti-patterns).
---
kinetic-director-layer
What — One scoped animation director that writes normalized pointer, local scroll, entrance, and chapter-state values into the active world (--mx, --my, --world-p, --room-p, etc.). It is the glue that makes reference-site motion feel choreographed rather than decorative.
Use in — Every world when the user asks for reference-grade parity, especially multi-world demos, long scrollytelling pages, and any page based on a strong reference site.
Tech — A requestAnimationFrame loop plus scroll and route/world-change hooks. Calculate local section progress from getBoundingClientRect(), scope all selectors to the active world/root, and write CSS vars or WebGL uniforms from one source of truth. See kinetic-parity.md.
Instrument — Tests must assert before/after pointer transforms, before/after scroll vars, active rows/panels/rooms/cards, and canvas pixel deltas. Static screenshots are not enough.
Fail when — Each section has unrelated CSS animations; hidden sections are counted as active; global page scroll drives all local scenes; smooth-scroll tests sample before the browser finishes moving.
---
webgl-shader-field
What — Full-bleed WebGL2 fragment shader rendering a procedural field (noise, voronoi, flow, light core). Pointer + scroll + time uniforms.
Use in — cinematic-dark, generative-system. Accent in luxury-alcove (background).
Tech — Raw WebGL2 + fragment shader. No three.js needed for a flat plane. Use full-screen triangle (drawArrays(TRIANGLES, 0, 3)).
Instrument — Uniforms: u_resolution, u_mouse, u_time, u_scroll, u_pulse, u_audio. Sample at 60fps with rAF. Pause when offscreen.
Fail when — Used alone as the hero "wow" — a flat shader gradient reads cheap. The reference sites layer GPU particles + bloom on top. For the real recipe see webgl-animation.md; promote to gpgpu-curl-particles + hdr-bloom-postfx for a hero moment.
---
gpgpu-curl-particles
What — Tens of thousands of GPU particles advected by a divergence-free curl-noise flow field, rendered as additive HDR points with a real perspective camera. They can morph onto a 3D shape / logo / word.
Use in — cinematic-dark (signature), generative-system, spatial-architecture (accent). This is the Active-Theory "Proton" technique.
Tech — FBO ping-pong: positions live in a square FLOAT texture (NEAREST, no mipmaps, 64²–256²). A sim pass reads prev → writes next (pos += curlNoise(pos*scale + time)*speed*HZ + mouse force + respawn). A render pass texelFetches positions, projects them, and draws gl.POINTS with additive blending (ONE,ONE). Raw WebGL2 or Three's GPUComputationRenderer. Full GLSL in webgl-animation.md §2.
Instrument — HZ/dt-scale the motion (frame-rate independence). Lerp the pointer before it becomes an attractor. Click = inject a shock impulse. Bake a mesh into a position texture to morph particles into a brand object.
Fail when — Particles just "float" with no force/attractor; no additive blend (looks like dust, not light); FLOAT target unsupported and you didn't fall back; > ~150k particles on mobile (tanks fps).
---
hdr-bloom-postfx
What — A multi-pass post chain that makes light read as light: render to an HDR buffer → bright-pass → separable Gaussian blur per mip → weighted composite, then tone map + chromatic aberration + vignette + grain.
Use in — cinematic-dark (signature), generative-system, luxury-alcove (subtle), spatial-architecture.
Tech — Scene → RGBA16F target. UnrealBloom params from the shipped code: nMips = 3, kernels [3,5,7,9,11], half-res mips. Run the bloom buffer well below DPR (Active Theory uses dpr 0.3) and gate it behind a perf test. Composite essentials (tone map / CA / vignette / grain) in webgl-animation.md §3.
Instrument — Threshold ~1.0 so only true highlights bloom. Keep bloomStrength tasteful; add a faint anamorphic streak on highlights for the "lens" feel. Dither/grain to kill banding.
Fail when — Bloom over an 8-bit (clamped) buffer → flat; bloom on everything (whole screen glows, text unreadable); full-res bloom (wastes GPU for no visual gain).
---
scroll-throttle-camera
What — Scroll stops being "navigation" and becomes throttle: scroll-progress is fed straight into the live scene's uniforms so descending the page visibly transforms the hero — camera dollies in, the orbit accelerates, post-fx (bloom / chromatic aberration / attractor strength) swells. This is the single cheapest way to make a WebGL hero feel "alive" instead of a looping wallpaper.
Use in — cinematic-dark (signature), generative-system, spatial-architecture, luxury-alcove (gentle).
Tech — Keep one global scrollProgress (0–1, clamped). Pipe it into uniforms each frame: angle += sp*K, camera.z = base − sp*K, bloomStrength = base + pulse*K + sp*K, attract = base + sp*K. Lerp where it would feel jumpy. Pair with a click = shock impulse that decays (shock *= pow(0.05, dt)).
Instrument — Make the promise legible: a short copy line ("scroll arms the orbit") + a live readout proves the cause/effect (see live-telemetry-readout). Tie the same sp to a couple of CSS-side details so the whole page moves as one system.
Fail when — The hero loops identically regardless of scroll (reads as a video); too many uniforms move at once (chaotic); no easing (camera snaps); reduced-motion users get a frozen blank canvas (draw one static frame).
---
live-telemetry-readout
What — A small monospace HUD that displays the actual live values driving the scene (pointer, scroll %, camera.z, particle count, fps, shock). It turns an abstract effect into something the visitor can read and trust — and signals real engineering, not a stock template.
Use in — cinematic-dark, generative-system, spatial-architecture. (Tonal variants: a "colophon" in editorial, a "proximity index" in spatial.)
Tech — Cache the DOM nodes once, then write textContent/bar widths from the render loop on a throttle (frame % 3). Drive <i><b> width bars from normalized params. Numbers from the same source of truth as the shader uniforms.
Instrument — Throttle to every 3–4 frames (DOM writes are the cost, not the math). Right-align numbers, pad with leading zeros for the "instrument" feel. Never invent numbers — read them from the live state.
Fail when — Updated every frame (layout thrash); shows fake/random numbers; so dense it competes with the headline.
---
count-up-stats
What — Big display numbers that animate from 0 → target the first time they scroll into view (eased, with thousands separators + optional suffix). A classic "this is substantial" beat between hero and footer.
Use in — Every world (tonal: neon mono in cinematic, serif in luxury, hand-drawn in papercraft, acid in festival).
Tech — IntersectionObserver(threshold ~0.5), guard with a dataset.counted flag so it runs once, requestAnimationFrame with cubic ease-out, Number.toLocaleString(). Read targets from data-count / data-count-suffix.
Instrument — One observer for all [data-count] nodes (reusable across worlds). ~1.3s duration. Keep numbers true to the build (particles, passes, worlds).
Fail when — Re-runs every time it re-enters view (jarring); animates dozens of numbers at once; counts to vanity numbers that aren't real.
---
content-ladder
What — A numbered, ruled list (01…06) where each rung pairs a short title + one sentence + a tiny code/spec chip. It adds genuine depth and rhythm below the hero without resorting to generic three-up "feature cards", and it documents how the page works (e.g. the render pipeline) as part of the design.
Use in — cinematic-dark (render pipeline), spatial-architecture (section strata), generative-system (the system), editorial (colophon spec).
Tech — <ol> with grid-template-columns: [num] 1fr [chip], hairline border-top per rung, hover wash. Reveal each rung with the shared data-reveal observer (stagger).
Instrument — Keep each rung to one idea + one line. The chip is monospace and world-tinted. 4–6 rungs max.
Fail when — Rungs become paragraphs; more than ~6 (becomes a wall); chips are decorative gibberish instead of real specs.
---
offscreen-worker-render
What — Move the entire WebGL render loop into a Web Worker via OffscreenCanvas, so heavy GPU work never blocks scroll, input, or layout.
Use in — Any world with a continuous WebGL hero (cinematic-dark, spatial-architecture, luxury-alcove). Active Theory ships this.
Tech — canvas.transferControlToOffscreen() → post to a worker that runs rAF + GL. Hand assets across with createImageBitmap. Mirror pointer/scroll/resize events into the worker. Provide a main-thread fallback when OffscreenCanvas is unavailable (Safari quirks).
Instrument — Keep the worker message rate low (batch pointer/scroll). Pause when the tab is hidden (visibilitychange). Cap DPR (min(dpr, 2)).
Fail when — You over-message the worker (defeats the point); no fallback path; you try to touch the DOM from the worker.
---
webgl-3d-scene
What — A Three.js or R3F scene with one or more 3D models. Camera moves on scroll. Lights, materials, reflections.
Use in — spatial-architecture, luxury-alcove, festival-kinetic (mascot), papercraft-tactile (path).
Tech — Three.js or React Three Fiber. Blender → GLB with Draco compression. PBR materials.
Instrument — One scene, one renderer. Use useScroll (R3F) or scroll-progress driving camera.position. Dispose meshes on unmount.
Fail when — Model is 50MB; lighting is flat; camera is locked.
---
2d-3d-2d-transition
What — Page transitions where DOM scroll seamlessly hands off to a 3D scene, then back to DOM. Uses multiple WebGL RenderTargets.
Use in — spatial-architecture (signature), luxury-alcove.
Tech — Three.js with 5 layers / RenderTargets: 1. Project Layer (2D media) 2. World Layer (3D scene) 3. Composite Layer (PlaneGeometry textured by World Layer) 4. UI Layer (cursor, chrome) 5. Postprocess Layer
Instrument — Camera Y position compared to a "waterline" plane Y to switch above/below modes. GSAP timelines synced to scroll.
Fail when — Used as eye candy without storytelling; jitters at section seams.
---
water-reflector
What — A reflective floor or water surface that reflects the scene above it.
Use in — spatial-architecture, luxury-alcove (mirror floor under product).
Tech — Three.js Reflector (extended). Use a low-resolution render target for the reflection to keep perf.
Instrument — Compare camera Y to waterline Y; toggle distortion shader for underwater mode.
Fail when — Reflector blocks readability; reflection is too sharp (looks fake) or too noisy.
---
scroll-camera-dolly
What — Scroll progress drives camera position along a Bezier path through the 3D scene.
Use in — spatial-architecture, luxury-alcove, papercraft-tactile, festival-kinetic.
Tech — THREE.CatmullRomCurve3 or CubicBezierCurve3. Use Lenis + ScrollTrigger.
Instrument — curve.getPointAt(progress) and curve.getTangentAt(progress) for position + lookAt. Smooth with damping.
Fail when — Camera path is straight (boring); progress is jittery (always damp).
---
lenis-smooth-scroll
What — Replace native scroll with Lenis for buttery 60fps smooth scrolling.
Use in — Every world except cinematic-dark (optional) and ritual-craft (optional).
Tech — npm i lenis or CDN. new Lenis({ duration: 1.2, easing: t => Math.min(1, 1.001 - 2 ** (-10 * t)) }). Drive requestAnimationFrame.
Instrument — Pair with GSAP ScrollTrigger: lenis.on('scroll', ScrollTrigger.update).
Fail when — Smooth is too slow (feels laggy on long pages); breaks accessibility (use prefers-reduced-motion to disable).
---
loader-ritual
What — A pre-page sequence: count, progress line, central object, tiny technical copy. Sets the tone.
Use in — cinematic-dark (signature), luxury-alcove (slow), spatial-architecture (subtle), festival-kinetic (energetic).
Tech — Fixed overlay, CSS animations + JS counter. Hide via body.is-loaded class with opacity 0, visibility hidden.
Instrument — Tie count completion to actual asset loading (Promise.all on images/models). Or fake-load 2–3s for atmosphere.
Fail when — Too long (>4s); not connected to any real loading; reused identically across worlds.
---
ascii-data-overlay
What — A grid of ASCII characters animating like a data readout. Sits behind / around the hero.
Use in — cinematic-dark, generative-system.
Tech — <pre> element with characters generated by JS. Animate with subtle drift / mix-blend-mode screen.
Instrument — Generate rows where (x + y) % 3 === 0 show characters, otherwise space. Update less than 30fps.
Fail when — Looks like Matrix rain (overdone); covers important text.
---
pointer-warped-shader
What — Pointer position shifts shader UV space. Glow, distortion, or orbit center follows cursor.
Use in — cinematic-dark, generative-system, luxury-alcove (subtle).
Tech — Smooth pointer with lerp (pointer.x += (target - pointer.x) * 0.08). Pass to u_mouse uniform.
Instrument — Always lerp — never use raw pointer; that feels jittery.
Fail when — Effect is too strong (feels seasick); pointer leaves window and shader sticks.
---
system-status-strip
What — Tiny mono text strip at the bottom or top showing frame number, status, system messages.
Use in — cinematic-dark, generative-system.
Tech — Fixed positioned <div> with monospace, white-on-black.
Instrument — Real data: frame counter, scroll percent, time of day, fps, build hash.
Fail when — Filled with fake placeholder strings; never updates.
---
scramble-text
What — Text scrambles into final form character-by-character.
Use in — cinematic-dark, generative-system, festival-kinetic.
Tech — JS loop swapping chars from a noise alphabet until each index "locks". 18–24 frames total.
Instrument — Use only on the hero word or one CTA. Trigger on load and on hover.
Fail when — Used on every text element (annoying); too slow (>1s); used in luxury-alcove (breaks ceremony).
---
custom-cursor-difference
What — Tiny circle cursor with mix-blend-mode: difference. Inverts whatever it's over.
Use in — cinematic-dark, editorial-interference, festival-kinetic.
Tech — Fixed div, follow pointer with damping, mix-blend-mode: difference, hide native cursor.
Instrument — Always hide on touch / hover-coarse devices. Always show on prefers-reduced-motion.
Fail when — Too big (looks like a target); inverts a critical button label and makes it illegible.
---
custom-cursor-lens
What — A larger lens cursor that magnifies, distorts, or shows alternate content beneath it.
Use in — editorial-interference, generative-system.
Tech — Fixed div with backdrop-filter, optional WebGL-driven distortion. Show extra label only on .spotlight regions.
Instrument — Trigger label swap on .magnetic / .spotlight regions.
Fail when — Too distracting on text-heavy sections.
Promote to → `loupe-grid-reveal` for the editorial hero mechanic: on a full-bleed 2D halftone canvas, near the pointer (1) tighten + heat the dots toward the hot accent (lens = max(0, 1 - dist/R), lerp color + radius by lens), and (2) clip a red baseline grid + crosshair to the lens circle so a print "loupe" only appears where you look. This turns an abstract cursor into the literal brand promise ("the cursor is the lens"). Keep the dot loop bounded by ceil(w/cell) and draw the grid with ctx.clip() to one circle. Fail: lens reveals nothing structural (just a blur) → reads generic.
---
magazine-contents
What — A real editorial table of contents: numbered rows, serif titles + one-line deck, dotted leaders, and a big display folio (page number) that counts up on reveal. The strongest "this has depth" beat for a type-anchored world, and pure CSS/DOM.
Use in — editorial-interference (signature depth), luxury-alcove (gallery index), any print-flavoured world.
Tech — <ol> with grid-template-columns: [num] 1fr [leader] auto. The leader is an empty cell with border-bottom: 2px dotted. Folios are [data-count] driven by count-up-stats. Hover flips the whole row to the hot accent. Pair with a ::first-letter drop cap on the lead paragraph (display face, hot accent, float: left).
Instrument — Use real page-ish numbers, not 1–5. 4–6 entries. Tie hover color to the world's single accent.
Fail when — It's just a styled <ul> with no folios/leaders (loses the magazine read); too many rows; multiple accents.
---
custom-cursor-stamp
What — A cursor that stamps shapes (confetti, stickers, brand mark) where it clicks. Best version: stamps pop in and stay (don't fade), are persisted to `localStorage`, and restore on reload — so the visitor literally co-authors the page. Each click also fires a short confetti burst for delight.
Use in — ritual-craft (signature), generative-system.
Tech — Absolute/fixed divs spawned at clientX/Y with a randomized --stamp-rot, a spring pop-in keyframe (ends at opacity 1, no fade). Keep a stampNodes[] + stampHistory[]; cap both (~24) and shift the oldest DOM node out. Persist stampHistory (label/x/y/color); on load, re-spawn with a persistOnly flag. Confetti = ~12 WAAPI bits flung along random angles, onfinish → remove() (skip under reduced-motion). Offer a "clear" control + a live counter so the mechanic is legible.
Instrument — Cap active stamps and recycle DOM; one storage key; counter reads stampHistory.length. Confetti colors pull from the world palette tokens.
Fail when — Used everywhere (chaos); never cleans up (memory leak); stamps fade so the "I left a mark" payoff is lost; not persisted (page feels disposable).
---
tactile-persistent-list
What — A paper-styled checklist (clipboard with a metal clip, dashed rules, hand checkboxes) the visitor can tick, with a live N/total done counter. State persists in localStorage; checking an item wobbles it, strikes it through, and pops confetti. The cheapest way to make a warm/handmade world feel interactive rather than decorative.
Use in — ritual-craft (depth), papercraft-tactile, any warmth-led brand.
Tech — <button> rows (not native checkboxes — easier to style + animate). A {key: bool} map in localStorage; refresh() toggles .is-done (green box + ✓ + line-through) and recomputes the counter. WAAPI spring on tick. Reuse the confetti-burst from the stamp mechanic at the row's bounding box.
Instrument — Persist under its own key. Keep 4–6 items, one of them on-brand and slightly silly ("Star the skill ⭐"). aria-pressed on each toggle.
Fail when — Looks tickable but isn't; no persistence (resets every visit); native checkbox styling fights the paper aesthetic.
---
magnetic-buttons
What — Buttons that translate toward the cursor when hovered.
Use in — editorial-interference, ritual-craft, festival-kinetic.
Tech — pointermove on button → compute offset from center → transform: translate(x*0.12, y*0.16).
Instrument — Reset on pointerleave. Disable on touch.
Fail when — Magnetic on every link; conflicts with positioned absolute elements.
---
cropped-mega-type
What — A wordmark sized at clamp(12rem, 26vw, 32rem) cropped by the viewport edge or by another element.
Use in — editorial-interference (signature), festival-kinetic, luxury-alcove (sparingly).
Tech — Single word in heavy display font. Position absolute, allow overflow.
Instrument — Use the actual brand word, not "Welcome". Crop by ~15–30% on at least one edge.
Fail when — Cropped so much it becomes unreadable on mobile.
---
image-mask-reveal
What — Image revealed by a cursor- or scroll-driven mask. CSS mask-image or canvas radial mask.
Use in — editorial-interference, luxury-alcove, cinematic-dark.
Tech — CSS mask-image: radial-gradient(circle at var(--mx), var(--my), transparent 100px, black 200px) driven by JS pointer vars.
Instrument — Always provide a static fallback for prefers-reduced-motion.
Fail when — Mask too small (gimmick); mask hides the most important image moment.
---
marquee-ticker
What — Horizontal scrolling strip of text or icons that loops infinitely.
Use in — editorial-interference (chrome), festival-kinetic, ritual-craft.
Tech — CSS @keyframes translating -50% over 20–40s, or JS with two copies of content.
Instrument — Pause on hover. Disable on prefers-reduced-motion.
Fail when — Too fast (motion sick); used in luxury-alcove (breaks ceremony).
---
pinned-horizontal-track
What — A section that becomes sticky vertically while inner content translates horizontally as the user scrolls.
Use in — ritual-craft (signature), festival-kinetic, editorial-interference.
Tech — .sticky container with height: N00vh, inner track with transform: translate3d(-X%, 0, 0) driven by scroll progress.
Instrument — Always fallback to vertical stacking under 720px width.
Fail when — Used on every section; user gets trapped scrolling endlessly.
---
pinned-scene-stack
What — A series of fixed sections that swap as the user scrolls, like slides.
Use in — editorial-interference, luxury-alcove (alcove rooms), papercraft-tactile.
Tech — Sections positioned position: sticky; top: 0 with height: 100vh. Use ScrollTrigger to swap visibility.
Instrument — Each scene should have a clear "exit" cue before the next begins.
Fail when — User can't tell scroll is doing anything; scenes overlap visually.
---
chapter-index-nav
What — A persistent index at top or side showing chapter numbers (01, 02, 03 or I, II, III). Click to jump. Updates on scroll.
Use in — festival-kinetic (signature), luxury-alcove, papercraft-tactile.
Tech — Fixed nav. Scroll observer updates active chapter. Use prefers-reduced-motion-safe scroll-behavior: smooth.
Instrument — Numbers must be ornamental, not just functional. Use sub-numbering (01/A, 01/B) for richness.
Fail when — Just looks like a generic nav menu; numbers feel arbitrary.
---
rive-character-motion
What — Rive animations for characters, mascots, or UI elements that respond to scroll, hover, or input.
Use in — festival-kinetic, ritual-craft, papercraft-tactile.
Tech — Rive runtime (web). Load .riv file. Bind state machine inputs to JS events.
Instrument — Use scroll progress as Rive input for narrative animation.
Fail when — File >500KB; animation loops but doesn't react.
---
hero-anchor-object
What — One memorable, unexpected hero object that anchors the entire page (the giant shoe, the giant glass, the giant origin).
Use in — festival-kinetic (signature), cinematic-dark, ritual-craft, papercraft-tactile.
Tech — Generated 3D / large illustration / generated bitmap. Must be unique to the brand.
Instrument — Anchor object should appear in 2+ scenes, transformed (zoomed, rotated, sliced) — not just a hero static.
Fail when — Generic icon; centered without composition; never reappears.
---
scroll-card-reveal
What — Product cards reveal in a numbered grid as the user scrolls. Each card has a hover state.
Use in — festival-kinetic, ritual-craft.
Tech — IntersectionObserver to add .is-visible. CSS opacity + transform transitions.
Instrument — Stagger reveals by ~80ms. Use a varied grid (2-1-3-2 layouts), not a strict 3-col.
Fail when — Strict uniform grid (feels SaaS-templated).
---
numbered-product-grid
What — A grid where each item has a chapter sub-number (01/A, 01/B) as visual scaffolding.
Use in — festival-kinetic.
Tech — CSS grid with the number as oversized background text or sidebar label.
Instrument — Numbers should be in the largest type on the card. Product name secondary.
Fail when — Numbers feel decorative only; same number style as competitors.
---
executive-quote-block
What — A block-quote from a real person with name + title, set in oversized italic display.
Use in — festival-kinetic, luxury-alcove, spatial-architecture.
Tech — Section with photo + quote + attribution. Quote 4–6 lines, broken at meaningful places.
Instrument — Real names, real titles, real quotes. Set type at 5–7vw.
Fail when — Fabricated quotes; corporate fluff; too small to be a moment.
---
r3f-baked-illustration
What — 2D illustrations textured onto low-poly 3D geometry. Creates a papercraft, hand-built feeling.
Use in — papercraft-tactile (signature), ritual-craft.
Tech — Illustrate in Krita / Procreate. Bake onto Blender low-poly meshes (planes, folded cards). Export GLB. Use R3F.
Instrument — UV maps must be hand-aligned. Use orthographic camera for "flat" look.
Fail when — Illustration is misaligned (texture stretch); 3D effect undermines hand feel.
---
scroll-path-character
What — A character moves along a Bezier path through a 3D scene or tactile SVG stage as user scrolls.
Use in — papercraft-tactile (signature), ritual-craft.
Tech — Full version: THREE.CatmullRomCurve3 + GLTFAnimationMixer, driving mixer.update() with scroll progress. Lean DOM version: SVG path.getTotalLength() + getPointAtLength(progress * len) and an absolutely positioned paper/character element.
Instrument — Loop the path for infinite scrolling effect. Use curve.getTangentAt or two nearby SVG points for character rotation. In CSS/DOM builds, the sticky stage must not sit inside any ancestor with overflow: hidden; that disables position: sticky in real browsers and pushes the character offscreen even though DOM checks pass.
Fail when — Path is too straight; character animation is decoupled from path direction; verification only checks left/top instead of screenshotting the sticky state; a custom cursor hides the character in proof screenshots.
---
paper-texture-overlay
What — A grainy paper texture overlaid on the entire page with mix-blend-mode: multiply or overlay.
Use in — papercraft-tactile, editorial-interference.
Tech — High-res paper grain PNG/SVG, fixed positioning, low opacity, blend mode.
Instrument — File must be < 50KB. Use SVG noise if possible.
Fail when — Texture too strong (looks dirty); used on pure dark world (no light to interact with).
---
chapter-page-flip
What — Page transitions that look like flipping a paper page.
Use in — papercraft-tactile.
Tech — CSS 3D rotateY on a perspective container. Or WebGL displacement.
Instrument — Sync flip to scroll direction. Use sound (paper rustle) if audio is on.
Fail when — Page flip is laggy (use will-change); used outside papercraft world.
---
web-audio-score
What — Ambient music + cue sounds via Web Audio API, threaded as a narrative layer.
Use in — luxury-alcove (signature), cinematic-dark, generative-system, papercraft-tactile.
Tech — Web Audio API. Decode buffer, loop ambient track at low gain. Add cue sounds on scroll milestones.
Instrument — Always require user gesture to start (mute toggle in nav). Default muted. Respect prefers-reduced-motion.
Fail when — Auto-plays loud; no mute control; obvious stock track.
---
hidden-gesture-reward
What — A hidden interaction (draw a circle, double-click, hold key) that triggers an easter egg.
Use in — luxury-alcove (signature), generative-system.
Tech — Track pointer path / gesture, fire event when matched.
Instrument — Reward must be on-brand (rotates product, reveals secret material, plays a sound cue). Don't gate critical content.
Fail when — Gesture is too hard to discover; reward is just a console.log.
---
sticker-stack
What — A stack of slightly-rotated, oversized sticker buttons as a CTA group.
Use in — ritual-craft (signature).
Tech — Inline-block elements with transform: rotate(±3deg). Borders 3px solid black. Box-shadow offset for "stuck" feel.
Instrument — Use chunky display type, 3–5 stickers max. Stagger rotation.
Fail when — Used in luxury-alcove or spatial-architecture (wrong world).
---
desktop-window-frame
What — A UI panel styled as an old-school desktop window (title bar, traffic lights, content grid).
Use in — ritual-craft, generative-system.
Tech — Plain CSS. Border, grid for content, traffic light dots in bar.
Instrument — Treat as a "scene-within-the-page" device. Avoid making it a real-feeling UI (avoid SaaS app screenshots).
Fail when — Looks like an actual product screenshot; mimics macOS / Windows exactly.
---
wobble-on-hover
What — A spring wobble on hover for tactile interactive elements.
Use in — ritual-craft.
Tech — CSS @keyframes or JS spring lib. Use cubic-bezier(0.34, 1.56, 0.64, 1).
Instrument — Use on stickers, panels, CTAs. Not on text or photos.
Fail when — Used everywhere (annoying); too slow / too fast.
---
hover-image-trail
What — A trail of images that follow the cursor on hover, like a swatch fan.
Use in — editorial-interference, ritual-craft.
Tech — Pre-load images. On pointermove, spawn a positioned image, animate it fading out within ~600ms. Limit count.
Instrument — Limit to ~6 images visible at once. Use brand-related images.
Fail when — Used on a small section without breathing room.
---
axonometric-overlay
What — An axonometric line diagram (floor plan, exploded view) overlaid as a faint guide.
Use in — spatial-architecture, festival-kinetic (technical aside).
Tech — SVG, animated on scroll (stroke-dasharray).
Instrument — Subtle. Below 30% opacity. Lines should align to actual content.
Fail when — Too noisy; not aligned to real layout grid.
---
proximity-index
What — A "X min walk / Y min drive" or distance index that grounds the page in geography.
Use in — spatial-architecture.
Tech — Plain HTML grid. Optional pulse animation on icon.
Instrument — Use real distances. Pair with a small icon (foot, car, metro).
Fail when — Numbers feel made-up; geographic context isn't shown.
---
parameter-sidebar
What — A live control panel exposing parameters of the system. Sliders, color pickers, seeds.
Use in — generative-system (signature).
Tech — Native <input type="range"> styled, or lil-gui / tweakpane. Connect to shader uniforms or canvas state.
Instrument — Allow user to save a seed / state to URL. Add a "share" button that copies URL.
Fail when — Hidden away; too many parameters (>6 max visible).
---
audio-reactive-uniforms
What — Microphone or audio buffer input modulates shader uniforms.
Use in — generative-system, cinematic-dark.
Tech — Web Audio AnalyserNode → getByteFrequencyData() → pass as u_audio[N] uniforms or texture.
Instrument — Require user gesture. Default muted. Add "tap to enable mic" overlay.
Fail when — Too sensitive (jitters); doesn't degrade gracefully without mic.
---
seed-url-state
What — Encode the page state (seed, color, scroll position) into the URL so it can be shared.
Use in — generative-system.
Tech — URLSearchParams. On state change, history.replaceState. On load, parse and restore.
Instrument — Show the active seed prominently. Add a "copy this seed" CTA.
Fail when — URL too long; state changes too frequently and history fills up.
---
particle-system
What — A field of particles (canvas2d or WebGL points) that react to pointer or scroll.
Use in — generative-system, cinematic-dark.
Tech — Canvas2d for ≤2000 particles. WebGL points for more. Use requestAnimationFrame. For a true hero-grade field (10k–65k), graduate to gpgpu-curl-particles (GPU sim) — see webgl-animation.md §2.
Instrument — Particles should do something (flow toward cursor, repel, swarm). Not just float.
Fail when — Just decoration; tanks framerate.
---
save-seed-cta
What — A button that downloads the current canvas as a high-res PNG or shareable card.
Use in — generative-system, papercraft-tactile (sign the last page).
Tech — canvas.toBlob + URL.createObjectURL + anchor click.
Instrument — Render at 2× resolution. Include seed and date in the file.
Fail when — Generates a low-res or watermarked output.
---
frame-counter
What — A monospace counter showing current frame, time, or fps.
Use in — cinematic-dark, generative-system.
Tech — Update text in rAF, throttled to ~10fps so it doesn't itself cause reflow.
Instrument — Pair with status strip. Use real data.
Fail when — Fake / static.
---
r3f-alcove-rooms
What — Multiple 3D rooms / scenes, one per product, scrolled between with seamless camera transitions.
Use in — luxury-alcove (signature).
Tech — Multiple <Canvas> or one canvas with conditional scene rendering. Dispose models when out of view.
Instrument — Each alcove should have its own micro-palette, materials, audio cue.
Fail when — All rooms look the same; transitions are abrupt.
---
pbr-product-render
What — A photoreal product render with PBR materials, HDR environment, ground reflection.
Use in — luxury-alcove, spatial-architecture (hardware).
Tech — Three.js or R3F with MeshPhysicalMaterial. Load HDR env map (RGBE loader).
Instrument — Use Draco for geometry, KTX2 for textures. Target ≤2MB total per product.
Fail when — Bad lighting (looks like a plastic toy); env map too obvious.
---
audio-ambient-loop
What — A short looping ambient audio track playing very low in the background.
Use in — luxury-alcove, papercraft-tactile.
Tech — Web Audio buffer source, gain low (~0.15), loop = true.
Instrument — Pair with mute toggle. Default muted on first visit; remember preference.
Fail when — Loop point is obvious; track feels stock; auto-plays.
---
Composition Tips
- Hero + 2 supports: pick one hero mechanic, two supports. More than 4 mechanics turns the page into noise.
- Mechanic must serve world: do not paste a sticker stack in luxury-alcove. Re-read the world's recommended list.
- Signature must be original: invent one mechanic the catalog doesn't list, fit for the brand.
- Mobile-safe: every mechanic must degrade or stack on mobile. Test before claiming success.
See composition-strategy.md for how to pick combinations and anti-template-rules.md for the audit.
Reference Sites
Mechanism inventories for the eight reference sites the skill was trained on. Use these as source material, never as templates to copy. Pair each row with style-worlds.md and mechanics-library.md when composing.
Research Protocol
For every new reference run, capture and preserve evidence before writing design code:
1. Open the live page in Chromium and wait through first render. 2. Save the rendered HTML plus every public JS/CSS response under research/refs/<site>/. 3. Capture screenshots at initial load, after pointer movement, after 5s, and after scroll. 4. Scan bundles for renderer and motion signals: WebGL/Three/OGL/R3F, RenderTargets, shader strings, FBO ping-pong, bloom, GLTF/DRACO, Lenis/GSAP/ScrollTrigger, Framer/Rive/Howler/Web Audio. 5. Record failures honestly. If a luxury/product site serves no public runtime bundle to the probe, classify that row as visual-only evidence instead of guessing. 6. Translate findings into mechanics and anti-patterns. Never copy branded objects, proprietary copy, or minified implementation code.
The target for demo work is 90% perceived effect parity: a viewer should feel the same level of craft, depth, motion, and specificity as the reference lineage, while the page remains original and legally distinct.
Source Links
| # | Site | URL |
|---|---|---|
| 1 | Sidewave | https://sidewave.it/#origin |
| 2 | Active Theory | https://activetheory.net/ |
| 3 | Blit Studio | https://blit.studio/ |
| 4 | Remote Rituals | https://remote-rituals.framer.website/ |
| 5 | AIR Center | https://aircenter.space/ |
| 6 | Razorpay Sprint 26 | https://razorpay.com/sprint/26 |
| 7 | Aimee's Papercraft World | https://aimees-papercraft-world.com/ |
| 8 | Cartier Watches & Wonders | https://www.cartier.com/en-fr/watchesandwonders |
---
1. Sidewave — cinematic-dark
Observed mechanisms
- Black void, almost no chrome, one small luminous origin object.
- WebGL2 canvas anchors the page; the object is the brand signal.
- Tiny technical copy behaves like a system status line.
- Motion feels continuous and procedural: pulse, orbit, loading/progress line.
- Many fixed layers, loading overlay, progress line,
webglsignals, single canvas, compact custom fonts.
Best takeaway — Make silence expensive. Let one object carry the drama.
Mechanics observed — webgl-shader-field, loader-ritual, pointer-warped-shader, system-status-strip, custom-cursor-difference.
Do not copy — The exact loader-count + line + center-orbit combo. It is the most-cloned signature of the past 18 months.
---
2. Active Theory — cinematic-dark
Observed mechanisms
- Dark immersive hero with a central digital sigil; WebGL2 / video heavy build.
- Sparse navigation, screen behaves like an installation.
- Ticker-like code marks, binary/ASCII texture, audio toggle, cookie layer.
- One WebGL2 canvas, two videos, very few DOM nodes, large JS modules, many fetch requests for runtime scene data/assets.
Best takeaway — Combine a strong central mark with ambient code noise and cinematic darkness.
Mechanics observed — webgl-3d-scene, ascii-data-overlay, marquee-ticker, web-audio-score, frame-counter.
Do not copy — A central rotating sigil + ASCII rain at the same time. Pick one.
---
3. Blit Studio — editorial-interference
Observed mechanisms
- White editorial field, huge cropped wordmark, scattered media, hot red-orange accent.
- Asymmetrical magazine layout; images collide with text instead of sitting in cards.
- Custom cursor removes the default web feeling.
- Scroll is the composition engine: sparse scenes, oversized phrases, visual interruptions.
- WordPress + Lenis smooth-scroll, seven videos, fixed header, color mode control, custom cursor/canvas-like fixed overlay.
Best takeaway — White space can be as extreme as black space when scale and placement are brave.
Mechanics observed — cropped-mega-type, lenis-smooth-scroll, custom-cursor-lens, image-mask-reveal, pinned-scene-stack.
Do not copy — The "studio name + cropped mega type + lone red dot" hero. Reskin with a new device.
---
4. Remote Rituals — ritual-craft
Observed mechanisms
- Hot pink playful world, chunky custom lettering, sticker navigation, toy-like illustration.
- Long scroll tells a daily routine through vignettes and interface metaphors.
- Many SVG/illustration assets, tactile pills, tabs, calendar/desktop motifs.
- Framer-generated site, 100+ SVGs, many image assets, fixed/pinned full-viewport horizontal scenes with saturated color panels.
Best takeaway — Handcrafted specificity beats generic polish.
Mechanics observed — sticker-stack, pinned-horizontal-track, desktop-window-frame, magnetic-buttons, wobble-on-hover.
Do not copy — Pink → blue → green saturated panels in sequence with sticker CTAs. Re-pick the color sequence and the metaphor.
---
5. AIR Center — spatial-architecture
Observed mechanisms
- Premium architectural showcase. Three glass towers as visual protagonist.
- 2D ↔ 3D ↔ 2D seamless transitions across 5 RenderTarget layers.
- Water reflector with above/below waterline detection (compares camera Y to plane Y).
- Frozen-wave faсade metaphor extended into the lobby (glass-wave ceiling).
- Proximity index (1 min walk Mall, 3 min walk Metro, 7 min drive Downtown, 11 min drive Highway).
- Lobby with 8m inclined columns; structural language carried through copy and 3D.
Tech — Three.js (tree-shaken), GSAP, Lenis, Barba.js, WordPress static gen, S3 + CloudFront, Vimeo for video. Reflector extended from Three.js's Reflector.js.
Best takeaway — When the brand is the architecture, the page must move like the architecture would in your hand.
Mechanics observed — webgl-3d-scene, 2d-3d-2d-transition, water-reflector, scroll-camera-dolly, proximity-index, axonometric-overlay, lenis-smooth-scroll.
Do not copy — Glass towers + frozen-wave + water reflector + proximity index. That is AIR. For other real-estate brands, find a different metaphor (e.g., light through louvres, copper patina, brick masonry).
---
6. Razorpay Sprint 26 — festival-kinetic
Observed mechanisms
- One-pager with 100+ scroll and click triggered interactions.
- Chapter index navigation (01/A, 01/B, II.) acts as both nav and visual scaffolding.
- Opens with a giant shoe — an unexpected hero anchor object for a fintech / payments launch.
- Each chapter has an executive quote block in oversized italic.
- Sub-chaptered product grids: Agentic Stack → Agentic Payments → Agentic Platform → Agent Studio…
- Mascot illustrations slide in via Rive; 3D hero models via Three.js + Blender.
Tech — Webflow + Rive + Three.js + Blender + GSAP. Designed in Figma. Two-month design-build sprint.
Best takeaway — B2B can be a festival. The unexpected hero object (shoe) re-anchors a 100-update product page as a shopper's journey.
Mechanics observed — chapter-index-nav, rive-character-motion, hero-anchor-object, executive-quote-block, numbered-product-grid, scroll-card-reveal.
Do not copy — 01/A 01/B 01/C numbering + giant unexpected object + execs quote + ScrollTrigger card reveal. Vary the unexpected object and the chapter style (try Roman, try Arabic with letters, try chapter "tracks" named after songs).
---
7. Aimee's Papercraft World — papercraft-tactile
Observed mechanisms
- Scroll-driven character walks a looping path through hand-drawn papercraft scenes.
- Notebook-paper aesthetic. 2-color palette (paper cream + ink).
- 2D illustrated assets baked onto 3D geometry in Blender, rendered with React Three Fiber.
- Looping path (Catmull-Rom or Bezier) so the experience can replay.
- Educational / open-source angle (full source + Blender files on GitHub).
Tech — React Three Fiber + Blender + Krita (2D). Lenis for smooth scroll.
Best takeaway — Tactile beats polished. Hand-drawn illustration baked onto 3D outperforms photoreal 3D for personal storytelling.
Mechanics observed — r3f-baked-illustration, scroll-path-character, paper-texture-overlay, lenis-smooth-scroll, chapter-page-flip (light).
Do not copy — Character walking a path through paper scenes. For other portfolios, find a different metaphor (e.g., a kite, a paper boat down a river, a hand turning over physical objects on a desk).
---
8. Cartier Watches & Wonders — luxury-alcove
Observed mechanisms
- Six floating 3D alcoves, one per watch, each a self-contained dreamlike environment.
- Scroll moves between rooms like a museum after hours.
- Each alcove has architecture, light, and materiality unique to one watch (water, mirrors, fog, gold).
- Hidden interactive gestures reward curiosity (e.g., rotate the product on a circle gesture).
- Web Audio score (Mooders) threaded as narrative layer.
- Scenes dispose and load as user crosses between alcoves.
Tech — Three.js + Blender + GSAP + Lenis + Web Audio API + Sass.
Best takeaway — Luxury storytelling = per-product micro-worlds with reflection, audio, and rewarded curiosity. The site is paced like a ritual, not a brochure.
Mechanics observed — r3f-alcove-rooms, webgl-3d-scene, water-reflector, scroll-camera-dolly, web-audio-score, hidden-gesture-reward, pbr-product-render, lenis-smooth-scroll.
Do not copy — Six 3D rooms with mirrored floors + atmospheric audio + hidden gestures. For other luxury brands, pick a different spatial metaphor (e.g., a vitrine sequence, an underground vault, a starlit terrace).
---
Cross-Site Patterns
What recurs across reference sites that the skill should always have in its toolbox:
- Lenis + GSAP — smooth scroll + scroll-driven animation, used in 6 of 8 references.
- One signature object — every reference has a single hero anchor (origin, sigil, wordmark, sticker world, glass tower, giant shoe, character, alcove). Always invent one for your brand.
- A loading or entrance ritual — even if subtle, every reference opens with intent (count, fade-in, mute toggle, intro animation).
- Mono / system chrome — even festival-kinetic uses mono numbers and labels for contrast.
- Mobile fallback — every reference downgrades gracefully on mobile, usually stacking pinned scenes vertically.
Anti-Pattern Summary
These are the most-cloned signatures of 2024–2026. Avoid the exact composition:
- "Black + WebGL origin + loader count + ASCII + mono status" → cloned 200+ times. Vary.
- "White + huge wordmark + lone red dot + Lenis + custom cursor" → cloned 100+ times. Vary.
- "Pink saturated panels + sticker CTA + chunky type + horizontal scroll" → cloned 80+ times. Vary.
- "01/02/03 chapter index + giant unexpected object + scroll cards + exec quotes" → cloning is starting now. Get ahead.
- "Six 3D rooms + Web Audio + mirror floor + hidden gesture" → expect this to be the next clone wave. Vary.
The skill protects against this by forcing the Signature Mechanic step and the audit in anti-template-rules.md.
Style Worlds
Eight distinct visual languages the skill can compose from. Pick exactly one as the lead world per project. Worlds are mutually exclusive on the lead axis — do not blend them into a templated average.
Each entry defines: identity, color logic, type system, motion grammar, layout grammar, asset strategy, recommended mechanics, and anti-patterns. Read the recommended mechanics from mechanics-library.md when composing.
---
1. cinematic-dark
Inspired by Sidewave, Active Theory.
Identity — A black void with one luminous object. The browser becomes a control room. Silence is part of the design.
When to use — Tech-forward products, AI/agents/infra, generative platforms, audio/music tools, anything where intrigue and authority both matter.
Color logic — 95% black/near-black (#020303–#10100e). 1 cold accent (cyan, ice blue, mint). 1 hot interrupt color used 1–2 times max (orange, magenta, acid). White only at small sizes.
Type system — Tiny mono system text (Consolas / IBM Plex Mono / system-ui mono) for chrome and labels. Compressed display (Impact / Anton / custom heavy condensed) for the one big mark. Avoid mid-size geometric sans.
Motion grammar — Continuous procedural loops, slow pulse, loading rituals, pointer-warped shaders, scan lines. No bouncy easing. Use ease-in-out curves around 800–1200ms for reveals.
Layout grammar — Centered or extreme corners. Fixed status strips. Vertical alignment. Almost no cards.
Asset strategy — One generated WebGL field as hero. Optional ASCII/data texture overlays. No stock photos. No illustration. Type and shader carry the meaning.
Recommended mechanics — webgl-shader-field, loader-ritual, ascii-data-overlay, pointer-warped-shader, system-status-strip, scramble-text, custom-cursor-difference.
Avoid — Gradient blobs, glassmorphism cards, big rounded buttons, marketing badges, illustrated mascots, soft pastels.
Signature mechanic seeds — A shader that mirrors the time of day; a loader that prints the user's IP city; a hero where the luminous object reacts to mic input.
---
2. editorial-interference
Inspired by Blit Studio.
Identity — A white magazine page where typography is the layout. Images crash into letters. A single accent color punches through.
When to use — Design studios, agencies, fashion, editorial products, portfolios, manifestos, indie launches.
Color logic — 90% white/paper (#f4f1e8–#ffffff). Black for type and rules. One hot interrupt (orange-red, traffic-red, electric-blue). No third color.
Type system — Huge cropped display (Druk / Sharp Grotesk / custom heavy serif) bleeding off edges. Tiny mono for captions and chrome. Allow real serif body when literary.
Motion grammar — Sparse. Scroll triggers oversized type to slide in, images to crash, cursor to morph. Use snappy curves, ~300–500ms. Smooth-scroll (Lenis) the page itself.
Layout grammar — Asymmetric magazine. Hero is a word, not a sentence. Images are placed like collage tiles, sometimes overlapping type. Empty space is dramatic.
Asset strategy — 3–6 mid-resolution photographic or generated images, placed editorially. Optional looping video stamps. Strong texture allowed (paper grain, halftone).
Recommended mechanics — lenis-smooth-scroll, custom-cursor-lens, cropped-mega-type, image-mask-reveal, pinned-scene-stack, hover-image-trail, marquee-ticker.
Avoid — Decorative gradients, cards with shadows, centered hero copy, "Get Started" CTAs in pill buttons, AI-illustrated mascots.
Signature mechanic seeds — A cursor that becomes a magnifier showing the print grid; a logo that fragments into a Swiss-poster layout; a footer printed like a colophon.
---
3. ritual-craft
Inspired by Remote Rituals.
Identity — A handcrafted toy operating system. Saturated panels, chunky lettering, sticker UI, calendar/desktop metaphors. Page feels operated like a toy.
When to use — Community products, remote work tools, calendar/scheduling apps, indie SaaS, education for kids/teens, lifestyle brands.
Color logic — Saturated and contrasting: hot pink, electric blue, acid green, traffic orange, banana yellow. 3–5 panels each owning one color. Use black 3px borders. White only inside cards.
Type system — Chunky custom display (Marlide / Cooper / handcrafted geometric) for headers. Mono for sticky-note copy. Avoid Inter / Geist / Roboto.
Motion grammar — Tactile bounce. Stickers wobble. Tabs swap with overshoot easing. Custom cursor stamps shapes. Use cubic-bezier(0.34, 1.56, 0.64, 1) for playful spring.
Layout grammar — Pinned horizontal scenes. Each scene is one colored room. Sticker stack as CTA group. Calendar/desktop frames as UI metaphor.
Asset strategy — Many SVG illustrations, hand-built 3D objects, sticker badges. 1 illustrated character or mascot allowed (but not generic).
Recommended mechanics — pinned-horizontal-track, sticker-stack, desktop-window-frame, magnetic-buttons, custom-cursor-stamp, wobble-on-hover, chapter-index.
Avoid — Dark mode anything, "elegant" thin type, restrained gradients, AI corporate gloss, beige minimalism.
Signature mechanic seeds — A sticker the user can drag onto the page and keep on next visit; a daily ritual scheduler that reads the user's local time; a chunky cursor that picks up confetti.
---
4. spatial-architecture
Inspired by AIR Center.
Identity — Premium architectural showcase. Glass, metal, water reflections. The composition is a building seen from impossible angles. Scroll is camera dolly.
When to use — Real estate, hotels, architecture firms, automotive, premium hardware, luxury campuses, B2B infrastructure.
Color logic — Cool greys, off-white, gunmetal. Optional warm twilight gradient as accent. Color must feel like daylight on glass, not branded.
Type system — Refined neutral sans (Söhne / Suisse / Helvetica Now) at small caps and large body. Serif optional for headlines (GT Sectra / Tiempos). No display fonts.
Motion grammar — Slow, monumental. Camera moves take 1500–3000ms. Materials respond to scroll with refraction or reflection. No bounce.
Layout grammar — Full-bleed image bands. Floor plans / sections as ambient diagrams. Long captions that read like a brochure. Vertical numerical index (1, 2, 3 min walk).
Asset strategy — High-fidelity 3D building model (Blender → GLB), photographic interiors, axonometric site plans. WebGL water reflector for "frozen waves".
Recommended mechanics — webgl-3d-scene, 2d-3d-2d-transition, water-reflector, scroll-camera-dolly, lenis-smooth-scroll, axonometric-overlay, proximity-index.
Avoid — Stock real-estate photography clichés, "Schedule a tour" CTAs in clip-art style, generic luxury black-gold palette, sticker UI.
Signature mechanic seeds — A scroll that crosses from above the waterline to underwater; a tower that fragments into its floor plates as you scroll; a panoramic that tracks the user's geolocation altitude.
---
5. festival-kinetic
Inspired by Razorpay Sprint 26.
Identity — A scroll-as-festival. Hundreds of micro-interactions, chapter index, illustrative density. B2B treated like a consumer launch. Feels like flipping through a stylized program.
When to use — Annual recaps, product launches, "Sprint" / "Wave" / "Spring update" pages, conference recaps, anything announcing many things at once.
Color logic — Brand primary + bright accent + black/white. Use sectional color shifts: each chapter (01, 02, 03…) owns a hue. High contrast within each chapter.
Type system — Heavy modern display (PP Editorial Old / Söhne Mono / Akkurat) for chapter headers. Compressed numerals (01/A, II.) as ornamental scaffolding. Body in clean grotesk.
Motion grammar — Click-and-scroll triggers everywhere. Numbered cards reveal. Mascot illustrations slide in. A surprise hero (e.g., giant shoe, giant glass, giant fingerprint). Use 400–700ms snappy curves.
Layout grammar — Long vertical scroll. Chapter index nav at top. Each chapter has 5–10 product cards. Big chapter wordmark + executive quote.
Asset strategy — Rive animations for character motion. 3D hero object (Blender → GLB). Many small icons. Cards may be skeuomorphic (ticket stub, calendar tear).
Recommended mechanics — chapter-index-nav, rive-character-motion, hero-anchor-object, scroll-card-reveal, executive-quote-block, numbered-product-grid, lenis-smooth-scroll.
Avoid — Single-section landing, restrained palettes, "minimal" anything, blog-grid layouts, generic SaaS hero ("Build faster with X").
Signature mechanic seeds — A scroll that opens like a physical shopping bag; a chapter index that turns into a printed program at the footer; a 3D mascot that mirrors the user's scroll velocity.
---
6. papercraft-tactile
Inspired by Aimee's Papercraft World.
Identity — A notebook-paper diorama. A character walks a path. Scroll moves the character through a world of paper folds, hand drawings, and notebook lines.
When to use — Personal portfolios, narrative pieces, education, charity, storytelling launches, indie creative tools.
Color logic — 2–3 colors max. Notebook cream + one ink color + optional accent. Use real paper texture overlay. No gradient.
Type system — Handwritten or notebook-style font (Caveat / IM Fell / custom hand-lettering) + one neutral grotesk. Small sizes only — let the illustration carry the page.
Motion grammar — Looping character animation. Paper crinkle micro-motion. Page bend on transitions. 500–800ms with elastic out.
Layout grammar — One continuous scrollytelling track. Camera follows character along a Bezier path. Sections are "chapters" of the path.
Asset strategy — Hand-drawn illustrations baked onto low-poly 3D in Blender (R3F-friendly). 2D illustration layered with 3D depth. Audio of paper rustle / pencil scratch optional.
Recommended mechanics — r3f-baked-illustration, scroll-path-character, paper-texture-overlay, lenis-smooth-scroll, chapter-page-flip, audio-ambient-loop.
Avoid — Hard chrome / glass, neon accents, mega-type, status strips, AI shader glow.
Signature mechanic seeds — A character that draws the next scene with their pencil as you scroll; a footer that folds the entire page back into a paper plane and flies it offscreen; the user can sign the last page.
---
7. luxury-alcove
Inspired by Cartier Watches & Wonders.
Identity — A museum after hours. Each product gets its own dreamlike 3D alcove. The user scrolls between rooms. Hidden gestures reward curiosity. A score plays.
When to use — Luxury goods, watches, jewelry, perfume, automotive, high-end fashion, exclusive launches, generational brands.
Color logic — Restrained: ivory, oxblood, deep navy, brass, gunmetal. Each alcove has its own micro-palette. No accent color that screams.
Type system — Refined serif (Bodoni Moda / GT Sectra / Heritage display) for product names. Italic small caps for captions. Light grotesk for chrome. Never display sans for headlines.
Motion grammar — Slow and ceremonial. 1500–3500ms transitions. Camera lingers. Materials shimmer subtly. Reflection / refraction is central. No snappy easing — only ease-in-out.
Layout grammar — Each alcove is one full viewport, scrolled through. Vertical chapter index optional. Product info appears as a hovering caption, not a card.
Asset strategy — Photoreal 3D product model with PBR materials (Blender → GLB with Draco). Atmospheric backgrounds (mirrored floor, drifting water, low fog). Web Audio score with ambient music + sound cues.
Recommended mechanics — webgl-3d-scene, r3f-alcove-rooms, scroll-camera-dolly, web-audio-score, hidden-gesture-reward, lenis-smooth-scroll, pbr-product-render.
Avoid — Brutalism, sticker UI, mono system text, sharp neon accents, "Buy now" buttons. Use "Discover" or "Explore" framing.
Signature mechanic seeds — A gesture that rotates the product when the user draws a circle with their cursor; a footer engraving the user's initials into the metal; an ambient soundscape that follows the user's scroll velocity.
---
8. generative-system
Custom world — for products that are systems.
Identity — The product itself becomes the visual. Particles, audio reactivity, procedural patterns, parameter exposure. The page is a live instrument.
When to use — Generative art tools, music apps, data viz products, simulation engines, AI inference platforms, anything where the artifact is alive.
Color logic — Either monochrome with one parametric accent, or a small palette derived from a generative seed shown in the URL (e.g., ?seed=4711). Treat color as data.
Type system — Mono for parameters. Display optional for one mark. Numbers everywhere — frame counter, seed, parameter values.
Motion grammar — Constant procedural motion. Pointer changes parameters. Audio (optional mic input) modulates the field. Scroll changes the algorithm, not just the scene.
Layout grammar — One full-bleed canvas. Parameter sidebar like a DAW or modular synth. Optional "save your seed" CTA.
Asset strategy — Pure procedural — no images. Optional one logo SVG. Optional ambient audio buffer.
Recommended mechanics — webgl-shader-field, parameter-sidebar, audio-reactive-uniforms, seed-url-state, particle-system, save-seed-cta, frame-counter.
Avoid — Stock photos, illustrated mascots, anything that hides the live system.
Signature mechanic seeds — A page that bakes the user's current seed into a downloadable poster; a hero that mutates if the user is idle for >30s; a "share this exact view" URL that encodes time + scroll + pointer.
---
How to choose
If two worlds tie after diagnosing the brand, run the uniqueness check from composition-strategy.md. Lock in one. Compose mechanics. Never blend three.
WebGL & Animation Methodology
How the reference sites actually achieve their "expensive" look. This is distilled from reading the shipped bundles of aircenter.space, razorpay.com/sprint/26, aimees-papercraft-world.com and activetheory.net (their minified JS was downloaded and scanned for libraries, GLSL, and render-pipeline calls). Treat it as the recipe book for the cinematic-dark, spatial-architecture, luxury-alcove, papercraft-tactile and generative-system worlds.
A flat full-screen fragment-shader gradient is NOT what these sites do. The "wow"
always comes from the same small set of techniques below. Use them.
---
1. Verified stacks (what each reference really runs)
| Site | Renderer | Scroll | Transitions | Signature GPU work |
|---|---|---|---|---|
| sidewave.it | Unity → WebGL2 export (unity-loader, DXT textures) | custom scroll-visuals.js | engine scenes | a whole game-engine scene compiled to the browser; Points, Web Audio |
| aircenter.space | OGL (lean WebGL) | Locomotive Scroll | Barba.js | Points particles, deferred reflections, Web Audio |
| blit.studio | Three.js (stock vendor build) | Lenis + GSAP ScrollTrigger | — | Draco-GLTF, InstancedMesh, FBO ping-pong, Howler audio, OffscreenCanvas worker, 42× setRenderTarget |
| razorpay /sprint/26 | Three.js | (native) + GSAP ScrollTrigger (100+ triggers) | — | Draco-GLTF models, FBO ping-pong, InstancedMesh, Rive vector UI, 44 inline canvases |
| aimees papercraft | React-Three-Fiber + drei | Lenis + ScrollTrigger | — | Draco-GLTF baked papercraft, Reflector mirror floor, fbm shaders, 63× setRenderTarget |
| active theory | proprietary Hydra (Three-like) | custom | custom | GPGPU curl-noise particles, UnrealBloom (+ lens streak), MRT deferred SSR/SSGI, OffscreenCanvas in a Worker |
| remote-rituals | Framer (no-code runtime) | Framer + ScrollTrigger | Framer | NO custom WebGL — saturated DOM panels, sticker UI, desktop-window cards, canvas image FX |
| cartier W&W | Three.js (3D rooms) | scene-pinned | — | per-product rooms, Web Audio score, hidden gestures |
Common denominators: smooth scroll → GSAP timelines → camera, GPU particles via FBO ping-pong, multi-pass bloom, Draco-compressed glTF, render off the main thread, feature-detect → fallback, frame-rate-independent motion.
2026-05-29 bundle refresh
The current CoolFE repo re-ran tools/research_refs.py against all eight references and saved public runtime artifacts under research/refs/<site>/. Treat the counts below as evidence from that capture, not permanent facts:
| Site folder | Public code saved | Canvas count | Flagged bundle signals |
|---|---|---|---|
sidewave | 27 JS/CSS files | 1 | Unity loader/framework, createShader, AudioContext, Points( |
activetheory / active-theory | 3 JS/CSS files | 0 in the probed DOM | curlNoise, UnrealBloomPass, FBO, DataTexture, GLTFLoader, DRACO, Points( |
blitstudio | 12 JS/CSS files | 0 in the probed DOM | THREE, ScrollTrigger, lenis, Howl, FBO, RawShaderMaterial, InstancedMesh, DRACO |
remoterituals | 17 JS/CSS files | 0 | Framer bundles, ScrollTrigger, Howler, dense DOM/SVG runtime signals |
aircenter | 2 newly captured JS/CSS files, with earlier cached bundles retained | 0 in the probe | ogl, barba, locomotive, THREE, AudioContext, Points( |
razorpay-sprint26 | 13 JS/CSS files | 44 | gsap, ScrollTrigger, THREE, DataTexture, FBO, InstancedMesh, GLTFLoader, DRACO, Rive |
aimees-papercraft | 3 JS/CSS files | 1 | @react-three, Lenis, ScrollTrigger, Reflector, fbm, WebGLRenderTarget, DRACO |
cartier-ww | 0 public JS/CSS files in the probe | 0 | visual-only evidence in this capture; do not claim fresh bundle proof |
If these references are re-run later, prefer the newest research/refs/*/_scan.json over this table. The methodology is stable; the live sites can change.
Two outliers worth knowing:
- Engine export (Sidewave) — for fully art-directed 3D you can ship a **Unity/Unreal →
WebGL** build. You get engine-grade scenes/lighting for free, at the cost of a big download and a long loader. Reserve for hero experiences, gate behind a loader ritual.
- No-code (Remote Rituals) — the
ritual-craftlook is pure DOM/CSS (saturated
panels, chunky melted display type, sticker rows, desktop-window cards) on Framer. Not every premium feel needs WebGL; match the technique to the world.
Library decision:
- No 3D models, just a field/particles/post FX → raw WebGL2 or OGL. Keep it dependency-free.
- 3D models, materials, reflections → Three.js (or R3F if the app is React).
- Crisp vector character/UI motion → Rive. Timeline choreography → GSAP + ScrollTrigger, clocked by Lenis.
---
2. GPU particles (the #1 "cool" generator)
Active Theory's particle engine ("Proton/Antimatter") is a textbook GPGPU FBO ping-pong system. Recreate it (raw WebGL2 or Three's GPUComputationRenderer):
1. State lives in a texture. A square FLOAT (or HALF_FLOAT fallback) render target, NEAREST filter, generateMipmaps = false. Each texel = one particle's xyz position (+ w = life). Default sizes are small: 64² = 4096 up to 256² = 65k. Two targets, ping-ponged. 2. Simulate with a full-screen pass that reads the previous position texture and writes the next. The motion is a curl-noise flow field (divergence-free → no sinks), plus optional attractors / mouse force, plus lifecycle respawn. Active Theory's literal curl preset:
// behavior pass (writes next position)
vec3 c = curlNoise(pos * uCurlNoiseScale * 0.1 + time * uCurlTimeScale * 0.1);
pos += c * uCurlNoiseSpeed * 0.01 * HZ; // HZ = frame-rate-independence// curl of a vec3 noise potential (finite differences)
vec3 snoiseVec3(vec3 x){ return vec3(snoise(x), snoise(x+19.1), snoise(x-33.7)); }
vec3 curlNoise(vec3 p){
const float e = 0.1;
vec3 dx=vec3(e,0,0), dy=vec3(0,e,0), dz=vec3(0,0,e);
float x=(snoiseVec3(p+dy).z-snoiseVec3(p-dy).z)-(snoiseVec3(p+dz).y-snoiseVec3(p-dz).y);
float y=(snoiseVec3(p+dz).x-snoiseVec3(p-dz).x)-(snoiseVec3(p+dx).z-snoiseVec3(p-dx).z);
float z=(snoiseVec3(p+dx).y-snoiseVec3(p-dx).y)-(snoiseVec3(p+dy).x-snoiseVec3(p-dy).x);
return normalize(vec3(x,y,z)+1e-5);
}3. Morph particles onto shapes. Bake a mesh's surface points into a position texture (texture2D(tShape3D, uv).xyz) and lerp toward it — this is how clouds of particles resolve into a logo / product / word. Other behaviors they ship: plane shape, point cloud, sine drift, attract/repel force, and mouse-fluid (flow = texture2D(tFluid, screenUV).xy). 4. Render the particles as gl.POINTS: the vertex shader texelFetches the position texture, projects with a real perspective camera, sets gl_PointSize (shrink with distance), and the fragment shader draws a soft round sprite with additive blending (ONE, ONE), colored by speed/depth/life. Real 3D camera + additive points = depth and glow the flat shader can never get.
3. Bloom (what makes light look like light)
Every reference runs a multi-pass UnrealBloom. The shipped params:
- Render the scene to an HDR target (
RGBA16F); 8-bit clamps highlights and bloom
goes flat.
- Bright pass (luminosity threshold ~1.0,
smoothWidth 0.01) → bright target. - Separable Gaussian blur, per mip (Active Theory uses
nMips = 3,
kernelSizeArray = [3,5,7,9,11]), horizontal then vertical, each mip at half the previous resolution.
- Composite: sum the mip blur textures weighted by
bloomFactors, tinted by
bloomTintColor, scaled by bloomStrength, added over the scene.
- Run bloom at LOW resolution — Active Theory's global bloom buffer is **`dpr:
0.3`**. Cheap and softer. Gate it behind a perf test.
Finish with a filmic composite pass: Reinhard tone map col/(1+col), chromatic aberration (offset R/B sampling, growing toward the edges), a faint anamorphic lens streak on highlights, vignette, and grain + dithering to kill banding.
// composite essentials
vec2 c = uv - 0.5; float ca = 0.002 + dot(c,c)*0.02; // CA grows to edges
vec3 col = scene + bloom * uBloomStrength;
col = col / (1.0 + col); // tone map
col *= smoothstep(1.15, 0.35, length(c)*1.4); // vignette
col += (hash(uv*uRes + uTime) - 0.5) * 0.025; // grainBlack-stage tuning guard
The most common failure is a canvas that is technically "bright and animated" but visually reads as a foggy wallpaper. Reference-grade cinematic WebGL should keep the stage black and make one energy object feel authored.
- Split the hero into three layers: a small procedural aura/origin pass, a
restrained GPU point cloud, then bloom/composite. Do not ask bloom to create the whole visual.
- Particle spawn should form lanes, arcs, rings, or a morph target, not a
uniform sphere. A sphere of additive points becomes a white sheet.
- Keep point sprites small and sharp. Use lower alpha, distance-based size, and
optional needle/spark masks instead of large soft discs.
- Bloom is an accent. Raise the bright-pass threshold before lowering the whole
scene opacity; otherwise the page becomes muddy but still washed out.
- Place the luminous origin away from primary text/HUD. The object can overlap
lightly, but it should not turn the headline into a glow mask.
- Add a browser metric that rejects fake passes: for a black-stage hero, sample
the first viewport and require a high dark-pixel fraction, a capped bright-pixel fraction, limited hot pixels, no shader errors, and a measurable pixel delta after pointer/click. In the CoolFE demo this is enforced by tools/verify_webgl.py.
4. 3D scene craft (spatial / luxury / papercraft)
- Geometry: author in Blender, export glTF + Draco (and KTX2 textures).
Target ≤ 2 MB per hero model; lazy-load the rest. This is why these sites hit ~1.3s LCP despite heavy 3D.
- Many objects, few draw calls:
InstancedMesh, or feed per-instance
offset/scale/orientation from a texture in the vertex shader.
- Reflections: a
Reflectormirror floor (low-res reflection RT) for product/water;
or a full deferred G-buffer (MRT) + screen-space reflections for glass architecture.
- 2D↔3D↔2D: render the 3D scene to a RenderTarget, texture a DOM-aligned plane with
it, and cross-fade at section seams using a "waterline" camera-Y test.
5. Motion & scroll architecture
- Lenis is the master clock:
lenis.on('scroll', ScrollTrigger.update)and drive
Lenis from one rAF loop that also gsap.tickers. Everything (camera dolly, pins, reveals, shader uScroll) reads from that single progress value.
- Frame-rate independence: multiply every per-frame delta by an
HZ/dt
factor so 120 Hz and 60 Hz look the same. Never assume 60 fps.
- Camera on a curve:
CatmullRomCurve3.getPointAt(progress)for position,
getTangentAt for lookAt; always damp.
- Pointer is always lerped before it touches a uniform; raw pointer feels jittery.
6. Performance & resilience (non-negotiable)
- Render off the main thread when you can: OffscreenCanvas + Web Worker
(createImageBitmap for asset handoff) keeps scroll at 60 fps. Active Theory does this.
- Cap DPR (
min(devicePixelRatio, 2)); run post-FX buffers far below DPR (bloom at 0.3). - Feature-detect: no WebGL2 / float-render / blocklisted GPU / a bot UA → redirect to a
static fallback (Active Theory ships a /fallback). Always honor prefers-reduced-motion.
- Pause the rAF loop when the canvas is offscreen or the tab is hidden.
- Dispose geometries/textures/RTs on teardown; pool render targets across passes.
7. The dependency-free port (what the demo ships)
When Three.js is overkill, the whole Active-Theory recipe fits in raw WebGL2 in one canvas, and that is what main.js (Cinematic Dark world) implements:
1. position FBO ping-pong (FLOAT, NEAREST) seeded on the CPU, 2. a curl-noise sim pass with a mouse attractor + click shock, HZ-scaled, 3. additive HDR points drawn with a real perspective camera (mouse parallax + slow orbit), 4. bright-pass → separable Gaussian (mips) → composite bloom, 5. filmic composite: tone map + chromatic aberration + vignette + grain, 6. feature-detect EXT_color_buffer_float; fall back to the old 2D canvas if absent; honor prefers-reduced-motion.
Verify by rendering in real headless Chromium (not just the IDE preview): the canvas must be non-blank, react to pointer/scroll/click, and show no shader-compile errors.
"""Write a chroma-backdrop image-generation prompt for CoolLanding assets.
The prompt intentionally asks for a fully visible subject on one flat key color.
That makes the asset safe to isolate with chroma_cut.py and avoids segmentation
damage from busy generated scenes.
"""
from __future__ import annotations
import argparse
import textwrap
BACKDROPS = {
"green": ("chroma green", "#00B140"),
"magenta": ("magenta", "#E5007E"),
"violet": ("violet", "#7A1FA2"),
}
WORLD_HINTS = {
"cinematic-dark": "black-stage technical object, luminous edge light, no stock-photo environment",
"editorial-interference": "editorial still-life, strong crop-ready silhouette, paper/halftone friendly",
"ritual-craft": "tactile sticker, doodle, paper object, thick readable silhouette",
"luxury-alcove": "premium product object, polished material, soft museum lighting, no visible brand marks",
"spatial-architecture": "architectural object or model, clean geometry, brochure-grade material",
"festival-kinetic": "event pass, badge, physical prop, bold silhouette and saturated accents",
"papercraft-tactile": "paper-cut illustration element, folded craft texture, hand-built silhouette",
"generative-system": "optional logo/object only; prefer procedural canvas over bitmap assets",
}
def choose_backdrop(args: argparse.Namespace) -> str:
if args.backdrop != "auto":
return args.backdrop
if args.contains_green:
return "magenta"
if args.many_bright_colors:
return "violet"
return "green"
def build_prompt(args: argparse.Namespace) -> str:
backdrop_key = choose_backdrop(args)
backdrop_name, hex_value = BACKDROPS[backdrop_key]
world_hint = WORLD_HINTS.get(args.world, "brand-specific visual object with a clean silhouette")
text_rule = "NO text, NO logo, NO brand name, NO watermark." if not args.allow_text else "Only include text if the brief explicitly requires it."
palette_rule = f"Do not use {backdrop_name} in the subject itself."
return textwrap.dedent(
f"""
{args.subject}, centered and fully visible with generous empty margin on all sides.
Style direction: {world_hint}.
Sharp focus, high-detail edges, soft even studio lighting.
CRITICAL: the entire background is one perfectly uniform, flat, saturated {backdrop_name} ({hex_value}), seamless edge to edge.
No gradient, no vignette, no surface, no cast shadow on the backdrop, no fake transparency checkerboard.
The subject floats cleanly on solid {backdrop_name}. {palette_rule}
{text_rule}
"""
).strip()
def main() -> int:
parser = argparse.ArgumentParser(description="Generate a CoolLanding chroma-backdrop image prompt.")
parser.add_argument("subject", help="Detailed subject to generate.")
parser.add_argument("--world", default="editorial-interference", choices=sorted(WORLD_HINTS), help="Style world for asset grammar.")
parser.add_argument("--backdrop", default="auto", choices=["auto", *BACKDROPS], help="Key color. Auto uses green unless collision flags are set.")
parser.add_argument("--contains-green", action="store_true", help="Use when the subject includes emerald, foliage, green UI, etc.")
parser.add_argument("--many-bright-colors", action="store_true", help="Use when the subject is a colorful sticker/pop asset.")
parser.add_argument("--allow-text", action="store_true", help="Do not forbid text/logos in the prompt.")
args = parser.parse_args()
print(build_prompt(args))
return 0
if __name__ == "__main__":
raise SystemExit(main())
"""Chroma-key and autocrop generated CoolLanding bitmap assets.
Use this after generating a subject on a known flat backdrop. It creates an
RGBA cutout with a soft color-distance matte, gated despill, optional erosion,
light feathering, and an opaque-bounds crop.
"""
from __future__ import annotations
import argparse
import os
from pathlib import Path
import numpy as np
from PIL import Image, ImageFilter
NAMED_COLORS = {
"green": (0, 177, 64), # #00B140
"magenta": (229, 0, 126), # #E5007E
"violet": (122, 31, 162), # #7A1FA2
}
def parse_color(value: str, image: Image.Image | None = None) -> tuple[int, int, int]:
raw = value.strip().lower()
if raw == "auto":
if image is None:
raise ValueError("auto color requires an image")
return sample_corner_color(image)
if raw in NAMED_COLORS:
return NAMED_COLORS[raw]
if raw.startswith("#") and len(raw) == 7:
return tuple(int(raw[i : i + 2], 16) for i in (1, 3, 5))
if "," in raw:
parts = [int(p.strip()) for p in raw.split(",")]
if len(parts) == 3 and all(0 <= p <= 255 for p in parts):
return tuple(parts)
raise ValueError(f"Unsupported color: {value}")
def sample_corner_color(image: Image.Image, size: int = 24) -> tuple[int, int, int]:
im = image.convert("RGB")
w, h = im.size
crops = [
im.crop((0, 0, min(size, w), min(size, h))),
im.crop((max(0, w - size), 0, w, min(size, h))),
im.crop((0, max(0, h - size), min(size, w), h)),
im.crop((max(0, w - size), max(0, h - size), w, h)),
]
samples = np.concatenate([np.asarray(c).reshape(-1, 3) for c in crops], axis=0)
return tuple(int(v) for v in np.median(samples, axis=0))
def smoothstep(x: np.ndarray, lo: float, hi: float) -> np.ndarray:
t = np.clip((x - lo) / max(hi - lo, 1e-6), 0.0, 1.0)
return t * t * (3.0 - 2.0 * t)
def despill(rgb: np.ndarray, bg: tuple[int, int, int], alpha: np.ndarray) -> np.ndarray:
r, g, b = rgb[..., 0], rgb[..., 1], rgb[..., 2]
br, bg_ch, bb = bg
edge_weight = np.clip(1.0 - alpha, 0.0, 1.0)
out = rgb.copy()
if bg_ch >= br and bg_ch >= bb:
cap = np.maximum(r, b)
out[..., 1] = g + (np.minimum(g, cap) - g) * edge_weight
else:
excess = np.clip(0.5 * (r + b) - g, 0, None)
out[..., 0] = r - excess * 0.9 * edge_weight
out[..., 2] = b - excess * 0.9 * edge_weight
return np.clip(out, 0, 255)
def autocrop(image: Image.Image, pad: int, alpha_thresh: int) -> Image.Image:
alpha = np.asarray(image)[..., 3]
ys, xs = np.where(alpha > alpha_thresh)
if len(xs) == 0:
return image
left = max(int(xs.min()) - pad, 0)
top = max(int(ys.min()) - pad, 0)
right = min(int(xs.max()) + pad + 1, image.width)
bottom = min(int(ys.max()) + pad + 1, image.height)
return image.crop((left, top, right, bottom))
def output_path(src: Path, out_dir: Path | None, suffix: str) -> Path:
name = f"{src.stem}{suffix}.png"
return (out_dir or src.parent) / name
def chroma_cut(src: Path, dst: Path, args: argparse.Namespace) -> dict[str, object]:
original = Image.open(src).convert("RGB")
bg = parse_color(args.bg, original)
arr = np.asarray(original).astype(np.float32)
bg_arr = np.array(bg, dtype=np.float32)
dist = np.sqrt(((arr - bg_arr) ** 2).sum(axis=-1))
alpha = smoothstep(dist, args.t_low, args.t_high)
rgb = despill(arr, bg, alpha)
alpha_img = Image.fromarray((alpha * 255).astype(np.uint8), "L")
for _ in range(max(0, args.erode)):
alpha_img = alpha_img.filter(ImageFilter.MinFilter(3))
if args.feather > 0:
alpha_img = alpha_img.filter(ImageFilter.GaussianBlur(args.feather))
out = Image.fromarray(rgb.astype(np.uint8), "RGB").convert("RGBA")
out.putalpha(alpha_img)
if args.crop:
out = autocrop(out, args.pad, args.alpha_thresh)
dst.parent.mkdir(parents=True, exist_ok=True)
out.save(dst)
coverage = float((np.asarray(alpha_img) > args.alpha_thresh).mean())
return {"src": str(src), "out": str(dst), "bg": bg, "coverage": round(coverage, 4), "size": out.size}
def main() -> int:
parser = argparse.ArgumentParser(description="Key and autocrop chroma-backdrop images into PNG cutouts.")
parser.add_argument("inputs", nargs="+", help="Input PNG/JPG files. Globs are expanded by the shell when supported.")
parser.add_argument("--bg", default="green", help="green, magenta, violet, auto, #RRGGBB, or R,G,B.")
parser.add_argument("--out-dir", default=None, help="Optional output directory. Defaults next to each source.")
parser.add_argument("--suffix", default="-cut", help="Output suffix before .png.")
parser.add_argument("--t-low", type=float, default=70.0, help="Distance where matte begins to become opaque.")
parser.add_argument("--t-high", type=float, default=135.0, help="Distance where matte reaches full opacity.")
parser.add_argument("--erode", type=int, default=1, help="MinFilter passes to remove hard backdrop fringe.")
parser.add_argument("--feather", type=float, default=0.7, help="Gaussian blur radius for alpha edge.")
parser.add_argument("--pad", type=int, default=10, help="Autocrop padding in px.")
parser.add_argument("--alpha-thresh", type=int, default=8, help="Alpha threshold for cropping/coverage.")
parser.add_argument("--no-crop", dest="crop", action="store_false", help="Keep original canvas size.")
parser.set_defaults(crop=True)
args = parser.parse_args()
out_dir = Path(args.out_dir) if args.out_dir else None
code = 0
for raw in args.inputs:
src = Path(raw)
if not src.exists():
print(f"missing: {src}")
code = 1
continue
try:
result = chroma_cut(src, output_path(src, out_dir, args.suffix), args)
print(f"ok {result['out']} bg={result['bg']} coverage={result['coverage']} size={result['size']}")
except Exception as exc:
print(f"failed {src}: {exc}")
code = 1
return code
if __name__ == "__main__":
raise SystemExit(main())
"""Render cutout PNGs on real landing-page backgrounds as a contact sheet."""
from __future__ import annotations
import argparse
from pathlib import Path
from PIL import Image, ImageDraw
DEFAULT_BACKGROUNDS = {
"dark": "#0e0b0d",
"cream": "#f3f0e8",
"kraft": "#d4b48c",
"blueblack": "#061016",
}
def parse_hex(value: str) -> tuple[int, int, int]:
raw = value.strip()
if raw.startswith("#") and len(raw) == 7:
return tuple(int(raw[i : i + 2], 16) for i in (1, 3, 5))
raise ValueError(f"Expected #RRGGBB, got {value}")
def parse_backgrounds(items: list[str] | None) -> dict[str, str]:
if not items:
return DEFAULT_BACKGROUNDS
out = {}
for item in items:
if "=" not in item:
raise ValueError("Backgrounds must be name=#RRGGBB")
name, color = item.split("=", 1)
parse_hex(color)
out[name.strip()] = color.strip()
return out
def fit(image: Image.Image, box: int) -> Image.Image:
im = image.copy()
im.thumbnail((box, box), Image.Resampling.LANCZOS)
return im
def main() -> int:
parser = argparse.ArgumentParser(description="Composite cutouts over target backgrounds for halo/spill review.")
parser.add_argument("inputs", nargs="+", help="RGBA cutout PNGs.")
parser.add_argument("--out", default="cutout-preview.png", help="Output contact sheet path.")
parser.add_argument("--bg", action="append", help="Background as name=#RRGGBB. Repeatable.")
parser.add_argument("--cell", type=int, default=300, help="Cell size in px.")
parser.add_argument("--pad", type=int, default=18, help="Padding in px.")
args = parser.parse_args()
backgrounds = parse_backgrounds(args.bg)
paths = [Path(p) for p in args.inputs]
missing = [str(p) for p in paths if not p.exists()]
if missing:
print("missing:", ", ".join(missing))
return 1
cols = len(paths)
rows = len(backgrounds)
label_h = 24
sheet_w = args.pad + cols * (args.cell + args.pad)
sheet_h = args.pad + rows * (args.cell + label_h + args.pad)
sheet = Image.new("RGB", (sheet_w, sheet_h), (238, 238, 238))
draw = ImageDraw.Draw(sheet)
for row, (bg_name, bg_hex) in enumerate(backgrounds.items()):
bg = parse_hex(bg_hex)
y = args.pad + row * (args.cell + label_h + args.pad)
draw.text((args.pad, y), bg_name, fill=(0, 0, 0))
for col, path in enumerate(paths):
x = args.pad + col * (args.cell + args.pad)
tile = Image.new("RGB", (args.cell, args.cell), bg)
im = fit(Image.open(path).convert("RGBA"), args.cell - 2 * args.pad)
ox = (args.cell - im.width) // 2
oy = (args.cell - im.height) // 2
tile.paste(im, (ox, oy), im)
sheet.paste(tile, (x, y + label_h))
if row == 0:
draw.text((x, 4), path.name[:34], fill=(0, 0, 0))
out = Path(args.out)
out.parent.mkdir(parents=True, exist_ok=True)
sheet.save(out, quality=90)
print(f"wrote {out}")
return 0
if __name__ == "__main__":
raise SystemExit(main())