Refactoring

This commit is contained in:
Felix Klement committed 2026-10-09 14:28:57 +02:00
1 parent fd58a8d32f
commit 97e219456d
29 files changed
+45 -408

No files matched your search

+24 -37
View File
@@ -38,18 +38,18 @@ Environment; see *Contact form* below.
| `src/i18n/ui.ts` | All interface copy, English and German, one object per language with the same shape. |
| `src/data/team.ts` | Team members, roles, portraits, links. |
| `src/content/insights/*.md` | Insights posts (content collection). Front matter: title, date, lang, category, readingTime, author, cover. |
| `src/components/home/*` | One file per home section, in page order: Hero, Manifesto, Method (with `MethodDiagram`), Stages (with `GridObject`), Sectors, Proof, Quote, Insights, Contact. |
| `src/components/home/GridObject.astro` | The wireframe objects on the stage and product cards (sphere, cube, plane, wave, steps, nested, stack). Geometry is computed at build time; single stroke in `--ink`. Each drawing is laid out by hand, so the `viewBox` is derived from the points as they are emitted, not assumed: a square centred on the drawing, padded for the stroke. A new kind can therefore never be clipped, and the card gives the drawing the flexible row so it sits centred between title and body. Each drawing is emitted in two groups, the lines that carry its idea and the grid around them, which is what the hover and the reveal act on. |
| `src/components/home/*` | One file per home section, in page order: Hero, Manifesto, Method (with `MethodDiagram`), Sectors, Partners, Quote, Insights, Contact. |
| `src/components/verifier/GridObject.astro` | The wireframe objects on the product cards (steps, nested, stack). Geometry is computed at build time; single stroke in `--ink`. Each drawing is laid out by hand, so the `viewBox` is derived from the points as they are emitted, not assumed: a square centred on the drawing, padded for the stroke. A new kind can therefore never be clipped, and the card gives the drawing the flexible row so it sits centred between title and body. Each drawing is emitted in two groups, the lines that carry its idea and the grid around them, which is what the hover acts on. |
| `src/components/home/MethodDiagram.astro` | The four-stage loop, wide and tall compositions. Labels come from `ui.method.stages`. |
| `src/components/verifier/*` | The CipherVerifier product page, in page order: Hero (line burst), Intro (image band), HowItWorks (five group cards, one schematic each; on wide screens the heading is sticky and the cards stack under it as you scroll), Cards, Facts, Outro. |
| `src/components/verifier/*` | The CipherVerifier product page, in page order: Hero (line burst), Intro (image band), HowItWorks (five group cards, one schematic each; on wide screens the heading is sticky and the cards stack under it as you scroll), Cards (with `GridObject`), Facts, Outro. |
| `src/components/verifier/SoonHero.astro`, `ComingSoon.astro` | The coming-soon version of `/cipherverifier`, shown while `verifierComingSoon` in `src/data/flags.ts` is true: hero on a build-time SVG relief of ridge lines in the logo blues, under the floating header, "Coming soon." with the alpha sign-up beside it, a status strip, and the product name set across the full width and cut by the hero's lower edge, release path, spec sheet and the first schematic. Copy in `ui.verifier.soon`. |
| `src/components/verifier/diagrams.ts` | The five schematics as data: a hand-placed wide layout and an auto-generated tall spine per group. `Schematic.astro` renders either. Labels come from `ui.verifier.how.groups`; the tuple shape is in `types.ts`. Every element carries the `group` of the node it belongs to, which drives the hover focus and the draw-in order. |
| `server/contact.mjs`, `server/mail/` | The handler for both forms (contact, alpha sign-up): validates, checks the proof of work, rate-limits and sends by SMTP. `server/mail/confirm.mjs` lays out the confirmation email (tables, inline styles, logo as an inline attachment). Its own `package.json`, so the image only carries nodemailer and altcha-lib. |
| `scripts/*.mjs` | Review tooling: `shot.mjs` (full page), `scroll-shots.mjs` (viewport by viewport), `tabs-test.mjs` (keyboard test for the sectors tabs), `contact-sheet.mjs`. Need `npx astro preview --port 4322`. |
| `scripts/*.mjs` | Review tooling (Playwright): `shot.mjs` (full page), `scroll-shots.mjs` and `stack-shots.mjs` (viewport by viewport), `motion-shots.mjs` (a draw-in over time), `hover-shot.mjs`, `tabs-test.mjs` and `tabs-shots.mjs` (sectors tabs), `panel-shots.mjs`, `object-fit-test.mjs` (grid objects inside their viewBox), and for the full product page's pinned steps `pinned-steps-test.mjs`, `panel-align-test.mjs`, `step-exit-test.mjs`. `contact-sheet.mjs` tiles a folder of images. Need `npx astro preview --port 4322`. |
| `scripts/research-figures.py` | Gives every paper in `src/data/research.json` its Chladni figure and colour field. `src/data/scholar/*.json` are the raw Google Scholar exports that file was built from. |
| `src/pages/_*.astro` | Shared page bodies. `index.astro` and `de/index.astro` render `_Home.astro` with a `lang` prop, and so on. |
| `src/assets/images/` | Source images. Astro emits AVIF with a WebP fallback and explicit dimensions. |
| `public/fonts/` | Self-hosted Inter Tight variable (latin, latin-ext). |
| `public/video/` | The home hero's background loop, MP4 and WebM. Shipped as-is; Astro does not process video. |
| `public/fonts/` | Self-hosted Inter Tight and JetBrains Mono, variable (latin, latin-ext). |
## Routes
@@ -151,47 +151,31 @@ The three newest posts appear on the home page automatically.
## The card drawings
The objects on the stage cards ("What we do.") and the product cards do not animate on arrival;
they are simply drawn. Hovering a card sets `--object-grid`, which the drawing answers by letting
its grid recede to 26% while the lines that carry the idea stay: the cube's own edges, the tile
lifted out of the plane, the wave's profiles, the inner cube inside its shell, the column to fix
first. The card also sets `--object-scale`. Both are custom properties the card owns and the
The objects on the product cards do not animate on arrival; they are simply drawn. Hovering a
card sets `--object-grid`, which the drawing answers by letting its grid recede to 26% while the
lines that carry the idea stay: the inner cube inside its shell, the column to fix first, the
newest layer of the stack. The card also sets `--object-scale`. Both are custom properties the card owns and the
drawing responds to, so the interaction lives with the card and the response with the drawing.
It is behind `@media (hover: hover)` so touch never sticks in it, and it is the same language as
the hover focus on the product page schematics.
## The hero video
## The hero
The home hero plays `public/video/hero-plant.mp4` / `.webm` behind the headline, over the
`plant-at-dusk.jpg` still. The still is the video's own first frame, so it carries the hero until
the video is ready and stays put for anyone who never gets one.
The video is only fetched when it will be seen: not under `prefers-reduced-motion`, not on
`saveData`, and not below 48rem, where a 21:9 frame would be cropped to a sliver for the most
expensive bytes. The sources are attached by script rather than in the markup, so nothing is
requested otherwise. A blocked autoplay also just leaves the still in place.
The source clip was generated with Magnific (Kling 2.5, 10 s, from the hero still as its start
frame, https://www.magnific.com/app/creation/5jPaI3qKxe). `scripts/encode-hero-video.sh` turns a
clip into the looping file: it plays forward, then backward, so the loop point cannot be seen, and
encodes 1920-wide H.264 and VP9. A 20-second loop lands at 862 KB and 472 KB. To replace it:
```sh
FFMPEG=/path/to/ffmpeg ./scripts/encode-hero-video.sh source.mp4 public/video/hero-plant 1920
```
Keep the first frame of any replacement equal to `plant-at-dusk.jpg`, or replace both together.
The home hero is a noise field in the logo's blues on night, drawn by a small WebGL shader
(`src/scripts/noise-field.ts`) that drifts slowly and bends towards the pointer. It renders at half
resolution, caps at 30 fps and only runs while the hero is on screen. Underneath sits
`hero-field.png`, a frame of the same shader, so the hand-over is invisible and the poster carries
the hero for anyone who never gets the canvas: reduced motion, no WebGL, no script.
## Imagery
The mast at dusk (`mast-at-dusk.jpg`) is the one documentary photograph from the old site; it
remains the cover of the first post. The five other scene images were generated with Magnific
remains the cover of the first post. The four other scene images were generated with Magnific
(Seedream 5 Pro) on 18 September 2026 in a desaturated documentary style, because no real
photography existed:
| File | Used in | Magnific creation |
|---|---|---|
| `plant-at-dusk.jpg` | Hero | https://www.magnific.com/app/creation/DoQZmiipcl |
| `monitoring-room-glass.jpg` | Method section | https://www.magnific.com/app/creation/bx34g4D5Y2 |
| `sector-5g.jpg` | Sectors, tab 1 | https://www.magnific.com/app/creation/s7ZQP52l8e |
| `sector-substation.jpg` | Sectors, tab 2 | https://www.magnific.com/app/creation/yi0r27vPW9 |
@@ -210,7 +194,7 @@ the Assembly Line" (premium licence), downloaded on 8 October 2026 and scaled to
They are placeholders in the sense of the brief: swap them for the company's own documentary
photography when it exists, keeping the same file names and the `img-doc` treatment. The grid
objects on the stage cards were prototyped as a Magnific sheet
objects on the product cards were prototyped as a Magnific sheet
(https://www.magnific.com/app/creation/aFsD5crfSh) and then rebuilt as procedural SVG so the
stroke matches the rest of the site.
@@ -237,9 +221,12 @@ them for review.
## Interaction and motion
Three islands of script: the mobile navigation toggle in `Header.astro`, the sectors tabs in
`Sectors.astro` (`src/scripts/tabs.ts`: ARIA tablist, arrow keys, Home and End), and the reveal
observer used by the product page's drawings.
Islands of script: the mobile navigation toggle in `Header.astro`, the hero's noise field
(`src/scripts/noise-field.ts`), the sectors tabs in `Sectors.astro` (`src/scripts/tabs.ts`: ARIA
tablist, arrow keys, Home and End), the quote picker, the two forms (`send-form.ts`,
`altcha.ts`), the research cards' figures on the team page (`chladni.ts`), the Insights filter,
the two-click embed on mention pages, the Matomo opt-out, and on the product page the pinned
steps and the verticals tabs.
Motion on the product page, all of it on wide screens: the hero's seventeen lines draw in on load
and meet in one point (off under `prefers-reduced-motion`); hovering a node in a schematic dims