Embed the effect in an existing site
The standalone page is the fastest way to ship the effect, but most real sites already have a page — a hero section that should assemble a product shot, a header that should dissolve a logo. For that, the studio emits the effect as a bare JavaScript module you splice into your own markup:
node cli.mjs hero.jpg --emit js --stdout > hero-scroll.js
# or, from the Studio: "Copy JS module"
The module is framework-agnostic on purpose. It doesn't render your content or wrap it in components; it mounts a canvas behind the page and publishes a clock. Your page keeps its own structure — React, plain HTML, a CMS template, anything that can load a script.
The contract: two things the host page owes
The module mounts its own fixed, full-viewport canvas at
z-index: 0 with pointer-events: none — it never
intercepts a click. In exchange, the host provides:
- A layered wrapper. Your visible content goes in a
container with
position: relative; z-index: 1, so it paints over the canvas instead of underneath it. - Real scroll height. The assembly track is the emitted
scroll length (
--scroll, default 400vh) minus one viewport — not the document height. Give the content at least that much height (min-height: 400vhis what the standalone page does). Anything parked below the track scrolls over the finished image, which is exactly where a call to action wants to live.
<div style="position: relative; z-index: 1; min-height: 400vh">
… your sections …
</div>
<script type="module" src="/hero-scroll.js"></script>
Load it as type="module": it imports three.js r160 — the one
external request it makes — from jsDelivr, falling back to unpkg if that host
is blocked.
Pacing your content on the camera's clock
The module publishes its progress so the page can ride it instead of inventing a second timeline:
--assembly— a custom property on:root, 0 to 1, republished only when it changes. Pure CSS can key opacity or transforms off it:opacity: calc(var(--assembly))fades a caption in as the picture lands.pixelScroll— aCustomEventonwindowcarryingdetail.assembly, the same number, for anything that needs JavaScript.pixelScroll:motion— dispatch with{ still: true }to hold the picture assembled (a "reduce motion" toggle, a modal opening). It is OR-ed withprefers-reduced-motion, never swapped: your toggle can add stillness, but the visitor's OS preference is the floor, and nothing on the page can override it back into motion.
Style the fallback, don't fear it
When WebGL is unavailable or no three.js host is reachable, the module
mounts the photograph as a still — framed the way the settled mosaic would
have been — publishes assembly as 1, and sets
data-forge-fallback on <html>. Content keyed
to the assembly lays out over a resolved image instead of waiting for one
that is never coming. Treat it as a design state, not an error: check your
page once with WebGL disabled, and add a
html[data-forge-fallback] rule if anything needs to sit
differently over the still.
Fitting it to a section, not a page
If the effect should own only the top of a long page, keep the track short
— forge with a smaller --scroll — and let the rest of your
document begin below it; once the camera runs out of track, the finished
image simply holds while normal scrolling continues. Forge with
--bg transparent when the canvas must sit over your site's own
background styling rather than painting its own.
The full list of seams and their exact semantics is in the
documentation; the mechanism that makes the landing
seamless is the how-it-works guide. And
if what you actually want is a whole page composed for you, that is
--theme.