Marketing site for Align, a pre-seed network that connects founders with the investors who back them. Eight pages, a custom grid system, and a generative logo animation — built from a Figma file, pixel for pixel.
Live: https://align-mauve.vercel.app · Source: https://github.com/k-jdev/align
| Layer | Choice |
|---|---|
| Framework | Next.js 16 (App Router, React 19, Server Components by default) |
| Language | TypeScript 5, strict: true |
| Styling | Tailwind CSS v4 (CSS-first @theme, no tailwind.config.js) |
| Components | shadcn/ui primitives + Base UI |
| Fonts | IBM Plex Sans / IBM Plex Mono via next/font |
| Animation | p5.js (isolated), CSS keyframes |
| Tooling | ESLint 9 (flat config), Prettier + prettier-plugin-tailwindcss |
- Eight routes: landing, about, founders, investors, work index, work detail, and three legal pages — all statically prerendered at build time.
- A four/eight-column layout system driven entirely by CSS custom properties, with a keyboard-toggled grid overlay for verifying alignment against Figma.
- Generative dithered logo on the landing hero, rendered with p5.js.
- Portfolio company pages generated from a typed data module via
generateStaticParams, with per-page metadata. - Legal pages (Terms, Privacy, Disclosures) rendered from one typed schema, so the three documents can never drift apart structurally.
- Responsive from 320px up, with a mobile nav and mobile-specific art direction.
The grid is the design system. Rather than hardcoding container widths, the
layout is expressed as four CSS variables — --grid-cols, --grid-gap,
--grid-pad, --grid-content — redefined at the lg breakpoint. Every section
composes GridContainer, which reads those variables. Changing the design's
column count is a one-line change in app/globals.css, not a sweep across
forty components.
The grid overlay is a dev tool, not a shipped feature. GridOverlay draws
the live column grid on Ctrl+G so a section can be checked against the Figma
frame in the browser. It is mounted from the root layout only when
process.env.NODE_ENV === "development", so it costs production visitors
nothing.
The p5 sketch lives in an iframe, on purpose. public/hero-logo.html is a
self-contained p5.js sketch that dithers the Align logo. Embedding it as an
iframe rather than a React component keeps a 60fps canvas loop, its own RAF
scheduling, and its own font loading entirely outside React's reconciliation —
and means a sketch crash degrades to a blank hero instead of taking the page
down.
Optical alignment is measured, not guessed. DynamicShiftText reads the
rendered text box and compensates for the left side bearing of the display
face, so large headings optically align to the grid edge the way they do in
Figma. It bails out to zero shift when the text wraps.
Content is typed data, not JSX. Portfolio companies (lib/work-detail.ts)
and legal documents (lib/legal-content.ts) are typed modules. Pages map over
them. Adding a portfolio company is one object; it gets a static route, sitemap
entry, and metadata for free.
Requires Node 20+.
git clone https://github.com/k-jdev/align.git
cd align
npm install
npm run devOpen http://localhost:3000. Press Ctrl+G on any page to toggle the grid overlay.
| Script | What it does |
|---|---|
npm run dev |
Dev server |
npm run build |
Production build (also typechecks) |
npm run start |
Serve the production build |
npm run lint |
ESLint |
npm run typecheck |
tsc --noEmit |
npm run format |
Prettier over all TS/TSX |
app/ routes, root layout, sitemap.ts, robots.ts
components/
landing/ about/ section components, one folder per page
founders/ investors/
work/ work-detail/
legal/
shared/ header, footer, GridContainer, GridOverlay, text effects
ui/ shadcn primitives (not hand-edited)
lib/ typed content modules + utilities
public/ images, logos, the standalone p5 sketch
- The p5 iframe costs a second document. It buys isolation and paid for itself during development, but a React-hosted canvas with a manual RAF loop would drop a request and let the sketch react to the theme. Worth revisiting now that the animation has stopped changing.
- Images are shipped unoptimized.
next.config.tssetsimages.unoptimized: true, so three PNGs weighing ~1.7MB reach mobile as-is. Converting the art to AVIF/WebP and turning the optimizer back on is the single largest win available on this site. - No tests. For a site this static, Playwright smoke tests over the eight routes — asserting no console errors and no broken internal links — would catch more real regressions per line than unit tests would.
- The legal pages are template copy. Terms, Privacy, and Disclosures demonstrate the typed-schema rendering, not reviewed legal text — Align has no operating entity behind it yet, so jurisdiction, venue, and registered address are deliberately unstated.
- Section components take no props. Several sections hardcode their copy.
Lifting that into
lib/the way the work and legal pages already do would make the whole site editable from one place.
- Replace placeholder portfolio companies with real ones
- AVIF/WebP art direction,
images.unoptimizedoff -
/contactpage with a real form - Playwright smoke suite in CI
- OG image generation via
next/og
MIT — see LICENSE.
