@theme-registry/refract 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -1
- package/dist/build/createCommand.d.ts +47 -0
- package/dist/build/createInterview.d.ts +56 -0
- package/dist/build/index.d.ts +4 -0
- package/dist/build/init.d.ts +42 -0
- package/dist/build/prompt.d.ts +76 -0
- package/dist/build/scaffold.d.ts +146 -0
- package/dist/build.cjs.js +1 -1
- package/dist/build.cjs.js.map +1 -1
- package/dist/build.esm.js +1 -1
- package/dist/build.esm.js.map +1 -1
- package/dist/cli.js +1139 -14
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/skills/theme-authoring/SKILL.md +3 -0
- package/skills/theme-scaffold/SKILL.md +130 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theme-registry/refract",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "The framework-agnostic, format-neutral theme compiler core — build a ThemeModel from a RawTheme, then lower it with any adapter package (CSS, SCSS, JSON, styled-components).",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Petyo Stoyanov",
|
|
@@ -39,6 +39,9 @@ patch. Full narrative reference lives in [`docs/authoring.md`](https://github.co
|
|
|
39
39
|
|
|
40
40
|
## Route to the right guide
|
|
41
41
|
|
|
42
|
+
- **No theme yet, starting from nothing** → **theme-scaffold**. `refract create` generates a
|
|
43
|
+
contrast-checked starting palette, type scale and spacing ramp from one seed colour; don't
|
|
44
|
+
hand-write a first theme from a blank file. (It emits *tokens only* — no recipes.)
|
|
42
45
|
- **Any recipe, states, `variants`, or `components` composition** → **recipes-and-composition**.
|
|
43
46
|
Recipes work identically across every subsystem, so that vocabulary lives in one place.
|
|
44
47
|
- **A specific token domain** (palettes, type scale, spacing, effects) → the domain guide above.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: theme-scaffold
|
|
3
|
+
description: Generate a starting RawTheme from one seed colour with `refract create`, or scaffold a whole publishable theme package with `npm create refract-theme`. Use when there is no theme yet and you need a defensible starting palette, type scale and spacing ramp rather than a blank file. Triggers: "refract create", "create a theme", "new theme", "scaffold a theme", "starter theme", "generate a palette", "npm create refract-theme", "new design system".
|
|
4
|
+
tier: core
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Scaffolding a theme
|
|
8
|
+
|
|
9
|
+
Two commands turn a seed colour into a real `RawTheme`. Use them instead of hand-writing a first
|
|
10
|
+
theme from nothing — the output clears a contrast bar, which a hand-rolled first palette usually
|
|
11
|
+
doesn't.
|
|
12
|
+
|
|
13
|
+
| Situation | Command | Writes |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| Project exists, needs a theme | `refract create` | `theme.raw.(ts\|js\|json)` |
|
|
16
|
+
| Nothing exists yet | `npm create refract-theme my-theme` | a whole publishable package |
|
|
17
|
+
| Tokens already exist elsewhere | `refract import tokens.json` | see **dtcg-import** |
|
|
18
|
+
|
|
19
|
+
Both run the **same interview** and the same generator. Neither changes the palette model: they call
|
|
20
|
+
the colour helpers the library already ships and write down what they return, **once**.
|
|
21
|
+
|
|
22
|
+
## The commands
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
refract create # interactive
|
|
26
|
+
refract create --yes # every default, asks nothing
|
|
27
|
+
refract create --seed "#4c6ef5" --colors 3 --scheme triadic --feel editorial --format json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Then wire the build — `refract init` **detects** the theme file and imports it:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
refract init # finds theme.raw.*, writes a config that imports it
|
|
34
|
+
refract build
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Flags mirror every prompt: `--seed`, `--colors <n|list>`, `--scheme`, `--manual`, `--feel`,
|
|
38
|
+
`--ratio`, `--base-size`, `--contrast <AA|AAA|none>`, `--reset`, `--format <ts|js|json>`, `--out`,
|
|
39
|
+
`--no-semantics`, `--no-neutral`, `--no-shadows`, `--yes`, `--force`. Every prompt is
|
|
40
|
+
non-interactive-safe: with no TTY it takes the default rather than blocking, so this is safe in CI.
|
|
41
|
+
|
|
42
|
+
## What you get — and what you don't
|
|
43
|
+
|
|
44
|
+
From one colour: brand palettes, semantic colours, a neutral ramp, shadow tints, a type scale with
|
|
45
|
+
derived leading and tracking, a spacing ramp, radius, elevation and motion — around 150 variables.
|
|
46
|
+
|
|
47
|
+
**No recipes.** This is the important one. The scaffold emits *tokens only*, so nothing composes
|
|
48
|
+
into a class list yet. Do not tell the user their buttons are themed — they have variables. Writing
|
|
49
|
+
recipes is the next step and it is theirs (or yours) to do: see **recipes-and-composition**.
|
|
50
|
+
|
|
51
|
+
Also absent by design: no `@keyframes` (nothing would reference one without a recipe), and no
|
|
52
|
+
components.
|
|
53
|
+
|
|
54
|
+
## Decisions baked into the output
|
|
55
|
+
|
|
56
|
+
Know these before you edit a generated theme, or you'll "fix" things that are deliberate.
|
|
57
|
+
|
|
58
|
+
- **Brand colours 2–5 are top-level palettes, not variants.** `harmony` in a hand-authored theme
|
|
59
|
+
emits `primary-complement` as a single flat leaf; the scaffolder promotes each member to its own
|
|
60
|
+
family (`secondary`, `tertiary`, …) with a full `50…900` ladder, because a flat leaf can't carry a
|
|
61
|
+
UI.
|
|
62
|
+
- **`base` is the brand colour.** The ladder is absolute lightness, so the seed lands wherever it
|
|
63
|
+
falls (often between two stops) and is reachable only as `base`. The `50…900` stops are for
|
|
64
|
+
surfaces, borders and states. Nothing snaps — the hex the user typed survives.
|
|
65
|
+
- **Semantic colours are hue-anchored, not rotated.** Rotating off the seed would make "danger"
|
|
66
|
+
whatever lands at +150°; from a red seed that's green. success/info/warning/danger start from
|
|
67
|
+
fixed hues and borrow only the seed's character.
|
|
68
|
+
- **A contrast pass ran before the file was written.** Every text pairing was scored and failing
|
|
69
|
+
colours were darkened in OKLCH points until they cleared the bar. If you change a `base`, re-run
|
|
70
|
+
`refract audit` — it is easy to lose AA by hand.
|
|
71
|
+
- **Derived leading and tracking are named after the size step they were tuned for**
|
|
72
|
+
(`lineheight-4xl`, not `lineheight-tight`), so the pairing documents itself without a recipe:
|
|
73
|
+
|
|
74
|
+
```css
|
|
75
|
+
font-size: var(--dt-typography-fontsize-4xl);
|
|
76
|
+
line-height: var(--dt-typography-lineheight-4xl);
|
|
77
|
+
letter-spacing: var(--dt-typography-letterspacing-4xl);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Retuning a generated theme
|
|
81
|
+
|
|
82
|
+
The output is **literal where the value came from an opinion, declarative where the engine
|
|
83
|
+
synthesizes**. That's why retuning is usually one word, not a table:
|
|
84
|
+
|
|
85
|
+
| Want | Change |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| A different brand colour | `colors.primary.base` — every step re-derives |
|
|
88
|
+
| A tighter type scale | `typography.fontSize.ratio` → `"major-second"` |
|
|
89
|
+
| More generous spacing | the multipliers in `layout.spacing.steps` |
|
|
90
|
+
| Softer corners | `borders.radius.base` |
|
|
91
|
+
|
|
92
|
+
Do **not** replace `fontSize: { base, ratio }` with a hand-listed ladder, or `spacing: { base, step,
|
|
93
|
+
steps }` with literal pixels — that throws away the intent the engine uses to synthesize.
|
|
94
|
+
|
|
95
|
+
## Gotchas
|
|
96
|
+
|
|
97
|
+
- **Re-running clobbers.** `refract create` refuses to overwrite an existing `theme.raw.*` without
|
|
98
|
+
`--force`. Don't pass `--force` over a theme the user has edited; generate to `--out` instead.
|
|
99
|
+
- **Format matters later, not now.** `.ts` · `.js` · `.json` compile to **byte-identical** output —
|
|
100
|
+
a scaffolded theme has no functions or recipes, so JSON loses nothing. It stops being true the
|
|
101
|
+
moment the theme needs a function-valued field (a custom scale `algorithm`); that requires `.ts`.
|
|
102
|
+
- **The spacing curve is linear on purpose.** `step: 4` keeps every stop on a 4px grid; the
|
|
103
|
+
geometric `ratio` curve gives `8 · 12 · 18 · 27 · 40.5` and is right for type, wrong for space.
|
|
104
|
+
- **`refract init` only skips its own starter palette when a theme file already exists.** In an
|
|
105
|
+
empty directory it still writes a self-contained config — so run `create` *before* `init`.
|
|
106
|
+
|
|
107
|
+
## Programmatic use
|
|
108
|
+
|
|
109
|
+
The generator is exported, so tooling can call it without a TTY:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { scaffoldTheme, runCreate } from "@theme-registry/refract/build";
|
|
113
|
+
|
|
114
|
+
const { raw, report } = scaffoldTheme({ seed: "#4c6ef5", brandCount: 3, feel: "editorial" });
|
|
115
|
+
report.contrast; // per-palette: ratio before/after, the nudge applied, whether it cleared the bar
|
|
116
|
+
report.brand; // each brand palette with the hue rotation that produced it
|
|
117
|
+
|
|
118
|
+
runCreate({ seed: "#4c6ef5", cwd: ".", format: "ts" }); // generate + write in one call
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`scaffoldTheme` is pure — no filesystem, no prompting, no randomness — so the same answers always
|
|
122
|
+
produce the same theme. Its tunable curves (leading, tracking, semantic hue anchors, feel presets)
|
|
123
|
+
are named constants at the top of `build/scaffold.ts`; they are opinions, and they are meant to be
|
|
124
|
+
arguable.
|
|
125
|
+
|
|
126
|
+
## Where to go next
|
|
127
|
+
|
|
128
|
+
**recipes-and-composition** to turn these tokens into classes · **colors** for the palette grammar
|
|
129
|
+
you're now editing · **build-config** for targets and emit modes · **overrides-and-child-themes** to
|
|
130
|
+
derive a second brand from the one you just generated.
|