Skip to content
Platform1 min read

Architecture

Three codebases, two extension runtimes and one static delivery pipeline.

Updated Nov 6, 20251 min readEdit this page
On this page

Lumo is split into three repositories so that permissions, release cadence and failure domains stay separate. The design language is the only thing deliberately shared across all three.

Product runtime#

Both extensions are WXT projects on Chrome MV3. React renders the surfaces; Tailwind and shadcn-style primitives provide the component layer; Motion handles layout and entrance animation.

LayerLumoLumo Userscripts
ShellWXT + MV3WXT + MV3
UIReact 19 + Tailwind 4React 19 + Tailwind 4
StateZustand + chrome.storageZustand + chrome.storage + IndexedDB
AI / toolsVercel AI SDK agent loop + MCPOptional MCP provider endpoint
EditorCodeMirror 6 / StreamdownCodeMirror 6 / Shiki
AnimationMotionMotion

Site runtime#

This site uses React Router 8 framework mode with ssr: false and full pre-rendering. The build renders every route to HTML, then hydrates into a normal SPA. No server runs in production.

react-router.config.tstypescript
export default {  ssr: false,  prerender: async ({ getStaticPaths }) => [    ...getStaticPaths(),    ...docPaths,  ],} satisfies Config;

The static output is build/client. Cloudflare Workers serves it as static assets; every known route already has a file, and unknown URLs fall through to the generated 404.html.

Shared design language#

  • OKLCH semantic tokens, with palette and accent axes.
  • The same type scale, radii, material and motion curves.
  • The same four design laws, applied to marketing and tool surfaces differently.
  • i18next resources with strict English/Chinese key parity.

One-way dependency

The website may document the products, but it must never import product runtime code. Documentation drifts; a shared import would couple releases.