Skip to content

Repository files navigation

Quartz Systems — website

The Quartz Systems landing page, ported from the Claude Design project (Quartz Landing.dc.html) to Next.js 16 (App Router) + Tailwind CSS 4.

npm run dev     # http://localhost:3000
npm run build
npm run start
npm run lint

Layout

src/app/globals.css       Design tokens (@theme) + base shell
src/app/layout.tsx        Fonts (Manrope, JetBrains Mono) + metadata
src/app/page.tsx          Section composition
src/components/           One file per section
public/assets/            Quartz mark
public/branding/          Lumen lockup

Design tokens

globals.css carries the design system's colors_and_type.css tokens in a Tailwind @theme block, so they generate utilities directly:

Token group Utilities
Ink scale --color-ink-0…11 bg-ink-2, text-ink-9, border-ink-5
Signal green --color-signal-50…900 bg-signal-500
Semantic bg-accent, hover:bg-accent-hover, text-on-accent, border-hairline
Radii rounded-md 6px, rounded-lg 10px, rounded-xl 14px
Motion ease-out is the DS curve cubic-bezier(0.22, 0.61, 0.36, 1)
Elevation shadow-nav, inset-shadow-line

The DS-native --qz-* names are re-exported as aliases in :root for anything authored against them directly.

Deployment

.github/workflows/deploy.yml builds on every push and publishes main to GitHub Pages.

The site is a static export (output: "export" in next.config.ts), so npm run build writes out/ and there is no Node server at runtime — next/image optimization is off and API routes, middleware, and other server-only features are unavailable.

The site is served from quartz.systems, set by public/CNAME. Next copies that file into out/, so each deploy reasserts the domain on Pages. The workflow also reads it to decide NEXT_PUBLIC_BASE_PATH, which feeds basePath/assetPrefix: a custom domain serves from the root, so the prefix is empty. Delete public/CNAME and the build falls back to /<repo> for the quartzsystems.github.io project URL.

Because basePath does not reach next/image when images are unoptimized, image assets are imported (import logoMark from "../../public/assets/logo-mark.png") rather than referenced as /assets/… URLs; the bundler rewrites imported URLs with the prefix. Root-relative asset URLs written by hand will 404 under a base path.

One-time repo setup: Settings → Pages → Source → GitHub Actions. Deploys fail until that is set; GITHUB_TOKEN cannot enable Pages itself on this org. The apex quartz.systems also needs A/AAAA records pointing at the Pages IPs before the domain resolves here.

Notes on the port

  • The hero's animated interference field was a DCLogic class in the design canvas; it is now src/components/hero-waves.tsx, a client component driving the same 460×130 ImageData field through requestAnimationFrame. It honours prefers-reduced-motion by painting one static frame, and accepts the original waveSpeed / waveDensity props.
  • Every style-hover attribute became a Tailwind hover: variant, and each anchor also sets its own colour explicitly, matching what the original declared inline.
  • box-content is load-bearing, not decoration. The design assumes the browser default box-sizing: content-box; Tailwind's Preflight forces border-box on everything. Where the design combines an explicit size with padding or a border, that flips the rendered geometry — max-width:1280px + padding:0 40px means 1280px of content between 40px gutters in the design, but only 1200px of content under border-box. Eight elements are affected: the six 1280px containers (hero copy, the four sections, footer inner) and the two bordered 46px buttons, which the design renders 48px tall. Each carries box-content so the numbers in the classes match the design source one-to-one.
  • The base rules in globals.css must stay inside @layer base. Unlayered declarations outrank every cascade layer, so writing a { color: … } at the top level of the file beats the text-* utilities in @layer utilities and repaints every link on the page accent green — which is exactly what happened to the navbar on the first pass. Keeping the block layered lets text-ink-11 / text-ink-11/62 win, so the current section reads white and the rest sit back at 62%.
  • Fonts are self-hosted via next/font/google rather than the design system's Google Fonts @import, so there is no render-blocking request or layout shift.
  • The design system's _ds_bundle.js exports no components (components: [] in its manifest) and the landing page uses no DS component markup, so only the tokens needed porting.
  • The Lumen intro grid is minmax(280px, 1fr) minmax(280px, 1.1fr), carried over verbatim from the design. It needs ~600px to fit, so below that it overflows (contained by overflow-x-hidden on the page wrapper) rather than stacking. Fix with a single-column fallback if you want it to reflow on phones.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages