customer-presentation/SITE_STRUCTURE_REFERENCE.md
2026-04-23 12:40:18 +02:00

22 KiB
Raw Blame History

Project Bifrost — Site Structure Reference

This document labels every editable piece of the site with a short name you can quote when asking for changes, and notes where each piece lives in the code. Use the labels (e.g. S1 lede, P3 footer) to point at changes precisely.


Top-level structure

The site has three pages, each occupying the full viewport. A dot-nav at the bottom switches between them.

/timeline  →  ┌─────────────────────────────────────────────┐
              │  [P1] TIMELINE                              │
              │  [P2] OVERVIEW (Project Bifrost scenes)     │
              │  [P3] ARCHIVE                               │
              └─────────────────────────────────────────────┘

Only one page is visible at a time. They are mutually exclusive — switching between them is a class toggle on the page wrapper, not a navigation.

Before reaching any of the three, users see the entrance at / (email form → welcome step). The entrance is a separate HTML file in public/.


[P1] TIMELINE — horizontal scroll catalog

Files: protected/index.html (#page-timeline, lines ~739758) + protected/timeline.js

A horizontal mousewheel-driven scroll through 23 editorial cards, set over a slowly rotating orthographic globe. Cards alternate above and below a central spine; each is accented by one of four colours (copper/ochre/terracotta/crimson) denoting register.

Label What it is Where to change
P1 page title "From the promise of AI to the loss of sovereignty." index.html line 740
P1 subtitle "Twenty-three headlines, quietly laid across a tinted map. Scroll the wheel — the map turns with you." index.html line 741
P1 globe Rotating orthographic globe that tracks scroll position from N. America → Europe timeline.jsbuildGlobe() + setRotation in applyScroll()
P1 events The 23 headline cards. Each has date, kind, accent, hed, body, source timeline.jsEVENTS array, lines 4102
P1 card styles Card layout, above/below-spine positioning, colour accents per accent value index.html CSS .evt, .accent-*
P1 year ticks "2022", "2023", … on the spine between groups of cards timeline.jsbuildTimeline(), year-tick loop
P1 "Read the editor's note" button Bottom-right, appears near the end of the catalog; fires dot-nav switch to Overview index.html line 747 (text) + .continue-btn CSS + timeline.js click handler

[P2] OVERVIEW — The Project Bifrost scroll

Files: protected/index.html (#page-overview, lines ~22322619) + protected/bifrost.js

A vertically scrolling container that holds six scroll-bound scenes. The Europe map sits as a fixed background behind them all and fades in/out with scroll position.

┌─ S1 HERO ──────────────┐
│  "Secure & Sovereign   │  ← Europe map fades behind
│   AI, hosted where it  │
│   belongs."            │
└────────────────────────┘
┌─ S2 ARCHITECTURE ──────┐
│  4 layer cards fall +  │  ← pinned, scrubbed
│  morph into 2x2 grid   │
└────────────────────────┘
┌─ S3 WORDS ─────────────┐
│  "...built with them,  │  ← words fly in
│   not just for them."  │
└────────────────────────┘
┌─ S4 BIFROST ARC ───────┐
│  🌈 aurora arc draws   │  ← "Introducing Project Bifrost"
│  "Project Bifrost"     │
└────────────────────────┘
┌─ S5 TREASURE MAP ──────┐
│  Community, Advisory   │  ← 3 stops on a winding path
│  Council, Pilot Proj.  │
└────────────────────────┘
┌─ S6 JOIN CTA + FOOTER ─┐
│  "Join us in shaping…" │  ← button → confirmation panel
│  [Proj] [Fenja] [Innov]│  ← 3-column footer
└────────────────────────┘

S0 — Europe map background

The map stays static behind all six scenes. It does not rotate with scroll; it only fades.

Label What it is Where
P2 Europe map Static orthographic globe centered on Europe, sitting behind the hero index.html line 2234 (.overview-globe) + CSS line 441
P2 map opacity ceiling Maximum map opacity (currently 0.42) bifrost.jsMAP_MAX_OPACITY constant
P2 map fade curve Fully visible 020% scroll, fades to 0 by 80% scroll, fades back in when scrolling up bifrost.jsupdateMapOpacity() function

S1 — Hero

Label What it is Where
S1 eyebrow "For regulated environments" index.html line 2246
S1 headline "Secure & Sovereign AI, hosted where it belongs." index.html lines 22472250
S1 lede "Enabling highly advanced AI capabilities hosted within the client's own secure infrastructure." index.html lines 22512253
S1 supported-by Innovationsfonden placeholder logo + "Supported by" strip index.html lines 22582267
S1 scroll hint "Scroll →" indicator bottom-right index.html lines 22682271
S1 hero styles Type scale, colours, grid positioning, left-column anchoring index.html CSS #hero, .hero-title, .hero-lede, .hero-foot
S1 hero animation Word-by-word reveal of the headline on scene entry bifrost.js — search HERO — staggered intro

S2 — Architecture stack

Four cards fall into a stack one at a time, then rearrange into a 2x2 grid. As they do, three copy panels crossfade on the left.

Label What it is Where
S2 copy panel A "All the capabilities to solve business use cases with AI. Four layers. One architecture. Every piece yours to own." index.html lines 22842288 (data-copy="0")
S2 copy panel B "Full client control. Complete sovereignty." + "Nothing proprietary above the hardware…" index.html lines 22892292 (data-copy="1")
S2 copy panel C "Built in Denmark. For Europe." + "Engineered against the standards that matter here…" index.html lines 22932297 (data-copy="2")
S2 card 1 — Foundation "AI — An open-source model, running on your own hardware." index.html lines 23022310 (data-layer="0")
S2 card 2 — Knowledge "The vocabulary of your business — learned, retained." index.html lines 23122320 (data-layer="1")
S2 card 3 — Tools "How the AIs act — not just what they know." index.html lines 23222330 (data-layer="2")
S2 card 4 — Agents "Specialists, collaborating to solve distinct tasks." index.html lines 23322340 (data-layer="3")
S2 stack animation The fall, stack, morph-to-grid scrub sequence bifrost.js — search ARCHITECTURE — two-phase scrubbed sequence
S2 card styles Shape, padding, "brain" illustration, eyebrow, grid-mode styles index.html CSS .layer-card, .card-box, .card-brain, .in-grid

S3 — Words fly in

Sixteen individual words fly in from random directions as the user scrolls, assembling into one full sentence. Two words (with and them,) are given extra visual weight.

Label What it is Where
S3 full sentence "But a platform for regulated organisations has to be built with them, not just for them." index.html lines 23612376
S3 highlight words with, them, — the two words with emphasis class hi index.html lines 23712372
S3 word styles + animation Individual word reveal with scatter/scale/blur bifrost.js — search WORDS fly in; CSS .words, .w, .w.hi

S4 — Bifrost aurora arc

A rainbow arc draws across the scene, then the "Project Bifrost" title fades in below it. This is the only place on the site where a gradient is used.

Label What it is Where
S4 eyebrow "Introducing" index.html line 2441
S4 name "Project Bifrost" (split into two tokens — "Project" + "Bifrost") index.html lines 24422445
S4 subtitle "The bridge between an industrial-grade AI platform and the realities of regulated organisations — built with them, not just for them." index.html lines 24462448
S4 arc The rainbow arc that draws across the scene index.html lines 23912436 — <svg> with #arcHalo, #arcMain, #arcThin
S4 arc colors The aurora gradient stops (ochre → terracotta → indigo → heather) index.html lines 23932408 — <linearGradient> stops
S4 arc animation Stroke-dashoffset draw-in on scroll bifrost.js — search PROJECT BIFROST REVEAL

S5 — Treasure map (3 stops)

A winding path draws down the scene, passing through three "stops" — each an illustrated card about one way to participate in Project Bifrost. Stops alternate left / right of the path.

Label What it is Where
S5 intro title "What being part of Project Bifrost means" index.html lines 24692471
S5 intro lede "Three ways to shape, to influence, and to build with the platform from the inside — a journey through what participation actually looks like." index.html lines 24722474
S5 winding path The bezier curve drawn between stops; rebuilt at runtime to pass through dot positions index.html lines 24822494 (SVG shell); bifrost.jsbuildMapPath()
S5 intro stop "Being part of Project Bifrost means three things — a community to shape the future with, a council to influence the platform through, and pilot projects that put it in your hands first." (centered introductory copy) index.html lines 24972504
S5 stop 1 — Community Eyebrow "Be part of a" + title "Community" + sub "Shape the future together" + body copy + illustration of six people in discussion index.html lines 25072518; illustration fenja/illustrations/community.svg
S5 stop 2 — Advisory Council Eyebrow "Be part of an" + title "Advisory Council" + sub "Turn insight into influence" + body copy + illustration of a man and a woman in conversation index.html lines 25212532; illustration fenja/illustrations/council.svg
S5 stop 3 — Pilot Projects Eyebrow "Be part of" + title "Pilot Projects" + sub "Access the platform before others" + body copy + illustration of two people at a computer index.html lines 25352546; illustration fenja/illustrations/pilot.svg
S5 path animation + per-stop reveals Draw-in of path; dot pops in + text/image fade on reach bifrost.js — search Treasure-map path draw
S5 styles Layout, alternating left/right stops, dots, path styling index.html CSS .map-intro, .map-canvas, .map-stop, .dot-anchor, .stop-*

The final scene is a large call-to-action headline with a single button. Clicking the button crossfades to a confirmation panel listing what happens next. Below, a three-column footer with brand marks.

Label What it is Where
S6 CTA eyebrow "Ready?" index.html line 2565
S6 CTA headline "Join us in shaping the future of trusted sovereign AI." index.html lines 25662568
S6 CTA button text "Join Project Bifrost" index.html lines 25692572
S6 CTA subtext "Built in Denmark. Supported by the Innovation Fund." index.html line 2573
S6 confirmation eyebrow "You're in" index.html line 2578
S6 confirmation headline "Thank you for joining Project Bifrost." index.html lines 25792581
S6 confirmation list item 1 "The Fenja AI team will reach out to you shortly." index.html line 2583
S6 confirmation list item 2 "You'll receive an invitation to the project portal soon…" index.html line 2584
S6 confirmation list item 3 "We're currently setting the date for the first advisory council meeting…" index.html line 2585
S6 confirmation list item 4 "We'll be in touch shortly about your participation in the pilot project." index.html line 2586
S6 footer left — "Project Bifrost" Wordmark rendered in Newsreader with italic emphasis on "Bifrost" index.html line 2593
S6 footer center — Fenja logo <img> pointing to /fenja/fenja-wordmark-black.svg index.html lines 25952599
S6 footer right — Innovationsfonden Placeholder slanted-I mark + "nnovationsfonden" text (to be swapped for real asset) index.html lines 26012612
S6 click handler CTA → confirmation crossfade + staggered checkmarks on list items bifrost.js — search SCENE 6 — Join section

[P3] ARCHIVE — 23-row table

Files: protected/index.html (#page-archive, lines ~26222651) + protected/timeline.js archive-builder IIFE

A tabular view of the same 23 events from the timeline, sorted chronologically. Each row fades its background on hover.

Label What it is Where
P3 headline "All twenty-three entries, in order of publication." index.html line 2625
P3 sub "Dates, sources and plate numbers for every card in the catalog. Hover a row to lift it from the paper." index.html lines 26262629
P3 table 5 columns: №, Date, Register, Headline, Source index.html table markup + timeline.js archive-builder IIFE (lines 406420)
P3 data Same EVENTS array as the timeline timeline.jsEVENTS
P3 footer "Fenja AI · Field Notes, No. IV / Catalog closed 14 April 2026 / Page III of III" index.html lines 26442648

Shared chrome — visible on all three pages

Files: protected/index.html (lines 2207 + 26532668) + protected/timeline.js

Label What it is Where
Site wordmark Top-left Fenja logo, 118px wide index.html line 2207
Dot-nav tray Subtle gradient fade at the bottom edge of the viewport index.html .dot-nav-tray
Dot-nav Bottom-center "Timeline / Overview / Archive" page switcher index.html lines 26532668
Dot-nav logic Page activation + bifrost lazy-init on first Overview visit timeline.jsactivatePage() function, lines 439457

Entrance — before login

Files: public/entrance.html + public/entrance.js

The only public-facing page. A single email field; on submit, if the email is on the invite list, advances to a welcome step. Otherwise shows an inline "not invited" message.

Label What it is Where
Entrance tagline "Thank you for your commitment and willingness to contribute." entrance.html step-email .tagline
Entrance email input The single input field with "your email" placeholder entrance.html step-email <form>
Entrance topographic currents Concentric-circle SVG background in the top-right entrance.jsdrawCurrents() IIFE
Entrance error messages "Please enter a valid email address." / "This email is not on the invite list." / "Too many attempts…" entrance.js — inside the submit handler
Welcome title "Thanks for your interest, [Name]." (or "Thank you for your interest." when no first name) — set by JS after a successful login entrance.jssetWelcomeTitle()
Welcome body, paragraph 1 "Thank you for joining and for your interest in enabling sovereign AI in Denmark and Europe. Project Bifrost is a deliberate effort to advance it — the conviction that how we build these systems, and where, will shape the next decades." entrance.html step-welcome .welcome-body (first one)
Welcome body, paragraph 2 "What follows is a timeline: twenty-three moments that explain why this matters now, and what the path looks like." entrance.html step-welcome .welcome-body (second one)
"Learn more" button The button that routes to /timeline entrance.html step-welcome #welcome-continue
Welcome logo ghost Faint Fenja wordmark occupying the right half of the viewport entrance.html .welcome-logo

Auth — server-side

Files: src/auth.js + src/sessions.js + src/db.js + bin/invite.js

For completeness — not UI, but labelled here so you can point at it when relevant.

Label What it is Where
Login endpoint POST /auth/login — accepts {email}, returns {ok, firstName} on success or {error: "not_invited"} with 403 src/auth.js
Login rate limit 30 attempts per IP per hour src/auth.jsrateLimit({…}) on /login route
Logout endpoint POST /auth/logout — clears session cookie src/auth.js
Me endpoint GET /auth/me — returns {email, firstName} for current session or 401 src/auth.js
Invite CLI node bin/invite.js add <email> [FirstName] / remove / list bin/invite.js
Invite schema invites(email, first_name, invited_at, invited_by) src/db.js
Session duration 30 days src/sessions.jsSESSION_TTL_MS

Design tokens — safe to change, affect everything cohesively

File: protected/fenja/colors_and_type.css

Token Value Meaning
--paper / --background #faf6ee Primary paper background
--ink / --on-surface #383831 Primary text colour
--ink-soft / --on-surface-variant #5f5e5e Muted text
--ink-dim / --on-surface-muted #8a887f Very muted text
--walnut / --secondary #785f53 Primary accent (links, focus rings)
--crimson #8a3a2f Destructive / error
--pigment-terracotta #b96b58 Warnings, S4 Bifrost accent
--pigment-copper #6d8c7c Success, organic / growth
--pigment-ochre #c29d59 Cautions, tertiary
--pigment-indigo #5a6d83 Info (only "blue" allowed)
--pigment-heather #8d7a85 Categorical, supportive
Aurora gradient stops ochre → terracotta → indigo → heather S4 arc only

Fonts: Newsreader (serif, for intent) and Manrope (sans, for execution). Both self-hosted as variable fonts in protected/fenja/fonts/.

The "no line" rule applies throughout: depth comes from tonal surface shifts, not 1px borders. Emphasis is applied via the Fenja rule — last keyword in Newsreader Bold Italic, followed by the absolute period.


How to ask for changes

Pick a label from the tables above and tell me what you want changed. Examples:

  • "Change S1 lede to say …"
  • "Swap the colour of the S4 arc from terracotta to copper"
  • "Remove S5 stop 2 entirely; renumber the path"
  • "Add a 5th item to the S6 confirmation list"
  • "Reorder: move S3 Words to come after S4 Bifrost Arc"
  • "Make the P2 Europe map fully fade out by 40% scroll instead of 80%"
  • "Change the Welcome title to read differently when the user has no first name"
  • "Update P1 events entry #14 (the November 2024 rupture) to say …"

If a change crosses multiple sections (for example, "add a fourth treasure map stop" or "reorganise the six scenes into five"), I'll lay out the pieces that need to move in a plan before writing code, so you can sign off.

If something you want to change isn't on this map, quote a phrase from the site and I'll find it.


File index — where each label's code lives

protected/
├── index.html                          [P1], [P2 except animations], [P3], shared chrome
├── timeline.js                         [P1 events + globe + card builder], [P3 table builder],
│                                       dot-nav logic + bifrost lazy-init
├── bifrost.js                          All [P2] scene animations + Europe map fade
├── vendor/
│   ├── lenis.min.js                    Smooth scroll (for [P2])
│   ├── gsap.min.js                     Animation engine
│   ├── scrolltrigger.min.js            Scroll-bound timelines
│   ├── d3-array.min.js                 Globe math (used by timeline.js)
│   ├── d3-geo.min.js                   Globe projection
│   ├── topojson-client.min.js          World topology parser
│   └── countries-110m.json             World country shapes
└── fenja/
    ├── colors_and_type.css             Design tokens
    ├── fonts/                          Manrope + Newsreader (variable fonts)
    ├── fenja-wordmark-black.svg        Logo — used by site-mark + S6 footer
    └── illustrations/
        ├── community.svg               S5 stop 1
        ├── council.svg                 S5 stop 2
        └── pilot.svg                   S5 stop 3

public/
├── entrance.html                       Entrance + welcome steps (before login)
└── entrance.js                         Entrance form behaviour, welcome title logic

src/
├── auth.js                             /auth/login, /auth/logout, /auth/me
├── db.js                               SQLite schema + prepared queries
├── sessions.js                         Session cookie lifecycle
└── middleware.js                       rateLimit() + requireAuth()

bin/
└── invite.js                           CLI: add / remove / list invites

server.js                               Entry point, CSP, routing