@fusion.dev/helix-theme 0.0.0-dev → 0.0.3

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/dist/index.d.ts CHANGED
@@ -14,9 +14,9 @@ export interface ThemeEngine {
14
14
  /**
15
15
  * Reads a hex color into its OKLCH components.
16
16
  *
17
- * @throws when the string is not a hex color. **The TypeScript engine
18
- * returned a `NaN` triple**, which every comparison is false against, so a
19
- * color that could not be read traveled onward looking like one.
17
+ * @throws when the string is not a hex color. Returning a `NaN` triple
18
+ * instead is worse: every comparison against it is false, so a color that
19
+ * could not be read travels onward looking like one.
20
20
  */
21
21
  hexToOklch(hex: string): Oklch;
22
22
  }
package/dist/types.d.ts CHANGED
@@ -1,15 +1,11 @@
1
1
  /**
2
2
  * The shapes a consumer writes and the shapes they get back.
3
3
  *
4
- * **Declarations only, and that is what is left of the TypeScript engine.** The
5
- * derivation is Rust now, reached through WebAssembly, so what a JavaScript
6
- * consumer needs from this package is the vocabulary rather than the solver. A
7
- * type is erased at build time, so nothing here is a second implementation of
8
- * anything: it cannot drift into disagreeing with the engine about an *answer*,
9
- * only about a *field name*, which is what `check:wasm` compares.
10
- *
11
- * The prose is kept whole from the files it came from. It is the argument for
12
- * why each field exists, and it was never about how any of them was computed.
4
+ * **Declarations only.** The derivation is Rust, reached through WebAssembly, so
5
+ * what a JavaScript consumer needs from this package is the vocabulary rather
6
+ * than the solver. A type is erased at build time, so nothing here is a second
7
+ * implementation of anything: it cannot drift into disagreeing with the engine
8
+ * about an *answer*, only about a *field name*, which is what is compared.
13
9
  */
14
10
  /** A color in OKLCH. Lightness 0 to 1, chroma from 0, hue in degrees. */
