VectoJS Styles
Use this skill to write VectoJS component styling that reads like CSS without
a parser, cascade, or selector. @vectojs/styles maps typed style objects
onto numeric entity fields; var(--key) token references resolve against a
flat theme and re-apply on setTheme.
Core workflow
- Confirm the installed
@vectojs/styles version; the API below is 0.2.0+.
- Define a theme once:
setTheme(tokens({ accent: '#2563eb', 'radius-md': 8 })) — flat keys, no -- prefix; PRESET_THEMES ships light (default) / dark / github / dracula.
- Write styles with
style({...}) (typed identity) and merge variants with css(base, override, ...) — later sources win, null/false skipped.
- Reference tokens in values:
backgroundColor: 'var(--accent)' — styles containing var() are tracked and re-applied automatically when setTheme(next) runs, recolouring the scene.
- Apply:
applyStyle(entity, style) writes mapped fields and returns { applied }; it marks the scene dirty once when anything was written.
- Verify with
@vectojs/devtools headless: inspectEntity/pickInScene read the same fields applyStyle wrote.
Key mapping (CSS name → entity field)
| CSS key |
Field / behaviour |
x/y/width/height |
same; bare number or px string |
opacity/scaleX/scaleY/rotation |
same; rotation in radians |
backgroundColor/color/borderColor |
bg/color/borderColor; strings pass through |
borderRadius |
radius |
padding |
single value, or { x, y } → paddingX/paddingY |
font |
full shorthand string |
fontFamily/fontSize/fontWeight |
composed into the entity's font shorthand, preserving other segments |
lineHeight/gap |
same |
textAlign |
'left' | 'justify' ONLY |
display |
'flex' only — validates the entity is a container |
flexDirection |
'row'→'horizontal', 'column'→'vertical' |
alignItems |
'flex-start'→'start', 'flex-end'→'end', 'center' |
flexWrap |
'wrap'→true, 'nowrap'→false |
Rules of the road
- Cross-component reuse: keys whose field the entity lacks are skipped
silently — one style object works on
Button, Text, and Stack.
- Loud failures: layout keys on non-containers, unknown keys, unknown
tokens, and invalid values (
'50%', '8em', textAlign: 'center',
alignItems: 'stretch') throw TypeError with the property name. A
migration must not fail silently.
- Values are px: bare numbers or
px strings only; %/em/rem
rejected.
setTheme re-applies only var()-tracked styles; literals are left
alone. setTheme throws if a new theme drops a referenced token or a token
value fails validation.
- No CSS fallback syntax:
var(--token, fallback) throws a targeted
TypeError wherever it arrives (direct value, composite string, padding
axis, token chain) — fallback resolution is not implemented, and the value
used to pass through silently unresolved. The detector tolerates whitespace
after var(, so var( --accent, #fff ) is caught too. Reference tokens
that exist in the theme instead.
- Button sizing is fixed at construction:
padding: {x,y} applied later
is read by consumers of paddingX/paddingY (e.g. Card layouts), not by
intrinsic sizing.
- No strings, no cascade: never parse CSS text, never implement
selectors/pseudo-states/media queries — the numeric VMT is the single
source of truth.
Migration checklist (web → VectoJS)
- Replace
#hex literals with tokens (var(--surface) etc.) or keep them —
literals are fine, they just don't theme-switch.
display: flex + flexDirection/gap/alignItems → the entity must be a
Stack/Flow (VectoJS has no auto-container conversion).
center/right text-align has no backing field — re-layout with
Stack({ align: 'center' }) instead.
transform: rotate(30deg) → rotation: Math.PI / 6 (radians).
- Pseudo-states (
:hover) → entity events (entity.on('hover')).
Cross-references
Component fields and constructor sizing → vectojs-core-runtime ·
layout containers → vectojs-responsive-layout · theme-switching
performance → vectojs-performance · verifying applied fields →
vectojs-devtools.
Base directory for this skill: /mnt/data/Workspace/Projects/vectojs/.agents/skills/vectojs-styles
1---2name: vectojs-styles3description: Use when styling VectoJS UI with @vectojs/styles — CSS-property-name style objects, var() token themes with setTheme switching, css() merging, font composition, per-axis padding, or migrating CSS/web styling habits onto the numeric Virtual Math Tree.4---56# VectoJS Styles78Use this skill to write VectoJS component styling that reads like CSS without9a parser, cascade, or selector. `@vectojs/styles` maps typed style objects10onto numeric entity fields; `var(--key)` token references resolve against a11flat theme and re-apply on `setTheme`.1213## Core workflow14151. Confirm the installed `@vectojs/styles` version; the API below is 0.2.0+.162. Define a theme once: `setTheme(tokens({ accent: '#2563eb', 'radius-md': 8 }))` — flat keys, no `--` prefix; `PRESET_THEMES` ships `light` (default) / `dark` / `github` / `dracula`.173. Write styles with `style({...})` (typed identity) and merge variants with `css(base, override, ...)` — later sources win, `null`/`false` skipped.184. Reference tokens in values: `backgroundColor: 'var(--accent)'` — styles containing `var()` are tracked and re-applied automatically when `setTheme(next)` runs, recolouring the scene.195. Apply: `applyStyle(entity, style)` writes mapped fields and returns `{ applied }`; it marks the scene dirty once when anything was written.206. Verify with `@vectojs/devtools` headless: `inspectEntity`/`pickInScene` read the same fields `applyStyle` wrote.2122## Key mapping (CSS name → entity field)2324| CSS key | Field / behaviour |25| --------------------------------------- | ---------------------------------------------------------------------- |26| `x`/`y`/`width`/`height` | same; bare number or `px` string |27| `opacity`/`scaleX`/`scaleY`/`rotation` | same; rotation in **radians** |28| `backgroundColor`/`color`/`borderColor` | `bg`/`color`/`borderColor`; strings pass through |29| `borderRadius` | `radius` |30| `padding` | single value, or `{ x, y }` → `paddingX`/`paddingY` |31| `font` | full shorthand string |32| `fontFamily`/`fontSize`/`fontWeight` | composed into the entity's `font` shorthand, preserving other segments |33| `lineHeight`/`gap` | same |34| `textAlign` | `'left' \| 'justify'` ONLY |35| `display` | `'flex'` only — validates the entity is a container |36| `flexDirection` | `'row'`→`'horizontal'`, `'column'`→`'vertical'` |37| `alignItems` | `'flex-start'`→`'start'`, `'flex-end'`→`'end'`, `'center'` |38| `flexWrap` | `'wrap'`→`true`, `'nowrap'`→`false` |3940## Rules of the road4142- **Cross-component reuse**: keys whose field the entity lacks are skipped43 silently — one style object works on `Button`, `Text`, and `Stack`.44- **Loud failures**: layout keys on non-containers, unknown keys, unknown45 tokens, and invalid values (`'50%'`, `'8em'`, `textAlign: 'center'`,46 `alignItems: 'stretch'`) throw `TypeError` with the property name. A47 migration must not fail silently.48- **Values are px**: bare numbers or `px` strings only; `%`/`em`/`rem`49 rejected.50- **`setTheme` re-applies only `var()`-tracked styles**; literals are left51 alone. `setTheme` throws if a new theme drops a referenced token or a token52 value fails validation.53- **No CSS fallback syntax**: `var(--token, fallback)` throws a targeted54 `TypeError` wherever it arrives (direct value, composite string, padding55 axis, token chain) — fallback resolution is not implemented, and the value56 used to pass through silently unresolved. The detector tolerates whitespace57 after `var(`, so `var( --accent, #fff )` is caught too. Reference tokens58 that exist in the theme instead.59- **Button sizing is fixed at construction**: `padding: {x,y}` applied later60 is read by consumers of `paddingX`/`paddingY` (e.g. Card layouts), not by61 intrinsic sizing.62- **No strings, no cascade**: never parse CSS text, never implement63 selectors/pseudo-states/media queries — the numeric VMT is the single64 source of truth.6566## Migration checklist (web → VectoJS)67681. Replace `#hex` literals with tokens (`var(--surface)` etc.) or keep them —69 literals are fine, they just don't theme-switch.702. `display: flex` + `flexDirection/gap/alignItems` → the entity must be a71 `Stack`/`Flow` (VectoJS has no auto-container conversion).723. `center`/`right` text-align has no backing field — re-layout with73 `Stack({ align: 'center' })` instead.744. `transform: rotate(30deg)` → `rotation: Math.PI / 6` (radians).755. Pseudo-states (`:hover`) → entity events (`entity.on('hover')`).7677## Cross-references7879Component fields and constructor sizing → **vectojs-core-runtime** ·80layout containers → **vectojs-responsive-layout** · theme-switching81performance → **vectojs-performance** · verifying applied fields →82**vectojs-devtools**.8384Base directory for this skill: /mnt/data/Workspace/Projects/vectojs/.agents/skills/vectojs-styles