okchroma 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OKChroma contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,135 @@
1
+ # OKChroma
2
+
3
+ **A color-system engine.** Give it one (or two) brand color(s) and it generates a complete,
4
+ accessible, theme-ready color system around it.
5
+
6
+ Each color family is a light and dark ramp built from pre-reserved roles — 2 papers,
7
+ 5 washes, 2 highlights, and 2 inks — plus a solid CTA resting/hover pair and their
8
+ on-text colors, for each brand hex inputted. Alongside the brand color(s), it generates neutral, info-color, and red/yellow/green signal color scales. The inputted hex color(s) is/are preserved in identity swatches for logos or other brand identity moments.
9
+
10
+ The point is **white-label predictability**: every ramps's stops land at the same
11
+ perceived lightness and play the same role, so you map your design tokens to step
12
+ **numbers** once and they hold for any color scale. Contrast is built into the math, not
13
+ bolted on after: the system solves against **WCAG** ratios (every text color guaranteed
14
+ to pass), with **APCA** as an added legibility floor on CTA text (Lc 65 clearance on top
15
+ of the 4.5:1 requirement).
16
+
17
+ Output comes in two interchangeable forms carrying the same values:
18
+
19
+ - **CSS custom properties** — per-brand CSS generated live (`brandCss`) + the static
20
+ `dist/signals.css`, via the semantic layer `tokens/semantic.css`.
21
+ - **Figma variables** — written into a Figma file by the bundled plugin.
22
+
23
+ The live demo and the Figma plugin are previews/front-ends; the engine and its output are
24
+ the product.
25
+
26
+ > The "reserved role per step" model is a conceptual nod to
27
+ > [Radix Colors](https://www.radix-ui.com/colors/docs/palette-composition/understanding-the-scale).
28
+ > It is **not** a dependency and does not affect the math — all color computation is original.
29
+
30
+ ## Quick start
31
+
32
+ ```bash
33
+ npm install
34
+ npm run demo:build # generate token CSS + bundle the demo
35
+ npx serve . # then open http://localhost:3000/demo/index.html
36
+ ```
37
+
38
+ Live editing: `npm run dev` (watch mode). Build the Figma plugin: `npm run plugin:build`,
39
+ then import `plugin/manifest.json` in Figma.
40
+
41
+ ## Use as an npm package
42
+
43
+ ```bash
44
+ npm install okchroma
45
+ ```
46
+
47
+ ```ts
48
+ import { resolveTheme, brandCss, signalsCss } from 'okchroma'
49
+
50
+ const t = resolveTheme({ primaryHex: '#E93D82', name: 'Acme' })
51
+ const css = brandCss('acme', 'Acme', t.themed) + '\n' + signalsCss()
52
+ ```
53
+
54
+ `resolveTheme` solves the full system for a seed (primary, optional secondary, neutral
55
+ source, signal policy). `brandCss` emits the solved light and dark values as CSS custom
56
+ properties scoped to `[data-brand="acme"]`, with dark values under
57
+ `[data-brand="acme"][data-theme="dark"]`; the per-brand neutral is included in the same
58
+ block. Variables are named `--brand-<token>`, `--neutral-<token>`, and
59
+ `--<signal>-<token>`. Inject the string into a `<style>` tag at runtime or write it to a
60
+ file at build time; `signalsCss()` is brand-independent and emitted once.
61
+
62
+ The same resolved theme feeds the other emitters: `themeToFigma` returns the Figma
63
+ variable payload, and `emitDtcgRamp` returns DTCG JSON carrying the live requirement in
64
+ `$extensions`. ESM and CJS builds ship with TypeScript declarations. The package bundles
65
+ its one runtime dependency (helmlab), so installing it adds nothing transitive.
66
+
67
+ ## How it works (30 seconds)
68
+
69
+ Every token is a **requirement the engine solves, not a frozen value**. A pure-data
70
+ declaration (`src/engine/requirements/spec.ts`) states each stop's producer (perceptual
71
+ placement, warm drift, chroma ladder) and its requirements (contrast floors, seam
72
+ separations, on-text rules); a resolver executes it per seed — **produce → require →
73
+ refine**. `resolveBrand(hex)` runs that engine, applies **policy** (status-color
74
+ collisions, signal shifts), and an **emitter** (`cssRender` / `figmaRender`) maps the
75
+ resolved stops onto named tokens and picks light vs dark. The declaration also
76
+ round-trips to DTCG tokens (`$value` fallback + the live requirement in `$extensions`).
77
+
78
+ - **Engine:** `src/engine/*` — pure TypeScript with one runtime dependency (helmlab,
79
+ the P2 adjacency metric), bundled into the npm package at build time.
80
+ - **Entry points:** `resolveBrand` (`src/engine/resolve.ts`) and `generateScale`
81
+ (`src/engine/colorEngine.ts`, an adapter over the resolver — same signature as always).
82
+ - **Build:** `src/build.ts` writes the one static output, `dist/signals.css`. There is no
83
+ brand roster: per-brand CSS is generated live by whichever caller resolves a hex (the
84
+ demo's hex input, a plugin's form field).
85
+
86
+ ## The Figma plugin
87
+
88
+ The bundled plugin runs the same engine inside Figma and writes the resolved system into
89
+ your file as variables: **theme** + **mode** collections whose semantic tokens alias onto
90
+ shared primitives — per-brand ramps under `brand/<name>`, with neutrals and signals
91
+ deduplicated across brands, light + dark values on every token.
92
+
93
+ **Install** — from source:
94
+
95
+ ```bash
96
+ npm install && npm run plugin:build
97
+ ```
98
+
99
+ then Figma → Plugins → Development → **Import plugin from manifest** →
100
+ `plugin/manifest.json`.
101
+
102
+ > The hosted download for **this** plugin is **withdrawn** as of 2026-07-29. The scale
103
+ > changed shape in that round — `highlight-9` and `on-highlight` were removed and the ink
104
+ > stops renumbered — and this plugin does not yet carry the rename table that migrates an
105
+ > existing Figma file across it, so updating an installed copy would orphan its variable
106
+ > bindings. Building from source is unaffected: a fresh file gets the new shape correctly.
107
+ >
108
+ > The **extended collections** plugin (Figma Enterprise) does carry the migration and is
109
+ > published as normal — **[install it here](https://egerrity.github.io/okchroma/install.html)**.
110
+
111
+ **Use** — name the brand, pick a primary, and Apply. Optional before applying:
112
+
113
+ - **Secondary color** — "+ Add secondary" starts on *From primary* (a pastel derived from
114
+ your primary); type any hex for a custom secondary in **Tint / Pastel / Outline / Exact**
115
+ style.
116
+ - **Neutral color** — *Default* (a touch of primary hue), *Medium* (slightly more tint), *Intense*, or *True grey*.
117
+ - **Contrast standard** — **APCA** (default) or **WCAG**. One profile per collection pair:
118
+ applying the other profile to an existing file forks a clearly-labeled second pair
119
+ (`theme-wcag`/`mode-wcag`) instead of ever mixing values.
120
+
121
+ Re-applying the same brand name updates it in place (after a confirm); a new name adds a
122
+ brand to the same collections — two applies with two brand colors is a multi-brand system
123
+ on shared foundations.
124
+
125
+ ## Documentation
126
+
127
+ Full system documentation — overview, architecture (data flow + design decisions),
128
+ dependencies, setup — is in **[docs/architecture.md](docs/architecture.md)**.
129
+ The scale model and its per-stop targets are in **[docs/scale.md](docs/scale.md)**.
130
+ The requirement-token schema — the DTCG token format, field by field, with real
131
+ emitted examples — is in **[docs/schema.md](docs/schema.md)**.
132
+
133
+ ## License
134
+
135
+ MIT