@daydreamui/tokens 0.0.0-stage → 0.4.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/README.md +181 -2
- package/dist/bridge.js +973 -0
- package/dist/index.js +1658 -0
- package/icon.svg +5 -0
- package/manifest.json +27 -0
- package/package.json +15 -4
package/README.md
CHANGED
|
@@ -1,3 +1,182 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Tokens
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A local Daydream plugin for exploring, extracting, and applying a visual theme.
|
|
4
|
+
Enable **Tokens** in Daydream's Plugins page (⌥⌘P). No account or external service is used.
|
|
5
|
+
|
|
6
|
+
From this repository, install the plugin with:
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
pnpm install
|
|
10
|
+
pnpm ship plugins/daydream.tokens --enable
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The build produces `plugins/daydream.tokens/dist/index.js`. The install command
|
|
14
|
+
copies the plugin into the user’s Daydream plugins folder and records its trust.
|
|
15
|
+
|
|
16
|
+
1. Choose one of ten brand-inspired presets. The carousel shows three at a time.
|
|
17
|
+
Or select viewports and choose **Extract from selection**; selecting an element
|
|
18
|
+
extracts its containing page. Or select a frame in Figma desktop and choose
|
|
19
|
+
**From Figma**, shown while Figma's Dev Mode MCP server answers.
|
|
20
|
+
2. Use **Refine tokens** to edit values. **Reset edits** restores the starting point.
|
|
21
|
+
Both operations affect only the preview.
|
|
22
|
+
3. **Apply to selected viewports** writes the theme and adopts existing styles on
|
|
23
|
+
all selected pages. One Undo restores the entire action. Repeated viewports and
|
|
24
|
+
shared stylesheets are written once.
|
|
25
|
+
4. **Create specimen page** creates a responsive HTML page for exploring the theme.
|
|
26
|
+
|
|
27
|
+
The preview is a temporary working draft, retained while the panel is minimized
|
|
28
|
+
and reset on reload or project change. The applied theme is ordinary CSS in the
|
|
29
|
+
project's files. Undo changes the pages; it does not replace the working draft.
|
|
30
|
+
|
|
31
|
+
## Applying a theme
|
|
32
|
+
|
|
33
|
+
Apply first reads each selected page's rendered styles and plans its source edits,
|
|
34
|
+
then writes through the public plugin API in one transaction. A refused write
|
|
35
|
+
cancels the transaction. It maps matching global color variables to semantic roles and converts supported
|
|
36
|
+
literal declarations to references to the new theme. Generated variables use a
|
|
37
|
+
`--tokens-` prefix, keeping the project’s existing token names and formats intact.
|
|
38
|
+
Component and conditional variable definitions remain authored. Inline styles are
|
|
39
|
+
edited through the same API.
|
|
40
|
+
|
|
41
|
+
Mapped styles include page, surface, action, text and border colors, font families,
|
|
42
|
+
heading weight/tracking (including the weight in a heading’s `font` shorthand),
|
|
43
|
+
corner radii, padding and gaps. Font conversion follows
|
|
44
|
+
the observed body and heading families, preserving other families such as code and
|
|
45
|
+
icon fonts. Spacing and radius values
|
|
46
|
+
in px/rem retain their proportions to the observed base value; zero values stay
|
|
47
|
+
zero. CSSOM parses individual values and supported shorthands. The plugin retains
|
|
48
|
+
selectors, media queries, `!important`, comments, content and layout dimensions.
|
|
49
|
+
|
|
50
|
+
A dedicated `:root:where(html)` rule holds the theme. Definitions are written into
|
|
51
|
+
every stylesheet whose declarations adopt references, so unselected consumers of
|
|
52
|
+
shared CSS receive the definitions too. Low-specificity heading, action and input
|
|
53
|
+
rules cover otherwise unstyled elements in an unconditional editable stylesheet.
|
|
54
|
+
Pages with authored cascade layers receive token values and source conversions,
|
|
55
|
+
but no generic element defaults: an unlayered fallback would override those
|
|
56
|
+
layers. Reapplying clears earlier generated defaults on these pages. Shared sheets
|
|
57
|
+
also omit defaults when another page on the canvas uses layers. This conservative
|
|
58
|
+
behavior stays within the existing plugin API; a page’s unstyled elements keep
|
|
59
|
+
their browser defaults when layers are present.
|
|
60
|
+
A page with only media-restricted sheets refuses Apply before any writes and asks
|
|
61
|
+
for an unconditional stylesheet. Applying again updates these rules; a sparse
|
|
62
|
+
extracted theme preserves omitted tokens and defaults still used by earlier edits. A page with no stylesheet gains its normal Daydream stylesheet/link;
|
|
63
|
+
Undo removes that creation. Shared stylesheets affect every page that links them,
|
|
64
|
+
including unselected pages.
|
|
65
|
+
|
|
66
|
+
Role inference is heuristic. Unmatched colors, gradients, background images,
|
|
67
|
+
shadows, SVG paints, complex calculations and unsupported units stay as authored.
|
|
68
|
+
Existing variable usages stay intact; editable definitions may be updated or mapped.
|
|
69
|
+
Interleaved comments inside a value are preserved by leaving that value unchanged.
|
|
70
|
+
A necessary edit to a read-only or unsupported rule refuses the action before any
|
|
71
|
+
writes. Conflicting mappings of a shared rule cancel the whole transaction. Adoption is
|
|
72
|
+
bounded to 2,000 elements per page and operates on page viewports, including independent variants.
|
|
73
|
+
|
|
74
|
+
## Extracting a theme
|
|
75
|
+
|
|
76
|
+
Extraction uses computed styles from mounted pages. It proposes colors, typography,
|
|
77
|
+
borders, radii, padding/gaps and shadows. Hidden subtrees are excluded. Duplicate
|
|
78
|
+
viewports do not inflate observations; responsive differences remain alternatives.
|
|
79
|
+
Results are bounded to 2,000 elements per viewport and five values per category.
|
|
80
|
+
|
|
81
|
+
Values include browser defaults and are resolved at the selected widths. Extraction
|
|
82
|
+
does not recover aliases, original units, hover states, pseudo-elements, iframe
|
|
83
|
+
content or fonts/assets, and does not write to the project. Missing preview roles
|
|
84
|
+
use specimen fallbacks.
|
|
85
|
+
|
|
86
|
+
## From Figma
|
|
87
|
+
|
|
88
|
+
**From Figma** reads the variables of what is selected in Figma desktop and loads
|
|
89
|
+
them into the preview, named after the selected frame as Figma's listing of the
|
|
90
|
+
selection names it (else "From Figma"). With several frames selected — up to 12;
|
|
91
|
+
past that the error line names the cap — the variables of each are read by id,
|
|
92
|
+
all at once under one bound of 40 s, and merged by name — the first frame's
|
|
93
|
+
value of a name wins — under the origin "3 frames from Figma"; a frame Figma
|
|
94
|
+
refuses, or that has not answered by the bound, is left out and counted among
|
|
95
|
+
the tokens left out, and only every one left out is an error. A layer inside a
|
|
96
|
+
component instance, which Figma lists with an id of its own shape and refuses
|
|
97
|
+
to read by it, is left out before anything is asked and counted too; with
|
|
98
|
+
nothing else selected the error line says to select its frame. Nothing
|
|
99
|
+
selected, Figma not there, and Figma too slow to answer are each one sentence.
|
|
100
|
+
It needs Figma desktop open with the Dev Mode MCP server enabled in its
|
|
101
|
+
preferences (the server runs on this machine at `http://127.0.0.1:3845`), and a
|
|
102
|
+
selected frame. The button is
|
|
103
|
+
there only while that server answers: the panel asks when it opens, when a
|
|
104
|
+
project opens and when this window gets focus back, so switching to Figma to
|
|
105
|
+
select and returning is enough. Nothing is sent anywhere, and nothing is written
|
|
106
|
+
to the project until Apply. The plugin's host part holds the connection
|
|
107
|
+
(`bridge.ts`, through `@daydream/figma-devmode`); without a Daydream host, or
|
|
108
|
+
with the host part off, the button is simply absent.
|
|
109
|
+
|
|
110
|
+
A variable's path becomes one custom property: lowercase, every run of
|
|
111
|
+
characters outside `a-z0-9` one dash (`color/brand/500` → `--color-brand-500`,
|
|
112
|
+
`Spacing/MD` → `--spacing-md`), a collision numbered `-2`, `-3`. Colors and
|
|
113
|
+
values with a unit stay as written. A bare number becomes `px`, unless the name
|
|
114
|
+
says it is unitless (`opacity`, `weight`, `line-height`, `ratio`, `z`); with
|
|
115
|
+
its `px` it is a length, so a weight never takes it. A family name or a stack
|
|
116
|
+
under a font-like name (`font`, `family`, `type`) is kept as written (`Arial`,
|
|
117
|
+
`Inter, sans-serif`); any other string is quoted. A value written as a reference
|
|
118
|
+
to another variable (`{color/brand/500}`; a `$` is a literal) becomes
|
|
119
|
+
`var(--color-brand-500)` when that variable is in the set — Figma's own server
|
|
120
|
+
answers an alias resolved to its value, so this serves a pasted or hand-written
|
|
121
|
+
text; a live import holds values alone, and a string whose text happens to be
|
|
122
|
+
another variable's name is that text, quoted. Booleans, nested objects,
|
|
123
|
+
references to variables outside the set, references that loop (two variables
|
|
124
|
+
aliasing each other, one aliasing itself) and values the browser cannot parse
|
|
125
|
+
are left out and counted in the status line.
|
|
126
|
+
|
|
127
|
+
The shared roles are suggested from the end of each path, each role once, as a
|
|
128
|
+
reference to the raw token (`--primary: var(--color-brand-500)`), so Apply
|
|
129
|
+
writes `--tokens-primary: var(--tokens-color-brand-500)`: `background` from
|
|
130
|
+
names ending in `background`, `bg`, `canvas`, `page` or `surface-0`; `foreground`
|
|
131
|
+
from `foreground`, `fg`, `text`, `text-primary`, `text-default`, `on-background`
|
|
132
|
+
or `ink`; `card` from `card`, `surface`, `elevated` or `panel`; `muted` from
|
|
133
|
+
`muted`, `subtle` or `secondary-surface`; `muted-foreground` from
|
|
134
|
+
`muted-foreground`, `text-secondary`, `secondary`, `hint` or `placeholder`;
|
|
135
|
+
`primary` from `primary`, `brand`, `accent`, `action` or `cta`;
|
|
136
|
+
`primary-foreground` from `primary-foreground`, `on-primary`, `on-brand` or
|
|
137
|
+
`on-accent`; `border` from `border`, `stroke`, `outline` or `divider`; `radius`
|
|
138
|
+
from `radius`, `corner` or `rounded`; `spacing` from `spacing`, `space`, `gap` or
|
|
139
|
+
`unit`; `font-sans` from `font-sans`, `font-family`, `sans`, `body-font` or
|
|
140
|
+
`font-body`; `font-heading` from `font-heading`, `heading-font` or `display`;
|
|
141
|
+
`heading-weight` from `heading-weight` or `weight-bold`; `heading-tracking` from
|
|
142
|
+
`heading-tracking`, `tracking` or `letter-spacing`. A trailing scale step
|
|
143
|
+
(`500`, `md`, `default`) is set aside, and `500`, `default`, `base`, `main` or
|
|
144
|
+
`md` is preferred when a scale has several steps; a variable named exactly as a
|
|
145
|
+
role is that role when its value is of the role's kind, and is renamed with a
|
|
146
|
+
number (`--primary-2`) when it is not, so a length never stands as a colour.
|
|
147
|
+
A role no name answers is left out, as a sparse extraction is. The role tokens come first in Refine, then the raw tokens they reference,
|
|
148
|
+
then the rest in Figma's order, up to the 100 tokens a theme may hold. An alias
|
|
149
|
+
is kept with what it points at, link by link, or left out whole, so nothing a
|
|
150
|
+
theme holds points at nothing; what the cap leaves out is counted too.
|
|
151
|
+
|
|
152
|
+
## Presets
|
|
153
|
+
|
|
154
|
+
Presets are original interpretations, not official brand themes or extracted design
|
|
155
|
+
systems. They use system fonts and contain no brand assets. Their references are
|
|
156
|
+
[Apple](https://www.apple.com/), [BMW](https://www.bmw.com/),
|
|
157
|
+
[Spotify](https://open.spotify.com/), [Airbnb](https://www.airbnb.com/),
|
|
158
|
+
[Nike](https://www.nike.com/), [Stripe](https://stripe.com/),
|
|
159
|
+
[Linear](https://linear.app/), [Notion](https://www.notion.com/),
|
|
160
|
+
[IKEA](https://www.ikea.com/), and [Ferrari](https://www.ferrari.com/).
|
|
161
|
+
This is an independent implementation with no Graphical API or archive integration.
|
|
162
|
+
|
|
163
|
+
The shared vocabulary is `--background`, `--foreground`, `--card`, `--muted`,
|
|
164
|
+
`--muted-foreground`, `--primary`, `--primary-foreground`, `--border`, `--radius`,
|
|
165
|
+
`--font-sans`, `--spacing`, `--font-heading`, `--heading-weight`, and
|
|
166
|
+
`--heading-tracking`. These are preview names; Apply writes `--tokens-background`,
|
|
167
|
+
`--tokens-primary`, etc. References between supplied tokens follow those names.
|
|
168
|
+
Extracted alternatives are retained as additional tokens.
|
|
169
|
+
|
|
170
|
+
## Validation
|
|
171
|
+
|
|
172
|
+
`pnpm test:kernel <daydream-checkout> plugins/daydream.tokens` covers real canvas
|
|
173
|
+
rendering, extraction, carousel navigation, source adoption, shared files, inline
|
|
174
|
+
styles, responsive rules, repeated application, refusal rollback, undo and specimen
|
|
175
|
+
creation, and the From Figma gesture with the host part's answers supplied in
|
|
176
|
+
memory. The conversion and the host part are unit tests over hand-written
|
|
177
|
+
variables and an injected client: no test contacts Figma. The plugin requires a
|
|
178
|
+
Daydream build reporting API 3.0; see the repository’s kernel pin and release gate
|
|
179
|
+
before shipping. Its runtime dependency is the workspace package
|
|
180
|
+
`@daydream/figma-devmode`: its host entry is what the host part loads, and its
|
|
181
|
+
browser entry (`@daydream/figma-devmode/browser`, the reachability probe) is
|
|
182
|
+
what the panel bundles.
|