Instructions
Getting started
Inter, DM Mono and Instrument Serif come from npm (Fontsource, src/fonts.ts). Humane is self-hosted in public/assets/fonts.
Change the Primitives and Theme variables at the top of src/styles/template.css. Every class reads from them, so one edit restyles the site. Cards and the menu use the Dark mode.
Font sizes and spacing are CSS variables in src/styles/template.css, with Tablet, Mobile and Mobile Portrait sizes.
The footer is one shared component (src/components/shared/Footer.astro); its work list reads the projects collection.
The menu lives in the Global UI component (src/components/shared/GlobalUi.astro). Edit each link’s text and URL there. Change only the first row of each link; the script copies it into the roll.
The footer quotes are one Testimonials component, so an edit updates every page. In the markup they sit in a list; the script stacks them and shows one at a time.
GSAP, ScrollTrigger, SplitText and ScrambleText are installed from npm (src/scripts/gsap-globals.ts). The head script (src/data/head/) only hides the page until the intro is ready; the template script (src/scripts/custom/) shows a static page if a plugin is missing.
Animation map
The 0 to 100% counter while a spiral coils over the screen and uncoils. Home only, on a direct visit. On tall phone screens a taller coil keeps the ribbon round. Element: data-animate="preloader".
The title letters rise in, then swell toward the cursor. Element: data-animate="wordmark".
Hides on scroll down and returns on scroll up, and blends over images. Element: data-animate="navbar".
Off by default. Set tilt above 0 and work cards lean back and stand up as they rise. Element: data-animate="tilt".
The children of an element fade up one by one. Element: data-animate="stagger".
Project images drift slowly inside their frame while you scroll.
Labels scramble into place. Element: data-animate="scramble".
An optional bubble that follows the mouse over elements with data-cursor.
Buttons with data-magnetic lean toward the cursor.
The page folds into a card and slides aside to show the menu; on close its rounded corners ease back to square as it grows. Elements: data-animate="page", "menu" and "menu-button".
The Amsterdam clock in the navbar and its blinking dot. Element: data-animate="clock".
A spiral uncoils over each project image the first time it scrolls in. Element: data-animate="cover" on the embed path.
Menu words roll up and draw a hand-drawn scribble. Elements: data-menu-item.
Hovering a footer Work link tints the footer and shows a preview image. Elements: data-footer-work.
Quotes change line by line with a progress line. Element: data-animate="testimonials".
The footer email fits the container width and rises letter by letter. Element: data-animate="email" with data-fit.
The footer slides out from behind the page while a shade clears. Element: data-animate="footer".
A liquid wave floods the card and the result fades in. Touch screens show a caption instead. The hover panel (.work_info) is plain markup in the card so you can edit it; the script hides it until hover. Element: data-animate="work-card".
Plays the project’s video field as a muted loop while the card is on screen. Element: .work_video with data-video-src.
Headings rise line by line and rules draw in. Elements: data-animate="lines" and "rule".
The About statement lights up word by word as you scroll. Element: data-animate="scrub".
Numbers count up from zero once in view. Element: data-count, or data-count="auto" for CMS values.
A blue fill enters from the edge the cursor comes in by. Element: data-animate="rows".
A blue spiral covers the page between internal links, and uncoils on the next page.
Big links swell letter by letter toward the cursor. Element: data-animate="liquid".
Client cells fill from the edge the cursor enters by and roll to the work done. Element: data-animate="clients".
Every .text-link gets an underline that draws in on hover.
The next project link reads its slug from data-next-slug, set from the nextSlug field.
Long project names shrink to fit the screen in the project title and the next-project link. Short names keep their full size.
On phones: no grey flash when a link is tapped, and buttons keep their resting colours after a tap.
Key settings
The easing used by most animations.
Global speed. 1 is normal and 0.8 is faster.
The Home % preloader.
The spiral page transition.
Degrees of image tilt. 0 turns it off.
The spiral reveal over project images.
Seconds the spiral takes to uncoil.
Seconds between cards that enter together.
How much title letters swell. 0 turns it off.
Seconds for the card hover wave to grow.
Size of the page card while the menu is open.
Seconds each testimonial stays.
Pull of magnetic buttons. 0 turns it off.
The optional cursor bubble.
Colour themes
The glass pill bottom left, inside Global UI, so it is on every page. Five colours: Royal Blue, Red, Green, Violet and Black. The white thumb slides to the chosen colour and the choice is saved in the visitor’s browser.
A theme rewrites the Primitives Blue 500, 700, 50 and Inverse, plus Theme Text secondary and Border primary. Every colour Variable is built on them, so text, lines, the menu, the cursor and the spirals all follow.
src/data/head/, Colour themes script: edit the theme’s line in FU_THEMES (main = brand colour, deep = hover shade, tint = pale surface). Then update its Swatch Variable so the dot matches.
Add a line to FU_THEMES with a new key, then duplicate a swatch button in Global UI and set its data-theme attribute to that key.
Royal Blue is the default. To launch in another colour, change DEFAULT in the script and the Blue Primitives to match. Red and Green are bright, so check small text contrast before you make one of them the default.
Delete theme-switch_component in Global UI and the Colour themes script in the head script. The site stays in your Blue Primitives.
Remove an effect
Most effects have a switch in FU at the top of the template script. Set it to false or 0.
Delete the data-animate attribute from the element. The block skips elements without it.
Delete its call, such as G26_rows(), from init() at the end of the template script.
Add ?static=1 to any URL to see every element in its final state with no motion.
Visitors who ask for reduced motion get instant reveals and no page transition.
Interactions
There is no interaction data. Every animation is GSAP code in the template script, so there is nothing else to edit.
CMS
The projects content collection (src/content/projects/) holds every project. The README explains each field.
Home shows the six projects listed in src/pages/index.astro.
An MP4 path or link under 3 MB in the video field. The card plays it as a muted loop. Leave it empty to show the image.
A pale hex colour the footer fades to while the project is hovered in the footer list.
Set nextSlug, next and nextTitle to the project linked at the bottom.
Card and footer links point at the Work page and carry the project slug in data-item-slug. The page transition reads it.
Inline SVG
One inline SVG spiral inside Global UI. Its colour follows the accent Variable.
The same inline spiral over each project image, in the page colour.
The spiral used by the Home preloader, as inline SVG.
The menu circle, wave and arrow are inline SVGs inside Global UI. Edit the path to change a shape.