English | 中文
The personal technical space of Michael Cai (蔡宇翔) — code, machine learning, and the interface experiment behind Structured Sparsity.
Structured Sparsity — everything exists, few things activate. Every piece of content is always rendered and deterministically placed; attention decides what surfaces.
SPARSITY.TECH is a personal website built with Next.js 16 and deployed as a standalone Node.js service. The homepage is an exercise in information design: instead of a fixed feed, content lives in a deterministic field — attention moving across it activates what matters.
- FIELD — the spatial representation. Nodes are placed by a deterministic solver and wrapped in a WebGL latent field whose contour lines respond to pointer, keyboard focus, and content activity.
- INDEX — the quiet representation. The same content, as a readable list. FIELD and INDEX are reversible views of one source of truth.
- Deterministic, not random — layout comes from a pure solver seeded by content ids. The same content and viewport always produce the same positions; there is no randomness and no force-directed simulation anywhere.
- Attention as interface — every node is always present (
dormant), a few becomeaware, one becomesactive. Attention is driven by pointer and keyboard focus, never by an auto-playing feed. - Calm by default — reduced-motion users get a static field, WebGL absence degrades gracefully to pure DOM, and development diagnostics can never leak into production.
- Mobile is a readable layout, not a scaled-down field.
| Layer | Choice |
|---|---|
| Framework | Next.js 16 (App Router, Turbopack) |
| UI | React 19, CSS Modules |
| Language | TypeScript (strict) |
| Rendering | WebGL 1 fragment shader, DPR-capped, pause-on-hidden |
| Tests | Vitest (unit) · Playwright (e2e, desktop + mobile) |
| Runtime | Node.js 22 standalone server, Nginx in front (see deploy/) |
Prerequisites: Node.js 22 and pnpm 11 (enable it via corepack).
corepack enable
pnpm install --frozen-lockfile
pnpm devThe development server runs at http://localhost:3000.
Build the production artifact and preview it locally:
pnpm build
pnpm preview # serves dist/standalone at http://127.0.0.1:4173pnpm build produces dist/standalone/ — a self-contained Node server with its dependencies and
static assets; the target machine needs Node.js 22 and nothing else. See
docs/deploy-ubuntu-26.04.md for the Ubuntu + Nginx layout.
pnpm check # formatting, lint, typecheck, unit tests, production build
pnpm test:e2e # Playwright against the standalone buildThe reference viewports are 1440×900 and 390×844. CI runs two jobs on push to main and
every pull request:
check— format, lint, typecheck, unit tests, production builde2e— desktop and mobile browser behavior: FIELD/INDEX round trips, keyboard focus, reduced motion, horizontal overflow, mobile envelope safety, and production diagnostic gating
Content metadata lives in a single registry and flows through a measure → solve → render pipeline:
flowchart LR
REG["content/registry.ts<br/>typed metadata,<br/>single source of truth"] --> UI["HomeExperience<br/>FIELD ⇄ INDEX client island"]
UI --> MEAS["DOM measurement<br/>envelopes & constraints"]
MEAS --> SOLVE["Spatial solver<br/>deterministic, envelope-safe"]
SOLVE -->|"node positions"| UI
SOLVE -->|"normalized nodes"| GL["Latent field renderer<br/>WebGL contours"]
UI -->|"attention<br/>(pointer / focus)"| GL
The solver and the renderer import neither React nor each other; high-frequency pointer and animation values stay inside the renderer, and React state only changes when attention actually changes. The full contract is in docs/architecture.md.
| Path | What lives there |
|---|---|
app/ |
Routes, metadata, robots, sitemap |
components/home/ |
The homepage experience and its tests |
content/ |
registry.ts — the single source of content truth |
features/spatial-layout/ |
Deterministic layout solver, geometry, DOM measurement |
features/latent-field/ |
WebGL contour renderer and its React adapter |
styles/ |
Design tokens and base styles |
tests/e2e/ |
Playwright desktop + mobile specs |
scripts/ |
Build helpers (standalone artifact preparation) |
deploy/ |
Nginx and systemd example files |
docs/ |
Architecture, acceptance, authoring, deployment, 中文 |
| Doc | Purpose |
|---|---|
| docs/architecture.md | Data flow, rendering boundaries, content policy |
| docs/visual-acceptance.md | Required viewports and states to verify before shipping |
| docs/content-authoring.md | How to add and change content safely |
| docs/deploy-ubuntu-26.04.md | Production artifact and Ubuntu/Nginx layout |
| AGENTS.md | Invariants and workflow for AI agents (useful for humans too) |
| docs/README.zh-CN.md | 中文说明 |
Note on
DESIGN_DIRECTION.md— this file is intentionally private: it is git-ignored and absent from clones by design. Do not commit it and do not treat its absence as a defect. When it is unavailable,AGENTS.mdand the docs above are the authoritative public design guidance.
The registry holds real metadata only: a title in the registry does not imply that an article or project page exists. Real content arrives together with its route — add the MDX body and a statically generated detail page in the same change as the registry record, never a dead link.
This is a personal space, but fixes and ideas are welcome — open an issue or a pull request.
Before changing layout, interaction, motion, or visual styling, read AGENTS.md (and
DESIGN_DIRECTION.md if you have it). No credentials are stored in this repository and nothing
deploys automatically.
Licensed under CC BY-NC-SA 4.0 (Attribution-NonCommercial-ShareAlike 4.0 International) — see LICENSE for the full terms. You may share and adapt this work, provided you give appropriate credit, do not use it for commercial purposes, and distribute any adaptations under the same license. This applies to the whole repository: code, content, and design.