Drift
Drift is a restrained portfolio for photographers and image-led creative practices. The homepage arranges the work into infinite gallery lanes that move in opposite directions, so a visitor meets a living wall of images rather than a static grid. Visitors can switch between two, three, and four columns on wide screens, and the layout reduces cleanly on tablets and phones.
Every image opens an accessible full-screen preview and links to a permanent project page, where Markdown copy and any number of additional photographs form a quiet editorial sequence. A native About panel, an image-backed contact page, and an optional blog round out the site without competing with the work.
| Property | Value |
|---|---|
| Tier | Pro ($49) |
| Category | Photography Portfolio |
| Font | Geist Variable (self-hosted) |
| Palette | Dark (#080808 canvas) and light (#e9e7e1 canvas) modes |
| Motion | GSAP for the gallery and reveals, Lenis on document pages |
| Collections | projects, blog |
| Configuration | Shared site content lives in src/config/site.ts |
Included routes
Section titled “Included routes”/- the counter-motion gallery, project previews, and the About panel/work/[slug]/- eight generated project pages/blog/and/blog/[slug]/- optional blog index and three generated articles/contact/- image-backed contact page with the enquiry form- Generated sitemap output
The production build generates 14 static pages.
What makes Drift different
Section titled “What makes Drift different”- The gallery moves, the work stays in charge - counter-moving lanes give the homepage rhythm without turning it into a slideshow, and the column count is the visitor’s choice.
- Every image has somewhere to go - a full-screen preview for a quick look, and a permanent project page for the full story, with as many photographs as the project needs.
- Accessible by construction - native dialogs handle focus and Escape, loop clones stay hidden from assistive technology, and a semantic project index keeps every project reachable by keyboard.
- Works without JavaScript - a static grid and the project index remain when scripts are off, and reduced-motion preferences stop the movement entirely.
- Local imagery - every photograph ships in
public/images/, with no remote image dependency.
Drift-specific setup
Section titled “Drift-specific setup”Change the identity and palette
Section titled “Change the identity and palette”Start in src/config/site.ts. The identity block holds the name, legal name, URL, language, and favicon. The theme block sets the default appearance and both palettes:
theme: { default: "dark", palette: { dark: { canvas: "#080808", ink: "#eeede8", muted: "rgba(238,237,232,.62)", line: "rgba(238,237,232,.18)", glass: "rgba(18,18,18,.62)", focus: "#f4ef6c", imageLabelBackground: "#000000", imageLabelText: "#ffffff", }, light: { canvas: "#e9e7e1", ink: "#101010", ... }, },}The image labels carry their own background and text colours in each palette, so captions stay legible over any photograph.
Tune the gallery
Section titled “Tune the gallery”siteConfig.gallery controls the homepage behaviour: defaultColumns (2, 3, or 4), the gap between images, the relative speeds of the slower and middle lanes, the smoothing and wheel response, and the first-load intro (intro.enabled, duration, staggerDuration). The labels for the column selector and the semantic project index live in the same block.
Add or edit projects
Section titled “Add or edit projects”Each project is a Markdown file in src/content/projects/ and generates /work/[slug]/. The frontmatter holds the title, year, discipline, location, description, cover image, alt text, focal point, aspect ratio, and an order value for the gallery. Add supporting photographs with additionalImages, each with its own alt text and focal point. The body is ordinary Markdown for the project story.
The labels around project pages (back link, detail headings, previous and next) live in siteConfig.projectPage.
Write or switch off the blog
Section titled “Write or switch off the blog”Articles live in src/content/blog/ as Markdown with a title, date, excerpt, image, and alt text. siteConfig.blog holds the listing heading, introduction, empty-state message, and labels. Set blog.enabled to false to remove the blog from the navigation and stop its routes from being generated.
Edit the About panel
Section titled “Edit the About panel”The About panel opens from the floating dock on the homepage. Its eyebrow, heading, biography, and availability line are in siteConfig.about.
Connect the contact form
Section titled “Connect the contact form”Drift starts in safe demo mode and sends no data. siteConfig.contact.form.provider accepts:
formspreeformsubmitnetlifycustomdemo
The same block holds the endpoint settings and every message the form shows. The fields themselves are defined in siteConfig.contact.fields, each with a name, label, type, placeholder, and required flag. The page background image, its blur, and the overlay colours for both modes are in siteConfig.contact.background.
Localization
Section titled “Localization”Drift is i18n-ready. English stays the complete source in src/config/site.ts; every other language is an override file that only holds the translated keys, and every route has a twin under src/pages/[locale]/ that builds once a second language is registered.
Copy src/i18n/locales/template.ts to src/i18n/locales/fr.ts, translate the keys you need, then register the language in src/i18n/config.ts.
Step by step, with the checklist: Add a language.
Agent-ready
Section titled “Agent-ready”The theme ships an AGENTS.md at its root, plus a CLAUDE.md that points at it. Claude Code, Cursor, Copilot, and Codex read these on open. For Drift, the guide spells out the rules that keep the gallery working: the gallery owns pointer, touch, and wheel input on the homepage, there is one GSAP ticker callback that must be torn down cleanly, loop clones stay hidden, and dialogs own focus.
HTML edition
Section titled “HTML edition”Drift is also available as a plain HTML template: the same design as ready-made HTML, CSS, and JavaScript files that open straight from disk, with no build step. Its README explains where the palette lives and how to connect the contact form.