@weasel-js/theme 0.5.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 orochi235
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,26 @@
1
+ # @weasel-js/theme
2
+
3
+ Design tokens shared by weasel-ui and weasel-hud — CSS variables + a parallel TS export.
4
+
5
+ Part of [weasel](https://github.com/orochi235/weasel), a domain-agnostic 2D
6
+ scene-graph canvas kit for React. See the
7
+ [API reference](https://orochi235.github.io/weasel/api/).
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ npm install @weasel-js/theme
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```ts
18
+ import { /* … */ } from '@weasel-js/theme';
19
+ import '@weasel-js/theme/tokens.css';
20
+ ```
21
+
22
+ The stylesheet is required — component styles ship as one bundled file.
23
+
24
+ ## License
25
+
26
+ MIT
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Source of truth for token default values. Mirrors tokens.css exactly,
3
+ * with var(--*) references resolved to their literal target value (TS
4
+ * exports can't reference each other syntactically the way CSS can with
5
+ * var()). The parity test in tokens.test.ts catches drift.
6
+ *
7
+ * color-mix() expressions are resolved to plausible hex approximations
8
+ * — consumers that need exact mixed values should read getComputedStyle
9
+ * from the live DOM rather than relying on these defaults.
10
+ */
11
+ declare const DEFAULT_TOKENS: {
12
+ readonly '--wzl-gray-50': "#f5f5f6";
13
+ readonly '--wzl-gray-100': "#e6e7e9";
14
+ readonly '--wzl-gray-200': "#c9cbcf";
15
+ readonly '--wzl-gray-300': "#9ea1a8";
16
+ readonly '--wzl-gray-400': "#6f737b";
17
+ readonly '--wzl-gray-500': "#4d5058";
18
+ readonly '--wzl-gray-600': "#383b42";
19
+ readonly '--wzl-gray-700': "#25272c";
20
+ readonly '--wzl-gray-800': "#181a1e";
21
+ readonly '--wzl-gray-900': "#0e0f12";
22
+ readonly '--wzl-accent-soft': "#1d1454";
23
+ readonly '--wzl-accent-base': "#2e1f7a";
24
+ readonly '--wzl-accent-strong': "#5841b8";
25
+ readonly '--wzl-danger-base': "#d94a3f";
26
+ readonly '--wzl-warning-base': "#d99a3f";
27
+ readonly '--wzl-success-base': "#2ec27e";
28
+ readonly '--wzl-radius-sm': "3px";
29
+ readonly '--wzl-radius-md': "5px";
30
+ readonly '--wzl-border-w': "1px";
31
+ readonly '--wzl-line-width': "2px";
32
+ readonly '--wzl-curve-width': "3px";
33
+ readonly '--wzl-motion-fast': "120ms";
34
+ readonly '--wzl-motion-medium': "240ms";
35
+ readonly '--wzl-ease-in-cubic': "cubic-bezier(0.32, 0, 0.67, 0)";
36
+ readonly '--wzl-ease-out-cubic': "cubic-bezier(0.33, 1, 0.68, 1)";
37
+ readonly '--wzl-ease-in-out-cubic': "cubic-bezier(0.65, 0, 0.35, 1)";
38
+ readonly '--wzl-ease-out-back': "cubic-bezier(0.34, 1.56, 0.64, 1)";
39
+ readonly '--wzl-line-subtle': "rgba(230, 231, 233, 0.10)";
40
+ readonly '--wzl-line': "rgba(230, 231, 233, 0.20)";
41
+ readonly '--wzl-line-strong': "rgba(230, 231, 233, 0.40)";
42
+ readonly '--wzl-curve-color': "#5841b8";
43
+ readonly '--wzl-font-ui': "'Oswald', 'Helvetica Neue Condensed', 'Arial Narrow', system-ui, sans-serif";
44
+ readonly '--wzl-font-display': "'Oswald', 'Helvetica Neue Condensed', 'Arial Narrow', system-ui, sans-serif";
45
+ readonly '--wzl-font-body': "'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif";
46
+ readonly '--wzl-font-mono': "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace";
47
+ readonly '--wzl-font-weight-light': "200";
48
+ readonly '--wzl-font-weight-normal': "300";
49
+ readonly '--wzl-font-weight-bold': "400";
50
+ readonly '--wzl-surface': "#181a1e";
51
+ readonly '--wzl-surface-raised': "#25272c";
52
+ readonly '--wzl-surface-sunken': "#0e0f12";
53
+ readonly '--wzl-fg': "#e6e7e9";
54
+ readonly '--wzl-fg-muted': "#9ea1a8";
55
+ readonly '--wzl-fg-subtle': "#6f737b";
56
+ readonly '--wzl-fg-on-accent': "#f5f5f6";
57
+ readonly '--wzl-border': "#25272c";
58
+ readonly '--wzl-border-strong': "#383b42";
59
+ readonly '--wzl-accent': "#2e1f7a";
60
+ readonly '--wzl-accent-fg': "#5841b8";
61
+ readonly '--wzl-accent-hover': "#5841b8";
62
+ readonly '--wzl-danger': "#d94a3f";
63
+ readonly '--wzl-warning': "#d99a3f";
64
+ readonly '--wzl-success': "#2ec27e";
65
+ readonly '--wzl-focus-ring': "#5841b8";
66
+ readonly '--wzl-glass-tint': "#2e1f7a";
67
+ readonly '--wzl-text': "#e6e7e9";
68
+ readonly '--wzl-text-muted': "#9ea1a8";
69
+ readonly '--wzl-bg': "#181a1e";
70
+ readonly '--wzl-muted': "#9ea1a8";
71
+ readonly '--wzl-panel-bg': "#181a1e";
72
+ readonly '--wzl-panel-border': "#25272c";
73
+ readonly '--wzl-input-bg': "#0e0f12";
74
+ readonly '--wzl-track-bg': "#0e0f12";
75
+ readonly '--wzl-track-border': "#25272c";
76
+ readonly '--wzl-thumb-fill': "#9ea1a8";
77
+ readonly '--wzl-thumb-border': "#383b42";
78
+ readonly '--wzl-thumb-text': "#0e0f12";
79
+ readonly '--wzl-button-fill': "#25272c";
80
+ readonly '--wzl-button-fill-hover': "#2f3138";
81
+ readonly '--wzl-button-fill-pressed': "#363941";
82
+ readonly '--wzl-button-text': "#e6e7e9";
83
+ };
84
+ type TokenName = keyof typeof DEFAULT_TOKENS;
85
+
86
+ export { DEFAULT_TOKENS, type TokenName };
package/dist/index.js ADDED
@@ -0,0 +1,92 @@
1
+ // src/tokens.ts
2
+ var DEFAULT_TOKENS = {
3
+ // Primitive — grays
4
+ "--wzl-gray-50": "#f5f5f6",
5
+ "--wzl-gray-100": "#e6e7e9",
6
+ "--wzl-gray-200": "#c9cbcf",
7
+ "--wzl-gray-300": "#9ea1a8",
8
+ "--wzl-gray-400": "#6f737b",
9
+ "--wzl-gray-500": "#4d5058",
10
+ "--wzl-gray-600": "#383b42",
11
+ "--wzl-gray-700": "#25272c",
12
+ "--wzl-gray-800": "#181a1e",
13
+ "--wzl-gray-900": "#0e0f12",
14
+ // Primitive — accent + status
15
+ "--wzl-accent-soft": "#1d1454",
16
+ "--wzl-accent-base": "#2e1f7a",
17
+ "--wzl-accent-strong": "#5841b8",
18
+ "--wzl-danger-base": "#d94a3f",
19
+ "--wzl-warning-base": "#d99a3f",
20
+ "--wzl-success-base": "#2ec27e",
21
+ // Geometry
22
+ "--wzl-radius-sm": "3px",
23
+ "--wzl-radius-md": "5px",
24
+ "--wzl-border-w": "1px",
25
+ "--wzl-line-width": "2px",
26
+ "--wzl-curve-width": "3px",
27
+ // Motion — durations + CSS equivalents of the JS easing library
28
+ "--wzl-motion-fast": "120ms",
29
+ "--wzl-motion-medium": "240ms",
30
+ "--wzl-ease-in-cubic": "cubic-bezier(0.32, 0, 0.67, 0)",
31
+ "--wzl-ease-out-cubic": "cubic-bezier(0.33, 1, 0.68, 1)",
32
+ "--wzl-ease-in-out-cubic": "cubic-bezier(0.65, 0, 0.35, 1)",
33
+ "--wzl-ease-out-back": "cubic-bezier(0.34, 1.56, 0.64, 1)",
34
+ // Structural lines — three opacity levels of fg. color-mix at runtime;
35
+ // hex approximations here resolve against the dark default fg.
36
+ "--wzl-line-subtle": "rgba(230, 231, 233, 0.10)",
37
+ "--wzl-line": "rgba(230, 231, 233, 0.20)",
38
+ "--wzl-line-strong": "rgba(230, 231, 233, 0.40)",
39
+ // Curve color — semantic alias for the accent.
40
+ "--wzl-curve-color": "#5841b8",
41
+ // Typography
42
+ "--wzl-font-ui": "'Oswald', 'Helvetica Neue Condensed', 'Arial Narrow', system-ui, sans-serif",
43
+ "--wzl-font-display": "'Oswald', 'Helvetica Neue Condensed', 'Arial Narrow', system-ui, sans-serif",
44
+ "--wzl-font-body": "'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif",
45
+ "--wzl-font-mono": "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
46
+ "--wzl-font-weight-light": "200",
47
+ "--wzl-font-weight-normal": "300",
48
+ "--wzl-font-weight-bold": "400",
49
+ // Semantic — surfaces
50
+ "--wzl-surface": "#181a1e",
51
+ "--wzl-surface-raised": "#25272c",
52
+ "--wzl-surface-sunken": "#0e0f12",
53
+ // Semantic — text
54
+ "--wzl-fg": "#e6e7e9",
55
+ "--wzl-fg-muted": "#9ea1a8",
56
+ "--wzl-fg-subtle": "#6f737b",
57
+ "--wzl-fg-on-accent": "#f5f5f6",
58
+ // Semantic — borders
59
+ "--wzl-border": "#25272c",
60
+ "--wzl-border-strong": "#383b42",
61
+ // Semantic — interactive
62
+ "--wzl-accent": "#2e1f7a",
63
+ "--wzl-accent-fg": "#5841b8",
64
+ "--wzl-accent-hover": "#5841b8",
65
+ "--wzl-danger": "#d94a3f",
66
+ "--wzl-warning": "#d99a3f",
67
+ "--wzl-success": "#2ec27e",
68
+ "--wzl-focus-ring": "#5841b8",
69
+ // Semantic — glass
70
+ "--wzl-glass-tint": "#2e1f7a",
71
+ // Deprecated aliases (kept for older consumers)
72
+ "--wzl-text": "#e6e7e9",
73
+ "--wzl-text-muted": "#9ea1a8",
74
+ "--wzl-bg": "#181a1e",
75
+ "--wzl-muted": "#9ea1a8",
76
+ "--wzl-panel-bg": "#181a1e",
77
+ "--wzl-panel-border": "#25272c",
78
+ "--wzl-input-bg": "#0e0f12",
79
+ "--wzl-track-bg": "#0e0f12",
80
+ "--wzl-track-border": "#25272c",
81
+ "--wzl-thumb-fill": "#9ea1a8",
82
+ "--wzl-thumb-border": "#383b42",
83
+ "--wzl-thumb-text": "#0e0f12",
84
+ "--wzl-button-fill": "#25272c",
85
+ "--wzl-button-fill-hover": "#2f3138",
86
+ "--wzl-button-fill-pressed": "#363941",
87
+ "--wzl-button-text": "#e6e7e9"
88
+ };
89
+
90
+ export { DEFAULT_TOKENS };
91
+ //# sourceMappingURL=index.js.map
92
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tokens.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Source of truth for token default values. Mirrors tokens.css exactly,\n * with var(--*) references resolved to their literal target value (TS\n * exports can't reference each other syntactically the way CSS can with\n * var()). The parity test in tokens.test.ts catches drift.\n *\n * color-mix() expressions are resolved to plausible hex approximations\n * — consumers that need exact mixed values should read getComputedStyle\n * from the live DOM rather than relying on these defaults.\n */\nexport const DEFAULT_TOKENS = {\n // Primitive — grays\n '--wzl-gray-50': '#f5f5f6',\n '--wzl-gray-100': '#e6e7e9',\n '--wzl-gray-200': '#c9cbcf',\n '--wzl-gray-300': '#9ea1a8',\n '--wzl-gray-400': '#6f737b',\n '--wzl-gray-500': '#4d5058',\n '--wzl-gray-600': '#383b42',\n '--wzl-gray-700': '#25272c',\n '--wzl-gray-800': '#181a1e',\n '--wzl-gray-900': '#0e0f12',\n\n // Primitive — accent + status\n '--wzl-accent-soft': '#1d1454',\n '--wzl-accent-base': '#2e1f7a',\n '--wzl-accent-strong': '#5841b8',\n '--wzl-danger-base': '#d94a3f',\n '--wzl-warning-base': '#d99a3f',\n '--wzl-success-base': '#2ec27e',\n\n // Geometry\n '--wzl-radius-sm': '3px',\n '--wzl-radius-md': '5px',\n '--wzl-border-w': '1px',\n '--wzl-line-width': '2px',\n '--wzl-curve-width': '3px',\n\n // Motion — durations + CSS equivalents of the JS easing library\n '--wzl-motion-fast': '120ms',\n '--wzl-motion-medium': '240ms',\n '--wzl-ease-in-cubic': 'cubic-bezier(0.32, 0, 0.67, 0)',\n '--wzl-ease-out-cubic': 'cubic-bezier(0.33, 1, 0.68, 1)',\n '--wzl-ease-in-out-cubic': 'cubic-bezier(0.65, 0, 0.35, 1)',\n '--wzl-ease-out-back': 'cubic-bezier(0.34, 1.56, 0.64, 1)',\n\n // Structural lines — three opacity levels of fg. color-mix at runtime;\n // hex approximations here resolve against the dark default fg.\n '--wzl-line-subtle': 'rgba(230, 231, 233, 0.10)',\n '--wzl-line': 'rgba(230, 231, 233, 0.20)',\n '--wzl-line-strong': 'rgba(230, 231, 233, 0.40)',\n\n // Curve color — semantic alias for the accent.\n '--wzl-curve-color': '#5841b8',\n\n // Typography\n '--wzl-font-ui': \"'Oswald', 'Helvetica Neue Condensed', 'Arial Narrow', system-ui, sans-serif\",\n '--wzl-font-display': \"'Oswald', 'Helvetica Neue Condensed', 'Arial Narrow', system-ui, sans-serif\",\n '--wzl-font-body': \"'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif\",\n '--wzl-font-mono': 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace',\n '--wzl-font-weight-light': '200',\n '--wzl-font-weight-normal': '300',\n '--wzl-font-weight-bold': '400',\n\n // Semantic — surfaces\n '--wzl-surface': '#181a1e',\n '--wzl-surface-raised': '#25272c',\n '--wzl-surface-sunken': '#0e0f12',\n\n // Semantic — text\n '--wzl-fg': '#e6e7e9',\n '--wzl-fg-muted': '#9ea1a8',\n '--wzl-fg-subtle': '#6f737b',\n '--wzl-fg-on-accent': '#f5f5f6',\n\n // Semantic — borders\n '--wzl-border': '#25272c',\n '--wzl-border-strong': '#383b42',\n\n // Semantic — interactive\n '--wzl-accent': '#2e1f7a',\n '--wzl-accent-fg': '#5841b8',\n '--wzl-accent-hover': '#5841b8',\n '--wzl-danger': '#d94a3f',\n '--wzl-warning': '#d99a3f',\n '--wzl-success': '#2ec27e',\n '--wzl-focus-ring': '#5841b8',\n\n // Semantic — glass\n '--wzl-glass-tint': '#2e1f7a',\n\n // Deprecated aliases (kept for older consumers)\n '--wzl-text': '#e6e7e9',\n '--wzl-text-muted': '#9ea1a8',\n '--wzl-bg': '#181a1e',\n '--wzl-muted': '#9ea1a8',\n '--wzl-panel-bg': '#181a1e',\n '--wzl-panel-border': '#25272c',\n '--wzl-input-bg': '#0e0f12',\n '--wzl-track-bg': '#0e0f12',\n '--wzl-track-border': '#25272c',\n '--wzl-thumb-fill': '#9ea1a8',\n '--wzl-thumb-border': '#383b42',\n '--wzl-thumb-text': '#0e0f12',\n '--wzl-button-fill': '#25272c',\n '--wzl-button-fill-hover': '#2f3138',\n '--wzl-button-fill-pressed': '#363941',\n '--wzl-button-text': '#e6e7e9',\n} as const;\n\nexport type TokenName = keyof typeof DEFAULT_TOKENS;\n"]}
@@ -0,0 +1,206 @@
1
+ /* Design tokens for the weasel design system. Shared by weasel-ui (DOM)
2
+ * and weasel-hud (WebGL). Apps with their own design system should skip
3
+ * this file and define the variables themselves at the desired scope.
4
+ *
5
+ * Structure:
6
+ * 1. Primitive scale — raw values, not for direct consumption
7
+ * 2. Semantic tokens — what components reference
8
+ * 3. Deprecated aliases — kept so older components keep rendering
9
+ */
10
+ @import url('https://fonts.googleapis.com/css2?family=Oswald:wght@200;300;400&display=swap');
11
+
12
+ :root {
13
+ /* ---------- 1. Primitive scale ---------- */
14
+
15
+ /* Neutrals — perceptually-spaced gray ramp. */
16
+ --wzl-gray-50: #f5f5f6;
17
+ --wzl-gray-100: #e6e7e9;
18
+ --wzl-gray-200: #c9cbcf;
19
+ --wzl-gray-300: #9ea1a8;
20
+ --wzl-gray-400: #6f737b;
21
+ --wzl-gray-500: #4d5058;
22
+ --wzl-gray-600: #383b42;
23
+ --wzl-gray-700: #25272c;
24
+ --wzl-gray-800: #181a1e;
25
+ --wzl-gray-900: #0e0f12;
26
+
27
+ /* Accent — midnight blue-violet. Deep and saturated; carries enough
28
+ * weight to anchor primary actions in both light and dark surfaces.
29
+ * Apps override at their own scope. */
30
+ --wzl-accent-soft: #1d1454;
31
+ --wzl-accent-base: #2e1f7a;
32
+ --wzl-accent-strong: #5841b8;
33
+
34
+ --wzl-danger-base: #d94a3f;
35
+ --wzl-warning-base: #d99a3f;
36
+ --wzl-success-base: #2ec27e;
37
+
38
+ /* Geometry */
39
+ --wzl-radius-sm: 3px;
40
+ --wzl-radius-md: 5px;
41
+ --wzl-border-w: 1px;
42
+
43
+ /* Motion. Easing names mirror the kit's JS easing library
44
+ * (src/animation/easings.ts) so DOM chrome and canvas animation share
45
+ * one vocabulary — each cubic-bezier is the standard CSS approximation
46
+ * of the Penner curve of the same name.
47
+ * fast : micro-interactions — hover, focus, pressed states.
48
+ * medium : entrances/exits — toasts, popovers, panels. */
49
+ --wzl-motion-fast: 120ms;
50
+ --wzl-motion-medium: 240ms;
51
+ --wzl-ease-in-cubic: cubic-bezier(0.32, 0, 0.67, 0);
52
+ --wzl-ease-out-cubic: cubic-bezier(0.33, 1, 0.68, 1);
53
+ --wzl-ease-in-out-cubic: cubic-bezier(0.65, 0, 0.35, 1);
54
+ --wzl-ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1);
55
+
56
+ /* Typography. UI/body defaults to Inter; display is Oswald and is loaded
57
+ * via the @import above (consumers either bring their own Inter or accept
58
+ * the system-ui fallback). */
59
+ /* UI / display face — Oswald condensed. Used for chrome labels, buttons,
60
+ * menus, and headings. Loaded weights are 200/300/400 only; the heavier
61
+ * cuts get too blocky for this face at any size. */
62
+ --wzl-font-ui: 'Oswald', 'Helvetica Neue Condensed', 'Arial Narrow', system-ui, sans-serif;
63
+ --wzl-font-display: 'Oswald', 'Helvetica Neue Condensed', 'Arial Narrow', system-ui, sans-serif;
64
+ /* Body face — Inter for paragraphs and long-form prose. Consumers must
65
+ * load the Inter webfont themselves (or accept the system-ui fallback). */
66
+ --wzl-font-body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
67
+ --wzl-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
68
+ /* Weight tokens are tuned to the UI face (Oswald 200/300/400). Body /
69
+ * prose text using Inter will typically hardcode its own weights (e.g.
70
+ * 400/700) rather than route through these. */
71
+ --wzl-font-weight-light: 200;
72
+ --wzl-font-weight-normal: 300;
73
+ --wzl-font-weight-bold: 400;
74
+
75
+ /* ---------- 2. Semantic tokens ---------- */
76
+
77
+ /* Surfaces — three depths. */
78
+ --wzl-surface: var(--wzl-gray-800);
79
+ --wzl-surface-raised: var(--wzl-gray-700);
80
+ --wzl-surface-sunken: var(--wzl-gray-900);
81
+
82
+ /* Text */
83
+ --wzl-fg: var(--wzl-gray-100);
84
+ --wzl-fg-muted: var(--wzl-gray-300);
85
+ --wzl-fg-subtle: var(--wzl-gray-400);
86
+ --wzl-fg-on-accent: var(--wzl-gray-50);
87
+
88
+ /* Borders */
89
+ --wzl-border: var(--wzl-gray-700);
90
+ --wzl-border-strong: var(--wzl-gray-600);
91
+
92
+ /* Lines — for structural strokes (gridlines, dividers, plot axes).
93
+ * Distinct from borders, which enclose UI elements; lines partition
94
+ * content. Three alpha steps over `--wzl-fg` so the line auto-tints
95
+ * for whichever surface it's drawn on without needing per-mode values.
96
+ * Perceptual jobs: `subtle` = barely-there separators (table rows),
97
+ * default = primary gridlines on sunken surfaces, `strong` = axes /
98
+ * emphasized dividers. */
99
+ --wzl-line-subtle: color-mix(in srgb, var(--wzl-fg) 10%, transparent);
100
+ --wzl-line: color-mix(in srgb, var(--wzl-fg) 20%, transparent);
101
+ --wzl-line-strong: color-mix(in srgb, var(--wzl-fg) 40%, transparent);
102
+ /* Stroke widths.
103
+ * --wzl-line-width : structural lines (gridlines, dividers, axes).
104
+ * --wzl-curve-width : drawn data curves / signal traces. Heavier than
105
+ * structural lines so the data reads as primary
106
+ * content. Independently tunable. */
107
+ --wzl-line-width: 2px;
108
+ --wzl-curve-width: 3px;
109
+ /* Curve color — used by plot components (CurveEditor today; future
110
+ * waveform / chart widgets). Routes through the bright accent variant
111
+ * because --wzl-accent (midnight purple) is too dim on sunken
112
+ * surfaces. */
113
+ --wzl-curve-color: var(--wzl-accent-strong);
114
+
115
+ /* Interactive */
116
+ --wzl-accent: var(--wzl-accent-base);
117
+ /* Accent for *foreground* use — text, icons, selected-state labels drawn
118
+ * directly on a surface. --wzl-accent is a fill; the midnight base is too
119
+ * dim to read as text against dark surfaces (same reason --wzl-curve-color
120
+ * routes through the strong variant). Flips to the deep base in light
121
+ * mode, where it's the legible one. */
122
+ --wzl-accent-fg: var(--wzl-accent-strong);
123
+ --wzl-accent-hover: var(--wzl-accent-strong);
124
+ --wzl-danger: var(--wzl-danger-base);
125
+ --wzl-warning: var(--wzl-warning-base);
126
+ --wzl-success: var(--wzl-success-base);
127
+ --wzl-focus-ring: var(--wzl-accent-strong);
128
+
129
+ /* Frosted glass — the kit's signature treatment. Components compose:
130
+ * background: color-mix(in srgb, var(--wzl-glass-tint) 78%, transparent);
131
+ * backdrop-filter: blur(3px);
132
+ * Override `--wzl-glass-tint` at the component scope to tint glass
133
+ * with something other than the accent (e.g. danger). */
134
+ --wzl-glass-tint: var(--wzl-accent);
135
+
136
+ /* ---------- 3. Deprecated aliases ---------- *
137
+ * Older components still reference these names. New code should use
138
+ * the semantic tokens above. These will be removed once every
139
+ * component has been migrated.
140
+ */
141
+ --wzl-text: var(--wzl-fg);
142
+ --wzl-text-muted: var(--wzl-fg-muted);
143
+ --wzl-bg: var(--wzl-surface);
144
+ --wzl-muted: var(--wzl-fg-muted);
145
+ --wzl-panel-bg: var(--wzl-surface);
146
+ --wzl-panel-border: var(--wzl-border);
147
+ --wzl-input-bg: var(--wzl-surface-sunken);
148
+ --wzl-track-bg: var(--wzl-surface-sunken);
149
+ --wzl-track-border: var(--wzl-border);
150
+ --wzl-thumb-fill: var(--wzl-fg-muted);
151
+ --wzl-thumb-border: var(--wzl-border-strong);
152
+ --wzl-thumb-text: var(--wzl-gray-900);
153
+ --wzl-button-fill: var(--wzl-surface-raised);
154
+ --wzl-button-fill-hover: color-mix(in srgb, var(--wzl-fg) 10%, transparent);
155
+ --wzl-button-fill-pressed: color-mix(in srgb, var(--wzl-fg) 18%, transparent);
156
+ --wzl-button-text: var(--wzl-fg);
157
+ }
158
+
159
+ /* Default the document's UI font to the token. Apps that want a
160
+ * different face override at their own scope. */
161
+ :root {
162
+ font-family: var(--wzl-font-ui);
163
+ font-weight: var(--wzl-font-weight-normal);
164
+ }
165
+
166
+ /* Explicit dark-mode rules so descendants with `data-theme="dark"` reassert
167
+ * the dark palette even when the document root is in light mode. Mirrors the
168
+ * dark values in `:root` for every semantic token that has a light override. */
169
+ [data-theme='dark'] {
170
+ color-scheme: dark;
171
+ --wzl-surface: var(--wzl-gray-800);
172
+ --wzl-surface-raised: var(--wzl-gray-700);
173
+ --wzl-surface-sunken: var(--wzl-gray-900);
174
+
175
+ --wzl-fg: var(--wzl-gray-100);
176
+ --wzl-fg-muted: var(--wzl-gray-300);
177
+ --wzl-fg-subtle: var(--wzl-gray-400);
178
+
179
+ --wzl-border: var(--wzl-gray-700);
180
+ --wzl-border-strong: var(--wzl-gray-600);
181
+
182
+ --wzl-accent-fg: var(--wzl-accent-strong);
183
+
184
+ --wzl-thumb-text: var(--wzl-gray-900);
185
+ }
186
+
187
+ /* Light-mode overrides. Only the semantic surface/text/border tokens flip;
188
+ * the primitive scale and accent ramp stay constant. Toggle by setting
189
+ * `data-theme="light"` on `<html>` (or any ancestor — these cascade). */
190
+ [data-theme='light'] {
191
+ color-scheme: light;
192
+ --wzl-surface: var(--wzl-gray-50);
193
+ --wzl-surface-raised: var(--wzl-gray-100);
194
+ --wzl-surface-sunken: var(--wzl-gray-200);
195
+
196
+ --wzl-fg: var(--wzl-gray-900);
197
+ --wzl-fg-muted: var(--wzl-gray-600);
198
+ --wzl-fg-subtle: var(--wzl-gray-500);
199
+
200
+ --wzl-border: var(--wzl-gray-200);
201
+ --wzl-border-strong: var(--wzl-gray-300);
202
+
203
+ --wzl-accent-fg: var(--wzl-accent-base);
204
+
205
+ --wzl-thumb-text: var(--wzl-gray-50);
206
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@weasel-js/theme",
3
+ "version": "0.5.0",
4
+ "description": "Design tokens shared by weasel-ui and weasel-hud — CSS variables + a parallel TS export.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": [
8
+ "*.css"
9
+ ],
10
+ "main": "./dist/index.js",
11
+ "module": "./dist/index.js",
12
+ "types": "./dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "import": "./dist/index.js",
16
+ "types": "./dist/index.d.ts"
17
+ },
18
+ "./tokens.css": "./dist/tokens.css",
19
+ "./package.json": "./package.json"
20
+ },
21
+ "author": "orochi235",
22
+ "homepage": "https://orochi235.github.io/weasel/",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/orochi235/weasel.git",
26
+ "directory": "packages/theme"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/orochi235/weasel/issues"
30
+ },
31
+ "engines": {
32
+ "node": ">=20"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "README.md",
37
+ "LICENSE"
38
+ ],
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "scripts": {
43
+ "build": "tsup && cp src/tokens.css dist/tokens.css"
44
+ }
45
+ }