8.9 KiB
Site update v5 — hero centered, real pin-scroll, card illustrations, bifrost headline breathing room
Four changes in this round. v4's wheelMultiplier sticky approach is replaced with a proper ScrollTrigger pin implementation because the previous attempts didn't feel sticky enough.
Files to replace
| File | What changed |
|---|---|
protected/index.html |
Hero centered vertically (align-items + padding reset); AI + Agents cards get custom mask-image illustrations; Project Bifrost headline padding + looser line-height |
protected/bifrost.js |
wheelMultiplier approach removed; ScrollTrigger pins added on hero, each map stop, and #bifrost-join; map path rebuilds on ScrollTrigger refresh |
protected/timeline.js |
No change from v4 — copy only if you want fresh copy alongside |
New files to upload
| File | Destination on server |
|---|---|
ai.png |
/opt/fenja/protected/fenja/illustrations/ai.png |
agents.png |
/opt/fenja/protected/fenja/illustrations/agents.png |
If you're using rsync with --delete, ensure the local protected/fenja/illustrations/ folder contains both PNGs so they end up on the VPS. Otherwise the AI and Agents cards will show blank (the mask-image URL points to 404).
Change-by-change
1. Hero vertically centered
#herois nowalign-items: center(wasstart) withpadding-top: 0.#page-overview #hero .hero-wrapalso haspadding-top: 0— parent centering now handles vertical position.- The whole block (eyebrow + title + lede + hero-foot row) reads as centered on viewport load. No block-level math needed — CSS grid does it.
2. Real scroll pinning via GSAP ScrollTrigger
v4's wheelMultiplier trick (reducing Lenis wheel input to 0.35× inside a "sticky zone") didn't produce the tactile "scroll a few times to pass" feel you wanted. Replaced entirely with proper GSAP ScrollTrigger pins.
How it works:
ScrollTrigger.create({
trigger: el,
start: 'center center',
end: '+=300', // 300px of extra scroll distance held
pin: true,
pinSpacing: true, // document grows by 300px — user MUST scroll through
anticipatePin: 1,
});
Pinned targets + their hold distances:
| Target | Hold | Why |
|---|---|---|
#hero |
+300px | Gentle hold on entry |
#bifrost-meaning .map-stop--intro |
+260px | Short — it's just an intro card |
#bifrost-meaning .map-stop[data-stop="1"] (Community) |
+360px | Full artifact card — noticeable hold |
#bifrost-meaning .map-stop[data-stop="2"] (Advisory Council) |
+360px | Same |
#bifrost-meaning .map-stop[data-stop="3"] (Pilot Projects) |
+360px | Same |
#bifrost-join |
+260px | CTA gets a moment before footer |
Deliberately NOT pinned (they already have their own pin/scrub mechanics — double-pinning would fight):
#stack-scene(S2 architecture — GSAP scrub pin)#words-scene(S3 — position:sticky pin inside tall parent)#bifrost(S4 — position:sticky pin on.bifrost-pin)
Why pinSpacing:true matters:
pinSpacing: true injects a spacer div that grows the document by the pin hold distance. Without it, the pin is visually held but the scroll counter advances normally — no "scroll multiple times" feeling. With it, every pin zone adds real scroll distance, so the user genuinely has to keep scrolling.
The map path rebuild:
pinSpacing: true pushes each subsequent map stop further down the document. The winding SVG path that connects the dots is computed from live DOM positions via buildMapPath(). To keep the path threading correctly through the shifted dots, buildMapPath now re-runs on every ScrollTrigger.refresh event. No manual intervention needed.
3. Card illustrations — AI + Agents
Two of the four architecture cards now carry bespoke illustrations:
- The AI (data-layer="0") →
/fenja/illustrations/ai.png— the single topographic orb - The Agents (data-layer="3") →
/fenja/illustrations/agents.png— central orb with six connected smaller orbs
How the rendering works:
The PNGs are white line-art on black backgrounds. They're applied via CSS mask-image on the existing .card-brain element. The black background becomes transparent (mask excludes black) and the white lines paint through in the card's paper fill color. Because it's a mask, the lines render as a single flat color on every card background — matches the existing design system.
Per-card overrides (layers 1 and 2 keep the default brain mask):
.layer-card[data-layer="0"] .card-brain {
mask-image: url('/fenja/illustrations/ai.png');
aspect-ratio: 1 / 1;
mask-size: contain;
mask-position: center;
}
.layer-card[data-layer="3"] .card-brain {
mask-image: url('/fenja/illustrations/agents.png');
aspect-ratio: 1 / 1;
mask-size: contain;
mask-position: center;
}
The PNGs must be deployed to /opt/fenja/protected/fenja/illustrations/ or the cards will show blank. See "New files to upload" above.
4. Project Bifrost headline — room to breathe
.bifrost-pin has overflow: hidden (it clips the aurora arc's off-screen portions). Combined with .bifrost-name's tight line-height: 0.95 and the italic "Bifrost" token's gradient background-clip: text, the top and bottom edges of the headline were getting clipped.
Fixes, both on .bifrost-name:
line-height: 0.95→1.12— room for ascenders and descenders- Added
padding: 0.12em 0.08em— generous vertical buffer absorbed into the headline's own box, so the parent.bifrost-pinoverflow:hidden doesn't reach into the glyphs
Parent overflow:hidden stays (it's protecting the arc animation). The headline simply carries its own breathing room now.
Spot-check after deploy
- Overview → hero text sits vertically centered on viewport load. Visually balanced — not clinging to top or bottom.
- Scroll past hero → real resistance. After a bit of wheel input, hero unpins and S2 comes in. NOT a smooth flyby.
- Scroll into treasure map. Each stop visibly holds as it reaches viewport center. You need several wheel flicks to pass through Community, then Advisory Council, then Pilot Projects.
- The winding SVG path still threads through each dot correctly — the path has rebuilt itself to account for the new document height from pin spacing.
- AI card shows a single textured orb illustration (white line-art, paper color on the card's color).
- Agents card shows the network-of-orbs illustration.
- Knowledge and Tools cards still show the default brain illustration.
- S4 Bifrost reveal: "Project Bifrost" headline visible top to bottom — no clipping on italic "Bifrost" tall letters.
Tuning knobs
If the pin holds feel too aggressive:
| Target | In bifrost.js (stickyPinSpecs array) |
Change |
|---|---|---|
| Less hero hold | { sel: '#hero', hold: 300 } |
→ 150 |
| Less treasure map hold | hold: 360 on data-stop entries |
→ 200 |
| Stronger hold | any hold: N |
→ higher N |
If a single pin feels wrong and you want to kill it without breaking others, just delete that entry from stickyPinSpecs.
If the pins break the map path threading (it's rebuilt on refresh but if something's off): open DevTools, scroll through, and verify buildMapPath is firing via the ScrollTrigger.addEventListener('refresh', buildMapPath) hook. The path uses live DOM positions so it should always match.
Things NOT touched
public/entrance.html/entrance.js— unchanged.- Any of
src/(auth, db, sessions) — unchanged. - S2 architecture scene (scrub pin intact), S3 words fly-in (sticky pin intact), S4 aurora arc (sticky pin intact).
- The topography parallax behind Europe map (from v3) — still present, still working.
- The Welcome dot, 7-section nav, hero-foot restructure — all still in place.
Deploy steps
# Local — copy the new files in
Copy-Item -Force site-update-v5\protected\index.html protected\index.html
Copy-Item -Force site-update-v5\protected\timeline.js protected\timeline.js
Copy-Item -Force site-update-v5\protected\bifrost.js protected\bifrost.js
# Create the illustrations folder if it doesn't exist and copy PNGs
New-Item -ItemType Directory -Force -Path protected\fenja\illustrations
Copy-Item -Force site-update-v5\protected\fenja\illustrations\ai.png protected\fenja\illustrations\
Copy-Item -Force site-update-v5\protected\fenja\illustrations\agents.png protected\fenja\illustrations\
# Test locally
npm run dev
# Verify all four changes work before pushing
# Commit + deploy
git add protected/
git commit -m "Hero centered, real ScrollTrigger pins, AI+Agents card illustrations, Bifrost headline breathing room"
# rsync + VPS steps same as before — rsync picks up the new PNGs automatically
On the VPS after rsync, verify the PNGs landed:
ls -la /opt/fenja/protected/fenja/illustrations/
# Should show: ai.png, agents.png, and the three existing stop illustrations
Then sudo systemctl restart fenja and spot-check.