plantasia.space-design
v0.9.2
Published
Shared design system for plantasia.space — design tokens, base styles, and React UI components. React-first, framework-agnostic: no Next.js, SSR-only, or bundler assumptions.
Downloads
3,287
Maintainers
Readme
plantasia.space-design
Shared design system for plantasia.space — Home for Regenerative Music.
This repo is the source of the plantasia.space-design npm package: design tokens,
base styles, brand effects, and (next) React UI components, shared by every
Plantasia Space frontend. React-first, framework-agnostic — no Next.js, SSR-only,
or package-manager assumptions.
Tracked by Linear epic PLA-174 (parent: ORB-41 visual/React refactor).
What's inside
| Path | What |
|---|---|
| src/tokens.css | All design tokens as plain CSS custom properties (light + .dark). Zero-build consumption. |
| src/styles/fonts.css | Brand webfonts: Orbit (titles), Inter (body), JetBrains Mono. |
| src/styles/base.css | Portable base styles (backgrounds, type, cursors, scrollbars). |
| src/styles/effects.css | Brand interactions: corner-bracket hovers, tab legs, segmented groups, filter rings, glass surfaces, motion. |
| src/styles/entity-frames.css | Entity shapes: circle (xPlorer), square (Track), diamond (Collection), hexagon (Orbiter), bordered rect (Entangled World). |
| src/index.css | Everything-in barrel import. |
| src/react/ | (coming — PLA-246) React components extracted from plantasia.space-root. |
| playground/ | Vite + React app: the developer UI kit (cd playground && npm i && npm run dev → http://localhost:5180). |
| src/react/components.generated.{json,ts} | Generated component manifest — every component's slot, variants, owned props, composition. The self-describing layer for CLIs / generators. See docs/COMPONENT-MANIFEST.md. |
| docs/DESIGN.md | Design-language reference (component patterns, spacing, voice). |
| docs/brand.md | Platform, entity, and voice/tone context. |
| archive/ | Pre-package material (static previews, Babel prototype, old token file). Superseded; kept for reference. |
Doc drift warning:
docs/DESIGN.mdanddocs/brand.mdstill describe the older teal/pink brand accents. Production (andsrc/tokens.css, extracted from the production app) uses the monochrome white/black palette —--xplorer-col-1: #fff,--xplorer-col-2: #000. Trust the tokens; the docs' color sections await a pass.
Consuming
Vanilla app, no build step
<link rel="stylesheet" href=".../plantasia.space-design/src/index.css" />
<!-- or just the tokens during migration: -->
<link rel="stylesheet" href=".../plantasia.space-design/src/tokens.css" />Bundled app (Vite, Next.js, anything)
import 'plantasia.space-design/tokens.css'; // tokens only
import 'plantasia.space-design/index.css'; // the full visual language
import 'plantasia.space-design/styles/entity-frames.css'; // à la carteTailwind v4 host (plantasia.space-root)
Keep your @theme inline block mapping the tokens into Tailwind; import the token
file first:
@import 'tailwindcss';
@import 'plantasia.space-design/tokens.css';
/* app-local @theme inline { --color-background: var(--background); … } */When the React components land, Tailwind hosts also add
@source "../node_modules/plantasia.space-design"; so component classes generate.
Theming contract
- Light is the default; dark ships as a
.darkclass on<html>(or any subtree). - Hosts may override any token at runtime by writing the custom property —
this is how the root app's theme-config and EW Studio's
studioTheme.jsalready work. Brand primitives to override first:--xplorer-col-1,--xplorer-col-2; everything semantic derives from those two plus the neutral scale. - Fonts: hosts may keep loading the same Google Fonts via
<link>in their own head (as the Next.js app does) instead ofstyles/fonts.css— token names are the contract, not the loader.
The extraction law — extract ⇒ migrate-back, always
When you move a component OUT of an app and INTO this library, the SAME branch must also migrate that app to consume the library version and DELETE the app's local copy.
Extracting a component here without retiring the original does not reduce duplication — it
creates a second copy, and the two drift apart forever. "I'll migrate the app later" is how we
end up with the same panel/section/color-control implemented twice (see Linear ORB-94 for the
current debt: the EW studio's vanilla panel.js / section.js / colorControl.js / swatchRow.js
were ported to React here but never removed from EW).
A clean extraction PR therefore touches two repos:
- This library — add/port the component, build, version.
- The source app — replace the local implementation with an import from
plantasia.space-design, delete the now-dead local file, and verify (typecheck + the app still renders).
Shared values follow the same rule, not just components: e.g. the nav breakpoint lives once in
src/breakpoints.ts (→ plantasia.space-design/breakpoints, framework-agnostic) and both root and
EW consume it — neither hard-codes its own. A pure value that server code reads must NOT ship from
the "use client" React barrel; give it its own non-React entry (see tsup.config.ts).
If you genuinely can't migrate the source app in the same PR (e.g. it's still vanilla JS and needs a React mount bridge first), file a debt ticket immediately and link it in the extraction PR — the duplication must be tracked, never silent.
Developing
CSS-only for now — no build, no dependencies. Edit src/, version with semver.
The React build (tsup → ESM + d.ts) arrives with PLA-246.
Codegen — keep the generated manifests fresh
Two files are generated, never hand-edited:
src/react/icons/manifest.generated.ts—npm run icons:generatesrc/react/components.generated.{json,ts}—npm run components:generate
npm run build regenerates both before bundling, so a published package is always
current. After adding or changing a component (export, data-slot, variant
options, or own props), run npm run components:generate to refresh the committed
manifest in your PR. npm run components:check fails if it's stale. See
docs/COMPONENT-MANIFEST.md.
Local testing — link, don't publish
Nothing goes to npm until a first version has been tested inside the real apps.
All sibling apps live next to this repo under ps-fe/, so they consume the local
package directly while developing:
# from the consuming app (orbiters, entangled-worlds-preview, plantasia.space-root):
npm install --no-save ../plantasia.space-design--no-save keeps the app's package.json and lockfile untouched (deploys/CI are
unaffected); the install symlinks node_modules/plantasia.space-design to this
folder, so package edits show up in the app's dev server live. Re-run the command
after a fresh npm install in the app (a clean install drops the unlisted link).
When a version is proven inside at least one app, publishing is a deliberate,
separate step: npm publish (public npm, unscoped — same flow as
entangled-worlds-orbiters-shared), then consumers switch to a real semver
dependency.
Consumers & migration state
| App | State |
|---|---|
| plantasia.space-root (Next 15) | Source of the extracted tokens/components; migrates to consume them in PLA-247. |
| orbiters (vanilla + Vite) | Adopts tokens.css + alias block in ORB-75. |
| entangled-worlds-preview (vanilla + Vite) | Bridges --studio-theme-* onto these tokens in ORB-76. |