15
11
  export interface Oklch {
@@ -24,7 +20,7 @@ export type Color = Oklch | string;
24
20
  *
25
21
  * Written as a relationship rather than a second color because a literal
26
22
  * drifts out of relation the moment anybody rethemes, which is the failure of
27
- * every palette with two hardcoded colours in it.
23
+ * every palette with two hardcoded colors in it.
28
24
  */
29
25
  export interface Relation {
30
26
  /**
@@ -126,10 +122,6 @@ export interface ThemeIntent {
126
122
  * **The one material choice that can invalidate the guarantee.** Contrast is
127
123
  * measured against a known ground and a translucent surface does not have
128
124
  * one, so a pair over it comes back `unverifiable` rather than measured.
129
- *
130
- * The audit found this half nearly done already: six declarations across two
131
- * families, both already behind hooks, so material needed a policy token to
132
- * default to and nothing else.
133
125
  */
134
126
  material?: {
135
127
  blur?: number;
@@ -138,12 +130,8 @@ export interface ThemeIntent {
138
130
  /**
139
131
  * The faces the theme is set in.
140
132
  *
141
- * **Type is part of a theme and had no input at all.** Twenty tokens across
142
- * five categories, families, sizes, weights, leading and tracking, were
143
- * unreachable from intent while every color in the palette was one field
144
- * away. Families are the half a consumer actually chooses; the size scale,
145
- * the weights and the spacing are the half that is a system, and they are
146
- * still fixed.
133
+ * **Families are the half a consumer chooses**; the size scale, the weights
134
+ * and the spacing are the half that is a system, and they stay fixed.
147
135
  *
148
136
  * `display` falls back to `body`, which is what the stylesheet already does:
149
137
  * a theme with one face is the common case and should not have to say so
@@ -190,12 +178,7 @@ export interface ThemeIntent {
190
178
  */
191
179
  namespace?: string;
192
180
  /**
193
- * How the theme's motion feels.
194
- *
195
- * **The other axis with no input at all**, alongside the half of type that is
196
- * a system: nine tokens, four durations and five curves, and a brand with a
197
- * snappy voice and one with a gentle one reached them the same way, which is
198
- * to say not at all.
181
+ * How the theme's motion feels: nine tokens, four durations and five curves.
199
182
  *
200
183
  * `character` sets the curve every component reaches for by default and
201
184
  * carries a duration multiplier with it, because the two are one decision: a
@@ -204,8 +187,7 @@ export interface ThemeIntent {
204
187
  *
205
188
  * `instant` is not scaled. It is 0 and means "do not animate", which is a
206
189
  * statement rather than a duration, and it emits no curves at all: three
207
- * easings for transitions of zero length is a contradiction the type used to
208
- * allow through `scale: 0`.
190
+ * easings for transitions of zero length is a contradiction.
209
191
  *
210
192
  * `precise` is the one character that is not physical. The other three
211
193
  * accelerate, settle or overshoot; linear reads as moved by a mechanism, and
@@ -222,8 +204,7 @@ export interface ThemeIntent {
222
204
  * Chroma 0 is a dead gray and is the default, matching `primitives.css`,
223
205
  * which records why: a fixed chroma is a rising *saturation* as a surface
224
206
  * darkens, so a trace that looks right on a light page reads navy across a
225
- * dark one. The engine used to hardcode 0.008, the exact value the
226
- * stylesheet had already rejected for that reason.
207
+ * dark one.
227
208
  */
228
209
  neutral?: {
229
210
  chroma?: number;
@@ -245,9 +226,8 @@ export interface ThemeIntent {
245
226
  * rather than a comment asking nicely.
246
227
  *
247
228
  * `fill` and `space` produce the same edge and lift, which is none of
248
- * either: the difference between them lives in the surface colours and in
249
- * `density`, not here. Said out loud because two values with one output
250
- * looks like a bug until it is explained.
229
+ * either: the difference between them lives in the surface colors and in
230
+ * `density`, not here. Two values with one output reads as a bug and is not.
251
231
  */
252
232
  separation?: {
253
233
  floating?: 'border' | 'fill' | 'shadow';
@@ -352,10 +332,10 @@ export interface Pairing {
352
332
  * measured and passed. Folding the two together is how a guarantee decays
353
333
  * into a claim about the pairs that happened to be easy.
354
334
  *
355
- * One producer today: a pairing naming a token this theme does not emit,
356
- * which a caller supplying their own `pairings` will legitimately do.
357
- * Translucent grounds are the second, when `material` lands: what sits
358
- * behind a glass surface is whatever the reader scrolled under it.
335
+ * Two producers: a pairing naming a token this theme does not emit, which a
336
+ * caller supplying their own `pairings` will legitimately do, and a ground
337
+ * the model marks unbounded, where what sits behind the surface is whatever
338
+ * the reader scrolled under it.
359
339
  */
360
340
  status: 'fail' | 'pass' | 'unverifiable';
361
341
  /**
@@ -369,13 +349,9 @@ export interface Pairing {
369
349
  /**
370
350
  * What a derivation produced.
371
351
  *
372
- * **No `intent`, which the TypeScript engine carried and nothing read.** It held
373
- * the resolved intent so a consumer could see what they got rather than what
374
- * they asked for, which is a real thing to want and was never used, never dumped
375
- * by the oracle, and therefore never checked. Serialising it across the boundary
376
- * means a `Serialize` on every shape in the vocabulary including three unions
377
- * with hand-written readers, which is a day of work for a field with no caller.
378
- * It goes back the moment one appears.
352
+ * **No resolved `intent` field.** Carrying one across the WebAssembly boundary
353
+ * means a `Serialize` on every shape in the vocabulary, three hand-read unions
354
+ * included, and no consumer has asked for it. It goes back when one does.
379
355
  */
380
356
  export interface DerivedTheme {
381
357
  /**
@@ -406,20 +382,19 @@ export interface DerivedTheme {
406
382
  pairings: Pairing[];
407
383
  /**
408
384
  * The seed values a consumer must write for `helix/styles` to re-derive the
409
- * halves this engine does not compute: the twenty-four series colours, the
385
+ * halves this engine does not compute: the twenty-four series colors, the
410
386
  * spacing scale and the corner radii.
411
387
  *
412
388
  * **Data rather than only a line of CSS**, because the two consumers apply it
413
389
  * differently. `toCss` renders a block; a page theming one panel writes the
414
390
  * properties onto that element. Both read this, so neither can hold a
415
- * different opinion about what the seed is, which is exactly what the
416
- * marketing site's hand-written bridge had become.
391
+ * different opinion about what the seed is.
417
392
  */
418
393
  seeds: Record<string, string>;
419
394
  tokens: DerivedToken[];
420
395
  /**
421
396
  * Pairings that failed their contrast target, pinned values included.
422
- * Rendered from `pairings`, and no longer the only record of a result.
397
+ * Rendered from `pairings`.
423
398
  */
424
399
  violations: string[];
425
400
  }
package/dist/types.js CHANGED
@@ -1,14 +1,10 @@
1
1
  /**
2
2
  * The shapes a consumer writes and the shapes they get back.
3
3
  *
4
- * **Declarations only, and that is what is left of the TypeScript engine.** The
5
- * derivation is Rust now, reached through WebAssembly, so what a JavaScript
6
- * consumer needs from this package is the vocabulary rather than the solver. A
7
- * type is erased at build time, so nothing here is a second implementation of
8
- * anything: it cannot drift into disagreeing with the engine about an *answer*,
9
- * only about a *field name*, which is what `check:wasm` compares.
10
- *
11
- * The prose is kept whole from the files it came from. It is the argument for
12
- * why each field exists, and it was never about how any of them was computed.
4
+ * **Declarations only.** The derivation is Rust, reached through WebAssembly, so
5
+ * what a JavaScript consumer needs from this package is the vocabulary rather
6
+ * than the solver. A type is erased at build time, so nothing here is a second
7
+ * implementation of anything: it cannot drift into disagreeing with the engine
8
+ * about an *answer*, only about a *field name*, which is what is compared.
13
9
  */
14
10
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fusion.dev/helix-theme",
3
3
  "description": "Theme derivation engine. Computes a complete, contrast-guaranteed token set from intent inputs.",
4
- "version": "0.0.0-dev",
4
+ "version": "0.0.3",
5
5
  "license": "MIT",
6
6
  "author": "Ross Sheppard <ross.sheppard@fusion.dev>",
7
7
  "repository": {
@@ -26,9 +26,14 @@
26
26
  "scripts": {
27
27
  "build": "tsc -p tsconfig.json",
28
28
  "test": "cargo test -p fusion-helix-theme --manifest-path ../../Cargo.toml",
29
- "typecheck": "tsc -p tsconfig.json --noEmit"
29
+ "typecheck": "tsc -p tsconfig.json --noEmit",
30
+ "wasm": "node scripts/build-wasm.mjs",
31
+ "wasm-check": "bun scripts/check-wasm.mjs"
30
32
  },
31
33
  "bugs": "https://github.com/project-fusion/fusion/issues",
34
+ "devDependencies": {
35
+ "@fusion.dev/scripts": "0.0.0-dev"
36
+ },
32
37
  "homepage": "https://fusion.dev",
33
38
  "keywords": [
34
39
  "theming",
@@ -11,9 +11,6 @@
11
11
  * intent-in-CSS-out function would have it deriving twice for one keystroke.
12
12
  * The result carries `css` keyed by selector, empty when none were asked for.
13
13
  *
14
- * For reference, the TypeScript engine this replaces took 39ms for the
15
- * derivation alone, so the builder does less work than it did rather than more.
16
- *
17
14
  * `selectors` is a JSON array, keeping the boundary uniformly JSON in and JSON
18
15
  * out rather than mixing in a bound array type for one argument.
19
16
  *
@@ -27,11 +24,10 @@ export function derive(intent: string, selectors: string): string;
27
24
  /**
28
25
  * Reads a hex color into its OKLCH components, as JSON.
29
26
  *
30
- * **Throws where the TypeScript returned `NaN`**, which is a deliberate change
31
- * and the same one `resolve` makes for a brand: `Number.parseInt` of something
32
- * that is not hex gives `NaN`, every comparison against which is false, so a
33
- * color that could not be read traveled onward looking like a color. A
34
- * caller passing the value of a color input never sees this.
27
+ * **Throws rather than returning a `NaN` triple**, which is the decision
28
+ * `resolve` makes for a brand: every comparison against `NaN` is false, so a
29
+ * color that could not be read travels onward looking like a color. A caller
30
+ * passing the value of a color input never sees this.
35
31
  *
36
32
  * # Errors
37
33
  *
@@ -10,9 +10,6 @@
10
10
  * intent-in-CSS-out function would have it deriving twice for one keystroke.
11
11
  * The result carries `css` keyed by selector, empty when none were asked for.
12
12
  *
13
- * For reference, the TypeScript engine this replaces took 39ms for the
14
- * derivation alone, so the builder does less work than it did rather than more.
15
- *
16
13
  * `selectors` is a JSON array, keeping the boundary uniformly JSON in and JSON
17
14
  * out rather than mixing in a bound array type for one argument.
18
15
  *
@@ -50,11 +47,10 @@ export function derive(intent, selectors) {
50
47
  /**
51
48
  * Reads a hex color into its OKLCH components, as JSON.
52
49
  *
53
- * **Throws where the TypeScript returned `NaN`**, which is a deliberate change
54
- * and the same one `resolve` makes for a brand: `Number.parseInt` of something
55
- * that is not hex gives `NaN`, every comparison against which is false, so a
56
- * color that could not be read traveled onward looking like a color. A
57
- * caller passing the value of a color input never sees this.
50
+ * **Throws rather than returning a `NaN` triple**, which is the decision
51
+ * `resolve` makes for a brand: every comparison against `NaN` is false, so a
52
+ * color that could not be read travels onward looking like a color. A caller
53
+ * passing the value of a color input never sees this.
58
54
  *
59
55
  * # Errors
60
56
  *
Binary file