v0.16.3: native DSSL spec, and the seven bugs writing it found
Browse filesnative/ holds a written specification of DSSL (12 chapters, two generated appendices), the shared
vocabulary data, and a Rust crate stub. No browser implements DSSL natively; this is the spec a
browser team would implement from, checked against the engine by scripts/test-native-spec.mjs.
Writing it showed where the engine and the language disagreed. Fixed:
- an unquoted url(http://...) lost the rest of the line to the comment stripper
- a typo at the end of a token path silently resolved to its parent token
- nesting under a selector list joined the wrong way (.a, .b { .c {} } and hover {})
- a backslash did not escape a quote in a value
- a nested li (or any HTML element name) got a "did you mean link" warning
New warnings, both compile fine: an unknown @layer name, and radius: xl with no token.
Every .dssl file in the repo and every doc example resolve to identical output before and after.
Open: D-6 (registry rule across files) needs a browser test. Binaries follow in a separate commit.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- GUIDE.md +2 -2
- PARITY.md +4 -0
- README.md +4 -4
- dssl-vscode/CHANGELOG.md +4 -0
- dssl-vscode/lib/engine/parser.js +11 -0
- dssl-vscode/lib/engine/resolver.js +54 -20
- dssl-vscode/package.json +1 -1
- llms.txt +6 -2
- native/.gitignore +1 -0
- native/Cargo.lock +158 -0
- native/Cargo.toml +18 -0
- native/README.md +42 -0
- native/data/vocabulary.json +4567 -0
- native/spec/01-overview.md +136 -0
- native/spec/02-syntax.md +212 -0
- native/spec/03-values.md +199 -0
- native/spec/04-tokens.md +133 -0
- native/spec/05-cascade.md +291 -0
- native/spec/06-properties.md +261 -0
- native/spec/07-motion.md +104 -0
- native/spec/08-effects.md +279 -0
- native/spec/09-diagnostics.md +81 -0
- native/spec/10-resolved-document.md +86 -0
- native/spec/11-browser-integration.md +155 -0
- native/spec/12-known-divergences.md +93 -0
- native/spec/README.md +54 -0
- native/spec/appendix-a-vocabulary.md +265 -0
- native/spec/appendix-b-messages.md +171 -0
- native/src/lib.rs +1 -0
- native/src/main.rs +1 -0
- package.json +1 -1
- public/dssl/index.js +1 -1
- public/dssl/parser.js +11 -0
- public/dssl/resolver.js +54 -20
- public/llms.txt +6 -2
- public/showcase/wood/wood.css +1 -1
- scripts/gen-native-vocab.mjs +178 -0
- scripts/test-all.mjs +1 -1
- scripts/test-native-spec.mjs +153 -0
- scripts/test-v0163.mjs +121 -0
- src/components/dssl/views/ChangelogView.tsx +8 -0
|
@@ -950,7 +950,7 @@ and listed, so the file you get always compiles.
|
|
| 950 |
```js
|
| 951 |
import { DSSL } from '/dssl/index.js' // or just use window.DSSL after boot
|
| 952 |
|
| 953 |
-
DSSL.version // "0.16.
|
| 954 |
DSSL.compile(source) // { ok, errors, warnings, stats, doc }: parse and resolve, no DOM
|
| 955 |
DSSL.apply(source, { name, scope, replace })
|
| 956 |
await DSSL.load(['a.dssl', 'b.dssl'])
|
|
@@ -985,7 +985,7 @@ Three ways to get it:
|
|
| 985 |
|
| 986 |
1. VSCodium: open the Extensions tab, search "DSSL" and install. It is on Open VSX:
|
| 987 |
https://open-vsx.org/extension/ehs-studio/dssl-vscode
|
| 988 |
-
2. VS Code: download `dssl-vscode/dssl-vscode-0.16.
|
| 989 |
Extensions panel, `...`, Install from VSIX. (The Microsoft Marketplace listing is not published yet.)
|
| 990 |
3. Build it yourself: `cd dssl-vscode && npx @vscode/vsce package --no-dependencies`.
|
| 991 |
|
|
|
|
| 950 |
```js
|
| 951 |
import { DSSL } from '/dssl/index.js' // or just use window.DSSL after boot
|
| 952 |
|
| 953 |
+
DSSL.version // "0.16.3": a string, not a function
|
| 954 |
DSSL.compile(source) // { ok, errors, warnings, stats, doc }: parse and resolve, no DOM
|
| 955 |
DSSL.apply(source, { name, scope, replace })
|
| 956 |
await DSSL.load(['a.dssl', 'b.dssl'])
|
|
|
|
| 985 |
|
| 986 |
1. VSCodium: open the Extensions tab, search "DSSL" and install. It is on Open VSX:
|
| 987 |
https://open-vsx.org/extension/ehs-studio/dssl-vscode
|
| 988 |
+
2. VS Code: download `dssl-vscode/dssl-vscode-0.16.3.vsix` from the repo files, then
|
| 989 |
Extensions panel, `...`, Install from VSIX. (The Microsoft Marketplace listing is not published yet.)
|
| 990 |
3. Build it yourself: `cd dssl-vscode && npx @vscode/vsce package --no-dependencies`.
|
| 991 |
|
|
@@ -62,6 +62,10 @@ so the boundary is explicit, not folklore.
|
|
| 62 |
- loud errors with did-you-mean, and a warnings channel for cascade-order footguns
|
| 63 |
- `freeze()` / `unfreeze()`: a live engine that can be parked at zero cost
|
| 64 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
## v0.16.2
|
| 66 |
|
| 67 |
`DSSL.lint`'s `css-loses` skips the output of `dssl build` (recognised by its `@layer tokens, base, components, utilities, pin` statement), because its reset is built to sit under the engine. The docs page of this site went from 4,314 false findings (0.16.0), to 111 (0.16.1), to none from its own CSS.
|
|
|
|
| 62 |
- loud errors with did-you-mean, and a warnings channel for cascade-order footguns
|
| 63 |
- `freeze()` / `unfreeze()`: a live engine that can be parked at zero cost
|
| 64 |
|
| 65 |
+
## v0.16.3
|
| 66 |
+
|
| 67 |
+
Seven places where the engine disagreed with the language are fixed: unquoted `url(http://...)`, token paths with a typo at the end, nesting under a selector list, an escaped quote in a value, and the false "did you mean link" warning on `li`. An unknown `@layer` name and `radius: xl` with no token now warn. All of them were found by writing a specification for native, JavaScript-free DSSL (`native/spec/`). A browser that implements DSSL natively does not exist yet: this is a written spec and checks, not a browser feature.
|
| 68 |
+
|
| 69 |
## v0.16.2
|
| 70 |
|
| 71 |
`DSSL.lint`'s `css-loses` skips the output of `dssl build` (recognised by its `@layer tokens, base, components, utilities, pin` statement), because its reset is built to sit under the engine. The docs page of this site went from 4,314 false findings (0.16.0), to 111 (0.16.1), to none from its own CSS.
|
|
@@ -68,7 +68,7 @@ Both drop a `dssl-engine/` folder next to you: the engine, a starter token set,
|
|
| 68 |
|
| 69 |
Prefer to click: [dssl-engine.zip](https://dssl-sable.vercel.app/dssl-engine.zip) or [dssl-engine.tar.gz](https://dssl-sable.vercel.app/dssl-engine.tar.gz). Same package, straight from the browser.
|
| 70 |
|
| 71 |
-
Writing your own .dssl? The official editor extension (`ehs-studio.dssl-vscode`) puts the real compiler in your editor: the squiggles are the same errors the browser console prints, completions come from your own token registry, and hovers explain the semantic vocabulary. One package for VS Code and VSCodium (same extension API). In VSCodium, search "DSSL" in the Extensions tab (it is on Open VSX: https://open-vsx.org/extension/ehs-studio/dssl-vscode). In VS Code, download `dssl-vscode/dssl-vscode-0.16.
|
| 72 |
|
| 73 |
AI agents and machine reviewers: this repo ships `llms.txt` (dense, structured facts), `AGENTS.md` (how to work on the codebase) and `PARITY.md` (the honest feature matrix against CSS). The site serves the same `llms.txt` at https://dssl-sable.vercel.app/llms.txt
|
| 74 |
|
|
@@ -470,7 +470,7 @@ await DSSL.lint(root) // contrast against the real background,
|
|
| 470 |
DSSL.play(el, 'boing', opts) // a one-shot motion from JS, as a promise
|
| 471 |
DSSL.motion('full') // run every motion whatever the system asks for
|
| 472 |
DSSL.auraZ(20) // where the aura canvas sits in the stack
|
| 473 |
-
DSSL.version // "0.16.
|
| 474 |
```
|
| 475 |
|
| 476 |
Auto-boot picks up every `link[rel="stylesheet/dssl"]` and `style[type="text/dssl"]`, applies them, and fires `dssl-ready` on `window`. `<html data-dssl-reset>` enables the small built-in reset.
|
|
@@ -546,7 +546,7 @@ const rep = DSSL.explain(document.querySelector('.doc-card'))
|
|
| 546 |
|
| 547 |
The matcher also pre-filters every rule through a cheap class/tag/id gate extracted from the selector's rightmost compound, so a recompute skips obvious non-matches instead of asking the browser rule by rule. The gate only ever says no; anything it does not fully understand falls back to native matching.
|
| 548 |
|
| 549 |
-
## What works today (v0.16.
|
| 550 |
|
| 551 |
- the full selector surface, including `:nth-child`, `:not`, `:is`, `:where`, `:has`
|
| 552 |
- flexbox and grid with `row:` / `column:` / `grid:` / `stack:` / `center:` sugar, place words now own an axis (`between` is main-axis, `stretch` is cross-axis) and conflicts warn instead of silently overwriting
|
|
@@ -586,7 +586,7 @@ The matcher also pre-filters every rule through a cheap class/tag/id gate extrac
|
|
| 586 |
|
| 587 |
## Status
|
| 588 |
|
| 589 |
-
v0.16.
|
| 590 |
|
| 591 |
## License
|
| 592 |
|
|
|
|
| 68 |
|
| 69 |
Prefer to click: [dssl-engine.zip](https://dssl-sable.vercel.app/dssl-engine.zip) or [dssl-engine.tar.gz](https://dssl-sable.vercel.app/dssl-engine.tar.gz). Same package, straight from the browser.
|
| 70 |
|
| 71 |
+
Writing your own .dssl? The official editor extension (`ehs-studio.dssl-vscode`) puts the real compiler in your editor: the squiggles are the same errors the browser console prints, completions come from your own token registry, and hovers explain the semantic vocabulary. One package for VS Code and VSCodium (same extension API). In VSCodium, search "DSSL" in the Extensions tab (it is on Open VSX: https://open-vsx.org/extension/ehs-studio/dssl-vscode). In VS Code, download `dssl-vscode/dssl-vscode-0.16.3.vsix` from the repo files, then Extensions panel -> ... -> Install from VSIX. See `dssl-vscode/PUBLISHING.md` for publishing.
|
| 72 |
|
| 73 |
AI agents and machine reviewers: this repo ships `llms.txt` (dense, structured facts), `AGENTS.md` (how to work on the codebase) and `PARITY.md` (the honest feature matrix against CSS). The site serves the same `llms.txt` at https://dssl-sable.vercel.app/llms.txt
|
| 74 |
|
|
|
|
| 470 |
DSSL.play(el, 'boing', opts) // a one-shot motion from JS, as a promise
|
| 471 |
DSSL.motion('full') // run every motion whatever the system asks for
|
| 472 |
DSSL.auraZ(20) // where the aura canvas sits in the stack
|
| 473 |
+
DSSL.version // "0.16.3", a string
|
| 474 |
```
|
| 475 |
|
| 476 |
Auto-boot picks up every `link[rel="stylesheet/dssl"]` and `style[type="text/dssl"]`, applies them, and fires `dssl-ready` on `window`. `<html data-dssl-reset>` enables the small built-in reset.
|
|
|
|
| 546 |
|
| 547 |
The matcher also pre-filters every rule through a cheap class/tag/id gate extracted from the selector's rightmost compound, so a recompute skips obvious non-matches instead of asking the browser rule by rule. The gate only ever says no; anything it does not fully understand falls back to native matching.
|
| 548 |
|
| 549 |
+
## What works today (v0.16.3)
|
| 550 |
|
| 551 |
- the full selector surface, including `:nth-child`, `:not`, `:is`, `:where`, `:has`
|
| 552 |
- flexbox and grid with `row:` / `column:` / `grid:` / `stack:` / `center:` sugar, place words now own an axis (`between` is main-axis, `stretch` is cross-axis) and conflicts warn instead of silently overwriting
|
|
|
|
| 586 |
|
| 587 |
## Status
|
| 588 |
|
| 589 |
+
v0.16.3, experimental, moving fast. The language grows whenever the site needs something it cannot express yet, so the site doubles as the test suite, and the docs examples are rendered and asserted in a real browser, so the guide cannot lie. Honest ledger: great for creative sites, prototypes, docs, playgrounds and internal tools; when a page must work without JavaScript, build the static subset with `dssl build` or pick another tool for that page. Freeze makes big static pages viable; live interaction is what the engine is for.
|
| 590 |
|
| 591 |
## License
|
| 592 |
|
|
@@ -1,5 +1,9 @@
|
|
| 1 |
# Changelog
|
| 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
## 0.16.2
|
| 4 |
|
| 5 |
- Bundled engine 0.16.2: `DSSL.lint` also skips the output of `dssl build` (its reset sits under the engine on purpose).
|
|
|
|
| 1 |
# Changelog
|
| 2 |
|
| 3 |
+
## 0.16.3
|
| 4 |
+
|
| 5 |
+
- Bundled engine 0.16.3: seven bug fixes found while writing the native spec (unquoted `url(http://...)`, nesting under selector lists, token path typos, escaped quotes, a false `li` warning) and two new warnings (unknown `@layer` name, `radius: xl` without a token).
|
| 6 |
+
|
| 7 |
## 0.16.2
|
| 8 |
|
| 9 |
- Bundled engine 0.16.2: `DSSL.lint` also skips the output of `dssl build` (its reset sits under the engine on purpose).
|
|
@@ -111,6 +111,17 @@ function stripComments(src) {
|
|
| 111 |
continue;
|
| 112 |
}
|
| 113 |
if (c === '"' || c === "'") { q = c; out += c; continue; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
if (c === '/' && n === '/') {
|
| 115 |
// v0.7.1 bugfix: this handler used to emit its own '\n' AND rewind so
|
| 116 |
// the main loop emitted the same newline again - every // comment
|
|
|
|
| 111 |
continue;
|
| 112 |
}
|
| 113 |
if (c === '"' || c === "'") { q = c; out += c; continue; }
|
| 114 |
+
// An unquoted url(...) is one token: the // in http://x.com/a.png is not a comment. Copy it through the
|
| 115 |
+
// closing paren untouched (newlines included, so line numbers hold). A quoted url is handled by the string rule above.
|
| 116 |
+
if ((c === 'u' || c === 'U') && /^url\(/i.test(src.slice(i, i + 4)) && !/[\w-]/.test(src[i - 1] || '')) {
|
| 117 |
+
let k = i + 4;
|
| 118 |
+
while (k < src.length && /\s/.test(src[k])) k++;
|
| 119 |
+
if (src[k] !== '"' && src[k] !== "'") {
|
| 120 |
+
let e = k;
|
| 121 |
+
while (e < src.length && src[e] !== ')') e += src[e] === '\\' ? 2 : 1;
|
| 122 |
+
if (e < src.length) { out += src.slice(i, e + 1); i = e; continue; }
|
| 123 |
+
}
|
| 124 |
+
}
|
| 125 |
if (c === '/' && n === '/') {
|
| 126 |
// v0.7.1 bugfix: this handler used to emit its own '\n' AND rewind so
|
| 127 |
// the main loop emitted the same newline again - every // comment
|
|
@@ -182,6 +182,13 @@ const LENGTH_FN = new Set('calc,min,max,clamp,round,mod,rem,abs,sign,hypot,pow,s
|
|
| 182 |
* - token references become var(--dssl-…), `token/NN` becomes color-mix
|
| 183 |
* - unknown identifiers are errors (with did-you-mean)
|
| 184 |
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 185 |
/** split a selector list at top-level commas (not inside :is(...) and friends) */
|
| 186 |
function splitTopLevel(sel) {
|
| 187 |
const out = []; let depth = 0, cur = '';
|
|
@@ -209,7 +216,7 @@ function resolveValue(raw, ctx) {
|
|
| 209 |
|
| 210 |
if (c === '"' || c === "'") {
|
| 211 |
let j = i + 1;
|
| 212 |
-
while (j < n && raw[j] !== c) j+
|
| 213 |
out += raw.slice(i, j + 1);
|
| 214 |
i = j + 1;
|
| 215 |
continue;
|
|
@@ -247,7 +254,7 @@ function resolveValue(raw, ctx) {
|
|
| 247 |
if (raw[j] === ')') depth--;
|
| 248 |
if (depth > 0 && (raw[j] === '"' || raw[j] === "'")) {
|
| 249 |
const q = raw[j]; j++;
|
| 250 |
-
while (j < n && raw[j] !== q) j+
|
| 251 |
}
|
| 252 |
j++;
|
| 253 |
}
|
|
@@ -386,16 +393,8 @@ function topSplit(str, sep) {
|
|
| 386 |
}
|
| 387 |
|
| 388 |
function findToken(tokens, ident) {
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
if (ident.includes('.')) {
|
| 392 |
-
const parts = ident.split('.');
|
| 393 |
-
for (let k = parts.length - 1; k > 0; k--) {
|
| 394 |
-
const key = parts.slice(0, k).join('.');
|
| 395 |
-
if (tokens.has(key)) return key; // hmm - partial match would change meaning; require exact
|
| 396 |
-
}
|
| 397 |
-
}
|
| 398 |
-
return null;
|
| 399 |
}
|
| 400 |
|
| 401 |
/* ------------------------------------------------------------------ *
|
|
@@ -438,7 +437,7 @@ function splitLayers(s) {
|
|
| 438 |
const out = []; let depth = 0, q = null, cur = '';
|
| 439 |
for (let i = 0; i < s.length; i++) {
|
| 440 |
const c = s[i];
|
| 441 |
-
if (q) { cur += c; if (c === q) q = null; continue; }
|
| 442 |
if (c === '"' || c === "'") { q = c; cur += c; continue; }
|
| 443 |
if (c === '(' || c === '[') depth++;
|
| 444 |
else if (c === ')' || c === ']') depth = Math.max(0, depth - 1);
|
|
@@ -866,7 +865,12 @@ const SEMANTIC = {
|
|
| 866 |
radius(v, ctx) {
|
| 867 |
const atoms = v.trim().split(/\s+/).filter(Boolean);
|
| 868 |
const out = atoms.map(a => {
|
| 869 |
-
if (['sm', 'md', 'lg', 'full', 'xl'].includes(a))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 870 |
if (/^[A-Za-z][\w-]*$/.test(a) && ctx.tokens && ctx.tokens.has('radius.' + a)) return `var(--dssl-radius-${a})`; // 0.14.0: radius { pill: 99 } then radius: pill
|
| 871 |
return resolveValue(a, ctx);
|
| 872 |
});
|
|
@@ -1614,7 +1618,7 @@ export function resolve(ast, file = 'inline.dssl', baseTokens = null, baseMotion
|
|
| 1614 |
break;
|
| 1615 |
}
|
| 1616 |
case 'selector': {
|
| 1617 |
-
if (/^[a-zA-Z][a-zA-Z0-9-]*$/.test(node.sel) && ctx.sel) {
|
| 1618 |
const near = didYouMean(node.sel.toLowerCase(), [...STATE_WORDS]);
|
| 1619 |
if (near) warnings.push({ file, line: node.line, message: `"${node.sel}" compiled as a descendant selector ("${combine(ctx.sel, node.sel)}")`, hint: `if you meant the state, it is spelled "${near}" - this block currently styles descendants called <${node.sel}>` });
|
| 1620 |
}
|
|
@@ -1632,7 +1636,7 @@ export function resolve(ast, file = 'inline.dssl', baseTokens = null, baseMotion
|
|
| 1632 |
break;
|
| 1633 |
}
|
| 1634 |
flushPending(node.line);
|
| 1635 |
-
const childCtx = { ...ctx, sel: ctx.sel
|
| 1636 |
// v0.7.2 - the arrow is motion/gradient-stop syntax; inside a seen
|
| 1637 |
// block it compiled into an inline style the browser rejects, so the
|
| 1638 |
// element just sat at its base style forever. Say so, loudly, and
|
|
@@ -1678,7 +1682,11 @@ export function resolve(ast, file = 'inline.dssl', baseTokens = null, baseMotion
|
|
| 1678 |
}
|
| 1679 |
case 'layer':
|
| 1680 |
case 'pin': {
|
| 1681 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1682 |
flushPending(node.line);
|
| 1683 |
const childCtx = { ...ctx, layer };
|
| 1684 |
const sub = { decls: [] };
|
|
@@ -1688,6 +1696,7 @@ export function resolve(ast, file = 'inline.dssl', baseTokens = null, baseMotion
|
|
| 1688 |
}
|
| 1689 |
case 'pseudo': {
|
| 1690 |
const base = ctx.sel || '*'; // top-level ::selection etc. means every element
|
|
|
|
| 1691 |
const srule = {
|
| 1692 |
id: ruleId++, sel: base, pseudo: node.name,
|
| 1693 |
media: ctx.media, signals: ctx.signals, containers: ctx.containers,
|
|
@@ -1724,6 +1733,17 @@ export function resolve(ast, file = 'inline.dssl', baseTokens = null, baseMotion
|
|
| 1724 |
fill(srule, node.children);
|
| 1725 |
if (srule.decls.length) shadowRules.push(srule);
|
| 1726 |
for (const st of stateRules) if (st.decls.length) shadowRules.push(st);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1727 |
break;
|
| 1728 |
}
|
| 1729 |
case 'tokens': {
|
|
@@ -1994,10 +2014,24 @@ export function resolve(ast, file = 'inline.dssl', baseTokens = null, baseMotion
|
|
| 1994 |
return { rules, shadowRules, raws, fontLinks, motions, motionFrames, errors, warnings, mediaQueries: [...mediaQueries], tokens: Object.fromEntries(tokenMap), registryRule };
|
| 1995 |
}
|
| 1996 |
|
| 1997 |
-
/**
|
|
|
|
| 1998 |
function combine(parent, child) {
|
| 1999 |
-
|
| 2000 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2001 |
}
|
| 2002 |
|
| 2003 |
/* v0.5.0 - where does a selector carry a pseudo-element?
|
|
|
|
| 182 |
* - token references become var(--dssl-…), `token/NN` becomes color-mix
|
| 183 |
* - unknown identifiers are errors (with did-you-mean)
|
| 184 |
*/
|
| 185 |
+
/** HTML element names: a bare one nested in a rule is a descendant selector on purpose, never a mistyped state word */
|
| 186 |
+
const HTML_ELEMENTS = new Set(('a,abbr,acronym,address,area,article,aside,audio,b,base,bdi,bdo,big,blockquote,body,br,button,canvas,caption,center,cite,code,col,colgroup,' +
|
| 187 |
+
'data,datalist,dd,del,details,dfn,dialog,dir,div,dl,dt,em,embed,fieldset,figcaption,figure,font,footer,form,frame,frameset,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,' +
|
| 188 |
+
'i,iframe,img,input,ins,kbd,label,legend,li,link,main,map,mark,marquee,menu,meta,meter,nav,nobr,noscript,object,ol,optgroup,option,output,p,param,picture,pre,progress,q,' +
|
| 189 |
+
'rp,rt,ruby,s,samp,script,search,section,select,slot,small,source,span,strike,strong,style,sub,summary,sup,table,tbody,td,template,textarea,tfoot,th,thead,time,title,tr,' +
|
| 190 |
+
'track,tt,u,ul,var,video,wbr,svg,math').split(','));
|
| 191 |
+
|
| 192 |
/** split a selector list at top-level commas (not inside :is(...) and friends) */
|
| 193 |
function splitTopLevel(sel) {
|
| 194 |
const out = []; let depth = 0, cur = '';
|
|
|
|
| 216 |
|
| 217 |
if (c === '"' || c === "'") {
|
| 218 |
let j = i + 1;
|
| 219 |
+
while (j < n && raw[j] !== c) j += raw[j] === '\\' ? 2 : 1; // a backslash escapes the next character
|
| 220 |
out += raw.slice(i, j + 1);
|
| 221 |
i = j + 1;
|
| 222 |
continue;
|
|
|
|
| 254 |
if (raw[j] === ')') depth--;
|
| 255 |
if (depth > 0 && (raw[j] === '"' || raw[j] === "'")) {
|
| 256 |
const q = raw[j]; j++;
|
| 257 |
+
while (j < n && raw[j] !== q) j += raw[j] === '\\' ? 2 : 1;
|
| 258 |
}
|
| 259 |
j++;
|
| 260 |
}
|
|
|
|
| 393 |
}
|
| 394 |
|
| 395 |
function findToken(tokens, ident) {
|
| 396 |
+
// exact key only: color.ink2.bogus must not quietly become color.ink2, it falls through to "unknown value"
|
| 397 |
+
return tokens.has(ident) ? ident : null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 398 |
}
|
| 399 |
|
| 400 |
/* ------------------------------------------------------------------ *
|
|
|
|
| 437 |
const out = []; let depth = 0, q = null, cur = '';
|
| 438 |
for (let i = 0; i < s.length; i++) {
|
| 439 |
const c = s[i];
|
| 440 |
+
if (q) { cur += c; if (c === q && s[i - 1] !== '\\') q = null; continue; }
|
| 441 |
if (c === '"' || c === "'") { q = c; cur += c; continue; }
|
| 442 |
if (c === '(' || c === '[') depth++;
|
| 443 |
else if (c === ')' || c === ']') depth = Math.max(0, depth - 1);
|
|
|
|
| 865 |
radius(v, ctx) {
|
| 866 |
const atoms = v.trim().split(/\s+/).filter(Boolean);
|
| 867 |
const out = atoms.map(a => {
|
| 868 |
+
if (['sm', 'md', 'lg', 'full', 'xl'].includes(a)) {
|
| 869 |
+
if (ctx.tokens && !ctx.tokens.has('radius.' + a) && ctx.warnings) {
|
| 870 |
+
ctx.warnings.push({ file: ctx.file, line: ctx.line, message: `radius "${a}" is not defined, so it will not apply`, hint: `add it with tokens { radius { ${a}: 32 } }` });
|
| 871 |
+
}
|
| 872 |
+
return `var(--dssl-radius-${a})`;
|
| 873 |
+
}
|
| 874 |
if (/^[A-Za-z][\w-]*$/.test(a) && ctx.tokens && ctx.tokens.has('radius.' + a)) return `var(--dssl-radius-${a})`; // 0.14.0: radius { pill: 99 } then radius: pill
|
| 875 |
return resolveValue(a, ctx);
|
| 876 |
});
|
|
|
|
| 1618 |
break;
|
| 1619 |
}
|
| 1620 |
case 'selector': {
|
| 1621 |
+
if (/^[a-zA-Z][a-zA-Z0-9-]*$/.test(node.sel) && ctx.sel && !HTML_ELEMENTS.has(node.sel.toLowerCase())) {
|
| 1622 |
const near = didYouMean(node.sel.toLowerCase(), [...STATE_WORDS]);
|
| 1623 |
if (near) warnings.push({ file, line: node.line, message: `"${node.sel}" compiled as a descendant selector ("${combine(ctx.sel, node.sel)}")`, hint: `if you meant the state, it is spelled "${near}" - this block currently styles descendants called <${node.sel}>` });
|
| 1624 |
}
|
|
|
|
| 1636 |
break;
|
| 1637 |
}
|
| 1638 |
flushPending(node.line);
|
| 1639 |
+
const childCtx = { ...ctx, sel: withState(ctx.sel, node.name) };
|
| 1640 |
// v0.7.2 - the arrow is motion/gradient-stop syntax; inside a seen
|
| 1641 |
// block it compiled into an inline style the browser rejects, so the
|
| 1642 |
// element just sat at its base style forever. Say so, loudly, and
|
|
|
|
| 1682 |
}
|
| 1683 |
case 'layer':
|
| 1684 |
case 'pin': {
|
| 1685 |
+
const LAYERS = ['tokens', 'base', 'components', 'utilities', 'pin'];
|
| 1686 |
+
const layer = node.kind === 'pin' ? 'pin' : (LAYERS.includes(node.name) ? node.name : 'components');
|
| 1687 |
+
if (node.kind === 'layer' && !LAYERS.includes(node.name)) {
|
| 1688 |
+
warnings.push({ file, line: node.line, message: `unknown layer "${node.name}", treated as "components"`, hint: didYouMean(node.name, LAYERS) || 'the layers are tokens, base, components, utilities, pin' });
|
| 1689 |
+
}
|
| 1690 |
flushPending(node.line);
|
| 1691 |
const childCtx = { ...ctx, layer };
|
| 1692 |
const sub = { decls: [] };
|
|
|
|
| 1696 |
}
|
| 1697 |
case 'pseudo': {
|
| 1698 |
const base = ctx.sel || '*'; // top-level ::selection etc. means every element
|
| 1699 |
+
const parts = splitTopLevel(base);
|
| 1700 |
const srule = {
|
| 1701 |
id: ruleId++, sel: base, pseudo: node.name,
|
| 1702 |
media: ctx.media, signals: ctx.signals, containers: ctx.containers,
|
|
|
|
| 1733 |
fill(srule, node.children);
|
| 1734 |
if (srule.decls.length) shadowRules.push(srule);
|
| 1735 |
for (const st of stateRules) if (st.decls.length) shadowRules.push(st);
|
| 1736 |
+
// a selector list in front of the block (.a, .b { ::before { } }): the rules above were built on the whole
|
| 1737 |
+
// list; give every further part its own copy so each gets its own pseudo-element rule
|
| 1738 |
+
if (parts.length > 1) {
|
| 1739 |
+
const built = [srule, ...stateRules].filter((r) => r.decls.length);
|
| 1740 |
+
for (const part of parts.slice(1)) {
|
| 1741 |
+
for (const r of built) {
|
| 1742 |
+
shadowRules.push({ ...r, decls: r.decls.map((d) => ({ ...d })), id: ruleId++, order: order++, sel: part + r.sel.slice(base.length) });
|
| 1743 |
+
}
|
| 1744 |
+
}
|
| 1745 |
+
for (const r of built) r.sel = parts[0] + r.sel.slice(base.length);
|
| 1746 |
+
}
|
| 1747 |
break;
|
| 1748 |
}
|
| 1749 |
case 'tokens': {
|
|
|
|
| 2014 |
return { rules, shadowRules, raws, fontLinks, motions, motionFrames, errors, warnings, mediaQueries: [...mediaQueries], tokens: Object.fromEntries(tokenMap), registryRule };
|
| 2015 |
}
|
| 2016 |
|
| 2017 |
+
/** `&` substitution + descendant join. Lists are split at top-level commas and every parent part is joined with
|
| 2018 |
+
* every child part (parent-major), so `.a, .b { .c { } }` is `.a .c, .b .c`. Commas inside :is( ) or [ ] stay put. */
|
| 2019 |
function combine(parent, child) {
|
| 2020 |
+
const pp = splitTopLevel(parent), cp = splitTopLevel(child);
|
| 2021 |
+
if (pp.length <= 1 && cp.length <= 1) {
|
| 2022 |
+
if (child.includes('&')) return child.split('&').join(parent);
|
| 2023 |
+
return parent + ' ' + child;
|
| 2024 |
+
}
|
| 2025 |
+
const out = [];
|
| 2026 |
+
for (const p of pp) for (const c of cp) out.push(c.includes('&') ? c.split('&').join(p) : p + ' ' + c);
|
| 2027 |
+
return out.join(', ');
|
| 2028 |
+
}
|
| 2029 |
+
|
| 2030 |
+
/** append a state to every part of a selector list: `.a, .b` + hover is `.a:hover, .b:hover` */
|
| 2031 |
+
function withState(sel, name) {
|
| 2032 |
+
const parts = splitTopLevel(sel);
|
| 2033 |
+
if (parts.length <= 1) return sel + ':' + name;
|
| 2034 |
+
return parts.map((p) => p + ':' + name).join(', ');
|
| 2035 |
}
|
| 2036 |
|
| 2037 |
/* v0.5.0 - where does a selector carry a pseudo-element?
|
|
@@ -2,7 +2,7 @@
|
|
| 2 |
"name": "dssl-vscode",
|
| 3 |
"displayName": "DSSL Language Support",
|
| 4 |
"description": "The DSSL style language in your editor: syntax highlighting, real-compiler diagnostics (the same errors the browser console shows), completions from the live token registry and for textures, auras and sliders, hover docs, an interactive designer with sliders and live previews for aura, texture and range sliders, and a CSS to DSSL converter. Works in VS Code and VSCodium.",
|
| 5 |
-
"version": "0.16.
|
| 6 |
"publisher": "ehs-studio",
|
| 7 |
"icon": "icon.png",
|
| 8 |
"license": "MIT",
|
|
|
|
| 2 |
"name": "dssl-vscode",
|
| 3 |
"displayName": "DSSL Language Support",
|
| 4 |
"description": "The DSSL style language in your editor: syntax highlighting, real-compiler diagnostics (the same errors the browser console shows), completions from the live token registry and for textures, auras and sliders, hover docs, an interactive designer with sliders and live previews for aura, texture and range sliders, and a CSS to DSSL converter. Works in VS Code and VSCodium.",
|
| 5 |
+
"version": "0.16.3",
|
| 6 |
"publisher": "ehs-studio",
|
| 7 |
"icon": "icon.png",
|
| 8 |
"license": "MIT",
|
|
@@ -5,7 +5,7 @@
|
|
| 5 |
- Site (docs, playground, changelog, bench): https://dssl-sable.vercel.app
|
| 6 |
- Repo + full docs in the README: https://huggingface.co/EHS-Studio/dssl
|
| 7 |
- Install: `curl -fsSL https://dssl-sable.vercel.app/install.sh | sh` (or the zip: https://dssl-sable.vercel.app/dssl-engine.zip)
|
| 8 |
-
- Version: 0.16.
|
| 9 |
- Feature matrix vs CSS: see PARITY.md in the repo
|
| 10 |
- For agents working ON the codebase: see AGENTS.md in the repo
|
| 11 |
|
|
@@ -64,6 +64,10 @@ DSSL.replay(sel) / DSSL.refresh([el]) / DSSL.errors() (a function) / DSSL.versio
|
|
| 64 |
- Alpha on a named colour works: `white/12`, `currentColor/20`. It used to compile to `white/12px`.
|
| 65 |
- The playground has a canvas.html tab, `?example=` links, lint warnings and an "as CSS" tab. The canvas keeps a short allow-list of tags and drops scripts, handlers, styles and ids.
|
| 66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
## 0.16.2
|
| 68 |
- `DSSL.lint`'s `css-loses` no longer judges the output of `dssl build` (its reset is built to sit under the engine), and ignores a rule whose value is the same as what DSSL wrote inline. On this site's docs page it reported 4,314 findings in 0.16.0; it now reports none from the site's own CSS.
|
| 69 |
|
|
@@ -132,4 +136,4 @@ Wait for the `dssl-ready` event on `window` before measuring layout: the engine
|
|
| 132 |
|
| 133 |
## Editor support
|
| 134 |
|
| 135 |
-
The official extension (VS Code and VSCodium, same .vsix) bundles the real parser and resolver: diagnostics identical to the browser console, completions from the workspace token registry, hover docs for the semantic vocabulary. In VSCodium, search "DSSL" in the Extensions tab (it is on Open VSX: https://open-vsx.org/extension/ehs-studio/dssl-vscode). In VS Code, download `dssl-vscode/dssl-vscode-0.16.
|
|
|
|
| 5 |
- Site (docs, playground, changelog, bench): https://dssl-sable.vercel.app
|
| 6 |
- Repo + full docs in the README: https://huggingface.co/EHS-Studio/dssl
|
| 7 |
- Install: `curl -fsSL https://dssl-sable.vercel.app/install.sh | sh` (or the zip: https://dssl-sable.vercel.app/dssl-engine.zip)
|
| 8 |
+
- Version: 0.16.3 (engine), MIT license
|
| 9 |
- Feature matrix vs CSS: see PARITY.md in the repo
|
| 10 |
- For agents working ON the codebase: see AGENTS.md in the repo
|
| 11 |
|
|
|
|
| 64 |
- Alpha on a named colour works: `white/12`, `currentColor/20`. It used to compile to `white/12px`.
|
| 65 |
- The playground has a canvas.html tab, `?example=` links, lint warnings and an "as CSS" tab. The canvas keeps a short allow-list of tags and drops scripts, handlers, styles and ids.
|
| 66 |
|
| 67 |
+
## 0.16.3
|
| 68 |
+
- Seven bugs found by writing the native spec (`native/spec/`) are fixed. An unquoted `url(http://x.com/a.png)` no longer loses the rest of the line to the comment stripper (also inside `raw { }`). A typo at the end of a token path (`color.ink.bogus`) is an `unknown value` error instead of quietly becoming `color.ink`. Nesting under a selector list joins every part: `.a, .b { .c { } }` is `.a .c, .b .c`, `hover { }` gives `.a:hover, .b:hover`, `.c, .d { }` under `.a` gives `.a .c, .a .d`, and `::before { }` gets one rule per part. A backslash escapes a quote in a value (`content: "a\"b"`). A nested `li` or any other HTML element name no longer gets a "did you mean link" warning.
|
| 69 |
+
- Two new warnings, both compile fine: an unknown `@layer` name (it is treated as `components`) and `radius: xl` when no `radius.xl` token exists.
|
| 70 |
+
|
| 71 |
## 0.16.2
|
| 72 |
- `DSSL.lint`'s `css-loses` no longer judges the output of `dssl build` (its reset is built to sit under the engine), and ignores a rule whose value is the same as what DSSL wrote inline. On this site's docs page it reported 4,314 findings in 0.16.0; it now reports none from the site's own CSS.
|
| 73 |
|
|
|
|
| 136 |
|
| 137 |
## Editor support
|
| 138 |
|
| 139 |
+
The official extension (VS Code and VSCodium, same .vsix) bundles the real parser and resolver: diagnostics identical to the browser console, completions from the workspace token registry, hover docs for the semantic vocabulary. In VSCodium, search "DSSL" in the Extensions tab (it is on Open VSX: https://open-vsx.org/extension/ehs-studio/dssl-vscode). In VS Code, download `dssl-vscode/dssl-vscode-0.16.3.vsix` from the repo files, then Extensions panel -> ... -> Install from VSIX. Source lives in `dssl-vscode/` in the repo.
|
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
target/
|
|
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is automatically @generated by Cargo.
|
| 2 |
+
# It is not intended for manual editing.
|
| 3 |
+
version = 4
|
| 4 |
+
|
| 5 |
+
[[package]]
|
| 6 |
+
name = "aho-corasick"
|
| 7 |
+
version = "1.1.5"
|
| 8 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 9 |
+
checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
|
| 10 |
+
dependencies = [
|
| 11 |
+
"memchr",
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
[[package]]
|
| 15 |
+
name = "bit-set"
|
| 16 |
+
version = "0.8.0"
|
| 17 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 18 |
+
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
| 19 |
+
dependencies = [
|
| 20 |
+
"bit-vec",
|
| 21 |
+
]
|
| 22 |
+
|
| 23 |
+
[[package]]
|
| 24 |
+
name = "bit-vec"
|
| 25 |
+
version = "0.8.0"
|
| 26 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 27 |
+
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
| 28 |
+
|
| 29 |
+
[[package]]
|
| 30 |
+
name = "dssl-native"
|
| 31 |
+
version = "0.1.0"
|
| 32 |
+
dependencies = [
|
| 33 |
+
"fancy-regex",
|
| 34 |
+
"serde_json",
|
| 35 |
+
]
|
| 36 |
+
|
| 37 |
+
[[package]]
|
| 38 |
+
name = "fancy-regex"
|
| 39 |
+
version = "0.14.0"
|
| 40 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 41 |
+
checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298"
|
| 42 |
+
dependencies = [
|
| 43 |
+
"bit-set",
|
| 44 |
+
"regex-automata",
|
| 45 |
+
"regex-syntax",
|
| 46 |
+
]
|
| 47 |
+
|
| 48 |
+
[[package]]
|
| 49 |
+
name = "itoa"
|
| 50 |
+
version = "1.0.18"
|
| 51 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 52 |
+
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
| 53 |
+
|
| 54 |
+
[[package]]
|
| 55 |
+
name = "memchr"
|
| 56 |
+
version = "2.8.3"
|
| 57 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 58 |
+
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
| 59 |
+
|
| 60 |
+
[[package]]
|
| 61 |
+
name = "proc-macro2"
|
| 62 |
+
version = "1.0.107"
|
| 63 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 64 |
+
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
| 65 |
+
dependencies = [
|
| 66 |
+
"unicode-ident",
|
| 67 |
+
]
|
| 68 |
+
|
| 69 |
+
[[package]]
|
| 70 |
+
name = "quote"
|
| 71 |
+
version = "1.0.47"
|
| 72 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 73 |
+
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
| 74 |
+
dependencies = [
|
| 75 |
+
"proc-macro2",
|
| 76 |
+
]
|
| 77 |
+
|
| 78 |
+
[[package]]
|
| 79 |
+
name = "regex-automata"
|
| 80 |
+
version = "0.4.18"
|
| 81 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 82 |
+
checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
|
| 83 |
+
dependencies = [
|
| 84 |
+
"aho-corasick",
|
| 85 |
+
"memchr",
|
| 86 |
+
"regex-syntax",
|
| 87 |
+
]
|
| 88 |
+
|
| 89 |
+
[[package]]
|
| 90 |
+
name = "regex-syntax"
|
| 91 |
+
version = "0.8.11"
|
| 92 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 93 |
+
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
| 94 |
+
|
| 95 |
+
[[package]]
|
| 96 |
+
name = "serde"
|
| 97 |
+
version = "1.0.229"
|
| 98 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 99 |
+
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
| 100 |
+
dependencies = [
|
| 101 |
+
"serde_core",
|
| 102 |
+
]
|
| 103 |
+
|
| 104 |
+
[[package]]
|
| 105 |
+
name = "serde_core"
|
| 106 |
+
version = "1.0.229"
|
| 107 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 108 |
+
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
| 109 |
+
dependencies = [
|
| 110 |
+
"serde_derive",
|
| 111 |
+
]
|
| 112 |
+
|
| 113 |
+
[[package]]
|
| 114 |
+
name = "serde_derive"
|
| 115 |
+
version = "1.0.229"
|
| 116 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 117 |
+
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
| 118 |
+
dependencies = [
|
| 119 |
+
"proc-macro2",
|
| 120 |
+
"quote",
|
| 121 |
+
"syn",
|
| 122 |
+
]
|
| 123 |
+
|
| 124 |
+
[[package]]
|
| 125 |
+
name = "serde_json"
|
| 126 |
+
version = "1.0.154"
|
| 127 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 128 |
+
checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6"
|
| 129 |
+
dependencies = [
|
| 130 |
+
"itoa",
|
| 131 |
+
"memchr",
|
| 132 |
+
"serde",
|
| 133 |
+
"serde_core",
|
| 134 |
+
"zmij",
|
| 135 |
+
]
|
| 136 |
+
|
| 137 |
+
[[package]]
|
| 138 |
+
name = "syn"
|
| 139 |
+
version = "3.0.9"
|
| 140 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 141 |
+
checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b"
|
| 142 |
+
dependencies = [
|
| 143 |
+
"proc-macro2",
|
| 144 |
+
"quote",
|
| 145 |
+
"unicode-ident",
|
| 146 |
+
]
|
| 147 |
+
|
| 148 |
+
[[package]]
|
| 149 |
+
name = "unicode-ident"
|
| 150 |
+
version = "1.0.27"
|
| 151 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 152 |
+
checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
|
| 153 |
+
|
| 154 |
+
[[package]]
|
| 155 |
+
name = "zmij"
|
| 156 |
+
version = "1.0.23"
|
| 157 |
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 158 |
+
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[package]
|
| 2 |
+
name = "dssl-native"
|
| 3 |
+
version = "0.1.0"
|
| 4 |
+
edition = "2021"
|
| 5 |
+
description = "DSSL reference compiler: a native, JavaScript-free implementation of the DSSL language"
|
| 6 |
+
license = "MIT"
|
| 7 |
+
|
| 8 |
+
[lib]
|
| 9 |
+
name = "dssl"
|
| 10 |
+
path = "src/lib.rs"
|
| 11 |
+
|
| 12 |
+
[[bin]]
|
| 13 |
+
name = "dssl-native"
|
| 14 |
+
path = "src/main.rs"
|
| 15 |
+
|
| 16 |
+
[dependencies]
|
| 17 |
+
serde_json = "1"
|
| 18 |
+
fancy-regex = "0.14"
|
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Native DSSL
|
| 2 |
+
|
| 3 |
+
DSSL today runs as a JavaScript engine. This folder is the start of DSSL as a language that does
|
| 4 |
+
not need JavaScript, the way CSS does not: a written specification, and a reference
|
| 5 |
+
implementation in Rust that a browser team can port or link.
|
| 6 |
+
|
| 7 |
+
## What is here
|
| 8 |
+
|
| 9 |
+
| Path | What it is | State |
|
| 10 |
+
|---|---|---|
|
| 11 |
+
| `spec/` | The specification, chapters 1 to 12 and two generated appendices | Written (draft, against engine 0.16.3) |
|
| 12 |
+
| `data/vocabulary.json` | Every word list the language uses, in the engine's order | Generated |
|
| 13 |
+
| `src/`, `Cargo.toml` | The Rust crate (`dssl-native`) | A stub that builds. No parser yet. |
|
| 14 |
+
| `../scripts/test-native-spec.mjs` | Runs every spec example, checks the prose and the fixed bugs, checks the generated files | Passing |
|
| 15 |
+
| `../scripts/gen-native-vocab.mjs` | Writes the data file and the appendices from the engine | Working |
|
| 16 |
+
|
| 17 |
+
## Honest status
|
| 18 |
+
|
| 19 |
+
- The spec covers the whole language, but not to the same depth everywhere. Syntax, values,
|
| 20 |
+
tokens, cascade, properties and motion are written precisely enough to implement from. The paint
|
| 21 |
+
half of texture, aura, slider and overlap is marked **Pending**: it is defined by the JavaScript
|
| 22 |
+
generators until it is written as prose (chapter 8).
|
| 23 |
+
- The Rust crate does nothing yet. Next is the parser (chapter 2), then the resolver (chapters 3
|
| 24 |
+
to 7), checked against the JavaScript engine over a corpus (chapter 10). Matching elements,
|
| 25 |
+
computing styles and paint are later levels (chapter 1.4).
|
| 26 |
+
- Nothing here is in a browser. Chapter 11 says what that would take.
|
| 27 |
+
|
| 28 |
+
## Bugs the spec found in the engine
|
| 29 |
+
|
| 30 |
+
Checking the spec against the engine found eight places where the engine did not behave as the
|
| 31 |
+
language promises (chapter 12). Seven are fixed in 0.16.3 and `scripts/test-v0163.mjs` keeps them
|
| 32 |
+
fixed. The eighth (D-6, how base tokens carry over between files) needs a two-file test in a
|
| 33 |
+
browser before anyone decides whether it is a bug.
|
| 34 |
+
|
| 35 |
+
## Commands
|
| 36 |
+
|
| 37 |
+
```sh
|
| 38 |
+
node scripts/test-native-spec.mjs # spec examples, prose promises, fixed bugs, generated files
|
| 39 |
+
node scripts/gen-native-vocab.mjs # rewrite native/data and the appendices after an engine change
|
| 40 |
+
node scripts/gen-native-vocab.mjs --check # fail if they are out of date
|
| 41 |
+
cd native && cargo build # the crate (a stub today)
|
| 42 |
+
```
|
|
@@ -0,0 +1,4567 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_about": "Generated by scripts/gen-native-vocab.mjs from public/dssl. Do not edit by hand. Array order is the engine's insertion order.",
|
| 3 |
+
"version": "0.16.3",
|
| 4 |
+
"stateWords": [
|
| 5 |
+
"hover",
|
| 6 |
+
"focus",
|
| 7 |
+
"focus-visible",
|
| 8 |
+
"active",
|
| 9 |
+
"disabled",
|
| 10 |
+
"checked",
|
| 11 |
+
"empty",
|
| 12 |
+
"target",
|
| 13 |
+
"required",
|
| 14 |
+
"invalid",
|
| 15 |
+
"valid",
|
| 16 |
+
"open",
|
| 17 |
+
"closed",
|
| 18 |
+
"placeholder-shown",
|
| 19 |
+
"read-only",
|
| 20 |
+
"read-write",
|
| 21 |
+
"enabled",
|
| 22 |
+
"indeterminate",
|
| 23 |
+
"first-child",
|
| 24 |
+
"last-child",
|
| 25 |
+
"only-child",
|
| 26 |
+
"first-of-type",
|
| 27 |
+
"last-of-type",
|
| 28 |
+
"link",
|
| 29 |
+
"visited",
|
| 30 |
+
"seen"
|
| 31 |
+
],
|
| 32 |
+
"pseudoElements": [
|
| 33 |
+
"before",
|
| 34 |
+
"after",
|
| 35 |
+
"placeholder",
|
| 36 |
+
"selection",
|
| 37 |
+
"marker",
|
| 38 |
+
"first-line",
|
| 39 |
+
"first-letter",
|
| 40 |
+
"backdrop",
|
| 41 |
+
"file-selector-button",
|
| 42 |
+
"part",
|
| 43 |
+
"slotted"
|
| 44 |
+
],
|
| 45 |
+
"vendorPseudoSource": "^-(webkit|moz|ms)-",
|
| 46 |
+
"cssKeywords": [
|
| 47 |
+
"inherit",
|
| 48 |
+
"initial",
|
| 49 |
+
"unset",
|
| 50 |
+
"revert",
|
| 51 |
+
"revert-layer",
|
| 52 |
+
"none",
|
| 53 |
+
"auto",
|
| 54 |
+
"currentcolor",
|
| 55 |
+
"transparent",
|
| 56 |
+
"from",
|
| 57 |
+
"stroke",
|
| 58 |
+
"markers",
|
| 59 |
+
"normal",
|
| 60 |
+
"black",
|
| 61 |
+
"silver",
|
| 62 |
+
"gray",
|
| 63 |
+
"white",
|
| 64 |
+
"maroon",
|
| 65 |
+
"red",
|
| 66 |
+
"purple",
|
| 67 |
+
"fuchsia",
|
| 68 |
+
"green",
|
| 69 |
+
"lime",
|
| 70 |
+
"olive",
|
| 71 |
+
"yellow",
|
| 72 |
+
"navy",
|
| 73 |
+
"blue",
|
| 74 |
+
"teal",
|
| 75 |
+
"aqua",
|
| 76 |
+
"orange",
|
| 77 |
+
"gold",
|
| 78 |
+
"pink",
|
| 79 |
+
"brown",
|
| 80 |
+
"violet",
|
| 81 |
+
"cyan",
|
| 82 |
+
"magenta",
|
| 83 |
+
"indigo",
|
| 84 |
+
"crimson",
|
| 85 |
+
"coral",
|
| 86 |
+
"tomato",
|
| 87 |
+
"goldenrod",
|
| 88 |
+
"khaki",
|
| 89 |
+
"slategray",
|
| 90 |
+
"slategrey",
|
| 91 |
+
"dimgray",
|
| 92 |
+
"dimgrey",
|
| 93 |
+
"lightgray",
|
| 94 |
+
"lightgrey",
|
| 95 |
+
"darkgray",
|
| 96 |
+
"darkgrey",
|
| 97 |
+
"gainsboro",
|
| 98 |
+
"whitesmoke",
|
| 99 |
+
"ghostwhite",
|
| 100 |
+
"ivory",
|
| 101 |
+
"beige",
|
| 102 |
+
"linen",
|
| 103 |
+
"seashell",
|
| 104 |
+
"snow",
|
| 105 |
+
"honeydew",
|
| 106 |
+
"mintcream",
|
| 107 |
+
"azure",
|
| 108 |
+
"aliceblue",
|
| 109 |
+
"lavender",
|
| 110 |
+
"canvas",
|
| 111 |
+
"canvastext",
|
| 112 |
+
"linktext",
|
| 113 |
+
"visitedtext",
|
| 114 |
+
"activetext",
|
| 115 |
+
"buttonface",
|
| 116 |
+
"buttontext",
|
| 117 |
+
"buttonborder",
|
| 118 |
+
"field",
|
| 119 |
+
"fieldtext",
|
| 120 |
+
"highlight",
|
| 121 |
+
"highlighttext",
|
| 122 |
+
"solid",
|
| 123 |
+
"dashed",
|
| 124 |
+
"dotted",
|
| 125 |
+
"double",
|
| 126 |
+
"groove",
|
| 127 |
+
"ridge",
|
| 128 |
+
"inset",
|
| 129 |
+
"outset",
|
| 130 |
+
"hidden",
|
| 131 |
+
"visible",
|
| 132 |
+
"block",
|
| 133 |
+
"inline",
|
| 134 |
+
"inline-block",
|
| 135 |
+
"flex",
|
| 136 |
+
"inline-flex",
|
| 137 |
+
"grid",
|
| 138 |
+
"inline-grid",
|
| 139 |
+
"flow-root",
|
| 140 |
+
"contents",
|
| 141 |
+
"table",
|
| 142 |
+
"table-row",
|
| 143 |
+
"table-cell",
|
| 144 |
+
"list-item",
|
| 145 |
+
"relative",
|
| 146 |
+
"absolute",
|
| 147 |
+
"fixed",
|
| 148 |
+
"sticky",
|
| 149 |
+
"static",
|
| 150 |
+
"start",
|
| 151 |
+
"end",
|
| 152 |
+
"center",
|
| 153 |
+
"left",
|
| 154 |
+
"right",
|
| 155 |
+
"between",
|
| 156 |
+
"around",
|
| 157 |
+
"evenly",
|
| 158 |
+
"baseline",
|
| 159 |
+
"stretch",
|
| 160 |
+
"space-between",
|
| 161 |
+
"space-around",
|
| 162 |
+
"space-evenly",
|
| 163 |
+
"wrap",
|
| 164 |
+
"nowrap",
|
| 165 |
+
"reverse",
|
| 166 |
+
"row",
|
| 167 |
+
"column",
|
| 168 |
+
"row-reverse",
|
| 169 |
+
"column-reverse",
|
| 170 |
+
"bold",
|
| 171 |
+
"bolder",
|
| 172 |
+
"lighter",
|
| 173 |
+
"italic",
|
| 174 |
+
"oblique",
|
| 175 |
+
"small-caps",
|
| 176 |
+
"uppercase",
|
| 177 |
+
"lowercase",
|
| 178 |
+
"capitalize",
|
| 179 |
+
"underline",
|
| 180 |
+
"overline",
|
| 181 |
+
"line-through",
|
| 182 |
+
"blink",
|
| 183 |
+
"ellipsis",
|
| 184 |
+
"clip",
|
| 185 |
+
"break-word",
|
| 186 |
+
"anywhere",
|
| 187 |
+
"pre",
|
| 188 |
+
"pre-wrap",
|
| 189 |
+
"pre-line",
|
| 190 |
+
"subpixel-antialiased",
|
| 191 |
+
"antialiased",
|
| 192 |
+
"pointer",
|
| 193 |
+
"progress",
|
| 194 |
+
"default",
|
| 195 |
+
"move",
|
| 196 |
+
"text",
|
| 197 |
+
"wait",
|
| 198 |
+
"help",
|
| 199 |
+
"grab",
|
| 200 |
+
"grabbing",
|
| 201 |
+
"not-allowed",
|
| 202 |
+
"zoom-in",
|
| 203 |
+
"zoom-out",
|
| 204 |
+
"copy",
|
| 205 |
+
"alias",
|
| 206 |
+
"crosshair",
|
| 207 |
+
"serif",
|
| 208 |
+
"sans-serif",
|
| 209 |
+
"monospace",
|
| 210 |
+
"cursive",
|
| 211 |
+
"fantasy",
|
| 212 |
+
"system-ui",
|
| 213 |
+
"ui-sans-serif",
|
| 214 |
+
"ui-monospace",
|
| 215 |
+
"ui-serif",
|
| 216 |
+
"ui-rounded",
|
| 217 |
+
"-apple-system",
|
| 218 |
+
"Roboto",
|
| 219 |
+
"Helvetica",
|
| 220 |
+
"Arial",
|
| 221 |
+
"Menlo",
|
| 222 |
+
"Consolas",
|
| 223 |
+
"SFMono-Regular",
|
| 224 |
+
"Liberation-Mono",
|
| 225 |
+
"Inter",
|
| 226 |
+
"Noto-Sans",
|
| 227 |
+
"Ubuntu",
|
| 228 |
+
"Cantarell",
|
| 229 |
+
"Oxygen",
|
| 230 |
+
"Fira-Sans",
|
| 231 |
+
"Droid-Sans",
|
| 232 |
+
"border-box",
|
| 233 |
+
"content-box",
|
| 234 |
+
"padding-box",
|
| 235 |
+
"fill-box",
|
| 236 |
+
"stroke-box",
|
| 237 |
+
"view-box",
|
| 238 |
+
"no-repeat",
|
| 239 |
+
"repeat-x",
|
| 240 |
+
"repeat-y",
|
| 241 |
+
"space",
|
| 242 |
+
"round",
|
| 243 |
+
"scroll",
|
| 244 |
+
"local",
|
| 245 |
+
"contain",
|
| 246 |
+
"cover",
|
| 247 |
+
"fill",
|
| 248 |
+
"fit-content",
|
| 249 |
+
"min-content",
|
| 250 |
+
"max-content",
|
| 251 |
+
"minmax",
|
| 252 |
+
"repeat",
|
| 253 |
+
"clamp",
|
| 254 |
+
"calc",
|
| 255 |
+
"var",
|
| 256 |
+
"url",
|
| 257 |
+
"env",
|
| 258 |
+
"attr",
|
| 259 |
+
"auto-fill",
|
| 260 |
+
"auto-fit",
|
| 261 |
+
"subgrid",
|
| 262 |
+
"dense",
|
| 263 |
+
"span",
|
| 264 |
+
"scaleX",
|
| 265 |
+
"scaleY",
|
| 266 |
+
"translateX",
|
| 267 |
+
"translateY",
|
| 268 |
+
"translate",
|
| 269 |
+
"rotate",
|
| 270 |
+
"skew",
|
| 271 |
+
"skewX",
|
| 272 |
+
"skewY",
|
| 273 |
+
"matrix",
|
| 274 |
+
"ease",
|
| 275 |
+
"ease-in",
|
| 276 |
+
"ease-out",
|
| 277 |
+
"ease-in-out",
|
| 278 |
+
"linear",
|
| 279 |
+
"step-start",
|
| 280 |
+
"step-end",
|
| 281 |
+
"steps",
|
| 282 |
+
"cubic-bezier",
|
| 283 |
+
"spring",
|
| 284 |
+
"bounce",
|
| 285 |
+
"smooth",
|
| 286 |
+
"snap",
|
| 287 |
+
"forwards",
|
| 288 |
+
"backwards",
|
| 289 |
+
"both",
|
| 290 |
+
"infinite",
|
| 291 |
+
"alternate",
|
| 292 |
+
"alternate-reverse",
|
| 293 |
+
"running",
|
| 294 |
+
"paused",
|
| 295 |
+
"safe",
|
| 296 |
+
"unsafe",
|
| 297 |
+
"legacy",
|
| 298 |
+
"loose",
|
| 299 |
+
"strict",
|
| 300 |
+
"spell-out",
|
| 301 |
+
"letters",
|
| 302 |
+
"isolate",
|
| 303 |
+
"isolation",
|
| 304 |
+
"blend",
|
| 305 |
+
"multiply",
|
| 306 |
+
"screen",
|
| 307 |
+
"overlay",
|
| 308 |
+
"darken",
|
| 309 |
+
"lighten",
|
| 310 |
+
"color-dodge",
|
| 311 |
+
"color-burn",
|
| 312 |
+
"hard-light",
|
| 313 |
+
"soft-light",
|
| 314 |
+
"difference",
|
| 315 |
+
"exclusion",
|
| 316 |
+
"hue",
|
| 317 |
+
"saturation",
|
| 318 |
+
"color",
|
| 319 |
+
"luminosity",
|
| 320 |
+
"plus-lighter",
|
| 321 |
+
"blur",
|
| 322 |
+
"brightness",
|
| 323 |
+
"contrast",
|
| 324 |
+
"grayscale",
|
| 325 |
+
"invert",
|
| 326 |
+
"opacity",
|
| 327 |
+
"sepia",
|
| 328 |
+
"saturate",
|
| 329 |
+
"drop-shadow",
|
| 330 |
+
"pointer coarse fine hover interactive",
|
| 331 |
+
"first",
|
| 332 |
+
"last",
|
| 333 |
+
"odd",
|
| 334 |
+
"even",
|
| 335 |
+
"all",
|
| 336 |
+
"portrait",
|
| 337 |
+
"landscape",
|
| 338 |
+
"print",
|
| 339 |
+
"and",
|
| 340 |
+
"not",
|
| 341 |
+
"only",
|
| 342 |
+
"inline-size",
|
| 343 |
+
"size",
|
| 344 |
+
"scroll-state",
|
| 345 |
+
"snapped",
|
| 346 |
+
"physical",
|
| 347 |
+
"logical",
|
| 348 |
+
"in",
|
| 349 |
+
"oklab",
|
| 350 |
+
"oklch",
|
| 351 |
+
"srgb",
|
| 352 |
+
"srgb-linear",
|
| 353 |
+
"display-p3",
|
| 354 |
+
"a98-rgb",
|
| 355 |
+
"prophoto-rgb",
|
| 356 |
+
"rec2020",
|
| 357 |
+
"xyz",
|
| 358 |
+
"xyz-d50",
|
| 359 |
+
"xyz-d65",
|
| 360 |
+
"shorter",
|
| 361 |
+
"longer",
|
| 362 |
+
"deg",
|
| 363 |
+
"grad",
|
| 364 |
+
"rad",
|
| 365 |
+
"turn",
|
| 366 |
+
"to",
|
| 367 |
+
"top",
|
| 368 |
+
"bottom",
|
| 369 |
+
"above",
|
| 370 |
+
"below",
|
| 371 |
+
"closest-side",
|
| 372 |
+
"farthest-side",
|
| 373 |
+
"ellipse",
|
| 374 |
+
"circle",
|
| 375 |
+
"at",
|
| 376 |
+
"plaintext",
|
| 377 |
+
"sideways",
|
| 378 |
+
"upright",
|
| 379 |
+
"mixed",
|
| 380 |
+
"ltr",
|
| 381 |
+
"rtl",
|
| 382 |
+
"transform",
|
| 383 |
+
"-webkit-box",
|
| 384 |
+
"-webkit-inline-box",
|
| 385 |
+
"thin",
|
| 386 |
+
"thick",
|
| 387 |
+
"medium",
|
| 388 |
+
"separate",
|
| 389 |
+
"collapse",
|
| 390 |
+
"vertical",
|
| 391 |
+
"horizontal",
|
| 392 |
+
"balance",
|
| 393 |
+
"pretty",
|
| 394 |
+
"orphans",
|
| 395 |
+
"manual",
|
| 396 |
+
"pixelated",
|
| 397 |
+
"crisp-edges",
|
| 398 |
+
"optimizeSpeed",
|
| 399 |
+
"optimizeLegibility",
|
| 400 |
+
"geometricPrecision",
|
| 401 |
+
"flex-start",
|
| 402 |
+
"flex-end",
|
| 403 |
+
"self-start",
|
| 404 |
+
"self-end",
|
| 405 |
+
"snap-block",
|
| 406 |
+
"snap-inline",
|
| 407 |
+
"swap",
|
| 408 |
+
"fallback",
|
| 409 |
+
"optional",
|
| 410 |
+
"-apple-pay-button",
|
| 411 |
+
"-infinity",
|
| 412 |
+
"-moz-mac-unified-toolbar",
|
| 413 |
+
"-moz-win-borderless-glass",
|
| 414 |
+
"-moz-win-browsertabbar-toolbox",
|
| 415 |
+
"-moz-win-communications-toolbox",
|
| 416 |
+
"-moz-win-communicationstext",
|
| 417 |
+
"-moz-win-exclude-glass",
|
| 418 |
+
"-moz-win-glass",
|
| 419 |
+
"-moz-win-media-toolbox",
|
| 420 |
+
"-moz-win-mediatext",
|
| 421 |
+
"-moz-window-button-box",
|
| 422 |
+
"-moz-window-button-box-maximized",
|
| 423 |
+
"-moz-window-button-close",
|
| 424 |
+
"-moz-window-button-maximize",
|
| 425 |
+
"-moz-window-button-minimize",
|
| 426 |
+
"-moz-window-button-restore",
|
| 427 |
+
"-moz-window-frame-bottom",
|
| 428 |
+
"-moz-window-frame-left",
|
| 429 |
+
"-moz-window-frame-right",
|
| 430 |
+
"-moz-window-titlebar",
|
| 431 |
+
"-moz-window-titlebar-maximized",
|
| 432 |
+
"-ms-autohiding-scrollbar",
|
| 433 |
+
"-n",
|
| 434 |
+
"-n-",
|
| 435 |
+
"accumulate",
|
| 436 |
+
"active",
|
| 437 |
+
"add",
|
| 438 |
+
"after",
|
| 439 |
+
"all-petite-caps",
|
| 440 |
+
"all-scroll",
|
| 441 |
+
"all-small-caps",
|
| 442 |
+
"allow-discrete",
|
| 443 |
+
"allow-end",
|
| 444 |
+
"allow-keywords",
|
| 445 |
+
"alpha",
|
| 446 |
+
"alphabetic",
|
| 447 |
+
"always",
|
| 448 |
+
"anchor-center",
|
| 449 |
+
"anchors-valid",
|
| 450 |
+
"anchors-visible",
|
| 451 |
+
"angle",
|
| 452 |
+
"annotation",
|
| 453 |
+
"antiquewhite",
|
| 454 |
+
"any",
|
| 455 |
+
"aquamarine",
|
| 456 |
+
"arcs",
|
| 457 |
+
"auto-add",
|
| 458 |
+
"auto-flow",
|
| 459 |
+
"auto-phrase",
|
| 460 |
+
"avoid",
|
| 461 |
+
"avoid-column",
|
| 462 |
+
"avoid-page",
|
| 463 |
+
"avoid-region",
|
| 464 |
+
"bar",
|
| 465 |
+
"before",
|
| 466 |
+
"bevel",
|
| 467 |
+
"bidi-override",
|
| 468 |
+
"bisque",
|
| 469 |
+
"blanchedalmond",
|
| 470 |
+
"blank",
|
| 471 |
+
"block-axis",
|
| 472 |
+
"block-end",
|
| 473 |
+
"block-start",
|
| 474 |
+
"blueviolet",
|
| 475 |
+
"border",
|
| 476 |
+
"border-area",
|
| 477 |
+
"both-edges",
|
| 478 |
+
"bottom-center",
|
| 479 |
+
"bottom-left",
|
| 480 |
+
"bottom-left-corner",
|
| 481 |
+
"bottom-right",
|
| 482 |
+
"bottom-right-corner",
|
| 483 |
+
"box-decoration",
|
| 484 |
+
"break-all",
|
| 485 |
+
"break-spaces",
|
| 486 |
+
"bt",
|
| 487 |
+
"burlywood",
|
| 488 |
+
"butt",
|
| 489 |
+
"button",
|
| 490 |
+
"button-arrow-down",
|
| 491 |
+
"button-arrow-next",
|
| 492 |
+
"button-arrow-previous",
|
| 493 |
+
"button-arrow-up",
|
| 494 |
+
"button-bevel",
|
| 495 |
+
"button-focus",
|
| 496 |
+
"cadetblue",
|
| 497 |
+
"cap",
|
| 498 |
+
"cap-height",
|
| 499 |
+
"caption",
|
| 500 |
+
"caret",
|
| 501 |
+
"cell",
|
| 502 |
+
"central",
|
| 503 |
+
"ch-width",
|
| 504 |
+
"chained",
|
| 505 |
+
"character-variant",
|
| 506 |
+
"chartreuse",
|
| 507 |
+
"checkbox",
|
| 508 |
+
"checkbox-container",
|
| 509 |
+
"checkbox-label",
|
| 510 |
+
"checkmenuitem",
|
| 511 |
+
"chocolate",
|
| 512 |
+
"clear",
|
| 513 |
+
"clone",
|
| 514 |
+
"close-quote",
|
| 515 |
+
"closest-corner",
|
| 516 |
+
"cm",
|
| 517 |
+
"col-resize",
|
| 518 |
+
"common-ligatures",
|
| 519 |
+
"compact",
|
| 520 |
+
"condensed",
|
| 521 |
+
"consistent",
|
| 522 |
+
"constrained",
|
| 523 |
+
"content",
|
| 524 |
+
"content-block-size",
|
| 525 |
+
"content-height",
|
| 526 |
+
"content-inline-size",
|
| 527 |
+
"content-width",
|
| 528 |
+
"context-fill",
|
| 529 |
+
"context-menu",
|
| 530 |
+
"context-stroke",
|
| 531 |
+
"contextual",
|
| 532 |
+
"cornflowerblue",
|
| 533 |
+
"cornsilk",
|
| 534 |
+
"cyclic",
|
| 535 |
+
"dark",
|
| 536 |
+
"darkblue",
|
| 537 |
+
"darkcyan",
|
| 538 |
+
"darkgoldenrod",
|
| 539 |
+
"darkgreen",
|
| 540 |
+
"darkkhaki",
|
| 541 |
+
"darkmagenta",
|
| 542 |
+
"darkolivegreen",
|
| 543 |
+
"darkorange",
|
| 544 |
+
"darkorchid",
|
| 545 |
+
"darkred",
|
| 546 |
+
"darksalmon",
|
| 547 |
+
"darkseagreen",
|
| 548 |
+
"darkslateblue",
|
| 549 |
+
"darkslategray",
|
| 550 |
+
"darkslategrey",
|
| 551 |
+
"darkturquoise",
|
| 552 |
+
"darkviolet",
|
| 553 |
+
"decreasing",
|
| 554 |
+
"deeppink",
|
| 555 |
+
"deepskyblue",
|
| 556 |
+
"default-button",
|
| 557 |
+
"definite-first",
|
| 558 |
+
"destination-atop",
|
| 559 |
+
"destination-in",
|
| 560 |
+
"destination-out",
|
| 561 |
+
"destination-over",
|
| 562 |
+
"diagonal-fractions",
|
| 563 |
+
"digits",
|
| 564 |
+
"disabled",
|
| 565 |
+
"discretionary-ligatures",
|
| 566 |
+
"display-p3-linear",
|
| 567 |
+
"dodgerblue",
|
| 568 |
+
"dot",
|
| 569 |
+
"double-circle",
|
| 570 |
+
"down",
|
| 571 |
+
"drag",
|
| 572 |
+
"dualbutton",
|
| 573 |
+
"e-resize",
|
| 574 |
+
"each-line",
|
| 575 |
+
"economy",
|
| 576 |
+
"edges",
|
| 577 |
+
"element",
|
| 578 |
+
"em",
|
| 579 |
+
"embed",
|
| 580 |
+
"emoji",
|
| 581 |
+
"enabled",
|
| 582 |
+
"entry",
|
| 583 |
+
"entry-crossing",
|
| 584 |
+
"evenodd",
|
| 585 |
+
"ew-resize",
|
| 586 |
+
"ex",
|
| 587 |
+
"ex-height",
|
| 588 |
+
"exact",
|
| 589 |
+
"exclude",
|
| 590 |
+
"exit",
|
| 591 |
+
"exit-crossing",
|
| 592 |
+
"expanded",
|
| 593 |
+
"extra-condensed",
|
| 594 |
+
"extra-expanded",
|
| 595 |
+
"false",
|
| 596 |
+
"fangsong",
|
| 597 |
+
"farthest-corner",
|
| 598 |
+
"fill-opacity",
|
| 599 |
+
"filled",
|
| 600 |
+
"firebrick",
|
| 601 |
+
"first-letter",
|
| 602 |
+
"fixed-position",
|
| 603 |
+
"flat",
|
| 604 |
+
"flex-flow",
|
| 605 |
+
"flex-visual",
|
| 606 |
+
"flip",
|
| 607 |
+
"flip-block",
|
| 608 |
+
"flip-inline",
|
| 609 |
+
"flip-start",
|
| 610 |
+
"floralwhite",
|
| 611 |
+
"flow",
|
| 612 |
+
"force-end",
|
| 613 |
+
"forestgreen",
|
| 614 |
+
"frequency",
|
| 615 |
+
"from-font",
|
| 616 |
+
"from-image",
|
| 617 |
+
"full-size-kana",
|
| 618 |
+
"full-width",
|
| 619 |
+
"grammar-error",
|
| 620 |
+
"greenyellow",
|
| 621 |
+
"grey",
|
| 622 |
+
"grid-columns",
|
| 623 |
+
"grid-order",
|
| 624 |
+
"grid-rows",
|
| 625 |
+
"grippers",
|
| 626 |
+
"groupbox",
|
| 627 |
+
"grow",
|
| 628 |
+
"hanging",
|
| 629 |
+
"height",
|
| 630 |
+
"hide",
|
| 631 |
+
"historical-forms",
|
| 632 |
+
"historical-ligatures",
|
| 633 |
+
"horizontal-tb",
|
| 634 |
+
"hotpink",
|
| 635 |
+
"hsl",
|
| 636 |
+
"hwb",
|
| 637 |
+
"i",
|
| 638 |
+
"ic",
|
| 639 |
+
"ic-height",
|
| 640 |
+
"ic-width",
|
| 641 |
+
"icon",
|
| 642 |
+
"ideograph-alpha",
|
| 643 |
+
"ideograph-numeric",
|
| 644 |
+
"ideograph-parenthesis",
|
| 645 |
+
"ideograph-space",
|
| 646 |
+
"ideographic",
|
| 647 |
+
"ideographic-ink",
|
| 648 |
+
"ignore",
|
| 649 |
+
"in-flow",
|
| 650 |
+
"inactive",
|
| 651 |
+
"increasing",
|
| 652 |
+
"indianred",
|
| 653 |
+
"inert",
|
| 654 |
+
"infinity",
|
| 655 |
+
"inline-axis",
|
| 656 |
+
"inline-end",
|
| 657 |
+
"inline-list-item",
|
| 658 |
+
"inline-start",
|
| 659 |
+
"inline-table",
|
| 660 |
+
"inner-spin-button",
|
| 661 |
+
"inside",
|
| 662 |
+
"integer",
|
| 663 |
+
"inter-character",
|
| 664 |
+
"inter-word",
|
| 665 |
+
"intersect",
|
| 666 |
+
"isolate-override",
|
| 667 |
+
"jis04",
|
| 668 |
+
"jis78",
|
| 669 |
+
"jis83",
|
| 670 |
+
"jis90",
|
| 671 |
+
"jump-both",
|
| 672 |
+
"jump-end",
|
| 673 |
+
"jump-none",
|
| 674 |
+
"jump-start",
|
| 675 |
+
"justify",
|
| 676 |
+
"keep-all",
|
| 677 |
+
"lab",
|
| 678 |
+
"large",
|
| 679 |
+
"larger",
|
| 680 |
+
"lavenderblush",
|
| 681 |
+
"lawngreen",
|
| 682 |
+
"layout",
|
| 683 |
+
"lch",
|
| 684 |
+
"leading-spaces",
|
| 685 |
+
"ledger",
|
| 686 |
+
"left-bottom",
|
| 687 |
+
"left-middle",
|
| 688 |
+
"left-top",
|
| 689 |
+
"legal",
|
| 690 |
+
"lemonchiffon",
|
| 691 |
+
"length",
|
| 692 |
+
"letter",
|
| 693 |
+
"lh",
|
| 694 |
+
"light",
|
| 695 |
+
"lightblue",
|
| 696 |
+
"lightcoral",
|
| 697 |
+
"lightcyan",
|
| 698 |
+
"lightgoldenrodyellow",
|
| 699 |
+
"lightgreen",
|
| 700 |
+
"lightpink",
|
| 701 |
+
"lightsalmon",
|
| 702 |
+
"lightseagreen",
|
| 703 |
+
"lightskyblue",
|
| 704 |
+
"lightslategray",
|
| 705 |
+
"lightslategrey",
|
| 706 |
+
"lightsteelblue",
|
| 707 |
+
"lightyellow",
|
| 708 |
+
"limegreen",
|
| 709 |
+
"lining-nums",
|
| 710 |
+
"listbox",
|
| 711 |
+
"listitem",
|
| 712 |
+
"literal-punctuation",
|
| 713 |
+
"lr",
|
| 714 |
+
"luminance",
|
| 715 |
+
"mandatory",
|
| 716 |
+
"manipulation",
|
| 717 |
+
"margin-box",
|
| 718 |
+
"match-element",
|
| 719 |
+
"match-parent",
|
| 720 |
+
"match-source",
|
| 721 |
+
"math",
|
| 722 |
+
"math-auto",
|
| 723 |
+
"mathematical",
|
| 724 |
+
"maximum",
|
| 725 |
+
"media-controls-background",
|
| 726 |
+
"media-controls-fullscreen-background",
|
| 727 |
+
"media-current-time-display",
|
| 728 |
+
"media-enter-fullscreen-button",
|
| 729 |
+
"media-exit-fullscreen-button",
|
| 730 |
+
"media-fullscreen-button",
|
| 731 |
+
"media-mute-button",
|
| 732 |
+
"media-overlay-play-button",
|
| 733 |
+
"media-play-button",
|
| 734 |
+
"media-seek-back-button",
|
| 735 |
+
"media-seek-forward-button",
|
| 736 |
+
"media-slider",
|
| 737 |
+
"media-sliderthumb",
|
| 738 |
+
"media-time-remaining-display",
|
| 739 |
+
"media-toggle-closed-captions-button",
|
| 740 |
+
"media-volume-slider",
|
| 741 |
+
"media-volume-slider-container",
|
| 742 |
+
"media-volume-sliderthumb",
|
| 743 |
+
"mediumaquamarine",
|
| 744 |
+
"mediumblue",
|
| 745 |
+
"mediumorchid",
|
| 746 |
+
"mediumpurple",
|
| 747 |
+
"mediumseagreen",
|
| 748 |
+
"mediumslateblue",
|
| 749 |
+
"mediumspringgreen",
|
| 750 |
+
"mediumturquoise",
|
| 751 |
+
"mediumvioletred",
|
| 752 |
+
"menu",
|
| 753 |
+
"menuarrow",
|
| 754 |
+
"menubar",
|
| 755 |
+
"menucheckbox",
|
| 756 |
+
"menuimage",
|
| 757 |
+
"menuitem",
|
| 758 |
+
"menuitemtext",
|
| 759 |
+
"menulist",
|
| 760 |
+
"menulist-button",
|
| 761 |
+
"menulist-text",
|
| 762 |
+
"menulist-textfield",
|
| 763 |
+
"menupopup",
|
| 764 |
+
"menuradio",
|
| 765 |
+
"menuseparator",
|
| 766 |
+
"message-box",
|
| 767 |
+
"meter",
|
| 768 |
+
"meterbar",
|
| 769 |
+
"meterchunk",
|
| 770 |
+
"middle",
|
| 771 |
+
"midnightblue",
|
| 772 |
+
"mistyrose",
|
| 773 |
+
"miter",
|
| 774 |
+
"miter-clip",
|
| 775 |
+
"mm",
|
| 776 |
+
"moccasin",
|
| 777 |
+
"most-block-size",
|
| 778 |
+
"most-height",
|
| 779 |
+
"most-inline-size",
|
| 780 |
+
"most-width",
|
| 781 |
+
"ms",
|
| 782 |
+
"multiple",
|
| 783 |
+
"n-",
|
| 784 |
+
"n-resize",
|
| 785 |
+
"navajowhite",
|
| 786 |
+
"ne-resize",
|
| 787 |
+
"nearest",
|
| 788 |
+
"nesw-resize",
|
| 789 |
+
"never",
|
| 790 |
+
"next",
|
| 791 |
+
"no-clip",
|
| 792 |
+
"no-close-quote",
|
| 793 |
+
"no-common-ligatures",
|
| 794 |
+
"no-contextual",
|
| 795 |
+
"no-discretionary-ligatures",
|
| 796 |
+
"no-drag",
|
| 797 |
+
"no-drop",
|
| 798 |
+
"no-historical-ligatures",
|
| 799 |
+
"no-limit",
|
| 800 |
+
"no-open-quote",
|
| 801 |
+
"no-overflow",
|
| 802 |
+
"no-punctuation",
|
| 803 |
+
"non-rotation",
|
| 804 |
+
"non-scaling-size",
|
| 805 |
+
"non-scaling-stroke",
|
| 806 |
+
"nonzero",
|
| 807 |
+
"notch",
|
| 808 |
+
"ns-resize",
|
| 809 |
+
"number",
|
| 810 |
+
"numeric",
|
| 811 |
+
"numeric-only",
|
| 812 |
+
"nw-resize",
|
| 813 |
+
"nwse-resize",
|
| 814 |
+
"objects",
|
| 815 |
+
"off",
|
| 816 |
+
"oldlace",
|
| 817 |
+
"oldstyle-nums",
|
| 818 |
+
"olivedrab",
|
| 819 |
+
"on",
|
| 820 |
+
"open",
|
| 821 |
+
"open-quote",
|
| 822 |
+
"or",
|
| 823 |
+
"orangered",
|
| 824 |
+
"orchid",
|
| 825 |
+
"ordered",
|
| 826 |
+
"ordinal",
|
| 827 |
+
"ornaments",
|
| 828 |
+
"outside",
|
| 829 |
+
"over",
|
| 830 |
+
"pack",
|
| 831 |
+
"padding",
|
| 832 |
+
"page",
|
| 833 |
+
"paint",
|
| 834 |
+
"painted",
|
| 835 |
+
"palegoldenrod",
|
| 836 |
+
"palegreen",
|
| 837 |
+
"paleturquoise",
|
| 838 |
+
"palevioletred",
|
| 839 |
+
"pan-down",
|
| 840 |
+
"pan-left",
|
| 841 |
+
"pan-right",
|
| 842 |
+
"pan-up",
|
| 843 |
+
"pan-x",
|
| 844 |
+
"pan-y",
|
| 845 |
+
"papayawhip",
|
| 846 |
+
"pause",
|
| 847 |
+
"pc",
|
| 848 |
+
"peachpuff",
|
| 849 |
+
"per-line",
|
| 850 |
+
"per-line-all",
|
| 851 |
+
"peru",
|
| 852 |
+
"petite-caps",
|
| 853 |
+
"pi",
|
| 854 |
+
"pinch-zoom",
|
| 855 |
+
"play",
|
| 856 |
+
"play-backwards",
|
| 857 |
+
"play-forwards",
|
| 858 |
+
"play-once",
|
| 859 |
+
"plum",
|
| 860 |
+
"plus-darker",
|
| 861 |
+
"position",
|
| 862 |
+
"powderblue",
|
| 863 |
+
"preserve",
|
| 864 |
+
"preserve-3d",
|
| 865 |
+
"preserve-breaks",
|
| 866 |
+
"preserve-parent-color",
|
| 867 |
+
"preserve-spaces",
|
| 868 |
+
"progress-bar",
|
| 869 |
+
"progress-bar-value",
|
| 870 |
+
"progressbar",
|
| 871 |
+
"progressbar-vertical",
|
| 872 |
+
"progresschunk",
|
| 873 |
+
"progresschunk-vertical",
|
| 874 |
+
"proportional-nums",
|
| 875 |
+
"proportional-width",
|
| 876 |
+
"proximity",
|
| 877 |
+
"pt",
|
| 878 |
+
"push-button",
|
| 879 |
+
"px",
|
| 880 |
+
"radio",
|
| 881 |
+
"radio-container",
|
| 882 |
+
"radio-label",
|
| 883 |
+
"radiomenuitem",
|
| 884 |
+
"railed",
|
| 885 |
+
"range",
|
| 886 |
+
"range-thumb",
|
| 887 |
+
"raw-string",
|
| 888 |
+
"read-only",
|
| 889 |
+
"read-write",
|
| 890 |
+
"read-write-plaintext-only",
|
| 891 |
+
"rebeccapurple",
|
| 892 |
+
"recto",
|
| 893 |
+
"region",
|
| 894 |
+
"rem",
|
| 895 |
+
"replace",
|
| 896 |
+
"replay",
|
| 897 |
+
"reset",
|
| 898 |
+
"resizer",
|
| 899 |
+
"resizerpanel",
|
| 900 |
+
"right-bottom",
|
| 901 |
+
"right-middle",
|
| 902 |
+
"right-top",
|
| 903 |
+
"rl",
|
| 904 |
+
"rlh",
|
| 905 |
+
"root",
|
| 906 |
+
"rosybrown",
|
| 907 |
+
"row-resize",
|
| 908 |
+
"royalblue",
|
| 909 |
+
"ruby",
|
| 910 |
+
"ruby-base",
|
| 911 |
+
"ruby-base-container",
|
| 912 |
+
"ruby-text",
|
| 913 |
+
"ruby-text-container",
|
| 914 |
+
"run-in",
|
| 915 |
+
"s",
|
| 916 |
+
"s-resize",
|
| 917 |
+
"saddlebrown",
|
| 918 |
+
"salmon",
|
| 919 |
+
"sandybrown",
|
| 920 |
+
"scale-down",
|
| 921 |
+
"scale-horizontal",
|
| 922 |
+
"scale-vertical",
|
| 923 |
+
"scalethumb-horizontal",
|
| 924 |
+
"scalethumb-vertical",
|
| 925 |
+
"scalethumbend",
|
| 926 |
+
"scalethumbstart",
|
| 927 |
+
"scalethumbtick",
|
| 928 |
+
"scoop",
|
| 929 |
+
"scroll-position",
|
| 930 |
+
"scrollbar",
|
| 931 |
+
"scrollbarbutton-down",
|
| 932 |
+
"scrollbarbutton-left",
|
| 933 |
+
"scrollbarbutton-right",
|
| 934 |
+
"scrollbarbutton-up",
|
| 935 |
+
"scrollbarthumb-horizontal",
|
| 936 |
+
"scrollbarthumb-vertical",
|
| 937 |
+
"scrollbartrack-horizontal",
|
| 938 |
+
"scrollbartrack-vertical",
|
| 939 |
+
"se-resize",
|
| 940 |
+
"seagreen",
|
| 941 |
+
"searchfield",
|
| 942 |
+
"searchfield-cancel-button",
|
| 943 |
+
"searchfield-decoration",
|
| 944 |
+
"searchfield-results-button",
|
| 945 |
+
"searchfield-results-decoration",
|
| 946 |
+
"select",
|
| 947 |
+
"select-after",
|
| 948 |
+
"select-all",
|
| 949 |
+
"select-before",
|
| 950 |
+
"select-menu",
|
| 951 |
+
"select-same",
|
| 952 |
+
"self",
|
| 953 |
+
"self-block",
|
| 954 |
+
"self-block-end",
|
| 955 |
+
"self-block-start",
|
| 956 |
+
"self-inline",
|
| 957 |
+
"self-inline-end",
|
| 958 |
+
"self-inline-start",
|
| 959 |
+
"semi-condensed",
|
| 960 |
+
"semi-expanded",
|
| 961 |
+
"separator",
|
| 962 |
+
"sesame",
|
| 963 |
+
"sheet",
|
| 964 |
+
"show",
|
| 965 |
+
"shrink",
|
| 966 |
+
"sides",
|
| 967 |
+
"sideways-lr",
|
| 968 |
+
"sideways-rl",
|
| 969 |
+
"sienna",
|
| 970 |
+
"simplified",
|
| 971 |
+
"single",
|
| 972 |
+
"skyblue",
|
| 973 |
+
"slashed-zero",
|
| 974 |
+
"slateblue",
|
| 975 |
+
"slice",
|
| 976 |
+
"slider-horizontal",
|
| 977 |
+
"slider-vertical",
|
| 978 |
+
"sliderthumb-horizontal",
|
| 979 |
+
"sliderthumb-vertical",
|
| 980 |
+
"small",
|
| 981 |
+
"small-caption",
|
| 982 |
+
"smaller",
|
| 983 |
+
"source-atop",
|
| 984 |
+
"source-in",
|
| 985 |
+
"source-order",
|
| 986 |
+
"source-out",
|
| 987 |
+
"source-over",
|
| 988 |
+
"space-all",
|
| 989 |
+
"space-first",
|
| 990 |
+
"spaces",
|
| 991 |
+
"span-all",
|
| 992 |
+
"span-block-end",
|
| 993 |
+
"span-block-start",
|
| 994 |
+
"span-bottom",
|
| 995 |
+
"span-end",
|
| 996 |
+
"span-inline-end",
|
| 997 |
+
"span-inline-start",
|
| 998 |
+
"span-left",
|
| 999 |
+
"span-right",
|
| 1000 |
+
"span-self-block-end",
|
| 1001 |
+
"span-self-block-start",
|
| 1002 |
+
"span-self-end",
|
| 1003 |
+
"span-self-inline-end",
|
| 1004 |
+
"span-self-inline-start",
|
| 1005 |
+
"span-self-start",
|
| 1006 |
+
"span-start",
|
| 1007 |
+
"span-top",
|
| 1008 |
+
"span-x-end",
|
| 1009 |
+
"span-x-self-end",
|
| 1010 |
+
"span-x-self-start",
|
| 1011 |
+
"span-x-start",
|
| 1012 |
+
"span-y-end",
|
| 1013 |
+
"span-y-self-end",
|
| 1014 |
+
"span-y-self-start",
|
| 1015 |
+
"span-y-start",
|
| 1016 |
+
"spelling-error",
|
| 1017 |
+
"spinner",
|
| 1018 |
+
"spinner-downbutton",
|
| 1019 |
+
"spinner-textfield",
|
| 1020 |
+
"spinner-upbutton",
|
| 1021 |
+
"splitter",
|
| 1022 |
+
"springgreen",
|
| 1023 |
+
"square",
|
| 1024 |
+
"square-button",
|
| 1025 |
+
"squircle",
|
| 1026 |
+
"stable",
|
| 1027 |
+
"stacked-fractions",
|
| 1028 |
+
"standard",
|
| 1029 |
+
"status-bar",
|
| 1030 |
+
"statusbar",
|
| 1031 |
+
"statusbarpanel",
|
| 1032 |
+
"steelblue",
|
| 1033 |
+
"stretch-to-fit",
|
| 1034 |
+
"string",
|
| 1035 |
+
"stroke-opacity",
|
| 1036 |
+
"style",
|
| 1037 |
+
"styleset",
|
| 1038 |
+
"stylistic",
|
| 1039 |
+
"sub",
|
| 1040 |
+
"subtract",
|
| 1041 |
+
"super",
|
| 1042 |
+
"sw-resize",
|
| 1043 |
+
"swash",
|
| 1044 |
+
"symbolic",
|
| 1045 |
+
"tab",
|
| 1046 |
+
"tab-scroll-arrow-back",
|
| 1047 |
+
"tab-scroll-arrow-forward",
|
| 1048 |
+
"table-caption",
|
| 1049 |
+
"table-column",
|
| 1050 |
+
"table-column-group",
|
| 1051 |
+
"table-footer-group",
|
| 1052 |
+
"table-header-group",
|
| 1053 |
+
"table-row-group",
|
| 1054 |
+
"tabpanel",
|
| 1055 |
+
"tabpanels",
|
| 1056 |
+
"tabular-nums",
|
| 1057 |
+
"tan",
|
| 1058 |
+
"tb",
|
| 1059 |
+
"text-after-edge",
|
| 1060 |
+
"text-before-edge",
|
| 1061 |
+
"text-bottom",
|
| 1062 |
+
"text-top",
|
| 1063 |
+
"textarea",
|
| 1064 |
+
"textfield",
|
| 1065 |
+
"textfield-multiline",
|
| 1066 |
+
"thistle",
|
| 1067 |
+
"time",
|
| 1068 |
+
"titling-caps",
|
| 1069 |
+
"to-zero",
|
| 1070 |
+
"toolbar",
|
| 1071 |
+
"toolbarbutton",
|
| 1072 |
+
"toolbarbutton-dropdown",
|
| 1073 |
+
"toolbargripper",
|
| 1074 |
+
"toolbox",
|
| 1075 |
+
"tooltip",
|
| 1076 |
+
"top-center",
|
| 1077 |
+
"top-left",
|
| 1078 |
+
"top-left-corner",
|
| 1079 |
+
"top-right",
|
| 1080 |
+
"top-right-corner",
|
| 1081 |
+
"touch",
|
| 1082 |
+
"traditional",
|
| 1083 |
+
"trailing-spaces",
|
| 1084 |
+
"treeheader",
|
| 1085 |
+
"treeheadercell",
|
| 1086 |
+
"treeheadersortarrow",
|
| 1087 |
+
"treeitem",
|
| 1088 |
+
"treeline",
|
| 1089 |
+
"treetwisty",
|
| 1090 |
+
"treetwistyopen",
|
| 1091 |
+
"treeview",
|
| 1092 |
+
"triangle",
|
| 1093 |
+
"trim-both",
|
| 1094 |
+
"trim-end",
|
| 1095 |
+
"trim-start",
|
| 1096 |
+
"true",
|
| 1097 |
+
"turquoise",
|
| 1098 |
+
"ultra-condensed",
|
| 1099 |
+
"ultra-expanded",
|
| 1100 |
+
"under",
|
| 1101 |
+
"underscore",
|
| 1102 |
+
"unicase",
|
| 1103 |
+
"unicode",
|
| 1104 |
+
"up",
|
| 1105 |
+
"vb",
|
| 1106 |
+
"verso",
|
| 1107 |
+
"vertical-lr",
|
| 1108 |
+
"vertical-rl",
|
| 1109 |
+
"vertical-text",
|
| 1110 |
+
"vertical-to-horizontal",
|
| 1111 |
+
"vh",
|
| 1112 |
+
"vi",
|
| 1113 |
+
"vmax",
|
| 1114 |
+
"vmin",
|
| 1115 |
+
"vw",
|
| 1116 |
+
"w-resize",
|
| 1117 |
+
"wavy",
|
| 1118 |
+
"weight",
|
| 1119 |
+
"wheat",
|
| 1120 |
+
"width",
|
| 1121 |
+
"wrap-reverse",
|
| 1122 |
+
"write-only",
|
| 1123 |
+
"x",
|
| 1124 |
+
"x-end",
|
| 1125 |
+
"x-large",
|
| 1126 |
+
"x-self-end",
|
| 1127 |
+
"x-self-start",
|
| 1128 |
+
"x-small",
|
| 1129 |
+
"x-start",
|
| 1130 |
+
"xor",
|
| 1131 |
+
"xx-large",
|
| 1132 |
+
"xx-small",
|
| 1133 |
+
"xxx-large",
|
| 1134 |
+
"y",
|
| 1135 |
+
"y-end",
|
| 1136 |
+
"y-self-end",
|
| 1137 |
+
"y-self-start",
|
| 1138 |
+
"y-start",
|
| 1139 |
+
"yellowgreen",
|
| 1140 |
+
"z",
|
| 1141 |
+
"zoom"
|
| 1142 |
+
],
|
| 1143 |
+
"knownProps": [
|
| 1144 |
+
"all",
|
| 1145 |
+
"appearance",
|
| 1146 |
+
"accent-color",
|
| 1147 |
+
"align-content",
|
| 1148 |
+
"align-items",
|
| 1149 |
+
"align-self",
|
| 1150 |
+
"align-tracks",
|
| 1151 |
+
"aspect-ratio",
|
| 1152 |
+
"backdrop-filter",
|
| 1153 |
+
"backface-visibility",
|
| 1154 |
+
"background",
|
| 1155 |
+
"background-attachment",
|
| 1156 |
+
"background-blend-mode",
|
| 1157 |
+
"background-clip",
|
| 1158 |
+
"background-color",
|
| 1159 |
+
"background-image",
|
| 1160 |
+
"background-origin",
|
| 1161 |
+
"background-position",
|
| 1162 |
+
"background-repeat",
|
| 1163 |
+
"background-size",
|
| 1164 |
+
"block-size",
|
| 1165 |
+
"border",
|
| 1166 |
+
"border-block",
|
| 1167 |
+
"border-block-color",
|
| 1168 |
+
"border-block-end",
|
| 1169 |
+
"border-block-end-color",
|
| 1170 |
+
"border-block-end-style",
|
| 1171 |
+
"border-block-end-width",
|
| 1172 |
+
"border-block-start",
|
| 1173 |
+
"border-block-start-color",
|
| 1174 |
+
"border-block-start-style",
|
| 1175 |
+
"border-block-start-width",
|
| 1176 |
+
"border-block-style",
|
| 1177 |
+
"border-block-width",
|
| 1178 |
+
"border-bottom",
|
| 1179 |
+
"border-bottom-color",
|
| 1180 |
+
"border-bottom-left-radius",
|
| 1181 |
+
"border-bottom-right-radius",
|
| 1182 |
+
"border-bottom-style",
|
| 1183 |
+
"border-bottom-width",
|
| 1184 |
+
"border-collapse",
|
| 1185 |
+
"border-color",
|
| 1186 |
+
"border-end-end-radius",
|
| 1187 |
+
"border-end-start-radius",
|
| 1188 |
+
"border-image",
|
| 1189 |
+
"border-image-outset",
|
| 1190 |
+
"border-image-repeat",
|
| 1191 |
+
"border-image-slice",
|
| 1192 |
+
"border-image-source",
|
| 1193 |
+
"border-image-width",
|
| 1194 |
+
"border-inline",
|
| 1195 |
+
"border-inline-color",
|
| 1196 |
+
"border-inline-end",
|
| 1197 |
+
"border-inline-end-color",
|
| 1198 |
+
"border-inline-end-style",
|
| 1199 |
+
"border-inline-end-width",
|
| 1200 |
+
"border-inline-start",
|
| 1201 |
+
"border-inline-start-color",
|
| 1202 |
+
"border-inline-start-style",
|
| 1203 |
+
"border-inline-start-width",
|
| 1204 |
+
"border-inline-style",
|
| 1205 |
+
"border-inline-width",
|
| 1206 |
+
"border-left",
|
| 1207 |
+
"border-left-color",
|
| 1208 |
+
"border-left-style",
|
| 1209 |
+
"border-left-width",
|
| 1210 |
+
"border-radius",
|
| 1211 |
+
"border-right",
|
| 1212 |
+
"border-right-color",
|
| 1213 |
+
"border-right-style",
|
| 1214 |
+
"border-right-width",
|
| 1215 |
+
"border-spacing",
|
| 1216 |
+
"border-start-end-radius",
|
| 1217 |
+
"border-start-start-radius",
|
| 1218 |
+
"border-style",
|
| 1219 |
+
"border-top",
|
| 1220 |
+
"border-top-color",
|
| 1221 |
+
"border-top-left-radius",
|
| 1222 |
+
"border-top-right-radius",
|
| 1223 |
+
"border-top-style",
|
| 1224 |
+
"border-top-width",
|
| 1225 |
+
"border-width",
|
| 1226 |
+
"bottom",
|
| 1227 |
+
"counter-reset",
|
| 1228 |
+
"counter-increment",
|
| 1229 |
+
"counter-set",
|
| 1230 |
+
"box-decoration-break",
|
| 1231 |
+
"box-shadow",
|
| 1232 |
+
"box-sizing",
|
| 1233 |
+
"break-after",
|
| 1234 |
+
"break-before",
|
| 1235 |
+
"break-inside",
|
| 1236 |
+
"caret-color",
|
| 1237 |
+
"caret-shape",
|
| 1238 |
+
"clear",
|
| 1239 |
+
"clip",
|
| 1240 |
+
"clip-path",
|
| 1241 |
+
"color",
|
| 1242 |
+
"color-scheme",
|
| 1243 |
+
"column-count",
|
| 1244 |
+
"column-fill",
|
| 1245 |
+
"column-gap",
|
| 1246 |
+
"column-rule",
|
| 1247 |
+
"column-rule-color",
|
| 1248 |
+
"column-rule-style",
|
| 1249 |
+
"column-rule-width",
|
| 1250 |
+
"column-span",
|
| 1251 |
+
"column-width",
|
| 1252 |
+
"columns",
|
| 1253 |
+
"contain",
|
| 1254 |
+
"contain-intrinsic-size",
|
| 1255 |
+
"container",
|
| 1256 |
+
"container-name",
|
| 1257 |
+
"container-type",
|
| 1258 |
+
"content",
|
| 1259 |
+
"content-visibility",
|
| 1260 |
+
"cursor",
|
| 1261 |
+
"caret",
|
| 1262 |
+
"display",
|
| 1263 |
+
"empty-cells",
|
| 1264 |
+
"filter",
|
| 1265 |
+
"flex",
|
| 1266 |
+
"flex-basis",
|
| 1267 |
+
"flex-direction",
|
| 1268 |
+
"flex-flow",
|
| 1269 |
+
"flex-grow",
|
| 1270 |
+
"flex-shrink",
|
| 1271 |
+
"flex-wrap",
|
| 1272 |
+
"float",
|
| 1273 |
+
"fill",
|
| 1274 |
+
"fill-rule",
|
| 1275 |
+
"fill-opacity",
|
| 1276 |
+
"stroke",
|
| 1277 |
+
"stroke-dasharray",
|
| 1278 |
+
"stroke-dashoffset",
|
| 1279 |
+
"stroke-linecap",
|
| 1280 |
+
"stroke-linejoin",
|
| 1281 |
+
"stroke-opacity",
|
| 1282 |
+
"stroke-width",
|
| 1283 |
+
"font",
|
| 1284 |
+
"font-family",
|
| 1285 |
+
"font-feature-settings",
|
| 1286 |
+
"font-kerning",
|
| 1287 |
+
"font-language-override",
|
| 1288 |
+
"font-optical-sizing",
|
| 1289 |
+
"font-palette",
|
| 1290 |
+
"font-size",
|
| 1291 |
+
"font-size-adjust",
|
| 1292 |
+
"font-stretch",
|
| 1293 |
+
"font-style",
|
| 1294 |
+
"font-synthesis",
|
| 1295 |
+
"font-variant",
|
| 1296 |
+
"font-variant-caps",
|
| 1297 |
+
"font-variant-east-asian",
|
| 1298 |
+
"font-variant-ligatures",
|
| 1299 |
+
"font-variant-numeric",
|
| 1300 |
+
"font-variant-position",
|
| 1301 |
+
"font-variation-settings",
|
| 1302 |
+
"font-weight",
|
| 1303 |
+
"forced-color-adjust",
|
| 1304 |
+
"gap",
|
| 1305 |
+
"grid",
|
| 1306 |
+
"grid-area",
|
| 1307 |
+
"grid-auto-columns",
|
| 1308 |
+
"grid-auto-flow",
|
| 1309 |
+
"grid-auto-rows",
|
| 1310 |
+
"grid-column",
|
| 1311 |
+
"grid-column-end",
|
| 1312 |
+
"grid-column-gap",
|
| 1313 |
+
"grid-column-start",
|
| 1314 |
+
"grid-gap",
|
| 1315 |
+
"grid-row",
|
| 1316 |
+
"grid-row-end",
|
| 1317 |
+
"grid-row-gap",
|
| 1318 |
+
"grid-row-start",
|
| 1319 |
+
"grid-template",
|
| 1320 |
+
"grid-template-areas",
|
| 1321 |
+
"grid-template-columns",
|
| 1322 |
+
"grid-template-rows",
|
| 1323 |
+
"hanging-punctuation",
|
| 1324 |
+
"height",
|
| 1325 |
+
"hyphenate-character",
|
| 1326 |
+
"hyphenate-limit-chars",
|
| 1327 |
+
"hyphens",
|
| 1328 |
+
"image-orientation",
|
| 1329 |
+
"image-rendering",
|
| 1330 |
+
"inline-size",
|
| 1331 |
+
"inset",
|
| 1332 |
+
"inset-block",
|
| 1333 |
+
"inset-block-end",
|
| 1334 |
+
"inset-block-start",
|
| 1335 |
+
"inset-inline",
|
| 1336 |
+
"inset-inline-end",
|
| 1337 |
+
"inset-inline-start",
|
| 1338 |
+
"isolation",
|
| 1339 |
+
"justify-content",
|
| 1340 |
+
"justify-items",
|
| 1341 |
+
"justify-self",
|
| 1342 |
+
"justify-tracks",
|
| 1343 |
+
"left",
|
| 1344 |
+
"letter-spacing",
|
| 1345 |
+
"line-break",
|
| 1346 |
+
"line-height",
|
| 1347 |
+
"list-style",
|
| 1348 |
+
"list-style-image",
|
| 1349 |
+
"list-style-position",
|
| 1350 |
+
"list-style-type",
|
| 1351 |
+
"margin",
|
| 1352 |
+
"margin-block",
|
| 1353 |
+
"margin-block-end",
|
| 1354 |
+
"margin-block-start",
|
| 1355 |
+
"margin-bottom",
|
| 1356 |
+
"margin-inline",
|
| 1357 |
+
"margin-inline-end",
|
| 1358 |
+
"margin-inline-start",
|
| 1359 |
+
"margin-left",
|
| 1360 |
+
"margin-right",
|
| 1361 |
+
"margin-top",
|
| 1362 |
+
"margin-trim",
|
| 1363 |
+
"mask",
|
| 1364 |
+
"mask-border",
|
| 1365 |
+
"mask-border-mode",
|
| 1366 |
+
"mask-border-outset",
|
| 1367 |
+
"mask-border-repeat",
|
| 1368 |
+
"mask-border-slice",
|
| 1369 |
+
"mask-border-source",
|
| 1370 |
+
"mask-border-width",
|
| 1371 |
+
"mask-clip",
|
| 1372 |
+
"mask-composite",
|
| 1373 |
+
"mask-image",
|
| 1374 |
+
"mask-mode",
|
| 1375 |
+
"mask-origin",
|
| 1376 |
+
"mask-position",
|
| 1377 |
+
"mask-repeat",
|
| 1378 |
+
"mask-size",
|
| 1379 |
+
"max-height",
|
| 1380 |
+
"max-inline-size",
|
| 1381 |
+
"max-width",
|
| 1382 |
+
"min-block-size",
|
| 1383 |
+
"min-height",
|
| 1384 |
+
"min-inline-size",
|
| 1385 |
+
"min-width",
|
| 1386 |
+
"mix-blend-mode",
|
| 1387 |
+
"object-fit",
|
| 1388 |
+
"object-position",
|
| 1389 |
+
"offset",
|
| 1390 |
+
"offset-anchor",
|
| 1391 |
+
"offset-distance",
|
| 1392 |
+
"offset-path",
|
| 1393 |
+
"offset-rotate",
|
| 1394 |
+
"opacity",
|
| 1395 |
+
"order",
|
| 1396 |
+
"outline",
|
| 1397 |
+
"outline-color",
|
| 1398 |
+
"outline-offset",
|
| 1399 |
+
"outline-style",
|
| 1400 |
+
"outline-width",
|
| 1401 |
+
"overflow",
|
| 1402 |
+
"overflow-anchor",
|
| 1403 |
+
"overflow-clip-margin",
|
| 1404 |
+
"overflow-wrap",
|
| 1405 |
+
"overflow-x",
|
| 1406 |
+
"overflow-y",
|
| 1407 |
+
"overscroll-behavior",
|
| 1408 |
+
"overscroll-behavior-block",
|
| 1409 |
+
"overscroll-behavior-inline",
|
| 1410 |
+
"overscroll-behavior-x",
|
| 1411 |
+
"overscroll-behavior-y",
|
| 1412 |
+
"padding",
|
| 1413 |
+
"padding-block",
|
| 1414 |
+
"padding-block-end",
|
| 1415 |
+
"padding-block-start",
|
| 1416 |
+
"padding-bottom",
|
| 1417 |
+
"padding-inline",
|
| 1418 |
+
"padding-inline-end",
|
| 1419 |
+
"padding-inline-start",
|
| 1420 |
+
"padding-left",
|
| 1421 |
+
"padding-right",
|
| 1422 |
+
"padding-top",
|
| 1423 |
+
"page-break-after",
|
| 1424 |
+
"page-break-before",
|
| 1425 |
+
"page-break-inside",
|
| 1426 |
+
"paint-order",
|
| 1427 |
+
"perspective",
|
| 1428 |
+
"perspective-origin",
|
| 1429 |
+
"place-content",
|
| 1430 |
+
"place-items",
|
| 1431 |
+
"place-self",
|
| 1432 |
+
"pointer-events",
|
| 1433 |
+
"position",
|
| 1434 |
+
"print-color-adjust",
|
| 1435 |
+
"quotes",
|
| 1436 |
+
"resize",
|
| 1437 |
+
"right",
|
| 1438 |
+
"rotate",
|
| 1439 |
+
"row-gap",
|
| 1440 |
+
"ruby-align",
|
| 1441 |
+
"ruby-merge",
|
| 1442 |
+
"scale",
|
| 1443 |
+
"scroll-behavior",
|
| 1444 |
+
"scroll-margin",
|
| 1445 |
+
"scroll-margin-block",
|
| 1446 |
+
"scroll-margin-block-end",
|
| 1447 |
+
"scroll-margin-block-start",
|
| 1448 |
+
"scroll-margin-bottom",
|
| 1449 |
+
"scroll-margin-inline",
|
| 1450 |
+
"scroll-margin-inline-end",
|
| 1451 |
+
"scroll-margin-inline-start",
|
| 1452 |
+
"scroll-margin-left",
|
| 1453 |
+
"scroll-margin-right",
|
| 1454 |
+
"scroll-margin-top",
|
| 1455 |
+
"scroll-padding",
|
| 1456 |
+
"scroll-padding-block",
|
| 1457 |
+
"scroll-padding-bottom",
|
| 1458 |
+
"scroll-padding-inline",
|
| 1459 |
+
"scroll-padding-left",
|
| 1460 |
+
"scroll-padding-right",
|
| 1461 |
+
"scroll-padding-top",
|
| 1462 |
+
"scroll-snap-align",
|
| 1463 |
+
"scroll-snap-stop",
|
| 1464 |
+
"scroll-snap-type",
|
| 1465 |
+
"scrollbar-color",
|
| 1466 |
+
"scrollbar-gutter",
|
| 1467 |
+
"scrollbar-width",
|
| 1468 |
+
"shape-image-threshold",
|
| 1469 |
+
"shape-margin",
|
| 1470 |
+
"shape-outside",
|
| 1471 |
+
"tab-size",
|
| 1472 |
+
"table-layout",
|
| 1473 |
+
"text-align",
|
| 1474 |
+
"text-align-last",
|
| 1475 |
+
"text-combine-upright",
|
| 1476 |
+
"text-decoration",
|
| 1477 |
+
"text-decoration-color",
|
| 1478 |
+
"text-decoration-line",
|
| 1479 |
+
"text-decoration-skip-ink",
|
| 1480 |
+
"text-decoration-style",
|
| 1481 |
+
"text-decoration-thickness",
|
| 1482 |
+
"text-emphasis",
|
| 1483 |
+
"text-emphasis-color",
|
| 1484 |
+
"text-emphasis-position",
|
| 1485 |
+
"text-emphasis-style",
|
| 1486 |
+
"text-indent",
|
| 1487 |
+
"text-justify",
|
| 1488 |
+
"text-orientation",
|
| 1489 |
+
"text-overflow",
|
| 1490 |
+
"text-rendering",
|
| 1491 |
+
"text-shadow",
|
| 1492 |
+
"text-transform",
|
| 1493 |
+
"text-underline-offset",
|
| 1494 |
+
"text-underline-position",
|
| 1495 |
+
"text-wrap",
|
| 1496 |
+
"top",
|
| 1497 |
+
"touch-action",
|
| 1498 |
+
"transform",
|
| 1499 |
+
"transform-box",
|
| 1500 |
+
"transform-origin",
|
| 1501 |
+
"transform-style",
|
| 1502 |
+
"transition",
|
| 1503 |
+
"transition-behavior",
|
| 1504 |
+
"transition-delay",
|
| 1505 |
+
"transition-duration",
|
| 1506 |
+
"transition-property",
|
| 1507 |
+
"transition-timing-function",
|
| 1508 |
+
"translate",
|
| 1509 |
+
"unicode-bidi",
|
| 1510 |
+
"user-select",
|
| 1511 |
+
"vertical-align",
|
| 1512 |
+
"visibility",
|
| 1513 |
+
"white-space",
|
| 1514 |
+
"white-space-collapse",
|
| 1515 |
+
"width",
|
| 1516 |
+
"will-change",
|
| 1517 |
+
"word-break",
|
| 1518 |
+
"word-spacing",
|
| 1519 |
+
"word-wrap",
|
| 1520 |
+
"writing-mode",
|
| 1521 |
+
"z-index",
|
| 1522 |
+
"zoom",
|
| 1523 |
+
"animation",
|
| 1524 |
+
"animation-composition",
|
| 1525 |
+
"animation-delay",
|
| 1526 |
+
"animation-direction",
|
| 1527 |
+
"animation-duration",
|
| 1528 |
+
"animation-fill-mode",
|
| 1529 |
+
"animation-iteration-count",
|
| 1530 |
+
"animation-name",
|
| 1531 |
+
"animation-play-state",
|
| 1532 |
+
"animation-range",
|
| 1533 |
+
"animation-timeline",
|
| 1534 |
+
"animation-timing-function",
|
| 1535 |
+
"view-transition-name",
|
| 1536 |
+
"interpolate-size",
|
| 1537 |
+
"text-box",
|
| 1538 |
+
"text-box-edge",
|
| 1539 |
+
"text-box-trim",
|
| 1540 |
+
"dynamic-range-limit",
|
| 1541 |
+
"field-sizing",
|
| 1542 |
+
"anchor-name",
|
| 1543 |
+
"position-anchor",
|
| 1544 |
+
"position-area",
|
| 1545 |
+
"scroll-timeline",
|
| 1546 |
+
"scroll-timeline-axis",
|
| 1547 |
+
"scroll-timeline-name",
|
| 1548 |
+
"timeline-scope",
|
| 1549 |
+
"view-timeline",
|
| 1550 |
+
"view-timeline-axis",
|
| 1551 |
+
"view-timeline-name",
|
| 1552 |
+
"-webkit-background-clip",
|
| 1553 |
+
"-webkit-text-fill-color",
|
| 1554 |
+
"-webkit-box-orient",
|
| 1555 |
+
"-webkit-line-clamp",
|
| 1556 |
+
"-webkit-tap-highlight-color",
|
| 1557 |
+
"-webkit-font-smoothing",
|
| 1558 |
+
"-moz-osx-font-smoothing",
|
| 1559 |
+
"-webkit-box-shadow",
|
| 1560 |
+
"-webkit-text-stroke",
|
| 1561 |
+
"-webkit-user-select",
|
| 1562 |
+
"-webkit-touch-callout",
|
| 1563 |
+
"-webkit-overflow-scrolling",
|
| 1564 |
+
"-webkit-appearance",
|
| 1565 |
+
"-moz-appearance",
|
| 1566 |
+
"-moz-binding",
|
| 1567 |
+
"-moz-border-bottom-colors",
|
| 1568 |
+
"-moz-border-left-colors",
|
| 1569 |
+
"-moz-border-right-colors",
|
| 1570 |
+
"-moz-border-top-colors",
|
| 1571 |
+
"-moz-context-properties",
|
| 1572 |
+
"-moz-float-edge",
|
| 1573 |
+
"-moz-force-broken-image-icon",
|
| 1574 |
+
"-moz-orient",
|
| 1575 |
+
"-moz-outline-radius",
|
| 1576 |
+
"-moz-outline-radius-bottomleft",
|
| 1577 |
+
"-moz-outline-radius-bottomright",
|
| 1578 |
+
"-moz-outline-radius-topleft",
|
| 1579 |
+
"-moz-outline-radius-topright",
|
| 1580 |
+
"-moz-stack-sizing",
|
| 1581 |
+
"-moz-text-blink",
|
| 1582 |
+
"-moz-user-focus",
|
| 1583 |
+
"-moz-user-input",
|
| 1584 |
+
"-moz-user-modify",
|
| 1585 |
+
"-moz-window-dragging",
|
| 1586 |
+
"-moz-window-shadow",
|
| 1587 |
+
"-ms-accelerator",
|
| 1588 |
+
"-ms-block-progression",
|
| 1589 |
+
"-ms-content-zoom-chaining",
|
| 1590 |
+
"-ms-content-zoom-limit",
|
| 1591 |
+
"-ms-content-zoom-limit-max",
|
| 1592 |
+
"-ms-content-zoom-limit-min",
|
| 1593 |
+
"-ms-content-zoom-snap",
|
| 1594 |
+
"-ms-content-zoom-snap-points",
|
| 1595 |
+
"-ms-content-zoom-snap-type",
|
| 1596 |
+
"-ms-content-zooming",
|
| 1597 |
+
"-ms-filter",
|
| 1598 |
+
"-ms-flow-from",
|
| 1599 |
+
"-ms-flow-into",
|
| 1600 |
+
"-ms-grid-columns",
|
| 1601 |
+
"-ms-grid-rows",
|
| 1602 |
+
"-ms-high-contrast-adjust",
|
| 1603 |
+
"-ms-hyphenate-limit-chars",
|
| 1604 |
+
"-ms-hyphenate-limit-lines",
|
| 1605 |
+
"-ms-hyphenate-limit-zone",
|
| 1606 |
+
"-ms-ime-align",
|
| 1607 |
+
"-ms-overflow-style",
|
| 1608 |
+
"-ms-scroll-chaining",
|
| 1609 |
+
"-ms-scroll-limit",
|
| 1610 |
+
"-ms-scroll-limit-x-max",
|
| 1611 |
+
"-ms-scroll-limit-x-min",
|
| 1612 |
+
"-ms-scroll-limit-y-max",
|
| 1613 |
+
"-ms-scroll-limit-y-min",
|
| 1614 |
+
"-ms-scroll-rails",
|
| 1615 |
+
"-ms-scroll-snap-points-x",
|
| 1616 |
+
"-ms-scroll-snap-points-y",
|
| 1617 |
+
"-ms-scroll-snap-type",
|
| 1618 |
+
"-ms-scroll-snap-x",
|
| 1619 |
+
"-ms-scroll-snap-y",
|
| 1620 |
+
"-ms-scroll-translation",
|
| 1621 |
+
"-ms-scrollbar-3dlight-color",
|
| 1622 |
+
"-ms-scrollbar-arrow-color",
|
| 1623 |
+
"-ms-scrollbar-base-color",
|
| 1624 |
+
"-ms-scrollbar-darkshadow-color",
|
| 1625 |
+
"-ms-scrollbar-face-color",
|
| 1626 |
+
"-ms-scrollbar-highlight-color",
|
| 1627 |
+
"-ms-scrollbar-shadow-color",
|
| 1628 |
+
"-ms-scrollbar-track-color",
|
| 1629 |
+
"-ms-text-autospace",
|
| 1630 |
+
"-ms-touch-select",
|
| 1631 |
+
"-ms-user-select",
|
| 1632 |
+
"-ms-wrap-flow",
|
| 1633 |
+
"-ms-wrap-margin",
|
| 1634 |
+
"-ms-wrap-through",
|
| 1635 |
+
"-webkit-border-after",
|
| 1636 |
+
"-webkit-border-after-color",
|
| 1637 |
+
"-webkit-border-after-style",
|
| 1638 |
+
"-webkit-border-after-width",
|
| 1639 |
+
"-webkit-border-before",
|
| 1640 |
+
"-webkit-border-before-color",
|
| 1641 |
+
"-webkit-border-before-style",
|
| 1642 |
+
"-webkit-border-before-width",
|
| 1643 |
+
"-webkit-border-end",
|
| 1644 |
+
"-webkit-border-end-color",
|
| 1645 |
+
"-webkit-border-end-style",
|
| 1646 |
+
"-webkit-border-end-width",
|
| 1647 |
+
"-webkit-border-start",
|
| 1648 |
+
"-webkit-border-start-color",
|
| 1649 |
+
"-webkit-border-start-style",
|
| 1650 |
+
"-webkit-border-start-width",
|
| 1651 |
+
"-webkit-box-reflect",
|
| 1652 |
+
"-webkit-mask",
|
| 1653 |
+
"-webkit-mask-attachment",
|
| 1654 |
+
"-webkit-mask-clip",
|
| 1655 |
+
"-webkit-mask-composite",
|
| 1656 |
+
"-webkit-mask-image",
|
| 1657 |
+
"-webkit-mask-origin",
|
| 1658 |
+
"-webkit-mask-position",
|
| 1659 |
+
"-webkit-mask-position-x",
|
| 1660 |
+
"-webkit-mask-position-y",
|
| 1661 |
+
"-webkit-mask-repeat",
|
| 1662 |
+
"-webkit-mask-repeat-x",
|
| 1663 |
+
"-webkit-mask-repeat-y",
|
| 1664 |
+
"-webkit-mask-size",
|
| 1665 |
+
"-webkit-text-stroke-color",
|
| 1666 |
+
"-webkit-text-stroke-width",
|
| 1667 |
+
"-webkit-user-modify",
|
| 1668 |
+
"alignment-baseline",
|
| 1669 |
+
"anchor-scope",
|
| 1670 |
+
"animation-range-end",
|
| 1671 |
+
"animation-range-start",
|
| 1672 |
+
"animation-trigger",
|
| 1673 |
+
"background-position-x",
|
| 1674 |
+
"background-position-y",
|
| 1675 |
+
"baseline-shift",
|
| 1676 |
+
"baseline-source",
|
| 1677 |
+
"border-shape",
|
| 1678 |
+
"box-align",
|
| 1679 |
+
"box-direction",
|
| 1680 |
+
"box-flex",
|
| 1681 |
+
"box-flex-group",
|
| 1682 |
+
"box-lines",
|
| 1683 |
+
"box-ordinal-group",
|
| 1684 |
+
"box-orient",
|
| 1685 |
+
"box-pack",
|
| 1686 |
+
"caption-side",
|
| 1687 |
+
"caret-animation",
|
| 1688 |
+
"clip-rule",
|
| 1689 |
+
"color-interpolation-filters",
|
| 1690 |
+
"column-height",
|
| 1691 |
+
"column-wrap",
|
| 1692 |
+
"contain-intrinsic-block-size",
|
| 1693 |
+
"contain-intrinsic-height",
|
| 1694 |
+
"contain-intrinsic-inline-size",
|
| 1695 |
+
"contain-intrinsic-width",
|
| 1696 |
+
"corner-block-end-shape",
|
| 1697 |
+
"corner-block-start-shape",
|
| 1698 |
+
"corner-bottom-left-shape",
|
| 1699 |
+
"corner-bottom-right-shape",
|
| 1700 |
+
"corner-bottom-shape",
|
| 1701 |
+
"corner-end-end-shape",
|
| 1702 |
+
"corner-end-start-shape",
|
| 1703 |
+
"corner-inline-end-shape",
|
| 1704 |
+
"corner-inline-start-shape",
|
| 1705 |
+
"corner-left-shape",
|
| 1706 |
+
"corner-right-shape",
|
| 1707 |
+
"corner-shape",
|
| 1708 |
+
"corner-start-end-shape",
|
| 1709 |
+
"corner-start-start-shape",
|
| 1710 |
+
"corner-top-left-shape",
|
| 1711 |
+
"corner-top-right-shape",
|
| 1712 |
+
"corner-top-shape",
|
| 1713 |
+
"cx",
|
| 1714 |
+
"cy",
|
| 1715 |
+
"d",
|
| 1716 |
+
"direction",
|
| 1717 |
+
"dominant-baseline",
|
| 1718 |
+
"flex-line-count",
|
| 1719 |
+
"flood-color",
|
| 1720 |
+
"flood-opacity",
|
| 1721 |
+
"font-smooth",
|
| 1722 |
+
"font-synthesis-position",
|
| 1723 |
+
"font-synthesis-small-caps",
|
| 1724 |
+
"font-synthesis-style",
|
| 1725 |
+
"font-synthesis-weight",
|
| 1726 |
+
"font-variant-alternates",
|
| 1727 |
+
"font-variant-emoji",
|
| 1728 |
+
"font-width",
|
| 1729 |
+
"frame-sizing",
|
| 1730 |
+
"image-resolution",
|
| 1731 |
+
"initial-letter",
|
| 1732 |
+
"initial-letter-align",
|
| 1733 |
+
"interactivity",
|
| 1734 |
+
"interest-delay",
|
| 1735 |
+
"interest-delay-end",
|
| 1736 |
+
"interest-delay-start",
|
| 1737 |
+
"lighting-color",
|
| 1738 |
+
"line-clamp",
|
| 1739 |
+
"line-height-step",
|
| 1740 |
+
"link-parameters",
|
| 1741 |
+
"marker",
|
| 1742 |
+
"marker-end",
|
| 1743 |
+
"marker-mid",
|
| 1744 |
+
"marker-start",
|
| 1745 |
+
"mask-type",
|
| 1746 |
+
"masonry-auto-flow",
|
| 1747 |
+
"math-depth",
|
| 1748 |
+
"math-shift",
|
| 1749 |
+
"math-style",
|
| 1750 |
+
"max-block-size",
|
| 1751 |
+
"max-lines",
|
| 1752 |
+
"object-view-box",
|
| 1753 |
+
"offset-position",
|
| 1754 |
+
"orphans",
|
| 1755 |
+
"overflow-block",
|
| 1756 |
+
"overflow-clip-box",
|
| 1757 |
+
"overflow-inline",
|
| 1758 |
+
"overlay",
|
| 1759 |
+
"page",
|
| 1760 |
+
"path-length",
|
| 1761 |
+
"position-try",
|
| 1762 |
+
"position-try-fallbacks",
|
| 1763 |
+
"position-try-order",
|
| 1764 |
+
"position-visibility",
|
| 1765 |
+
"r",
|
| 1766 |
+
"reading-flow",
|
| 1767 |
+
"reading-order",
|
| 1768 |
+
"ruby-overhang",
|
| 1769 |
+
"ruby-position",
|
| 1770 |
+
"rx",
|
| 1771 |
+
"ry",
|
| 1772 |
+
"scroll-axis-lock",
|
| 1773 |
+
"scroll-initial-target",
|
| 1774 |
+
"scroll-marker-group",
|
| 1775 |
+
"scroll-padding-block-end",
|
| 1776 |
+
"scroll-padding-block-start",
|
| 1777 |
+
"scroll-padding-inline-end",
|
| 1778 |
+
"scroll-padding-inline-start",
|
| 1779 |
+
"scroll-target-group",
|
| 1780 |
+
"shape-rendering",
|
| 1781 |
+
"speak-as",
|
| 1782 |
+
"stop-color",
|
| 1783 |
+
"stop-opacity",
|
| 1784 |
+
"stroke-color",
|
| 1785 |
+
"stroke-miterlimit",
|
| 1786 |
+
"text-anchor",
|
| 1787 |
+
"text-autospace",
|
| 1788 |
+
"text-decoration-inset",
|
| 1789 |
+
"text-decoration-skip",
|
| 1790 |
+
"text-fit",
|
| 1791 |
+
"text-size-adjust",
|
| 1792 |
+
"text-spacing-trim",
|
| 1793 |
+
"text-wrap-mode",
|
| 1794 |
+
"text-wrap-style",
|
| 1795 |
+
"timeline-trigger",
|
| 1796 |
+
"timeline-trigger-activation-range",
|
| 1797 |
+
"timeline-trigger-activation-range-end",
|
| 1798 |
+
"timeline-trigger-activation-range-start",
|
| 1799 |
+
"timeline-trigger-active-range",
|
| 1800 |
+
"timeline-trigger-active-range-end",
|
| 1801 |
+
"timeline-trigger-active-range-start",
|
| 1802 |
+
"timeline-trigger-name",
|
| 1803 |
+
"timeline-trigger-source",
|
| 1804 |
+
"trigger-scope",
|
| 1805 |
+
"vector-effect",
|
| 1806 |
+
"view-timeline-inset",
|
| 1807 |
+
"view-transition-class",
|
| 1808 |
+
"view-transition-scope",
|
| 1809 |
+
"widows",
|
| 1810 |
+
"window-drag",
|
| 1811 |
+
"x",
|
| 1812 |
+
"y"
|
| 1813 |
+
],
|
| 1814 |
+
"unitlessProps": [
|
| 1815 |
+
"opacity",
|
| 1816 |
+
"line-height",
|
| 1817 |
+
"z-index",
|
| 1818 |
+
"font-weight",
|
| 1819 |
+
"flex-grow",
|
| 1820 |
+
"flex-shrink",
|
| 1821 |
+
"flex",
|
| 1822 |
+
"order",
|
| 1823 |
+
"scale",
|
| 1824 |
+
"widows",
|
| 1825 |
+
"orphans",
|
| 1826 |
+
"column-count",
|
| 1827 |
+
"aspect-ratio",
|
| 1828 |
+
"animation-iteration-count",
|
| 1829 |
+
"flood-opacity",
|
| 1830 |
+
"fill-opacity",
|
| 1831 |
+
"stop-opacity",
|
| 1832 |
+
"shape-image-threshold",
|
| 1833 |
+
"counter-reset",
|
| 1834 |
+
"counter-increment",
|
| 1835 |
+
"counter-set",
|
| 1836 |
+
"grid-row",
|
| 1837 |
+
"grid-column",
|
| 1838 |
+
"grid-area",
|
| 1839 |
+
"font-feature-settings",
|
| 1840 |
+
"font-variation-settings",
|
| 1841 |
+
"tab-size",
|
| 1842 |
+
"-webkit-line-clamp",
|
| 1843 |
+
"line-clamp",
|
| 1844 |
+
"stroke-miterlimit",
|
| 1845 |
+
"stroke-opacity",
|
| 1846 |
+
"initial-letter",
|
| 1847 |
+
"font-size-adjust"
|
| 1848 |
+
],
|
| 1849 |
+
"timeProps": [
|
| 1850 |
+
"transition-delay",
|
| 1851 |
+
"transition-duration",
|
| 1852 |
+
"animation-delay",
|
| 1853 |
+
"animation-duration",
|
| 1854 |
+
"animation"
|
| 1855 |
+
],
|
| 1856 |
+
"unitlessFns": [
|
| 1857 |
+
"oklch",
|
| 1858 |
+
"oklab",
|
| 1859 |
+
"lab",
|
| 1860 |
+
"lch",
|
| 1861 |
+
"hsl",
|
| 1862 |
+
"hsla",
|
| 1863 |
+
"rgb",
|
| 1864 |
+
"rgba",
|
| 1865 |
+
"hwb",
|
| 1866 |
+
"color",
|
| 1867 |
+
"color-mix",
|
| 1868 |
+
"light-dark",
|
| 1869 |
+
"brightness",
|
| 1870 |
+
"saturate",
|
| 1871 |
+
"contrast",
|
| 1872 |
+
"grayscale",
|
| 1873 |
+
"sepia",
|
| 1874 |
+
"invert",
|
| 1875 |
+
"opacity",
|
| 1876 |
+
"scale",
|
| 1877 |
+
"scalex",
|
| 1878 |
+
"scaley",
|
| 1879 |
+
"scalez",
|
| 1880 |
+
"scale3d",
|
| 1881 |
+
"steps",
|
| 1882 |
+
"cubic-bezier",
|
| 1883 |
+
"linear",
|
| 1884 |
+
"radial",
|
| 1885 |
+
"conic"
|
| 1886 |
+
],
|
| 1887 |
+
"lengthFns": [
|
| 1888 |
+
"calc",
|
| 1889 |
+
"min",
|
| 1890 |
+
"max",
|
| 1891 |
+
"clamp",
|
| 1892 |
+
"round",
|
| 1893 |
+
"mod",
|
| 1894 |
+
"rem",
|
| 1895 |
+
"abs",
|
| 1896 |
+
"sign",
|
| 1897 |
+
"hypot",
|
| 1898 |
+
"pow",
|
| 1899 |
+
"sqrt",
|
| 1900 |
+
"log",
|
| 1901 |
+
"exp",
|
| 1902 |
+
"blur",
|
| 1903 |
+
"drop-shadow"
|
| 1904 |
+
],
|
| 1905 |
+
"colorWords": [
|
| 1906 |
+
"black",
|
| 1907 |
+
"silver",
|
| 1908 |
+
"gray",
|
| 1909 |
+
"white",
|
| 1910 |
+
"maroon",
|
| 1911 |
+
"red",
|
| 1912 |
+
"purple",
|
| 1913 |
+
"fuchsia",
|
| 1914 |
+
"green",
|
| 1915 |
+
"lime",
|
| 1916 |
+
"olive",
|
| 1917 |
+
"yellow",
|
| 1918 |
+
"navy",
|
| 1919 |
+
"blue",
|
| 1920 |
+
"teal",
|
| 1921 |
+
"aqua",
|
| 1922 |
+
"orange",
|
| 1923 |
+
"gold",
|
| 1924 |
+
"pink",
|
| 1925 |
+
"brown",
|
| 1926 |
+
"violet",
|
| 1927 |
+
"cyan",
|
| 1928 |
+
"magenta",
|
| 1929 |
+
"indigo",
|
| 1930 |
+
"crimson",
|
| 1931 |
+
"coral",
|
| 1932 |
+
"tomato",
|
| 1933 |
+
"goldenrod",
|
| 1934 |
+
"khaki",
|
| 1935 |
+
"slategray",
|
| 1936 |
+
"slategrey",
|
| 1937 |
+
"dimgray",
|
| 1938 |
+
"dimgrey",
|
| 1939 |
+
"lightgray",
|
| 1940 |
+
"lightgrey",
|
| 1941 |
+
"darkgray",
|
| 1942 |
+
"darkgrey",
|
| 1943 |
+
"gainsboro",
|
| 1944 |
+
"whitesmoke",
|
| 1945 |
+
"ghostwhite",
|
| 1946 |
+
"ivory",
|
| 1947 |
+
"beige",
|
| 1948 |
+
"linen",
|
| 1949 |
+
"seashell",
|
| 1950 |
+
"snow",
|
| 1951 |
+
"honeydew",
|
| 1952 |
+
"mintcream",
|
| 1953 |
+
"azure",
|
| 1954 |
+
"aliceblue",
|
| 1955 |
+
"lavender",
|
| 1956 |
+
"canvas",
|
| 1957 |
+
"canvastext",
|
| 1958 |
+
"linktext",
|
| 1959 |
+
"visitedtext",
|
| 1960 |
+
"activetext",
|
| 1961 |
+
"buttonface",
|
| 1962 |
+
"buttontext",
|
| 1963 |
+
"buttonborder",
|
| 1964 |
+
"field",
|
| 1965 |
+
"fieldtext",
|
| 1966 |
+
"highlight",
|
| 1967 |
+
"highlighttext",
|
| 1968 |
+
"currentcolor",
|
| 1969 |
+
"transparent"
|
| 1970 |
+
],
|
| 1971 |
+
"fluidProps": [
|
| 1972 |
+
"font-size",
|
| 1973 |
+
"width",
|
| 1974 |
+
"height",
|
| 1975 |
+
"inline-size",
|
| 1976 |
+
"block-size",
|
| 1977 |
+
"min-width",
|
| 1978 |
+
"max-width",
|
| 1979 |
+
"min-height",
|
| 1980 |
+
"max-height",
|
| 1981 |
+
"gap",
|
| 1982 |
+
"row-gap",
|
| 1983 |
+
"column-gap",
|
| 1984 |
+
"padding",
|
| 1985 |
+
"margin",
|
| 1986 |
+
"inset",
|
| 1987 |
+
"top",
|
| 1988 |
+
"right",
|
| 1989 |
+
"bottom",
|
| 1990 |
+
"left",
|
| 1991 |
+
"padding-top",
|
| 1992 |
+
"padding-right",
|
| 1993 |
+
"padding-bottom",
|
| 1994 |
+
"padding-left",
|
| 1995 |
+
"padding-inline",
|
| 1996 |
+
"padding-block",
|
| 1997 |
+
"margin-top",
|
| 1998 |
+
"margin-right",
|
| 1999 |
+
"margin-bottom",
|
| 2000 |
+
"margin-left",
|
| 2001 |
+
"margin-inline",
|
| 2002 |
+
"margin-block",
|
| 2003 |
+
"letter-spacing",
|
| 2004 |
+
"border-radius"
|
| 2005 |
+
],
|
| 2006 |
+
"placeWords": {
|
| 2007 |
+
"center": [
|
| 2008 |
+
"center",
|
| 2009 |
+
"center"
|
| 2010 |
+
],
|
| 2011 |
+
"start": [
|
| 2012 |
+
"start",
|
| 2013 |
+
"flex-start"
|
| 2014 |
+
],
|
| 2015 |
+
"end": [
|
| 2016 |
+
"end",
|
| 2017 |
+
"flex-end"
|
| 2018 |
+
],
|
| 2019 |
+
"between": [
|
| 2020 |
+
"center",
|
| 2021 |
+
"space-between"
|
| 2022 |
+
],
|
| 2023 |
+
"around": [
|
| 2024 |
+
"center",
|
| 2025 |
+
"space-around"
|
| 2026 |
+
],
|
| 2027 |
+
"evenly": [
|
| 2028 |
+
"center",
|
| 2029 |
+
"space-evenly"
|
| 2030 |
+
],
|
| 2031 |
+
"stretch": [
|
| 2032 |
+
"stretch",
|
| 2033 |
+
"flex-start"
|
| 2034 |
+
],
|
| 2035 |
+
"baseline": [
|
| 2036 |
+
"baseline",
|
| 2037 |
+
"flex-start"
|
| 2038 |
+
]
|
| 2039 |
+
},
|
| 2040 |
+
"easings": {
|
| 2041 |
+
"snap": "cubic-bezier(0.2, 0.9, 0.3, 1)",
|
| 2042 |
+
"smooth": "cubic-bezier(0.4, 0, 0.2, 1)",
|
| 2043 |
+
"bounce": "cubic-bezier(0.34, 1.56, 0.64, 1)",
|
| 2044 |
+
"linear": "linear",
|
| 2045 |
+
"ease": "ease",
|
| 2046 |
+
"ease-in": "ease-in",
|
| 2047 |
+
"ease-out": "ease-out",
|
| 2048 |
+
"ease-in-out": "ease-in-out"
|
| 2049 |
+
},
|
| 2050 |
+
"defaultTokens": {
|
| 2051 |
+
"color.ink": "#16161d",
|
| 2052 |
+
"color.paper": "#faf7f2",
|
| 2053 |
+
"color.card": "#ffffff",
|
| 2054 |
+
"color.muted": "#6f6a7a",
|
| 2055 |
+
"color.line": "#e5ded2",
|
| 2056 |
+
"color.accent": "oklch(62% 0.19 35)",
|
| 2057 |
+
"color.accent-ink": "#fff6ee",
|
| 2058 |
+
"color.ok": "#2e7d4f",
|
| 2059 |
+
"color.err": "#b3372e",
|
| 2060 |
+
"space.1": "4",
|
| 2061 |
+
"space.2": "8",
|
| 2062 |
+
"space.3": "12",
|
| 2063 |
+
"space.4": "16",
|
| 2064 |
+
"space.5": "24",
|
| 2065 |
+
"space.6": "32",
|
| 2066 |
+
"space.7": "48",
|
| 2067 |
+
"space.8": "64",
|
| 2068 |
+
"radius.sm": "8",
|
| 2069 |
+
"radius.md": "14",
|
| 2070 |
+
"radius.lg": "22",
|
| 2071 |
+
"radius.full": "999",
|
| 2072 |
+
"shadow.sm": "0 1 2 color.ink/8, 0 1 3 color.ink/6",
|
| 2073 |
+
"shadow.md": "0 2 4 color.ink/10, 0 4 12 color.ink/8",
|
| 2074 |
+
"shadow.lg": "0 4 8 color.ink/12, 0 12 32 color.ink/12",
|
| 2075 |
+
"shadow.xl": "0 8 16 color.ink/14, 0 24 64 color.ink/16",
|
| 2076 |
+
"font.sans": "system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif",
|
| 2077 |
+
"font.mono": "ui-monospace, SFMono-Regular, Menlo, Consolas, \"Liberation Mono\", monospace"
|
| 2078 |
+
},
|
| 2079 |
+
"semanticNames": [
|
| 2080 |
+
"size",
|
| 2081 |
+
"row",
|
| 2082 |
+
"column",
|
| 2083 |
+
"grid",
|
| 2084 |
+
"stack",
|
| 2085 |
+
"place",
|
| 2086 |
+
"center",
|
| 2087 |
+
"cover",
|
| 2088 |
+
"sticky",
|
| 2089 |
+
"font",
|
| 2090 |
+
"fluid",
|
| 2091 |
+
"shadow",
|
| 2092 |
+
"radius",
|
| 2093 |
+
"circle",
|
| 2094 |
+
"align",
|
| 2095 |
+
"z",
|
| 2096 |
+
"grow",
|
| 2097 |
+
"shrink",
|
| 2098 |
+
"basis",
|
| 2099 |
+
"truncate",
|
| 2100 |
+
"visually-hidden",
|
| 2101 |
+
"transition",
|
| 2102 |
+
"animate",
|
| 2103 |
+
"stagger",
|
| 2104 |
+
"overlap",
|
| 2105 |
+
"bend",
|
| 2106 |
+
"bend-y",
|
| 2107 |
+
"bend-up",
|
| 2108 |
+
"fold",
|
| 2109 |
+
"bend-around",
|
| 2110 |
+
"stretch",
|
| 2111 |
+
"gradient",
|
| 2112 |
+
"text-stroke",
|
| 2113 |
+
"yield",
|
| 2114 |
+
"outline-shape",
|
| 2115 |
+
"rotate",
|
| 2116 |
+
"gradient-text",
|
| 2117 |
+
"gradient-flow",
|
| 2118 |
+
"texture",
|
| 2119 |
+
"aura",
|
| 2120 |
+
"aura-glow",
|
| 2121 |
+
"aura-particle",
|
| 2122 |
+
"aura-particles",
|
| 2123 |
+
"glow-particle",
|
| 2124 |
+
"glow-particles",
|
| 2125 |
+
"aura-glow-particle",
|
| 2126 |
+
"aura-glow-particles",
|
| 2127 |
+
"glass",
|
| 2128 |
+
"tilt",
|
| 2129 |
+
"slider"
|
| 2130 |
+
],
|
| 2131 |
+
"namedColors": {
|
| 2132 |
+
"aliceblue": "#f0f8ff",
|
| 2133 |
+
"antiquewhite": "#faebd7",
|
| 2134 |
+
"aqua": "#00ffff",
|
| 2135 |
+
"aquamarine": "#7fffd4",
|
| 2136 |
+
"azure": "#f0ffff",
|
| 2137 |
+
"beige": "#f5f5dc",
|
| 2138 |
+
"bisque": "#ffe4c4",
|
| 2139 |
+
"black": "#000000",
|
| 2140 |
+
"blanchedalmond": "#ffebcd",
|
| 2141 |
+
"blue": "#0000ff",
|
| 2142 |
+
"blueviolet": "#8a2be2",
|
| 2143 |
+
"brown": "#a52a2a",
|
| 2144 |
+
"burlywood": "#deb887",
|
| 2145 |
+
"cadetblue": "#5f9ea0",
|
| 2146 |
+
"chartreuse": "#7fff00",
|
| 2147 |
+
"chocolate": "#d2691e",
|
| 2148 |
+
"coral": "#ff7f50",
|
| 2149 |
+
"cornflowerblue": "#6495ed",
|
| 2150 |
+
"cornsilk": "#fff8dc",
|
| 2151 |
+
"crimson": "#dc143c",
|
| 2152 |
+
"cyan": "#00ffff",
|
| 2153 |
+
"darkblue": "#00008b",
|
| 2154 |
+
"darkcyan": "#008b8b",
|
| 2155 |
+
"darkgoldenrod": "#b8860b",
|
| 2156 |
+
"darkgray": "#a9a9a9",
|
| 2157 |
+
"darkgreen": "#006400",
|
| 2158 |
+
"darkgrey": "#a9a9a9",
|
| 2159 |
+
"darkkhaki": "#bdb76b",
|
| 2160 |
+
"darkmagenta": "#8b008b",
|
| 2161 |
+
"darkolivegreen": "#556b2f",
|
| 2162 |
+
"darkorange": "#ff8c00",
|
| 2163 |
+
"darkorchid": "#9932cc",
|
| 2164 |
+
"darkred": "#8b0000",
|
| 2165 |
+
"darksalmon": "#e9967a",
|
| 2166 |
+
"darkseagreen": "#8fbc8f",
|
| 2167 |
+
"darkslateblue": "#483d8b",
|
| 2168 |
+
"darkslategray": "#2f4f4f",
|
| 2169 |
+
"darkslategrey": "#2f4f4f",
|
| 2170 |
+
"darkturquoise": "#00ced1",
|
| 2171 |
+
"darkviolet": "#9400d3",
|
| 2172 |
+
"deeppink": "#ff1493",
|
| 2173 |
+
"deepskyblue": "#00bfff",
|
| 2174 |
+
"dimgray": "#696969",
|
| 2175 |
+
"dimgrey": "#696969",
|
| 2176 |
+
"dodgerblue": "#1e90ff",
|
| 2177 |
+
"firebrick": "#b22222",
|
| 2178 |
+
"floralwhite": "#fffaf0",
|
| 2179 |
+
"forestgreen": "#228b22",
|
| 2180 |
+
"fuchsia": "#ff00ff",
|
| 2181 |
+
"gainsboro": "#dcdcdc",
|
| 2182 |
+
"ghostwhite": "#f8f8ff",
|
| 2183 |
+
"gold": "#ffd700",
|
| 2184 |
+
"goldenrod": "#daa520",
|
| 2185 |
+
"gray": "#808080",
|
| 2186 |
+
"green": "#008000",
|
| 2187 |
+
"greenyellow": "#adff2f",
|
| 2188 |
+
"grey": "#808080",
|
| 2189 |
+
"honeydew": "#f0fff0",
|
| 2190 |
+
"hotpink": "#ff69b4",
|
| 2191 |
+
"indianred": "#cd5c5c",
|
| 2192 |
+
"indigo": "#4b0082",
|
| 2193 |
+
"ivory": "#fffff0",
|
| 2194 |
+
"khaki": "#f0e68c",
|
| 2195 |
+
"lavender": "#e6e6fa",
|
| 2196 |
+
"lavenderblush": "#fff0f5",
|
| 2197 |
+
"lawngreen": "#7cfc00",
|
| 2198 |
+
"lemonchiffon": "#fffacd",
|
| 2199 |
+
"lightblue": "#add8e6",
|
| 2200 |
+
"lightcoral": "#f08080",
|
| 2201 |
+
"lightcyan": "#e0ffff",
|
| 2202 |
+
"lightgoldenrodyellow": "#fafad2",
|
| 2203 |
+
"lightgray": "#d3d3d3",
|
| 2204 |
+
"lightgreen": "#90ee90",
|
| 2205 |
+
"lightgrey": "#d3d3d3",
|
| 2206 |
+
"lightpink": "#ffb6c1",
|
| 2207 |
+
"lightsalmon": "#ffa07a",
|
| 2208 |
+
"lightseagreen": "#20b2aa",
|
| 2209 |
+
"lightskyblue": "#87cefa",
|
| 2210 |
+
"lightslategray": "#778899",
|
| 2211 |
+
"lightslategrey": "#778899",
|
| 2212 |
+
"lightsteelblue": "#b0c4de",
|
| 2213 |
+
"lightyellow": "#ffffe0",
|
| 2214 |
+
"lime": "#00ff00",
|
| 2215 |
+
"limegreen": "#32cd32",
|
| 2216 |
+
"linen": "#faf0e6",
|
| 2217 |
+
"magenta": "#ff00ff",
|
| 2218 |
+
"maroon": "#800000",
|
| 2219 |
+
"mediumaquamarine": "#66cdaa",
|
| 2220 |
+
"mediumblue": "#0000cd",
|
| 2221 |
+
"mediumorchid": "#ba55d3",
|
| 2222 |
+
"mediumpurple": "#9370db",
|
| 2223 |
+
"mediumseagreen": "#3cb371",
|
| 2224 |
+
"mediumslateblue": "#7b68ee",
|
| 2225 |
+
"mediumspringgreen": "#00fa9a",
|
| 2226 |
+
"mediumturquoise": "#48d1cc",
|
| 2227 |
+
"mediumvioletred": "#c71585",
|
| 2228 |
+
"midnightblue": "#191970",
|
| 2229 |
+
"mintcream": "#f5fffa",
|
| 2230 |
+
"mistyrose": "#ffe4e1",
|
| 2231 |
+
"moccasin": "#ffe4b5",
|
| 2232 |
+
"navajowhite": "#ffdead",
|
| 2233 |
+
"navy": "#000080",
|
| 2234 |
+
"oldlace": "#fdf5e6",
|
| 2235 |
+
"olive": "#808000",
|
| 2236 |
+
"olivedrab": "#6b8e23",
|
| 2237 |
+
"orange": "#ffa500",
|
| 2238 |
+
"orangered": "#ff4500",
|
| 2239 |
+
"orchid": "#da70d6",
|
| 2240 |
+
"palegoldenrod": "#eee8aa",
|
| 2241 |
+
"palegreen": "#98fb98",
|
| 2242 |
+
"paleturquoise": "#afeeee",
|
| 2243 |
+
"palevioletred": "#db7093",
|
| 2244 |
+
"papayawhip": "#ffefd5",
|
| 2245 |
+
"peachpuff": "#ffdab9",
|
| 2246 |
+
"peru": "#cd853f",
|
| 2247 |
+
"pink": "#ffc0cb",
|
| 2248 |
+
"plum": "#dda0dd",
|
| 2249 |
+
"powderblue": "#b0e0e6",
|
| 2250 |
+
"purple": "#800080",
|
| 2251 |
+
"rebeccapurple": "#663399",
|
| 2252 |
+
"red": "#ff0000",
|
| 2253 |
+
"rosybrown": "#bc8f8f",
|
| 2254 |
+
"royalblue": "#4169e1",
|
| 2255 |
+
"saddlebrown": "#8b4513",
|
| 2256 |
+
"salmon": "#fa8072",
|
| 2257 |
+
"sandybrown": "#f4a460",
|
| 2258 |
+
"seagreen": "#2e8b57",
|
| 2259 |
+
"seashell": "#fff5ee",
|
| 2260 |
+
"sienna": "#a0522d",
|
| 2261 |
+
"silver": "#c0c0c0",
|
| 2262 |
+
"skyblue": "#87ceeb",
|
| 2263 |
+
"slateblue": "#6a5acd",
|
| 2264 |
+
"slategray": "#708090",
|
| 2265 |
+
"slategrey": "#708090",
|
| 2266 |
+
"snow": "#fffafa",
|
| 2267 |
+
"springgreen": "#00ff7f",
|
| 2268 |
+
"steelblue": "#4682b4",
|
| 2269 |
+
"tan": "#d2b48c",
|
| 2270 |
+
"teal": "#008080",
|
| 2271 |
+
"thistle": "#d8bfd8",
|
| 2272 |
+
"tomato": "#ff6347",
|
| 2273 |
+
"turquoise": "#40e0d0",
|
| 2274 |
+
"violet": "#ee82ee",
|
| 2275 |
+
"wheat": "#f5deb3",
|
| 2276 |
+
"white": "#ffffff",
|
| 2277 |
+
"whitesmoke": "#f5f5f5",
|
| 2278 |
+
"yellow": "#ffff00",
|
| 2279 |
+
"yellowgreen": "#9acd32"
|
| 2280 |
+
},
|
| 2281 |
+
"texture": {
|
| 2282 |
+
"generators": [
|
| 2283 |
+
"noise",
|
| 2284 |
+
"bump",
|
| 2285 |
+
"lines",
|
| 2286 |
+
"dots",
|
| 2287 |
+
"grid",
|
| 2288 |
+
"checker",
|
| 2289 |
+
"weave",
|
| 2290 |
+
"carbon",
|
| 2291 |
+
"waves",
|
| 2292 |
+
"hex",
|
| 2293 |
+
"rings",
|
| 2294 |
+
"bricks",
|
| 2295 |
+
"herringbone",
|
| 2296 |
+
"plaid",
|
| 2297 |
+
"scales",
|
| 2298 |
+
"chevron",
|
| 2299 |
+
"diamonds",
|
| 2300 |
+
"triangles",
|
| 2301 |
+
"starfield",
|
| 2302 |
+
"terrazzo"
|
| 2303 |
+
],
|
| 2304 |
+
"blendModes": [
|
| 2305 |
+
"normal",
|
| 2306 |
+
"multiply",
|
| 2307 |
+
"screen",
|
| 2308 |
+
"overlay",
|
| 2309 |
+
"soft-light",
|
| 2310 |
+
"hard-light",
|
| 2311 |
+
"color-burn",
|
| 2312 |
+
"color-dodge",
|
| 2313 |
+
"darken",
|
| 2314 |
+
"lighten",
|
| 2315 |
+
"difference",
|
| 2316 |
+
"exclusion"
|
| 2317 |
+
],
|
| 2318 |
+
"keys": {
|
| 2319 |
+
"scale": {
|
| 2320 |
+
"words": 1,
|
| 2321 |
+
"kind": "number",
|
| 2322 |
+
"min": 0.1,
|
| 2323 |
+
"max": 2000,
|
| 2324 |
+
"doc": "feature size in px: how big the grains, cells or lines are"
|
| 2325 |
+
},
|
| 2326 |
+
"intensity": {
|
| 2327 |
+
"words": 1,
|
| 2328 |
+
"kind": "number",
|
| 2329 |
+
"min": 0,
|
| 2330 |
+
"max": 2,
|
| 2331 |
+
"doc": "how strong the layer is, 0 to 1 (more than 1 over-drives it)"
|
| 2332 |
+
},
|
| 2333 |
+
"contrast": {
|
| 2334 |
+
"words": 1,
|
| 2335 |
+
"kind": "number",
|
| 2336 |
+
"min": 0,
|
| 2337 |
+
"max": 40,
|
| 2338 |
+
"doc": "noise contrast: 1 is as generated, higher is harsher"
|
| 2339 |
+
},
|
| 2340 |
+
"threshold": {
|
| 2341 |
+
"words": 1,
|
| 2342 |
+
"kind": "number",
|
| 2343 |
+
"min": 0,
|
| 2344 |
+
"max": 1,
|
| 2345 |
+
"doc": "noise cut-off: only values above it show (glitter uses a high one)"
|
| 2346 |
+
},
|
| 2347 |
+
"contour": {
|
| 2348 |
+
"words": 1,
|
| 2349 |
+
"kind": "number",
|
| 2350 |
+
"min": 0.005,
|
| 2351 |
+
"max": 0.5,
|
| 2352 |
+
"doc": "draw thin lines where the noise crosses the threshold, instead of a plain cut: veins, rings, contours"
|
| 2353 |
+
},
|
| 2354 |
+
"octaves": {
|
| 2355 |
+
"words": 1,
|
| 2356 |
+
"kind": "number",
|
| 2357 |
+
"min": 1,
|
| 2358 |
+
"max": 8,
|
| 2359 |
+
"int": true,
|
| 2360 |
+
"doc": "noise detail layers, 1 is smooth, 5 is rough"
|
| 2361 |
+
},
|
| 2362 |
+
"seed": {
|
| 2363 |
+
"words": 1,
|
| 2364 |
+
"kind": "number",
|
| 2365 |
+
"min": 0,
|
| 2366 |
+
"max": 99999,
|
| 2367 |
+
"int": true,
|
| 2368 |
+
"doc": "a different random pattern with the same look"
|
| 2369 |
+
},
|
| 2370 |
+
"stretch": {
|
| 2371 |
+
"words": 2,
|
| 2372 |
+
"kind": "numbers",
|
| 2373 |
+
"min": 0.1,
|
| 2374 |
+
"max": 200,
|
| 2375 |
+
"doc": "stretch noise features along x and y, e.g. stretch 40 1 for wood grain"
|
| 2376 |
+
},
|
| 2377 |
+
"depth": {
|
| 2378 |
+
"words": 1,
|
| 2379 |
+
"kind": "number",
|
| 2380 |
+
"min": 0,
|
| 2381 |
+
"max": 30,
|
| 2382 |
+
"doc": "bump height: how deep the relief looks"
|
| 2383 |
+
},
|
| 2384 |
+
"light": {
|
| 2385 |
+
"words": 1,
|
| 2386 |
+
"kind": "number",
|
| 2387 |
+
"min": -360,
|
| 2388 |
+
"max": 360,
|
| 2389 |
+
"doc": "bump light direction in degrees"
|
| 2390 |
+
},
|
| 2391 |
+
"angle": {
|
| 2392 |
+
"words": 1,
|
| 2393 |
+
"kind": "number",
|
| 2394 |
+
"min": -360,
|
| 2395 |
+
"max": 360,
|
| 2396 |
+
"doc": "direction of lines and patterns, in degrees"
|
| 2397 |
+
},
|
| 2398 |
+
"thickness": {
|
| 2399 |
+
"words": 1,
|
| 2400 |
+
"kind": "number",
|
| 2401 |
+
"min": 0.1,
|
| 2402 |
+
"max": 500,
|
| 2403 |
+
"doc": "line or grid-line width in px"
|
| 2404 |
+
},
|
| 2405 |
+
"radius": {
|
| 2406 |
+
"words": 1,
|
| 2407 |
+
"kind": "number",
|
| 2408 |
+
"min": 0.02,
|
| 2409 |
+
"max": 1,
|
| 2410 |
+
"doc": "dot size as a fraction of the cell (plaid: how wide the bands are as a fraction of the repeat)"
|
| 2411 |
+
},
|
| 2412 |
+
"softness": {
|
| 2413 |
+
"words": 1,
|
| 2414 |
+
"kind": "number",
|
| 2415 |
+
"min": 0,
|
| 2416 |
+
"max": 1,
|
| 2417 |
+
"doc": "how soft the edges of dots and lines are"
|
| 2418 |
+
},
|
| 2419 |
+
"animate": {
|
| 2420 |
+
"words": 1,
|
| 2421 |
+
"kind": "number",
|
| 2422 |
+
"min": 0,
|
| 2423 |
+
"max": 60000,
|
| 2424 |
+
"doc": "milliseconds per shimmer step (film-grain flicker); 0 is still"
|
| 2425 |
+
},
|
| 2426 |
+
"type": {
|
| 2427 |
+
"words": 1,
|
| 2428 |
+
"kind": "word",
|
| 2429 |
+
"values": [
|
| 2430 |
+
"fractal",
|
| 2431 |
+
"turbulence"
|
| 2432 |
+
],
|
| 2433 |
+
"doc": "noise flavour: fractal is clouds, turbulence is veins"
|
| 2434 |
+
},
|
| 2435 |
+
"blend": {
|
| 2436 |
+
"words": 1,
|
| 2437 |
+
"kind": "word",
|
| 2438 |
+
"values": [
|
| 2439 |
+
"normal",
|
| 2440 |
+
"multiply",
|
| 2441 |
+
"screen",
|
| 2442 |
+
"overlay",
|
| 2443 |
+
"soft-light",
|
| 2444 |
+
"hard-light",
|
| 2445 |
+
"color-burn",
|
| 2446 |
+
"color-dodge",
|
| 2447 |
+
"darken",
|
| 2448 |
+
"lighten",
|
| 2449 |
+
"difference",
|
| 2450 |
+
"exclusion"
|
| 2451 |
+
],
|
| 2452 |
+
"doc": "how the layer mixes with what is under it"
|
| 2453 |
+
},
|
| 2454 |
+
"color": {
|
| 2455 |
+
"words": 1,
|
| 2456 |
+
"kind": "color",
|
| 2457 |
+
"doc": "the main colour (dark end of noise, ink of lines and dots)"
|
| 2458 |
+
},
|
| 2459 |
+
"color2": {
|
| 2460 |
+
"words": 1,
|
| 2461 |
+
"kind": "color",
|
| 2462 |
+
"doc": "the second colour (light end of noise, background cell of patterns)"
|
| 2463 |
+
},
|
| 2464 |
+
"figure": {
|
| 2465 |
+
"words": 1,
|
| 2466 |
+
"kind": "number",
|
| 2467 |
+
"min": 0,
|
| 2468 |
+
"max": 1,
|
| 2469 |
+
"doc": "rings generator: how strongly the growth rings arch into a cathedral figure, 0 is straight grain"
|
| 2470 |
+
},
|
| 2471 |
+
"warp": {
|
| 2472 |
+
"words": 1,
|
| 2473 |
+
"kind": "number",
|
| 2474 |
+
"min": 0,
|
| 2475 |
+
"max": 1,
|
| 2476 |
+
"doc": "rings generator: how much each ring wobbles along its length"
|
| 2477 |
+
},
|
| 2478 |
+
"pores": {
|
| 2479 |
+
"words": 1,
|
| 2480 |
+
"kind": "number",
|
| 2481 |
+
"min": 0,
|
| 2482 |
+
"max": 1,
|
| 2483 |
+
"doc": "rings generator: fine fibre and pore streaks between the rings"
|
| 2484 |
+
},
|
| 2485 |
+
"knots": {
|
| 2486 |
+
"words": 1,
|
| 2487 |
+
"kind": "number",
|
| 2488 |
+
"min": 0,
|
| 2489 |
+
"max": 8,
|
| 2490 |
+
"int": true,
|
| 2491 |
+
"doc": "rings generator: how many knots in one tile (the pattern repeats, so keep it small)"
|
| 2492 |
+
},
|
| 2493 |
+
"planks": {
|
| 2494 |
+
"words": 1,
|
| 2495 |
+
"kind": "number",
|
| 2496 |
+
"min": 24,
|
| 2497 |
+
"max": 1200,
|
| 2498 |
+
"doc": "rings generator: lay it out as planks this many px tall, with a seam and a slightly different board each"
|
| 2499 |
+
},
|
| 2500 |
+
"symmetrical": {
|
| 2501 |
+
"words": 1,
|
| 2502 |
+
"kind": "word",
|
| 2503 |
+
"values": [
|
| 2504 |
+
"both",
|
| 2505 |
+
"x",
|
| 2506 |
+
"y"
|
| 2507 |
+
],
|
| 2508 |
+
"optional": true,
|
| 2509 |
+
"doc": "mirror every other tile, so each edge meets its own reflection: no seam, and the repeat is twice as far apart. x mirrors left to right, y top to bottom, both (the default) does both. Works on the image-based textures (noise, bump, rings, waves, hex)."
|
| 2510 |
+
},
|
| 2511 |
+
"density": {
|
| 2512 |
+
"words": 1,
|
| 2513 |
+
"kind": "number",
|
| 2514 |
+
"min": 0.05,
|
| 2515 |
+
"max": 20,
|
| 2516 |
+
"doc": "starfield and terrazzo: how many stars or chips in a tile, 1 is normal"
|
| 2517 |
+
},
|
| 2518 |
+
"invert": {
|
| 2519 |
+
"words": 0,
|
| 2520 |
+
"kind": "flag",
|
| 2521 |
+
"doc": "swap the two colours"
|
| 2522 |
+
}
|
| 2523 |
+
},
|
| 2524 |
+
"presetNames": [
|
| 2525 |
+
"grain",
|
| 2526 |
+
"noise",
|
| 2527 |
+
"rough",
|
| 2528 |
+
"sand",
|
| 2529 |
+
"paper",
|
| 2530 |
+
"cloud",
|
| 2531 |
+
"concrete",
|
| 2532 |
+
"stone",
|
| 2533 |
+
"crumpled",
|
| 2534 |
+
"glitter",
|
| 2535 |
+
"frost",
|
| 2536 |
+
"marble",
|
| 2537 |
+
"wood",
|
| 2538 |
+
"oak",
|
| 2539 |
+
"walnut",
|
| 2540 |
+
"cherry",
|
| 2541 |
+
"maple",
|
| 2542 |
+
"pine",
|
| 2543 |
+
"mahogany",
|
| 2544 |
+
"ebony",
|
| 2545 |
+
"birch",
|
| 2546 |
+
"oak-planks",
|
| 2547 |
+
"walnut-planks",
|
| 2548 |
+
"bark",
|
| 2549 |
+
"leather",
|
| 2550 |
+
"brushed",
|
| 2551 |
+
"canvas",
|
| 2552 |
+
"linen",
|
| 2553 |
+
"denim",
|
| 2554 |
+
"carbon",
|
| 2555 |
+
"scanlines",
|
| 2556 |
+
"halftone",
|
| 2557 |
+
"dots",
|
| 2558 |
+
"lines",
|
| 2559 |
+
"grid",
|
| 2560 |
+
"checker",
|
| 2561 |
+
"crosshatch",
|
| 2562 |
+
"stripes",
|
| 2563 |
+
"waves",
|
| 2564 |
+
"hex",
|
| 2565 |
+
"bricks",
|
| 2566 |
+
"bricks-old",
|
| 2567 |
+
"herringbone",
|
| 2568 |
+
"plaid",
|
| 2569 |
+
"tartan",
|
| 2570 |
+
"gingham",
|
| 2571 |
+
"scales",
|
| 2572 |
+
"mermaid",
|
| 2573 |
+
"shingles",
|
| 2574 |
+
"chevron",
|
| 2575 |
+
"argyle",
|
| 2576 |
+
"lowpoly",
|
| 2577 |
+
"tiles",
|
| 2578 |
+
"blueprint",
|
| 2579 |
+
"granite",
|
| 2580 |
+
"slate",
|
| 2581 |
+
"sandstone",
|
| 2582 |
+
"terrazzo",
|
| 2583 |
+
"confetti",
|
| 2584 |
+
"rust",
|
| 2585 |
+
"corrugated",
|
| 2586 |
+
"cork",
|
| 2587 |
+
"kraft",
|
| 2588 |
+
"felt",
|
| 2589 |
+
"burlap",
|
| 2590 |
+
"stucco",
|
| 2591 |
+
"starfield",
|
| 2592 |
+
"snow",
|
| 2593 |
+
"grass",
|
| 2594 |
+
"water",
|
| 2595 |
+
"rain",
|
| 2596 |
+
"lava",
|
| 2597 |
+
"topo"
|
| 2598 |
+
],
|
| 2599 |
+
"presets": {
|
| 2600 |
+
"grain": {
|
| 2601 |
+
"doc": "fine film grain, neutral on any colour",
|
| 2602 |
+
"mask": true,
|
| 2603 |
+
"layers": [
|
| 2604 |
+
{
|
| 2605 |
+
"gen": "noise",
|
| 2606 |
+
"scale": 1.1,
|
| 2607 |
+
"octaves": 2,
|
| 2608 |
+
"contrast": 1.7,
|
| 2609 |
+
"intensity": 0.5,
|
| 2610 |
+
"color": "#000",
|
| 2611 |
+
"color2": "#fff",
|
| 2612 |
+
"blend": "overlay"
|
| 2613 |
+
}
|
| 2614 |
+
]
|
| 2615 |
+
},
|
| 2616 |
+
"noise": {
|
| 2617 |
+
"doc": "coarser static",
|
| 2618 |
+
"mask": true,
|
| 2619 |
+
"layers": [
|
| 2620 |
+
{
|
| 2621 |
+
"gen": "noise",
|
| 2622 |
+
"scale": 2.6,
|
| 2623 |
+
"octaves": 3,
|
| 2624 |
+
"contrast": 1.9,
|
| 2625 |
+
"intensity": 0.5,
|
| 2626 |
+
"color": "#000",
|
| 2627 |
+
"color2": "#fff",
|
| 2628 |
+
"blend": "overlay"
|
| 2629 |
+
}
|
| 2630 |
+
]
|
| 2631 |
+
},
|
| 2632 |
+
"rough": {
|
| 2633 |
+
"doc": "gritty relief, like a rough cast wall",
|
| 2634 |
+
"mask": true,
|
| 2635 |
+
"layers": [
|
| 2636 |
+
{
|
| 2637 |
+
"gen": "bump",
|
| 2638 |
+
"scale": 3,
|
| 2639 |
+
"octaves": 4,
|
| 2640 |
+
"depth": 3.4,
|
| 2641 |
+
"light": 135,
|
| 2642 |
+
"intensity": 0.75,
|
| 2643 |
+
"color": "#000",
|
| 2644 |
+
"color2": "#fff",
|
| 2645 |
+
"blend": "overlay"
|
| 2646 |
+
}
|
| 2647 |
+
]
|
| 2648 |
+
},
|
| 2649 |
+
"sand": {
|
| 2650 |
+
"doc": "warm fine sand grains",
|
| 2651 |
+
"mask": true,
|
| 2652 |
+
"layers": [
|
| 2653 |
+
{
|
| 2654 |
+
"gen": "bump",
|
| 2655 |
+
"scale": 1.5,
|
| 2656 |
+
"octaves": 3,
|
| 2657 |
+
"depth": 2.2,
|
| 2658 |
+
"light": 130,
|
| 2659 |
+
"intensity": 0.7,
|
| 2660 |
+
"color": "#5a4426",
|
| 2661 |
+
"color2": "#fff1d0",
|
| 2662 |
+
"blend": "overlay"
|
| 2663 |
+
}
|
| 2664 |
+
]
|
| 2665 |
+
},
|
| 2666 |
+
"paper": {
|
| 2667 |
+
"doc": "soft paper fibre with a little unevenness",
|
| 2668 |
+
"layers": [
|
| 2669 |
+
{
|
| 2670 |
+
"gen": "noise",
|
| 2671 |
+
"scale": 1.5,
|
| 2672 |
+
"octaves": 4,
|
| 2673 |
+
"contrast": 1.2,
|
| 2674 |
+
"intensity": 0.3,
|
| 2675 |
+
"color": "#000",
|
| 2676 |
+
"color2": "#fff",
|
| 2677 |
+
"blend": "overlay"
|
| 2678 |
+
},
|
| 2679 |
+
{
|
| 2680 |
+
"gen": "noise",
|
| 2681 |
+
"scale": 120,
|
| 2682 |
+
"octaves": 3,
|
| 2683 |
+
"contrast": 1.3,
|
| 2684 |
+
"intensity": 0.25,
|
| 2685 |
+
"color": "#000",
|
| 2686 |
+
"color2": "#fff",
|
| 2687 |
+
"blend": "soft-light",
|
| 2688 |
+
"seed": 7
|
| 2689 |
+
}
|
| 2690 |
+
]
|
| 2691 |
+
},
|
| 2692 |
+
"cloud": {
|
| 2693 |
+
"doc": "big soft cloudy variation",
|
| 2694 |
+
"mask": true,
|
| 2695 |
+
"layers": [
|
| 2696 |
+
{
|
| 2697 |
+
"gen": "noise",
|
| 2698 |
+
"scale": 90,
|
| 2699 |
+
"octaves": 5,
|
| 2700 |
+
"contrast": 1.6,
|
| 2701 |
+
"intensity": 0.7,
|
| 2702 |
+
"color": "#000",
|
| 2703 |
+
"color2": "#fff",
|
| 2704 |
+
"blend": "soft-light"
|
| 2705 |
+
}
|
| 2706 |
+
]
|
| 2707 |
+
},
|
| 2708 |
+
"concrete": {
|
| 2709 |
+
"doc": "pitted concrete",
|
| 2710 |
+
"layers": [
|
| 2711 |
+
{
|
| 2712 |
+
"gen": "bump",
|
| 2713 |
+
"scale": 6,
|
| 2714 |
+
"octaves": 5,
|
| 2715 |
+
"depth": 2.6,
|
| 2716 |
+
"light": 135,
|
| 2717 |
+
"intensity": 0.7,
|
| 2718 |
+
"color": "#000",
|
| 2719 |
+
"color2": "#fff",
|
| 2720 |
+
"blend": "overlay"
|
| 2721 |
+
},
|
| 2722 |
+
{
|
| 2723 |
+
"gen": "noise",
|
| 2724 |
+
"scale": 140,
|
| 2725 |
+
"octaves": 4,
|
| 2726 |
+
"contrast": 1.5,
|
| 2727 |
+
"intensity": 0.45,
|
| 2728 |
+
"color": "#000",
|
| 2729 |
+
"color2": "#fff",
|
| 2730 |
+
"blend": "soft-light",
|
| 2731 |
+
"seed": 3
|
| 2732 |
+
}
|
| 2733 |
+
]
|
| 2734 |
+
},
|
| 2735 |
+
"stone": {
|
| 2736 |
+
"doc": "carved stone with broad relief",
|
| 2737 |
+
"layers": [
|
| 2738 |
+
{
|
| 2739 |
+
"gen": "bump",
|
| 2740 |
+
"scale": 26,
|
| 2741 |
+
"octaves": 5,
|
| 2742 |
+
"depth": 2.4,
|
| 2743 |
+
"light": 125,
|
| 2744 |
+
"intensity": 0.75,
|
| 2745 |
+
"color": "#000",
|
| 2746 |
+
"color2": "#fff",
|
| 2747 |
+
"blend": "overlay"
|
| 2748 |
+
}
|
| 2749 |
+
]
|
| 2750 |
+
},
|
| 2751 |
+
"crumpled": {
|
| 2752 |
+
"doc": "crumpled foil or paper, big creases",
|
| 2753 |
+
"layers": [
|
| 2754 |
+
{
|
| 2755 |
+
"gen": "bump",
|
| 2756 |
+
"scale": 34,
|
| 2757 |
+
"octaves": 4,
|
| 2758 |
+
"depth": 4,
|
| 2759 |
+
"light": 135,
|
| 2760 |
+
"intensity": 0.8,
|
| 2761 |
+
"color": "#000",
|
| 2762 |
+
"color2": "#fff",
|
| 2763 |
+
"blend": "overlay",
|
| 2764 |
+
"seed": 11
|
| 2765 |
+
}
|
| 2766 |
+
]
|
| 2767 |
+
},
|
| 2768 |
+
"glitter": {
|
| 2769 |
+
"doc": "sparse bright sparkles",
|
| 2770 |
+
"mask": true,
|
| 2771 |
+
"layers": [
|
| 2772 |
+
{
|
| 2773 |
+
"gen": "noise",
|
| 2774 |
+
"scale": 1.2,
|
| 2775 |
+
"octaves": 1,
|
| 2776 |
+
"contrast": 16,
|
| 2777 |
+
"threshold": 0.66,
|
| 2778 |
+
"intensity": 1,
|
| 2779 |
+
"color": "rgba(255,255,255,0)",
|
| 2780 |
+
"color2": "#fff",
|
| 2781 |
+
"blend": "screen",
|
| 2782 |
+
"seed": 5
|
| 2783 |
+
}
|
| 2784 |
+
]
|
| 2785 |
+
},
|
| 2786 |
+
"frost": {
|
| 2787 |
+
"doc": "fine icy crystals",
|
| 2788 |
+
"layers": [
|
| 2789 |
+
{
|
| 2790 |
+
"gen": "bump",
|
| 2791 |
+
"scale": 2.2,
|
| 2792 |
+
"octaves": 4,
|
| 2793 |
+
"depth": 3.2,
|
| 2794 |
+
"light": 140,
|
| 2795 |
+
"intensity": 0.95,
|
| 2796 |
+
"color": "rgba(160,210,255,0)",
|
| 2797 |
+
"color2": "#ffffff",
|
| 2798 |
+
"blend": "screen"
|
| 2799 |
+
}
|
| 2800 |
+
]
|
| 2801 |
+
},
|
| 2802 |
+
"marble": {
|
| 2803 |
+
"doc": "veined marble",
|
| 2804 |
+
"layers": [
|
| 2805 |
+
{
|
| 2806 |
+
"gen": "noise",
|
| 2807 |
+
"scale": 120,
|
| 2808 |
+
"octaves": 5,
|
| 2809 |
+
"contour": 0.035,
|
| 2810 |
+
"threshold": 0.5,
|
| 2811 |
+
"intensity": 0.9,
|
| 2812 |
+
"color": "#6c6877",
|
| 2813 |
+
"color2": "rgba(247,245,240,0)",
|
| 2814 |
+
"blend": "multiply",
|
| 2815 |
+
"seed": 4
|
| 2816 |
+
},
|
| 2817 |
+
{
|
| 2818 |
+
"gen": "noise",
|
| 2819 |
+
"scale": 120,
|
| 2820 |
+
"octaves": 5,
|
| 2821 |
+
"contour": 0.16,
|
| 2822 |
+
"threshold": 0.5,
|
| 2823 |
+
"intensity": 0.25,
|
| 2824 |
+
"color": "#9b97a6",
|
| 2825 |
+
"color2": "rgba(247,245,240,0)",
|
| 2826 |
+
"blend": "multiply",
|
| 2827 |
+
"seed": 4
|
| 2828 |
+
},
|
| 2829 |
+
{
|
| 2830 |
+
"gen": "noise",
|
| 2831 |
+
"scale": 200,
|
| 2832 |
+
"octaves": 3,
|
| 2833 |
+
"contrast": 1.4,
|
| 2834 |
+
"intensity": 0.3,
|
| 2835 |
+
"color": "#cfc9c0",
|
| 2836 |
+
"color2": "#fbfaf7",
|
| 2837 |
+
"blend": "soft-light",
|
| 2838 |
+
"seed": 21
|
| 2839 |
+
}
|
| 2840 |
+
]
|
| 2841 |
+
},
|
| 2842 |
+
"wood": {
|
| 2843 |
+
"doc": "long wood grain, along x (use angle 90 for vertical)",
|
| 2844 |
+
"layers": [
|
| 2845 |
+
{
|
| 2846 |
+
"gen": "noise",
|
| 2847 |
+
"scale": 4,
|
| 2848 |
+
"octaves": 3,
|
| 2849 |
+
"contrast": 1.8,
|
| 2850 |
+
"stretch": [
|
| 2851 |
+
40,
|
| 2852 |
+
1
|
| 2853 |
+
],
|
| 2854 |
+
"intensity": 1,
|
| 2855 |
+
"color": "#7a4b24",
|
| 2856 |
+
"color2": "#c99a62",
|
| 2857 |
+
"blend": "multiply"
|
| 2858 |
+
}
|
| 2859 |
+
]
|
| 2860 |
+
},
|
| 2861 |
+
"oak": {
|
| 2862 |
+
"doc": "oak: open grain, tan with brown rings",
|
| 2863 |
+
"layers": [
|
| 2864 |
+
{
|
| 2865 |
+
"gen": "rings",
|
| 2866 |
+
"scale": 11,
|
| 2867 |
+
"color": "#8a5f33",
|
| 2868 |
+
"color2": "#c9a574",
|
| 2869 |
+
"contrast": 1.3,
|
| 2870 |
+
"figure": 0.55,
|
| 2871 |
+
"warp": 0.45,
|
| 2872 |
+
"pores": 0.5,
|
| 2873 |
+
"seed": 3,
|
| 2874 |
+
"blend": "normal"
|
| 2875 |
+
}
|
| 2876 |
+
]
|
| 2877 |
+
},
|
| 2878 |
+
"walnut": {
|
| 2879 |
+
"doc": "walnut: dark chocolate with black-brown rings",
|
| 2880 |
+
"layers": [
|
| 2881 |
+
{
|
| 2882 |
+
"gen": "rings",
|
| 2883 |
+
"scale": 9,
|
| 2884 |
+
"color": "#2b1a10",
|
| 2885 |
+
"color2": "#6a4631",
|
| 2886 |
+
"contrast": 1.2,
|
| 2887 |
+
"figure": 0.5,
|
| 2888 |
+
"warp": 0.55,
|
| 2889 |
+
"pores": 0.45,
|
| 2890 |
+
"seed": 8,
|
| 2891 |
+
"blend": "normal"
|
| 2892 |
+
}
|
| 2893 |
+
]
|
| 2894 |
+
},
|
| 2895 |
+
"cherry": {
|
| 2896 |
+
"doc": "cherry: warm red-brown with fine rings",
|
| 2897 |
+
"layers": [
|
| 2898 |
+
{
|
| 2899 |
+
"gen": "rings",
|
| 2900 |
+
"scale": 8,
|
| 2901 |
+
"color": "#7a3a1c",
|
| 2902 |
+
"color2": "#bb7443",
|
| 2903 |
+
"contrast": 1.1,
|
| 2904 |
+
"figure": 0.4,
|
| 2905 |
+
"warp": 0.35,
|
| 2906 |
+
"pores": 0.35,
|
| 2907 |
+
"seed": 5,
|
| 2908 |
+
"blend": "normal"
|
| 2909 |
+
}
|
| 2910 |
+
]
|
| 2911 |
+
},
|
| 2912 |
+
"maple": {
|
| 2913 |
+
"doc": "maple: pale, tight, nearly plain grain",
|
| 2914 |
+
"layers": [
|
| 2915 |
+
{
|
| 2916 |
+
"gen": "rings",
|
| 2917 |
+
"scale": 13,
|
| 2918 |
+
"color": "#c79a5a",
|
| 2919 |
+
"color2": "#ecd6ab",
|
| 2920 |
+
"contrast": 0.8,
|
| 2921 |
+
"figure": 0.25,
|
| 2922 |
+
"warp": 0.3,
|
| 2923 |
+
"pores": 0.25,
|
| 2924 |
+
"seed": 11,
|
| 2925 |
+
"blend": "normal"
|
| 2926 |
+
}
|
| 2927 |
+
]
|
| 2928 |
+
},
|
| 2929 |
+
"pine": {
|
| 2930 |
+
"doc": "pine: light yellow wood with wide rings and knots",
|
| 2931 |
+
"layers": [
|
| 2932 |
+
{
|
| 2933 |
+
"gen": "rings",
|
| 2934 |
+
"scale": 16,
|
| 2935 |
+
"color": "#b5742f",
|
| 2936 |
+
"color2": "#e6c081",
|
| 2937 |
+
"contrast": 1.4,
|
| 2938 |
+
"figure": 0.65,
|
| 2939 |
+
"warp": 0.5,
|
| 2940 |
+
"pores": 0.4,
|
| 2941 |
+
"knots": 2,
|
| 2942 |
+
"seed": 14,
|
| 2943 |
+
"blend": "normal"
|
| 2944 |
+
}
|
| 2945 |
+
]
|
| 2946 |
+
},
|
| 2947 |
+
"mahogany": {
|
| 2948 |
+
"doc": "mahogany: deep red-brown, straight grain",
|
| 2949 |
+
"layers": [
|
| 2950 |
+
{
|
| 2951 |
+
"gen": "rings",
|
| 2952 |
+
"scale": 10,
|
| 2953 |
+
"color": "#4a2012",
|
| 2954 |
+
"color2": "#8c4727",
|
| 2955 |
+
"contrast": 1.1,
|
| 2956 |
+
"figure": 0.3,
|
| 2957 |
+
"warp": 0.3,
|
| 2958 |
+
"pores": 0.4,
|
| 2959 |
+
"seed": 6,
|
| 2960 |
+
"blend": "normal"
|
| 2961 |
+
}
|
| 2962 |
+
]
|
| 2963 |
+
},
|
| 2964 |
+
"ebony": {
|
| 2965 |
+
"doc": "ebony: nearly black with faint streaks",
|
| 2966 |
+
"layers": [
|
| 2967 |
+
{
|
| 2968 |
+
"gen": "rings",
|
| 2969 |
+
"scale": 12,
|
| 2970 |
+
"color": "#0c0908",
|
| 2971 |
+
"color2": "#2d2621",
|
| 2972 |
+
"contrast": 0.7,
|
| 2973 |
+
"figure": 0.2,
|
| 2974 |
+
"warp": 0.25,
|
| 2975 |
+
"pores": 0.3,
|
| 2976 |
+
"seed": 2,
|
| 2977 |
+
"blend": "normal"
|
| 2978 |
+
}
|
| 2979 |
+
]
|
| 2980 |
+
},
|
| 2981 |
+
"birch": {
|
| 2982 |
+
"doc": "birch: creamy pale wood with fine rings",
|
| 2983 |
+
"layers": [
|
| 2984 |
+
{
|
| 2985 |
+
"gen": "rings",
|
| 2986 |
+
"scale": 10,
|
| 2987 |
+
"color": "#d2ae74",
|
| 2988 |
+
"color2": "#f0dfb9",
|
| 2989 |
+
"contrast": 0.9,
|
| 2990 |
+
"figure": 0.3,
|
| 2991 |
+
"warp": 0.35,
|
| 2992 |
+
"pores": 0.25,
|
| 2993 |
+
"seed": 9,
|
| 2994 |
+
"blend": "normal"
|
| 2995 |
+
}
|
| 2996 |
+
]
|
| 2997 |
+
},
|
| 2998 |
+
"oak-planks": {
|
| 2999 |
+
"doc": "oak laid as planks, with seams",
|
| 3000 |
+
"layers": [
|
| 3001 |
+
{
|
| 3002 |
+
"gen": "rings",
|
| 3003 |
+
"scale": 11,
|
| 3004 |
+
"color": "#8a5f33",
|
| 3005 |
+
"color2": "#c9a574",
|
| 3006 |
+
"contrast": 1.3,
|
| 3007 |
+
"figure": 0.55,
|
| 3008 |
+
"warp": 0.45,
|
| 3009 |
+
"pores": 0.5,
|
| 3010 |
+
"planks": 110,
|
| 3011 |
+
"seed": 3,
|
| 3012 |
+
"blend": "normal"
|
| 3013 |
+
}
|
| 3014 |
+
]
|
| 3015 |
+
},
|
| 3016 |
+
"walnut-planks": {
|
| 3017 |
+
"doc": "walnut laid as planks, with seams",
|
| 3018 |
+
"layers": [
|
| 3019 |
+
{
|
| 3020 |
+
"gen": "rings",
|
| 3021 |
+
"scale": 9,
|
| 3022 |
+
"color": "#2b1a10",
|
| 3023 |
+
"color2": "#6a4631",
|
| 3024 |
+
"contrast": 1.2,
|
| 3025 |
+
"figure": 0.5,
|
| 3026 |
+
"warp": 0.55,
|
| 3027 |
+
"pores": 0.45,
|
| 3028 |
+
"planks": 96,
|
| 3029 |
+
"seed": 8,
|
| 3030 |
+
"blend": "normal"
|
| 3031 |
+
}
|
| 3032 |
+
]
|
| 3033 |
+
},
|
| 3034 |
+
"bark": {
|
| 3035 |
+
"doc": "rough vertical bark",
|
| 3036 |
+
"layers": [
|
| 3037 |
+
{
|
| 3038 |
+
"gen": "bump",
|
| 3039 |
+
"scale": 10,
|
| 3040 |
+
"octaves": 4,
|
| 3041 |
+
"depth": 5,
|
| 3042 |
+
"stretch": [
|
| 3043 |
+
1,
|
| 3044 |
+
6
|
| 3045 |
+
],
|
| 3046 |
+
"light": 150,
|
| 3047 |
+
"intensity": 0.8,
|
| 3048 |
+
"color": "#000",
|
| 3049 |
+
"color2": "#fff",
|
| 3050 |
+
"blend": "overlay"
|
| 3051 |
+
}
|
| 3052 |
+
]
|
| 3053 |
+
},
|
| 3054 |
+
"leather": {
|
| 3055 |
+
"doc": "pebbled leather",
|
| 3056 |
+
"layers": [
|
| 3057 |
+
{
|
| 3058 |
+
"gen": "bump",
|
| 3059 |
+
"scale": 5,
|
| 3060 |
+
"octaves": 2,
|
| 3061 |
+
"depth": 4.2,
|
| 3062 |
+
"light": 120,
|
| 3063 |
+
"intensity": 0.85,
|
| 3064 |
+
"color": "#000",
|
| 3065 |
+
"color2": "#fff",
|
| 3066 |
+
"blend": "overlay"
|
| 3067 |
+
}
|
| 3068 |
+
]
|
| 3069 |
+
},
|
| 3070 |
+
"brushed": {
|
| 3071 |
+
"doc": "brushed metal, fine lines along x",
|
| 3072 |
+
"layers": [
|
| 3073 |
+
{
|
| 3074 |
+
"gen": "noise",
|
| 3075 |
+
"scale": 1.2,
|
| 3076 |
+
"octaves": 2,
|
| 3077 |
+
"contrast": 1.5,
|
| 3078 |
+
"stretch": [
|
| 3079 |
+
60,
|
| 3080 |
+
1
|
| 3081 |
+
],
|
| 3082 |
+
"intensity": 0.5,
|
| 3083 |
+
"color": "#000",
|
| 3084 |
+
"color2": "#fff",
|
| 3085 |
+
"blend": "overlay"
|
| 3086 |
+
}
|
| 3087 |
+
]
|
| 3088 |
+
},
|
| 3089 |
+
"canvas": {
|
| 3090 |
+
"doc": "artist canvas weave",
|
| 3091 |
+
"layers": [
|
| 3092 |
+
{
|
| 3093 |
+
"gen": "weave",
|
| 3094 |
+
"scale": 3,
|
| 3095 |
+
"thickness": 1,
|
| 3096 |
+
"intensity": 0.5,
|
| 3097 |
+
"color": "#000",
|
| 3098 |
+
"blend": "multiply"
|
| 3099 |
+
},
|
| 3100 |
+
{
|
| 3101 |
+
"gen": "noise",
|
| 3102 |
+
"scale": 1.4,
|
| 3103 |
+
"octaves": 3,
|
| 3104 |
+
"contrast": 1.3,
|
| 3105 |
+
"intensity": 0.3,
|
| 3106 |
+
"color": "#000",
|
| 3107 |
+
"color2": "#fff",
|
| 3108 |
+
"blend": "overlay"
|
| 3109 |
+
}
|
| 3110 |
+
]
|
| 3111 |
+
},
|
| 3112 |
+
"linen": {
|
| 3113 |
+
"doc": "loose linen weave with slubs",
|
| 3114 |
+
"layers": [
|
| 3115 |
+
{
|
| 3116 |
+
"gen": "weave",
|
| 3117 |
+
"scale": 4,
|
| 3118 |
+
"thickness": 1.2,
|
| 3119 |
+
"intensity": 0.4,
|
| 3120 |
+
"color": "#5a4a32",
|
| 3121 |
+
"blend": "multiply"
|
| 3122 |
+
},
|
| 3123 |
+
{
|
| 3124 |
+
"gen": "noise",
|
| 3125 |
+
"scale": 80,
|
| 3126 |
+
"octaves": 3,
|
| 3127 |
+
"contrast": 1.4,
|
| 3128 |
+
"stretch": [
|
| 3129 |
+
8,
|
| 3130 |
+
1
|
| 3131 |
+
],
|
| 3132 |
+
"intensity": 0.25,
|
| 3133 |
+
"color": "#000",
|
| 3134 |
+
"color2": "#fff",
|
| 3135 |
+
"blend": "soft-light",
|
| 3136 |
+
"seed": 9
|
| 3137 |
+
}
|
| 3138 |
+
]
|
| 3139 |
+
},
|
| 3140 |
+
"denim": {
|
| 3141 |
+
"doc": "diagonal twill, blue by default",
|
| 3142 |
+
"layers": [
|
| 3143 |
+
{
|
| 3144 |
+
"gen": "lines",
|
| 3145 |
+
"angle": 45,
|
| 3146 |
+
"scale": 3,
|
| 3147 |
+
"thickness": 1.4,
|
| 3148 |
+
"intensity": 0.45,
|
| 3149 |
+
"color": "#0d2147",
|
| 3150 |
+
"blend": "multiply"
|
| 3151 |
+
},
|
| 3152 |
+
{
|
| 3153 |
+
"gen": "noise",
|
| 3154 |
+
"scale": 1.3,
|
| 3155 |
+
"octaves": 3,
|
| 3156 |
+
"contrast": 1.4,
|
| 3157 |
+
"intensity": 0.3,
|
| 3158 |
+
"color": "#000",
|
| 3159 |
+
"color2": "#fff",
|
| 3160 |
+
"blend": "overlay",
|
| 3161 |
+
"seed": 2
|
| 3162 |
+
}
|
| 3163 |
+
]
|
| 3164 |
+
},
|
| 3165 |
+
"carbon": {
|
| 3166 |
+
"doc": "carbon fibre twill",
|
| 3167 |
+
"layers": [
|
| 3168 |
+
{
|
| 3169 |
+
"gen": "carbon",
|
| 3170 |
+
"scale": 20,
|
| 3171 |
+
"intensity": 1,
|
| 3172 |
+
"color": "#151515",
|
| 3173 |
+
"color2": "#262626",
|
| 3174 |
+
"blend": "normal"
|
| 3175 |
+
}
|
| 3176 |
+
]
|
| 3177 |
+
},
|
| 3178 |
+
"scanlines": {
|
| 3179 |
+
"doc": "CRT scanlines",
|
| 3180 |
+
"layers": [
|
| 3181 |
+
{
|
| 3182 |
+
"gen": "lines",
|
| 3183 |
+
"angle": 0,
|
| 3184 |
+
"scale": 4,
|
| 3185 |
+
"thickness": 2,
|
| 3186 |
+
"intensity": 0.28,
|
| 3187 |
+
"color": "#000",
|
| 3188 |
+
"blend": "normal"
|
| 3189 |
+
}
|
| 3190 |
+
]
|
| 3191 |
+
},
|
| 3192 |
+
"halftone": {
|
| 3193 |
+
"doc": "newsprint dots",
|
| 3194 |
+
"layers": [
|
| 3195 |
+
{
|
| 3196 |
+
"gen": "dots",
|
| 3197 |
+
"scale": 8,
|
| 3198 |
+
"radius": 0.2,
|
| 3199 |
+
"softness": 0.2,
|
| 3200 |
+
"intensity": 0.55,
|
| 3201 |
+
"color": "#000",
|
| 3202 |
+
"blend": "multiply",
|
| 3203 |
+
"stagger": true
|
| 3204 |
+
}
|
| 3205 |
+
]
|
| 3206 |
+
},
|
| 3207 |
+
"dots": {
|
| 3208 |
+
"doc": "a plain dot grid",
|
| 3209 |
+
"layers": [
|
| 3210 |
+
{
|
| 3211 |
+
"gen": "dots",
|
| 3212 |
+
"scale": 14,
|
| 3213 |
+
"radius": 0.16,
|
| 3214 |
+
"softness": 0.05,
|
| 3215 |
+
"intensity": 0.35,
|
| 3216 |
+
"color": "#000",
|
| 3217 |
+
"blend": "normal"
|
| 3218 |
+
}
|
| 3219 |
+
]
|
| 3220 |
+
},
|
| 3221 |
+
"lines": {
|
| 3222 |
+
"doc": "diagonal hairlines",
|
| 3223 |
+
"layers": [
|
| 3224 |
+
{
|
| 3225 |
+
"gen": "lines",
|
| 3226 |
+
"angle": 45,
|
| 3227 |
+
"scale": 8,
|
| 3228 |
+
"thickness": 1,
|
| 3229 |
+
"intensity": 0.3,
|
| 3230 |
+
"color": "#000",
|
| 3231 |
+
"blend": "normal"
|
| 3232 |
+
}
|
| 3233 |
+
]
|
| 3234 |
+
},
|
| 3235 |
+
"grid": {
|
| 3236 |
+
"doc": "a square grid, like graph paper",
|
| 3237 |
+
"layers": [
|
| 3238 |
+
{
|
| 3239 |
+
"gen": "grid",
|
| 3240 |
+
"scale": 24,
|
| 3241 |
+
"thickness": 1,
|
| 3242 |
+
"intensity": 0.25,
|
| 3243 |
+
"color": "#000",
|
| 3244 |
+
"blend": "normal"
|
| 3245 |
+
}
|
| 3246 |
+
]
|
| 3247 |
+
},
|
| 3248 |
+
"checker": {
|
| 3249 |
+
"doc": "checkerboard",
|
| 3250 |
+
"layers": [
|
| 3251 |
+
{
|
| 3252 |
+
"gen": "checker",
|
| 3253 |
+
"scale": 24,
|
| 3254 |
+
"intensity": 0.12,
|
| 3255 |
+
"color": "#000",
|
| 3256 |
+
"blend": "normal"
|
| 3257 |
+
}
|
| 3258 |
+
]
|
| 3259 |
+
},
|
| 3260 |
+
"crosshatch": {
|
| 3261 |
+
"doc": "crossed hairlines",
|
| 3262 |
+
"layers": [
|
| 3263 |
+
{
|
| 3264 |
+
"gen": "lines",
|
| 3265 |
+
"angle": 45,
|
| 3266 |
+
"scale": 6,
|
| 3267 |
+
"thickness": 1,
|
| 3268 |
+
"intensity": 0.28,
|
| 3269 |
+
"color": "#000",
|
| 3270 |
+
"blend": "normal"
|
| 3271 |
+
},
|
| 3272 |
+
{
|
| 3273 |
+
"gen": "lines",
|
| 3274 |
+
"angle": -45,
|
| 3275 |
+
"scale": 6,
|
| 3276 |
+
"thickness": 1,
|
| 3277 |
+
"intensity": 0.28,
|
| 3278 |
+
"color": "#000",
|
| 3279 |
+
"blend": "normal"
|
| 3280 |
+
}
|
| 3281 |
+
]
|
| 3282 |
+
},
|
| 3283 |
+
"stripes": {
|
| 3284 |
+
"doc": "bold diagonal stripes",
|
| 3285 |
+
"layers": [
|
| 3286 |
+
{
|
| 3287 |
+
"gen": "lines",
|
| 3288 |
+
"angle": 45,
|
| 3289 |
+
"scale": 32,
|
| 3290 |
+
"thickness": 16,
|
| 3291 |
+
"intensity": 0.12,
|
| 3292 |
+
"color": "#000",
|
| 3293 |
+
"blend": "normal"
|
| 3294 |
+
}
|
| 3295 |
+
]
|
| 3296 |
+
},
|
| 3297 |
+
"waves": {
|
| 3298 |
+
"doc": "soft repeating waves",
|
| 3299 |
+
"layers": [
|
| 3300 |
+
{
|
| 3301 |
+
"gen": "waves",
|
| 3302 |
+
"scale": 40,
|
| 3303 |
+
"thickness": 1.2,
|
| 3304 |
+
"intensity": 0.3,
|
| 3305 |
+
"color": "#000",
|
| 3306 |
+
"blend": "normal"
|
| 3307 |
+
}
|
| 3308 |
+
]
|
| 3309 |
+
},
|
| 3310 |
+
"hex": {
|
| 3311 |
+
"doc": "honeycomb",
|
| 3312 |
+
"layers": [
|
| 3313 |
+
{
|
| 3314 |
+
"gen": "hex",
|
| 3315 |
+
"scale": 28,
|
| 3316 |
+
"thickness": 1,
|
| 3317 |
+
"intensity": 0.28,
|
| 3318 |
+
"color": "#000",
|
| 3319 |
+
"blend": "normal"
|
| 3320 |
+
}
|
| 3321 |
+
]
|
| 3322 |
+
},
|
| 3323 |
+
"bricks": {
|
| 3324 |
+
"doc": "a red brick wall, light mortar",
|
| 3325 |
+
"layers": [
|
| 3326 |
+
{
|
| 3327 |
+
"gen": "bump",
|
| 3328 |
+
"scale": 3,
|
| 3329 |
+
"octaves": 3,
|
| 3330 |
+
"depth": 2.2,
|
| 3331 |
+
"light": 135,
|
| 3332 |
+
"intensity": 0.55,
|
| 3333 |
+
"color": "#000",
|
| 3334 |
+
"color2": "#fff",
|
| 3335 |
+
"blend": "overlay",
|
| 3336 |
+
"seed": 3
|
| 3337 |
+
},
|
| 3338 |
+
{
|
| 3339 |
+
"gen": "bricks",
|
| 3340 |
+
"scale": 56,
|
| 3341 |
+
"thickness": 3.5,
|
| 3342 |
+
"intensity": 1,
|
| 3343 |
+
"color": "#d9d0c4",
|
| 3344 |
+
"color2": "#a4402b",
|
| 3345 |
+
"blend": "normal"
|
| 3346 |
+
}
|
| 3347 |
+
]
|
| 3348 |
+
},
|
| 3349 |
+
"bricks-old": {
|
| 3350 |
+
"doc": "weathered dark brick",
|
| 3351 |
+
"layers": [
|
| 3352 |
+
{
|
| 3353 |
+
"gen": "noise",
|
| 3354 |
+
"scale": 40,
|
| 3355 |
+
"octaves": 4,
|
| 3356 |
+
"contrast": 1.5,
|
| 3357 |
+
"intensity": 0.5,
|
| 3358 |
+
"color": "#000",
|
| 3359 |
+
"color2": "#fff",
|
| 3360 |
+
"blend": "soft-light",
|
| 3361 |
+
"seed": 12
|
| 3362 |
+
},
|
| 3363 |
+
{
|
| 3364 |
+
"gen": "bump",
|
| 3365 |
+
"scale": 3,
|
| 3366 |
+
"octaves": 4,
|
| 3367 |
+
"depth": 3.2,
|
| 3368 |
+
"light": 135,
|
| 3369 |
+
"intensity": 0.7,
|
| 3370 |
+
"color": "#000",
|
| 3371 |
+
"color2": "#fff",
|
| 3372 |
+
"blend": "overlay",
|
| 3373 |
+
"seed": 5
|
| 3374 |
+
},
|
| 3375 |
+
{
|
| 3376 |
+
"gen": "bricks",
|
| 3377 |
+
"scale": 52,
|
| 3378 |
+
"thickness": 4,
|
| 3379 |
+
"intensity": 1,
|
| 3380 |
+
"color": "#6d665e",
|
| 3381 |
+
"color2": "#74301f",
|
| 3382 |
+
"blend": "normal"
|
| 3383 |
+
}
|
| 3384 |
+
]
|
| 3385 |
+
},
|
| 3386 |
+
"herringbone": {
|
| 3387 |
+
"doc": "parquet laid in a zigzag, every board a slightly different shade",
|
| 3388 |
+
"layers": [
|
| 3389 |
+
{
|
| 3390 |
+
"gen": "noise",
|
| 3391 |
+
"scale": 1.2,
|
| 3392 |
+
"octaves": 3,
|
| 3393 |
+
"contrast": 1.4,
|
| 3394 |
+
"stretch": [
|
| 3395 |
+
30,
|
| 3396 |
+
1
|
| 3397 |
+
],
|
| 3398 |
+
"intensity": 0.25,
|
| 3399 |
+
"color": "#000",
|
| 3400 |
+
"color2": "#fff",
|
| 3401 |
+
"blend": "overlay",
|
| 3402 |
+
"seed": 4
|
| 3403 |
+
},
|
| 3404 |
+
{
|
| 3405 |
+
"gen": "herringbone",
|
| 3406 |
+
"scale": 22,
|
| 3407 |
+
"thickness": 1.4,
|
| 3408 |
+
"intensity": 1,
|
| 3409 |
+
"color": "#2a1a0e",
|
| 3410 |
+
"color2": "#b9854d",
|
| 3411 |
+
"seed": 4,
|
| 3412 |
+
"blend": "normal"
|
| 3413 |
+
}
|
| 3414 |
+
]
|
| 3415 |
+
},
|
| 3416 |
+
"plaid": {
|
| 3417 |
+
"doc": "simple plaid: wide bands crossing, thin lines between",
|
| 3418 |
+
"layers": [
|
| 3419 |
+
{
|
| 3420 |
+
"gen": "plaid",
|
| 3421 |
+
"scale": 64,
|
| 3422 |
+
"thickness": 2,
|
| 3423 |
+
"intensity": 0.5,
|
| 3424 |
+
"color": "#9b1b1b",
|
| 3425 |
+
"blend": "multiply"
|
| 3426 |
+
}
|
| 3427 |
+
]
|
| 3428 |
+
},
|
| 3429 |
+
"tartan": {
|
| 3430 |
+
"doc": "a red tartan with green and navy bands",
|
| 3431 |
+
"layers": [
|
| 3432 |
+
{
|
| 3433 |
+
"gen": "plaid",
|
| 3434 |
+
"scale": 96,
|
| 3435 |
+
"thickness": 3,
|
| 3436 |
+
"radius": 0.18,
|
| 3437 |
+
"intensity": 0.6,
|
| 3438 |
+
"color": "#0f1f55",
|
| 3439 |
+
"blend": "multiply"
|
| 3440 |
+
},
|
| 3441 |
+
{
|
| 3442 |
+
"gen": "plaid",
|
| 3443 |
+
"scale": 48,
|
| 3444 |
+
"thickness": 2,
|
| 3445 |
+
"radius": 0.3,
|
| 3446 |
+
"intensity": 0.65,
|
| 3447 |
+
"color": "#12503a",
|
| 3448 |
+
"blend": "multiply"
|
| 3449 |
+
},
|
| 3450 |
+
{
|
| 3451 |
+
"gen": "plaid",
|
| 3452 |
+
"scale": 48,
|
| 3453 |
+
"thickness": 1,
|
| 3454 |
+
"radius": 0.001,
|
| 3455 |
+
"intensity": 1,
|
| 3456 |
+
"color": "#a11d24",
|
| 3457 |
+
"color2": "#a11d24",
|
| 3458 |
+
"blend": "normal"
|
| 3459 |
+
}
|
| 3460 |
+
]
|
| 3461 |
+
},
|
| 3462 |
+
"gingham": {
|
| 3463 |
+
"doc": "small checks, the picnic cloth",
|
| 3464 |
+
"layers": [
|
| 3465 |
+
{
|
| 3466 |
+
"gen": "plaid",
|
| 3467 |
+
"scale": 28,
|
| 3468 |
+
"thickness": 1,
|
| 3469 |
+
"radius": 0.5,
|
| 3470 |
+
"intensity": 0.5,
|
| 3471 |
+
"color": "#c0392b",
|
| 3472 |
+
"color2": "#ffffff",
|
| 3473 |
+
"blend": "normal"
|
| 3474 |
+
}
|
| 3475 |
+
]
|
| 3476 |
+
},
|
| 3477 |
+
"scales": {
|
| 3478 |
+
"doc": "overlapping scales",
|
| 3479 |
+
"layers": [
|
| 3480 |
+
{
|
| 3481 |
+
"gen": "scales",
|
| 3482 |
+
"scale": 36,
|
| 3483 |
+
"thickness": 1.2,
|
| 3484 |
+
"intensity": 0.4,
|
| 3485 |
+
"color": "#000",
|
| 3486 |
+
"blend": "normal"
|
| 3487 |
+
}
|
| 3488 |
+
]
|
| 3489 |
+
},
|
| 3490 |
+
"mermaid": {
|
| 3491 |
+
"doc": "teal fish scales",
|
| 3492 |
+
"layers": [
|
| 3493 |
+
{
|
| 3494 |
+
"gen": "scales",
|
| 3495 |
+
"scale": 34,
|
| 3496 |
+
"thickness": 1.4,
|
| 3497 |
+
"intensity": 1,
|
| 3498 |
+
"color": "#0a5560",
|
| 3499 |
+
"color2": "#1fa8a0",
|
| 3500 |
+
"blend": "normal"
|
| 3501 |
+
}
|
| 3502 |
+
]
|
| 3503 |
+
},
|
| 3504 |
+
"shingles": {
|
| 3505 |
+
"doc": "roof shingles",
|
| 3506 |
+
"layers": [
|
| 3507 |
+
{
|
| 3508 |
+
"gen": "scales",
|
| 3509 |
+
"scale": 60,
|
| 3510 |
+
"thickness": 2,
|
| 3511 |
+
"intensity": 1,
|
| 3512 |
+
"color": "#201c1a",
|
| 3513 |
+
"color2": "#5b4a42",
|
| 3514 |
+
"blend": "normal"
|
| 3515 |
+
}
|
| 3516 |
+
]
|
| 3517 |
+
},
|
| 3518 |
+
"chevron": {
|
| 3519 |
+
"doc": "zigzag bands",
|
| 3520 |
+
"layers": [
|
| 3521 |
+
{
|
| 3522 |
+
"gen": "chevron",
|
| 3523 |
+
"scale": 40,
|
| 3524 |
+
"thickness": 6,
|
| 3525 |
+
"intensity": 0.3,
|
| 3526 |
+
"color": "#000",
|
| 3527 |
+
"blend": "normal"
|
| 3528 |
+
}
|
| 3529 |
+
]
|
| 3530 |
+
},
|
| 3531 |
+
"argyle": {
|
| 3532 |
+
"doc": "a diamond lattice, filled",
|
| 3533 |
+
"layers": [
|
| 3534 |
+
{
|
| 3535 |
+
"gen": "diamonds",
|
| 3536 |
+
"scale": 44,
|
| 3537 |
+
"thickness": 1.4,
|
| 3538 |
+
"intensity": 0.9,
|
| 3539 |
+
"color": "#e8e0d0",
|
| 3540 |
+
"color2": "#2f3e6b",
|
| 3541 |
+
"blend": "normal"
|
| 3542 |
+
}
|
| 3543 |
+
]
|
| 3544 |
+
},
|
| 3545 |
+
"lowpoly": {
|
| 3546 |
+
"doc": "low-poly facets in two tones",
|
| 3547 |
+
"layers": [
|
| 3548 |
+
{
|
| 3549 |
+
"gen": "triangles",
|
| 3550 |
+
"scale": 72,
|
| 3551 |
+
"intensity": 0.5,
|
| 3552 |
+
"color": "#000",
|
| 3553 |
+
"color2": "#fff",
|
| 3554 |
+
"seed": 3,
|
| 3555 |
+
"blend": "overlay"
|
| 3556 |
+
}
|
| 3557 |
+
]
|
| 3558 |
+
},
|
| 3559 |
+
"tiles": {
|
| 3560 |
+
"doc": "square tiles with grout",
|
| 3561 |
+
"layers": [
|
| 3562 |
+
{
|
| 3563 |
+
"gen": "bump",
|
| 3564 |
+
"scale": 40,
|
| 3565 |
+
"octaves": 2,
|
| 3566 |
+
"depth": 1.4,
|
| 3567 |
+
"light": 135,
|
| 3568 |
+
"intensity": 0.4,
|
| 3569 |
+
"color": "#000",
|
| 3570 |
+
"color2": "#fff",
|
| 3571 |
+
"blend": "overlay",
|
| 3572 |
+
"seed": 6
|
| 3573 |
+
},
|
| 3574 |
+
{
|
| 3575 |
+
"gen": "grid",
|
| 3576 |
+
"scale": 64,
|
| 3577 |
+
"thickness": 3,
|
| 3578 |
+
"intensity": 0.5,
|
| 3579 |
+
"color": "#000",
|
| 3580 |
+
"blend": "normal"
|
| 3581 |
+
}
|
| 3582 |
+
]
|
| 3583 |
+
},
|
| 3584 |
+
"blueprint": {
|
| 3585 |
+
"doc": "drafting grid, fine and coarse",
|
| 3586 |
+
"layers": [
|
| 3587 |
+
{
|
| 3588 |
+
"gen": "grid",
|
| 3589 |
+
"scale": 100,
|
| 3590 |
+
"thickness": 1.4,
|
| 3591 |
+
"intensity": 0.5,
|
| 3592 |
+
"color": "#ffffff",
|
| 3593 |
+
"blend": "normal"
|
| 3594 |
+
},
|
| 3595 |
+
{
|
| 3596 |
+
"gen": "grid",
|
| 3597 |
+
"scale": 20,
|
| 3598 |
+
"thickness": 1,
|
| 3599 |
+
"intensity": 0.22,
|
| 3600 |
+
"color": "#ffffff",
|
| 3601 |
+
"blend": "normal"
|
| 3602 |
+
}
|
| 3603 |
+
]
|
| 3604 |
+
},
|
| 3605 |
+
"granite": {
|
| 3606 |
+
"doc": "speckled granite",
|
| 3607 |
+
"layers": [
|
| 3608 |
+
{
|
| 3609 |
+
"gen": "noise",
|
| 3610 |
+
"scale": 1.8,
|
| 3611 |
+
"octaves": 1,
|
| 3612 |
+
"contrast": 9,
|
| 3613 |
+
"threshold": 0.62,
|
| 3614 |
+
"intensity": 0.5,
|
| 3615 |
+
"color": "rgba(0,0,0,0)",
|
| 3616 |
+
"color2": "#000",
|
| 3617 |
+
"blend": "multiply",
|
| 3618 |
+
"seed": 2
|
| 3619 |
+
},
|
| 3620 |
+
{
|
| 3621 |
+
"gen": "noise",
|
| 3622 |
+
"scale": 1.8,
|
| 3623 |
+
"octaves": 1,
|
| 3624 |
+
"contrast": 9,
|
| 3625 |
+
"threshold": 0.7,
|
| 3626 |
+
"intensity": 0.55,
|
| 3627 |
+
"color": "rgba(255,255,255,0)",
|
| 3628 |
+
"color2": "#fff",
|
| 3629 |
+
"blend": "screen",
|
| 3630 |
+
"seed": 7
|
| 3631 |
+
},
|
| 3632 |
+
{
|
| 3633 |
+
"gen": "bump",
|
| 3634 |
+
"scale": 8,
|
| 3635 |
+
"octaves": 3,
|
| 3636 |
+
"depth": 1.2,
|
| 3637 |
+
"light": 135,
|
| 3638 |
+
"intensity": 0.4,
|
| 3639 |
+
"color": "#000",
|
| 3640 |
+
"color2": "#fff",
|
| 3641 |
+
"blend": "overlay",
|
| 3642 |
+
"seed": 4
|
| 3643 |
+
}
|
| 3644 |
+
]
|
| 3645 |
+
},
|
| 3646 |
+
"slate": {
|
| 3647 |
+
"doc": "layered slate",
|
| 3648 |
+
"layers": [
|
| 3649 |
+
{
|
| 3650 |
+
"gen": "bump",
|
| 3651 |
+
"scale": 18,
|
| 3652 |
+
"octaves": 4,
|
| 3653 |
+
"depth": 2.4,
|
| 3654 |
+
"stretch": [
|
| 3655 |
+
2.4,
|
| 3656 |
+
1
|
| 3657 |
+
],
|
| 3658 |
+
"light": 135,
|
| 3659 |
+
"intensity": 0.8,
|
| 3660 |
+
"color": "#000",
|
| 3661 |
+
"color2": "#fff",
|
| 3662 |
+
"blend": "overlay",
|
| 3663 |
+
"seed": 5
|
| 3664 |
+
},
|
| 3665 |
+
{
|
| 3666 |
+
"gen": "noise",
|
| 3667 |
+
"scale": 90,
|
| 3668 |
+
"octaves": 3,
|
| 3669 |
+
"contrast": 1.4,
|
| 3670 |
+
"intensity": 0.35,
|
| 3671 |
+
"color": "#000",
|
| 3672 |
+
"color2": "#fff",
|
| 3673 |
+
"blend": "soft-light",
|
| 3674 |
+
"seed": 8
|
| 3675 |
+
}
|
| 3676 |
+
]
|
| 3677 |
+
},
|
| 3678 |
+
"sandstone": {
|
| 3679 |
+
"doc": "banded sandstone",
|
| 3680 |
+
"layers": [
|
| 3681 |
+
{
|
| 3682 |
+
"gen": "bump",
|
| 3683 |
+
"scale": 3,
|
| 3684 |
+
"octaves": 3,
|
| 3685 |
+
"depth": 1.6,
|
| 3686 |
+
"light": 130,
|
| 3687 |
+
"intensity": 0.5,
|
| 3688 |
+
"color": "#000",
|
| 3689 |
+
"color2": "#fff",
|
| 3690 |
+
"blend": "overlay",
|
| 3691 |
+
"seed": 9
|
| 3692 |
+
},
|
| 3693 |
+
{
|
| 3694 |
+
"gen": "noise",
|
| 3695 |
+
"scale": 10,
|
| 3696 |
+
"octaves": 3,
|
| 3697 |
+
"contrast": 1.6,
|
| 3698 |
+
"stretch": [
|
| 3699 |
+
30,
|
| 3700 |
+
1
|
| 3701 |
+
],
|
| 3702 |
+
"intensity": 0.8,
|
| 3703 |
+
"color": "#8a5a3a",
|
| 3704 |
+
"color2": "#e2b784",
|
| 3705 |
+
"blend": "multiply",
|
| 3706 |
+
"seed": 14
|
| 3707 |
+
}
|
| 3708 |
+
]
|
| 3709 |
+
},
|
| 3710 |
+
"terrazzo": {
|
| 3711 |
+
"doc": "chips of stone in cement",
|
| 3712 |
+
"layers": [
|
| 3713 |
+
{
|
| 3714 |
+
"gen": "terrazzo",
|
| 3715 |
+
"scale": 240,
|
| 3716 |
+
"density": 1,
|
| 3717 |
+
"intensity": 0.9,
|
| 3718 |
+
"color": "#c9a98f",
|
| 3719 |
+
"color2": "#6b7a8f",
|
| 3720 |
+
"seed": 6,
|
| 3721 |
+
"blend": "normal"
|
| 3722 |
+
}
|
| 3723 |
+
]
|
| 3724 |
+
},
|
| 3725 |
+
"confetti": {
|
| 3726 |
+
"doc": "bright scraps scattered, flat",
|
| 3727 |
+
"layers": [
|
| 3728 |
+
{
|
| 3729 |
+
"gen": "terrazzo",
|
| 3730 |
+
"scale": 260,
|
| 3731 |
+
"density": 0.5,
|
| 3732 |
+
"intensity": 1,
|
| 3733 |
+
"color": "#ff4d6d",
|
| 3734 |
+
"color2": "#4dabf7",
|
| 3735 |
+
"seed": 11,
|
| 3736 |
+
"blend": "normal"
|
| 3737 |
+
}
|
| 3738 |
+
]
|
| 3739 |
+
},
|
| 3740 |
+
"rust": {
|
| 3741 |
+
"doc": "rusted metal",
|
| 3742 |
+
"layers": [
|
| 3743 |
+
{
|
| 3744 |
+
"gen": "bump",
|
| 3745 |
+
"scale": 4,
|
| 3746 |
+
"octaves": 4,
|
| 3747 |
+
"depth": 3,
|
| 3748 |
+
"light": 135,
|
| 3749 |
+
"intensity": 0.6,
|
| 3750 |
+
"color": "#000",
|
| 3751 |
+
"color2": "#fff",
|
| 3752 |
+
"blend": "overlay",
|
| 3753 |
+
"seed": 3
|
| 3754 |
+
},
|
| 3755 |
+
{
|
| 3756 |
+
"gen": "noise",
|
| 3757 |
+
"scale": 70,
|
| 3758 |
+
"octaves": 5,
|
| 3759 |
+
"contrast": 1.9,
|
| 3760 |
+
"intensity": 0.85,
|
| 3761 |
+
"color": "#3b1d0b",
|
| 3762 |
+
"color2": "#b4602a",
|
| 3763 |
+
"blend": "multiply",
|
| 3764 |
+
"seed": 5
|
| 3765 |
+
}
|
| 3766 |
+
]
|
| 3767 |
+
},
|
| 3768 |
+
"corrugated": {
|
| 3769 |
+
"doc": "corrugated metal sheet",
|
| 3770 |
+
"layers": [
|
| 3771 |
+
{
|
| 3772 |
+
"gen": "lines",
|
| 3773 |
+
"angle": 90,
|
| 3774 |
+
"scale": 12,
|
| 3775 |
+
"thickness": 6,
|
| 3776 |
+
"softness": 1,
|
| 3777 |
+
"intensity": 0.3,
|
| 3778 |
+
"color": "#000",
|
| 3779 |
+
"blend": "overlay"
|
| 3780 |
+
}
|
| 3781 |
+
]
|
| 3782 |
+
},
|
| 3783 |
+
"cork": {
|
| 3784 |
+
"doc": "cork board",
|
| 3785 |
+
"layers": [
|
| 3786 |
+
{
|
| 3787 |
+
"gen": "bump",
|
| 3788 |
+
"scale": 4,
|
| 3789 |
+
"octaves": 3,
|
| 3790 |
+
"depth": 3,
|
| 3791 |
+
"light": 135,
|
| 3792 |
+
"intensity": 0.7,
|
| 3793 |
+
"color": "#000",
|
| 3794 |
+
"color2": "#fff",
|
| 3795 |
+
"blend": "overlay",
|
| 3796 |
+
"seed": 2
|
| 3797 |
+
},
|
| 3798 |
+
{
|
| 3799 |
+
"gen": "noise",
|
| 3800 |
+
"scale": 3,
|
| 3801 |
+
"octaves": 3,
|
| 3802 |
+
"contrast": 2.2,
|
| 3803 |
+
"intensity": 0.8,
|
| 3804 |
+
"color": "#8a5a2b",
|
| 3805 |
+
"color2": "#d6a566",
|
| 3806 |
+
"blend": "multiply",
|
| 3807 |
+
"seed": 8
|
| 3808 |
+
}
|
| 3809 |
+
]
|
| 3810 |
+
},
|
| 3811 |
+
"kraft": {
|
| 3812 |
+
"doc": "brown packing paper",
|
| 3813 |
+
"layers": [
|
| 3814 |
+
{
|
| 3815 |
+
"gen": "noise",
|
| 3816 |
+
"scale": 1.4,
|
| 3817 |
+
"octaves": 3,
|
| 3818 |
+
"contrast": 1.4,
|
| 3819 |
+
"stretch": [
|
| 3820 |
+
6,
|
| 3821 |
+
1
|
| 3822 |
+
],
|
| 3823 |
+
"intensity": 0.35,
|
| 3824 |
+
"color": "#000",
|
| 3825 |
+
"color2": "#fff",
|
| 3826 |
+
"blend": "overlay",
|
| 3827 |
+
"seed": 2
|
| 3828 |
+
},
|
| 3829 |
+
{
|
| 3830 |
+
"gen": "noise",
|
| 3831 |
+
"scale": 60,
|
| 3832 |
+
"octaves": 3,
|
| 3833 |
+
"contrast": 1.3,
|
| 3834 |
+
"intensity": 0.25,
|
| 3835 |
+
"color": "#6b4a2a",
|
| 3836 |
+
"color2": "#d1a874",
|
| 3837 |
+
"blend": "multiply",
|
| 3838 |
+
"seed": 7
|
| 3839 |
+
}
|
| 3840 |
+
]
|
| 3841 |
+
},
|
| 3842 |
+
"felt": {
|
| 3843 |
+
"doc": "soft wool felt",
|
| 3844 |
+
"layers": [
|
| 3845 |
+
{
|
| 3846 |
+
"gen": "noise",
|
| 3847 |
+
"scale": 1,
|
| 3848 |
+
"octaves": 4,
|
| 3849 |
+
"contrast": 1.2,
|
| 3850 |
+
"intensity": 0.45,
|
| 3851 |
+
"color": "#000",
|
| 3852 |
+
"color2": "#fff",
|
| 3853 |
+
"blend": "overlay",
|
| 3854 |
+
"seed": 3
|
| 3855 |
+
},
|
| 3856 |
+
{
|
| 3857 |
+
"gen": "noise",
|
| 3858 |
+
"scale": 40,
|
| 3859 |
+
"octaves": 3,
|
| 3860 |
+
"contrast": 1.2,
|
| 3861 |
+
"intensity": 0.2,
|
| 3862 |
+
"color": "#000",
|
| 3863 |
+
"color2": "#fff",
|
| 3864 |
+
"blend": "soft-light",
|
| 3865 |
+
"seed": 9
|
| 3866 |
+
}
|
| 3867 |
+
]
|
| 3868 |
+
},
|
| 3869 |
+
"burlap": {
|
| 3870 |
+
"doc": "coarse sacking",
|
| 3871 |
+
"layers": [
|
| 3872 |
+
{
|
| 3873 |
+
"gen": "weave",
|
| 3874 |
+
"scale": 7,
|
| 3875 |
+
"thickness": 2.2,
|
| 3876 |
+
"intensity": 0.55,
|
| 3877 |
+
"color": "#3b2a14",
|
| 3878 |
+
"blend": "multiply"
|
| 3879 |
+
},
|
| 3880 |
+
{
|
| 3881 |
+
"gen": "noise",
|
| 3882 |
+
"scale": 30,
|
| 3883 |
+
"octaves": 3,
|
| 3884 |
+
"contrast": 1.5,
|
| 3885 |
+
"stretch": [
|
| 3886 |
+
6,
|
| 3887 |
+
1
|
| 3888 |
+
],
|
| 3889 |
+
"intensity": 0.3,
|
| 3890 |
+
"color": "#000",
|
| 3891 |
+
"color2": "#fff",
|
| 3892 |
+
"blend": "overlay",
|
| 3893 |
+
"seed": 4
|
| 3894 |
+
}
|
| 3895 |
+
]
|
| 3896 |
+
},
|
| 3897 |
+
"stucco": {
|
| 3898 |
+
"doc": "rough plaster",
|
| 3899 |
+
"layers": [
|
| 3900 |
+
{
|
| 3901 |
+
"gen": "bump",
|
| 3902 |
+
"scale": 9,
|
| 3903 |
+
"octaves": 3,
|
| 3904 |
+
"depth": 3.6,
|
| 3905 |
+
"light": 135,
|
| 3906 |
+
"intensity": 0.7,
|
| 3907 |
+
"color": "#000",
|
| 3908 |
+
"color2": "#fff",
|
| 3909 |
+
"blend": "overlay",
|
| 3910 |
+
"seed": 6
|
| 3911 |
+
},
|
| 3912 |
+
{
|
| 3913 |
+
"gen": "noise",
|
| 3914 |
+
"scale": 120,
|
| 3915 |
+
"octaves": 3,
|
| 3916 |
+
"contrast": 1.2,
|
| 3917 |
+
"intensity": 0.2,
|
| 3918 |
+
"color": "#000",
|
| 3919 |
+
"color2": "#fff",
|
| 3920 |
+
"blend": "soft-light",
|
| 3921 |
+
"seed": 1
|
| 3922 |
+
}
|
| 3923 |
+
]
|
| 3924 |
+
},
|
| 3925 |
+
"starfield": {
|
| 3926 |
+
"doc": "a night sky of small and large stars",
|
| 3927 |
+
"layers": [
|
| 3928 |
+
{
|
| 3929 |
+
"gen": "starfield",
|
| 3930 |
+
"scale": 300,
|
| 3931 |
+
"thickness": 2.4,
|
| 3932 |
+
"density": 0.25,
|
| 3933 |
+
"intensity": 1,
|
| 3934 |
+
"color": "#cfe3ff",
|
| 3935 |
+
"seed": 9,
|
| 3936 |
+
"blend": "normal"
|
| 3937 |
+
},
|
| 3938 |
+
{
|
| 3939 |
+
"gen": "starfield",
|
| 3940 |
+
"scale": 240,
|
| 3941 |
+
"thickness": 1.2,
|
| 3942 |
+
"density": 1.3,
|
| 3943 |
+
"intensity": 0.9,
|
| 3944 |
+
"color": "#ffffff",
|
| 3945 |
+
"seed": 5,
|
| 3946 |
+
"blend": "normal"
|
| 3947 |
+
}
|
| 3948 |
+
]
|
| 3949 |
+
},
|
| 3950 |
+
"snow": {
|
| 3951 |
+
"doc": "fresh snow with a few sparkles",
|
| 3952 |
+
"layers": [
|
| 3953 |
+
{
|
| 3954 |
+
"gen": "noise",
|
| 3955 |
+
"scale": 1.2,
|
| 3956 |
+
"octaves": 1,
|
| 3957 |
+
"contrast": 16,
|
| 3958 |
+
"threshold": 0.72,
|
| 3959 |
+
"intensity": 1,
|
| 3960 |
+
"color": "rgba(255,255,255,0)",
|
| 3961 |
+
"color2": "#fff",
|
| 3962 |
+
"blend": "screen",
|
| 3963 |
+
"seed": 5
|
| 3964 |
+
},
|
| 3965 |
+
{
|
| 3966 |
+
"gen": "noise",
|
| 3967 |
+
"scale": 90,
|
| 3968 |
+
"octaves": 4,
|
| 3969 |
+
"contrast": 1.4,
|
| 3970 |
+
"intensity": 0.5,
|
| 3971 |
+
"color": "#9fb6d6",
|
| 3972 |
+
"color2": "#ffffff",
|
| 3973 |
+
"blend": "soft-light",
|
| 3974 |
+
"seed": 3
|
| 3975 |
+
}
|
| 3976 |
+
]
|
| 3977 |
+
},
|
| 3978 |
+
"grass": {
|
| 3979 |
+
"doc": "blades of grass seen from above",
|
| 3980 |
+
"layers": [
|
| 3981 |
+
{
|
| 3982 |
+
"gen": "noise",
|
| 3983 |
+
"scale": 2,
|
| 3984 |
+
"octaves": 4,
|
| 3985 |
+
"contrast": 2,
|
| 3986 |
+
"stretch": [
|
| 3987 |
+
1,
|
| 3988 |
+
9
|
| 3989 |
+
],
|
| 3990 |
+
"intensity": 0.9,
|
| 3991 |
+
"color": "#2f6b2a",
|
| 3992 |
+
"color2": "#8cc152",
|
| 3993 |
+
"blend": "multiply",
|
| 3994 |
+
"seed": 4
|
| 3995 |
+
}
|
| 3996 |
+
]
|
| 3997 |
+
},
|
| 3998 |
+
"water": {
|
| 3999 |
+
"doc": "water with light ripples",
|
| 4000 |
+
"layers": [
|
| 4001 |
+
{
|
| 4002 |
+
"gen": "waves",
|
| 4003 |
+
"scale": 56,
|
| 4004 |
+
"thickness": 1.6,
|
| 4005 |
+
"intensity": 0.22,
|
| 4006 |
+
"color": "#ffffff",
|
| 4007 |
+
"blend": "normal"
|
| 4008 |
+
},
|
| 4009 |
+
{
|
| 4010 |
+
"gen": "noise",
|
| 4011 |
+
"scale": 100,
|
| 4012 |
+
"octaves": 4,
|
| 4013 |
+
"contrast": 1.5,
|
| 4014 |
+
"intensity": 0.8,
|
| 4015 |
+
"color": "#0a3d62",
|
| 4016 |
+
"color2": "#3c9bd6",
|
| 4017 |
+
"blend": "multiply",
|
| 4018 |
+
"seed": 6
|
| 4019 |
+
}
|
| 4020 |
+
]
|
| 4021 |
+
},
|
| 4022 |
+
"rain": {
|
| 4023 |
+
"doc": "slanted rain streaks",
|
| 4024 |
+
"layers": [
|
| 4025 |
+
{
|
| 4026 |
+
"gen": "lines",
|
| 4027 |
+
"angle": 100,
|
| 4028 |
+
"scale": 14,
|
| 4029 |
+
"thickness": 1,
|
| 4030 |
+
"softness": 0.6,
|
| 4031 |
+
"intensity": 0.35,
|
| 4032 |
+
"color": "#ffffff",
|
| 4033 |
+
"blend": "normal"
|
| 4034 |
+
}
|
| 4035 |
+
]
|
| 4036 |
+
},
|
| 4037 |
+
"lava": {
|
| 4038 |
+
"doc": "glowing cracks in dark rock",
|
| 4039 |
+
"layers": [
|
| 4040 |
+
{
|
| 4041 |
+
"gen": "noise",
|
| 4042 |
+
"scale": 90,
|
| 4043 |
+
"octaves": 4,
|
| 4044 |
+
"contour": 0.05,
|
| 4045 |
+
"threshold": 0.5,
|
| 4046 |
+
"intensity": 1,
|
| 4047 |
+
"color": "#ffb300",
|
| 4048 |
+
"color2": "rgba(255,60,0,0)",
|
| 4049 |
+
"blend": "screen",
|
| 4050 |
+
"seed": 7
|
| 4051 |
+
},
|
| 4052 |
+
{
|
| 4053 |
+
"gen": "noise",
|
| 4054 |
+
"scale": 60,
|
| 4055 |
+
"octaves": 5,
|
| 4056 |
+
"contrast": 1.8,
|
| 4057 |
+
"intensity": 0.9,
|
| 4058 |
+
"color": "#1a0500",
|
| 4059 |
+
"color2": "#7a1a00",
|
| 4060 |
+
"blend": "multiply",
|
| 4061 |
+
"seed": 3
|
| 4062 |
+
}
|
| 4063 |
+
]
|
| 4064 |
+
},
|
| 4065 |
+
"topo": {
|
| 4066 |
+
"doc": "contour lines, like a map",
|
| 4067 |
+
"layers": [
|
| 4068 |
+
{
|
| 4069 |
+
"gen": "noise",
|
| 4070 |
+
"scale": 140,
|
| 4071 |
+
"octaves": 4,
|
| 4072 |
+
"contour": 0.02,
|
| 4073 |
+
"threshold": 0.4,
|
| 4074 |
+
"intensity": 0.35,
|
| 4075 |
+
"color": "#000",
|
| 4076 |
+
"color2": "rgba(0,0,0,0)",
|
| 4077 |
+
"blend": "normal",
|
| 4078 |
+
"seed": 8
|
| 4079 |
+
},
|
| 4080 |
+
{
|
| 4081 |
+
"gen": "noise",
|
| 4082 |
+
"scale": 140,
|
| 4083 |
+
"octaves": 4,
|
| 4084 |
+
"contour": 0.02,
|
| 4085 |
+
"threshold": 0.5,
|
| 4086 |
+
"intensity": 0.5,
|
| 4087 |
+
"color": "#000",
|
| 4088 |
+
"color2": "rgba(0,0,0,0)",
|
| 4089 |
+
"blend": "normal",
|
| 4090 |
+
"seed": 8
|
| 4091 |
+
},
|
| 4092 |
+
{
|
| 4093 |
+
"gen": "noise",
|
| 4094 |
+
"scale": 140,
|
| 4095 |
+
"octaves": 4,
|
| 4096 |
+
"contour": 0.02,
|
| 4097 |
+
"threshold": 0.6,
|
| 4098 |
+
"intensity": 0.35,
|
| 4099 |
+
"color": "#000",
|
| 4100 |
+
"color2": "rgba(0,0,0,0)",
|
| 4101 |
+
"blend": "normal",
|
| 4102 |
+
"seed": 8
|
| 4103 |
+
}
|
| 4104 |
+
]
|
| 4105 |
+
}
|
| 4106 |
+
}
|
| 4107 |
+
},
|
| 4108 |
+
"aura": {
|
| 4109 |
+
"fromWords": [
|
| 4110 |
+
"edge",
|
| 4111 |
+
"outline",
|
| 4112 |
+
"bottom",
|
| 4113 |
+
"top",
|
| 4114 |
+
"left",
|
| 4115 |
+
"right",
|
| 4116 |
+
"center",
|
| 4117 |
+
"corners",
|
| 4118 |
+
"thumb"
|
| 4119 |
+
],
|
| 4120 |
+
"shapes": [
|
| 4121 |
+
"circle",
|
| 4122 |
+
"spark",
|
| 4123 |
+
"square",
|
| 4124 |
+
"ring",
|
| 4125 |
+
"star",
|
| 4126 |
+
"flame",
|
| 4127 |
+
"smoke",
|
| 4128 |
+
"line",
|
| 4129 |
+
"heart",
|
| 4130 |
+
"diamond",
|
| 4131 |
+
"triangle",
|
| 4132 |
+
"plus",
|
| 4133 |
+
"drop",
|
| 4134 |
+
"bubble",
|
| 4135 |
+
"snowflake",
|
| 4136 |
+
"confetti",
|
| 4137 |
+
"leaf"
|
| 4138 |
+
],
|
| 4139 |
+
"dirWords": {
|
| 4140 |
+
"up": -90,
|
| 4141 |
+
"down": 90,
|
| 4142 |
+
"left": 180,
|
| 4143 |
+
"right": 0,
|
| 4144 |
+
"out": "out",
|
| 4145 |
+
"in": "in"
|
| 4146 |
+
},
|
| 4147 |
+
"blends": [
|
| 4148 |
+
"add",
|
| 4149 |
+
"normal"
|
| 4150 |
+
],
|
| 4151 |
+
"glowKeys": {
|
| 4152 |
+
"color": {
|
| 4153 |
+
"kind": "color",
|
| 4154 |
+
"words": 1,
|
| 4155 |
+
"doc": "the light colour (default: the element's text colour)"
|
| 4156 |
+
},
|
| 4157 |
+
"radius": {
|
| 4158 |
+
"kind": "number",
|
| 4159 |
+
"words": 1,
|
| 4160 |
+
"min": 1,
|
| 4161 |
+
"max": 400,
|
| 4162 |
+
"doc": "how far the glow reaches, in px"
|
| 4163 |
+
},
|
| 4164 |
+
"intensity": {
|
| 4165 |
+
"kind": "number",
|
| 4166 |
+
"words": 1,
|
| 4167 |
+
"min": 0,
|
| 4168 |
+
"max": 4,
|
| 4169 |
+
"doc": "brightness, 1 is normal"
|
| 4170 |
+
},
|
| 4171 |
+
"pulse": {
|
| 4172 |
+
"kind": "number",
|
| 4173 |
+
"words": 1,
|
| 4174 |
+
"min": 0,
|
| 4175 |
+
"max": 60000,
|
| 4176 |
+
"doc": "milliseconds for one breath in and out; 0 is steady"
|
| 4177 |
+
},
|
| 4178 |
+
"depth": {
|
| 4179 |
+
"kind": "number",
|
| 4180 |
+
"words": 1,
|
| 4181 |
+
"min": 0,
|
| 4182 |
+
"max": 1,
|
| 4183 |
+
"doc": "how deep the pulse goes, 0 to 1"
|
| 4184 |
+
},
|
| 4185 |
+
"flicker": {
|
| 4186 |
+
"kind": "number",
|
| 4187 |
+
"words": 1,
|
| 4188 |
+
"min": 0,
|
| 4189 |
+
"max": 1,
|
| 4190 |
+
"doc": "random flicker, like a flame: 0 is steady, 1 is wild"
|
| 4191 |
+
},
|
| 4192 |
+
"seed": {
|
| 4193 |
+
"kind": "number",
|
| 4194 |
+
"words": 1,
|
| 4195 |
+
"min": 0,
|
| 4196 |
+
"max": 99999,
|
| 4197 |
+
"int": true,
|
| 4198 |
+
"doc": "a different random flicker with the same look"
|
| 4199 |
+
},
|
| 4200 |
+
"texture": {
|
| 4201 |
+
"kind": "texture",
|
| 4202 |
+
"words": 1,
|
| 4203 |
+
"doc": "texture(grain scale 2): break the light up with a texture"
|
| 4204 |
+
},
|
| 4205 |
+
"essential": {
|
| 4206 |
+
"kind": "flag",
|
| 4207 |
+
"words": 0,
|
| 4208 |
+
"doc": "keep animating even when the visitor prefers reduced motion"
|
| 4209 |
+
},
|
| 4210 |
+
"unclipped": {
|
| 4211 |
+
"kind": "flag",
|
| 4212 |
+
"words": 0,
|
| 4213 |
+
"doc": "let the light spill out of a parent that clips (overflow: hidden, auto, scroll). Without it the aura is cut at that edge, like the element itself"
|
| 4214 |
+
},
|
| 4215 |
+
"around": {
|
| 4216 |
+
"kind": "around",
|
| 4217 |
+
"words": 1,
|
| 4218 |
+
"doc": "the shape the light follows: follow (the default: the element's clip-path or rounded corners), box, round, pill, diamond, triangle, hexagon, octagon, pentagon, star, star4, star6, cross, heart, drop, bolt, alpha (an <img> or <canvas>'s visible pixels), or polygon(50% 0, 100% 50%, 50% 100%, 0 50%)"
|
| 4219 |
+
},
|
| 4220 |
+
"inner": {
|
| 4221 |
+
"kind": "flag",
|
| 4222 |
+
"words": 0,
|
| 4223 |
+
"doc": "light inside the edge (a rim) instead of outside it"
|
| 4224 |
+
},
|
| 4225 |
+
"rays": {
|
| 4226 |
+
"kind": "number",
|
| 4227 |
+
"words": 1,
|
| 4228 |
+
"min": 1,
|
| 4229 |
+
"max": 64,
|
| 4230 |
+
"int": true,
|
| 4231 |
+
"doc": "that many beams of light from the middle, slowly turning (see spin)"
|
| 4232 |
+
},
|
| 4233 |
+
"spin": {
|
| 4234 |
+
"kind": "number",
|
| 4235 |
+
"words": 1,
|
| 4236 |
+
"min": -3600,
|
| 4237 |
+
"max": 3600,
|
| 4238 |
+
"doc": "rays turn this many degrees a second (default 10); on particles, how fast each one tumbles"
|
| 4239 |
+
},
|
| 4240 |
+
"ripple": {
|
| 4241 |
+
"kind": "number",
|
| 4242 |
+
"words": 1,
|
| 4243 |
+
"min": 200,
|
| 4244 |
+
"max": 60000,
|
| 4245 |
+
"doc": "rings that spread out from the shape and fade, one every this many milliseconds"
|
| 4246 |
+
},
|
| 4247 |
+
"nohalo": {
|
| 4248 |
+
"kind": "flag",
|
| 4249 |
+
"words": 0,
|
| 4250 |
+
"doc": "only the rays and ripples, without the soft halo"
|
| 4251 |
+
},
|
| 4252 |
+
"always": {
|
| 4253 |
+
"kind": "flag",
|
| 4254 |
+
"words": 0,
|
| 4255 |
+
"doc": "keep emitting even when the element cannot be seen (opacity 0, display: none, visibility: hidden, on it or an ancestor): for an invisible anchor that smoke or sparks come out of"
|
| 4256 |
+
},
|
| 4257 |
+
"z": {
|
| 4258 |
+
"kind": "number",
|
| 4259 |
+
"words": 1,
|
| 4260 |
+
"min": -1000000,
|
| 4261 |
+
"max": 2147483000,
|
| 4262 |
+
"int": true,
|
| 4263 |
+
"doc": "the z-index of the layer this light is drawn on: `z 5` puts it under a hill with z-index 10. It meets elements in the page's root stacking context"
|
| 4264 |
+
}
|
| 4265 |
+
},
|
| 4266 |
+
"particleKeys": {
|
| 4267 |
+
"color": {
|
| 4268 |
+
"kind": "colors",
|
| 4269 |
+
"words": 1,
|
| 4270 |
+
"doc": "colours over a particle's life: color #ff0 -> #f60 -> transparent"
|
| 4271 |
+
},
|
| 4272 |
+
"count": {
|
| 4273 |
+
"kind": "number",
|
| 4274 |
+
"words": 1,
|
| 4275 |
+
"min": 1,
|
| 4276 |
+
"max": 600,
|
| 4277 |
+
"int": true,
|
| 4278 |
+
"doc": "how many particles are alive at once"
|
| 4279 |
+
},
|
| 4280 |
+
"size": {
|
| 4281 |
+
"kind": "range",
|
| 4282 |
+
"words": 2,
|
| 4283 |
+
"min": 0.5,
|
| 4284 |
+
"max": 300,
|
| 4285 |
+
"doc": "diameter in px: size 4, or size 10 4 (start and end of a random range)"
|
| 4286 |
+
},
|
| 4287 |
+
"life": {
|
| 4288 |
+
"kind": "range",
|
| 4289 |
+
"words": 2,
|
| 4290 |
+
"min": 50,
|
| 4291 |
+
"max": 60000,
|
| 4292 |
+
"doc": "how long one lives, in ms: life 900, or life 600 1200"
|
| 4293 |
+
},
|
| 4294 |
+
"speed": {
|
| 4295 |
+
"kind": "range",
|
| 4296 |
+
"words": 2,
|
| 4297 |
+
"min": 0,
|
| 4298 |
+
"max": 3000,
|
| 4299 |
+
"doc": "px per second: speed 60, or speed 30 90"
|
| 4300 |
+
},
|
| 4301 |
+
"dir": {
|
| 4302 |
+
"kind": "dir",
|
| 4303 |
+
"words": 1,
|
| 4304 |
+
"doc": "where they head: up, down, left, right, out, in, or degrees (-90 is up)"
|
| 4305 |
+
},
|
| 4306 |
+
"spread": {
|
| 4307 |
+
"kind": "number",
|
| 4308 |
+
"words": 1,
|
| 4309 |
+
"min": 0,
|
| 4310 |
+
"max": 360,
|
| 4311 |
+
"doc": "how wide the fan of directions is, in degrees"
|
| 4312 |
+
},
|
| 4313 |
+
"gravity": {
|
| 4314 |
+
"kind": "number",
|
| 4315 |
+
"words": 1,
|
| 4316 |
+
"min": -2000,
|
| 4317 |
+
"max": 2000,
|
| 4318 |
+
"doc": "px/s squared; negative pulls up (flames), positive down (snow)"
|
| 4319 |
+
},
|
| 4320 |
+
"drag": {
|
| 4321 |
+
"kind": "number",
|
| 4322 |
+
"words": 1,
|
| 4323 |
+
"min": 0,
|
| 4324 |
+
"max": 10,
|
| 4325 |
+
"doc": "air resistance: how fast particles slow down"
|
| 4326 |
+
},
|
| 4327 |
+
"turbulence": {
|
| 4328 |
+
"kind": "number",
|
| 4329 |
+
"words": 1,
|
| 4330 |
+
"min": 0,
|
| 4331 |
+
"max": 1000,
|
| 4332 |
+
"doc": "random sideways wobble, px/s"
|
| 4333 |
+
},
|
| 4334 |
+
"from": {
|
| 4335 |
+
"kind": "word",
|
| 4336 |
+
"words": 1,
|
| 4337 |
+
"values": [
|
| 4338 |
+
"edge",
|
| 4339 |
+
"outline",
|
| 4340 |
+
"bottom",
|
| 4341 |
+
"top",
|
| 4342 |
+
"left",
|
| 4343 |
+
"right",
|
| 4344 |
+
"center",
|
| 4345 |
+
"corners",
|
| 4346 |
+
"thumb"
|
| 4347 |
+
],
|
| 4348 |
+
"doc": "where they are born: edge or outline (along the element's real outline, see around), bottom, top, left, right, center, corners, thumb (range sliders)"
|
| 4349 |
+
},
|
| 4350 |
+
"shape": {
|
| 4351 |
+
"kind": "word",
|
| 4352 |
+
"words": 1,
|
| 4353 |
+
"values": [
|
| 4354 |
+
"circle",
|
| 4355 |
+
"spark",
|
| 4356 |
+
"square",
|
| 4357 |
+
"ring",
|
| 4358 |
+
"star",
|
| 4359 |
+
"flame",
|
| 4360 |
+
"smoke",
|
| 4361 |
+
"line",
|
| 4362 |
+
"heart",
|
| 4363 |
+
"diamond",
|
| 4364 |
+
"triangle",
|
| 4365 |
+
"plus",
|
| 4366 |
+
"drop",
|
| 4367 |
+
"bubble",
|
| 4368 |
+
"snowflake",
|
| 4369 |
+
"confetti",
|
| 4370 |
+
"leaf"
|
| 4371 |
+
],
|
| 4372 |
+
"doc": "circle, spark, square, ring, star, flame, smoke, line, heart, diamond, triangle, plus, drop, bubble, snowflake, confetti or leaf"
|
| 4373 |
+
},
|
| 4374 |
+
"grow": {
|
| 4375 |
+
"kind": "number",
|
| 4376 |
+
"words": 1,
|
| 4377 |
+
"min": 0,
|
| 4378 |
+
"max": 10,
|
| 4379 |
+
"doc": "size at the end of life as a multiple of the start: 0.2 shrinks, 3 swells"
|
| 4380 |
+
},
|
| 4381 |
+
"blend": {
|
| 4382 |
+
"kind": "word",
|
| 4383 |
+
"words": 1,
|
| 4384 |
+
"values": [
|
| 4385 |
+
"add",
|
| 4386 |
+
"normal"
|
| 4387 |
+
],
|
| 4388 |
+
"doc": "add makes overlapping particles brighter, normal just stacks them"
|
| 4389 |
+
},
|
| 4390 |
+
"glowing": {
|
| 4391 |
+
"kind": "flag",
|
| 4392 |
+
"words": 0,
|
| 4393 |
+
"doc": "soft glowing particles that add light"
|
| 4394 |
+
},
|
| 4395 |
+
"behind": {
|
| 4396 |
+
"kind": "flag",
|
| 4397 |
+
"words": 0,
|
| 4398 |
+
"doc": "draw only outside the element's box, as if the element hid them"
|
| 4399 |
+
},
|
| 4400 |
+
"seed": {
|
| 4401 |
+
"kind": "number",
|
| 4402 |
+
"words": 1,
|
| 4403 |
+
"min": 0,
|
| 4404 |
+
"max": 99999,
|
| 4405 |
+
"int": true,
|
| 4406 |
+
"doc": "a different random pattern with the same look"
|
| 4407 |
+
},
|
| 4408 |
+
"texture": {
|
| 4409 |
+
"kind": "texture",
|
| 4410 |
+
"words": 1,
|
| 4411 |
+
"doc": "texture(grain): grainy particles"
|
| 4412 |
+
},
|
| 4413 |
+
"essential": {
|
| 4414 |
+
"kind": "flag",
|
| 4415 |
+
"words": 0,
|
| 4416 |
+
"doc": "keep animating even when the visitor prefers reduced motion"
|
| 4417 |
+
},
|
| 4418 |
+
"unclipped": {
|
| 4419 |
+
"kind": "flag",
|
| 4420 |
+
"words": 0,
|
| 4421 |
+
"doc": "let the particles leave a parent that clips (overflow: hidden, auto, scroll). Without it they are cut at that edge"
|
| 4422 |
+
},
|
| 4423 |
+
"around": {
|
| 4424 |
+
"kind": "around",
|
| 4425 |
+
"words": 1,
|
| 4426 |
+
"doc": "the shape `from edge` and `from outline` follow: follow (the default), box, round, pill, diamond, triangle, hexagon, octagon, pentagon, star, star4, star6, cross, heart, drop, bolt, or polygon(...)"
|
| 4427 |
+
},
|
| 4428 |
+
"palette": {
|
| 4429 |
+
"kind": "flag",
|
| 4430 |
+
"words": 0,
|
| 4431 |
+
"doc": "each particle takes ONE of the colours (confetti) instead of fading through them"
|
| 4432 |
+
},
|
| 4433 |
+
"spin": {
|
| 4434 |
+
"kind": "number",
|
| 4435 |
+
"words": 1,
|
| 4436 |
+
"min": -3600,
|
| 4437 |
+
"max": 3600,
|
| 4438 |
+
"doc": "how fast each particle tumbles, in degrees a second (random direction)"
|
| 4439 |
+
},
|
| 4440 |
+
"wind": {
|
| 4441 |
+
"kind": "number",
|
| 4442 |
+
"words": 1,
|
| 4443 |
+
"min": -3000,
|
| 4444 |
+
"max": 3000,
|
| 4445 |
+
"doc": "a sideways push, px/s squared; negative pushes left"
|
| 4446 |
+
},
|
| 4447 |
+
"orbit": {
|
| 4448 |
+
"kind": "number",
|
| 4449 |
+
"words": 1,
|
| 4450 |
+
"min": -3600,
|
| 4451 |
+
"max": 3600,
|
| 4452 |
+
"doc": "the particles circle the middle of the element, this many degrees a second"
|
| 4453 |
+
},
|
| 4454 |
+
"always": {
|
| 4455 |
+
"kind": "flag",
|
| 4456 |
+
"words": 0,
|
| 4457 |
+
"doc": "keep emitting even when the element cannot be seen (opacity 0, display: none, visibility: hidden, on it or an ancestor): for an invisible anchor that smoke or sparks come out of"
|
| 4458 |
+
},
|
| 4459 |
+
"z": {
|
| 4460 |
+
"kind": "number",
|
| 4461 |
+
"words": 1,
|
| 4462 |
+
"min": -1000000,
|
| 4463 |
+
"max": 2147483000,
|
| 4464 |
+
"int": true,
|
| 4465 |
+
"doc": "the z-index of the layer these particles are drawn on: `z 5` puts them under a hill with z-index 10. It meets elements in the page's root stacking context"
|
| 4466 |
+
}
|
| 4467 |
+
},
|
| 4468 |
+
"glowDefaults": {
|
| 4469 |
+
"radius": 24,
|
| 4470 |
+
"intensity": 1,
|
| 4471 |
+
"pulse": 0,
|
| 4472 |
+
"depth": 0.35,
|
| 4473 |
+
"flicker": 0,
|
| 4474 |
+
"seed": 1
|
| 4475 |
+
},
|
| 4476 |
+
"particleDefaults": {
|
| 4477 |
+
"count": 40,
|
| 4478 |
+
"size": [
|
| 4479 |
+
4,
|
| 4480 |
+
4
|
| 4481 |
+
],
|
| 4482 |
+
"life": [
|
| 4483 |
+
900,
|
| 4484 |
+
900
|
| 4485 |
+
],
|
| 4486 |
+
"speed": [
|
| 4487 |
+
40,
|
| 4488 |
+
40
|
| 4489 |
+
],
|
| 4490 |
+
"dir": -90,
|
| 4491 |
+
"spread": 30,
|
| 4492 |
+
"gravity": 0,
|
| 4493 |
+
"drag": 0,
|
| 4494 |
+
"turbulence": 0,
|
| 4495 |
+
"from": "edge",
|
| 4496 |
+
"shape": "circle",
|
| 4497 |
+
"grow": 0.3,
|
| 4498 |
+
"blend": null,
|
| 4499 |
+
"glowing": false,
|
| 4500 |
+
"seed": 1
|
| 4501 |
+
},
|
| 4502 |
+
"aroundNames": [
|
| 4503 |
+
"follow",
|
| 4504 |
+
"box",
|
| 4505 |
+
"round",
|
| 4506 |
+
"pill",
|
| 4507 |
+
"alpha",
|
| 4508 |
+
"diamond",
|
| 4509 |
+
"triangle",
|
| 4510 |
+
"hexagon",
|
| 4511 |
+
"octagon",
|
| 4512 |
+
"pentagon",
|
| 4513 |
+
"star",
|
| 4514 |
+
"star4",
|
| 4515 |
+
"star6",
|
| 4516 |
+
"cross",
|
| 4517 |
+
"heart",
|
| 4518 |
+
"drop",
|
| 4519 |
+
"bolt"
|
| 4520 |
+
]
|
| 4521 |
+
},
|
| 4522 |
+
"slider": {
|
| 4523 |
+
"clauses": {
|
| 4524 |
+
"track": "track [height] [color] [radius <n>|full]",
|
| 4525 |
+
"fill": "fill <color> | fill none",
|
| 4526 |
+
"thumb": "thumb <size> [color]",
|
| 4527 |
+
"shape": "shape circle | square | diamond | pill | bar",
|
| 4528 |
+
"ring": "ring <width> <color>",
|
| 4529 |
+
"glow": "glow <color> <radius>",
|
| 4530 |
+
"ticks": "ticks <count> [color] [length]",
|
| 4531 |
+
"graph": "graph <v1> <v2> ... (each 0 to 100)",
|
| 4532 |
+
"graph-height": "graph-height <px>",
|
| 4533 |
+
"graph-gap": "graph-gap <px>"
|
| 4534 |
+
},
|
| 4535 |
+
"thumbShapes": [
|
| 4536 |
+
"circle",
|
| 4537 |
+
"square",
|
| 4538 |
+
"diamond",
|
| 4539 |
+
"pill",
|
| 4540 |
+
"bar"
|
| 4541 |
+
]
|
| 4542 |
+
},
|
| 4543 |
+
"effects": {
|
| 4544 |
+
"glassWords": {
|
| 4545 |
+
"blur": "a number: how many px to blur what is behind the element (default 16)",
|
| 4546 |
+
"saturate": "saturate <n>: colour boost for what shows through, 1 is unchanged (default 1.5)",
|
| 4547 |
+
"bright": "bright <n>: brightness of what shows through, 1 is unchanged",
|
| 4548 |
+
"tint": "tint <color> | tint none: the milky layer on top (default: a faint wash of the text colour)"
|
| 4549 |
+
},
|
| 4550 |
+
"tiltWords": {
|
| 4551 |
+
"max": "a number: the largest tilt in degrees (default 8)",
|
| 4552 |
+
"lift": "lift <n>: scale while the pointer is over it, e.g. 1.04",
|
| 4553 |
+
"perspective": "perspective <px>: how strong the 3D depth looks (default 900)",
|
| 4554 |
+
"speed": "speed <0.05 to 1>: how quickly it follows (default 0.18)",
|
| 4555 |
+
"invert": "invert: tilt away from the pointer instead of toward it",
|
| 4556 |
+
"glare": "glare: also keep --dssl-gx and --dssl-gy (0% to 100%) pointing at the pointer, for your own highlight"
|
| 4557 |
+
}
|
| 4558 |
+
},
|
| 4559 |
+
"fonts": {
|
| 4560 |
+
"words": {
|
| 4561 |
+
"weights": "a weight (400), several (400 700), or a variable range (100..900)",
|
| 4562 |
+
"italic": "also load the italic of each weight",
|
| 4563 |
+
"display": "display <swap|block|fallback|optional>: how the text behaves while the font loads (default swap)",
|
| 4564 |
+
"from": "from \"/path/to/file.woff2\": use your own file instead of Google Fonts"
|
| 4565 |
+
}
|
| 4566 |
+
}
|
| 4567 |
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 1. Overview
|
| 2 |
+
|
| 3 |
+
## 1.1 What DSSL is
|
| 4 |
+
|
| 5 |
+
DSSL is a style language. A DSSL file is plain text. It holds tokens (named design values),
|
| 6 |
+
rules (selector blocks), states, conditions, motions and a few effect descriptions. A DSSL
|
| 7 |
+
implementation reads that text and decides how every element in a document should look.
|
| 8 |
+
|
| 9 |
+
A DSSL file describes a result. It does not say how to reach it. That is the whole idea of a
|
| 10 |
+
style language, and it is what makes native support possible: the author says what, the
|
| 11 |
+
engine decides how.
|
| 12 |
+
|
| 13 |
+
## 1.2 What CSS does (and what that means for DSSL)
|
| 14 |
+
|
| 15 |
+
CSS is not compiled. There is no step that turns a stylesheet into machine code or into some
|
| 16 |
+
other language that the browser then runs. A browser engine is an interpreter for a
|
| 17 |
+
declarative language, and it keeps the interpreted form alive for as long as the page lives.
|
| 18 |
+
|
| 19 |
+
Here is what a browser does with a stylesheet, in order:
|
| 20 |
+
|
| 21 |
+
1. **Tokenize and parse.** The engine's own code (C++ in Chrome and Safari, Rust in Firefox)
|
| 22 |
+
reads the text and builds rule objects. The collection of rule objects is the CSSOM.
|
| 23 |
+
2. **Style resolution.** For every element, the engine finds the rules whose selectors match,
|
| 24 |
+
sorts them by the cascade (origin, layer, specificity, order), picks the winning
|
| 25 |
+
declaration for each property, and resolves it into a computed value. The result is one
|
| 26 |
+
computed style per element.
|
| 27 |
+
3. **Layout.** Using the computed styles, the engine works out the size and position of every
|
| 28 |
+
box.
|
| 29 |
+
4. **Paint.** The engine turns boxes and computed values into drawing commands: fill this
|
| 30 |
+
rectangle, draw this text, blur that shadow.
|
| 31 |
+
5. **Composite.** Painted layers are combined on the GPU and shown.
|
| 32 |
+
|
| 33 |
+
Engines do optimise stage 2. They index rules by class, id and tag so they do not test every
|
| 34 |
+
selector against every element, they cache results, and some compile selectors to machine
|
| 35 |
+
code. None of that changes what a stylesheet means. It is an implementation detail.
|
| 36 |
+
|
| 37 |
+
Every CSS property is built-in code inside the engine. `background` is a paint routine,
|
| 38 |
+
`width` is a layout input, `border-radius` changes the shape that paint clips to. Nothing in
|
| 39 |
+
this path runs JavaScript.
|
| 40 |
+
|
| 41 |
+
### What native DSSL means
|
| 42 |
+
|
| 43 |
+
Native DSSL means a browser reads DSSL text with its own parser and feeds the result into the
|
| 44 |
+
same stages. Which stages matter depends on the feature:
|
| 45 |
+
|
| 46 |
+
| DSSL feature | CSS stage it joins | What the engine must add |
|
| 47 |
+
|---|---|---|
|
| 48 |
+
| Syntax, tokens, semantic properties (`row:`, `radius:`, `fluid`) | 1 and 2 | A DSSL parser. After that, they are ordinary computed values. |
|
| 49 |
+
| Layers, states, media, containers | 2 | Nothing new: the cascade already has these concepts. |
|
| 50 |
+
| `@signal` | 2 | A way for the page to set named values the cascade can read. |
|
| 51 |
+
| `motion`, `animate` | 2 and 4 | Mapping to the engine's existing keyframe animation. |
|
| 52 |
+
| `texture`, `aura`, `glass`, `slider` | 4 | New drawing code, the way `box-shadow` once was new. |
|
| 53 |
+
| `fold`, `bend-around`, `tilt`, `overlap` | 3 and 4 | Hooks that see box sizes, so they must run during or after layout. |
|
| 54 |
+
|
| 55 |
+
The first four rows are small. The last two rows are where real engineering is needed, and
|
| 56 |
+
chapter 11 says exactly what.
|
| 57 |
+
|
| 58 |
+
## 1.3 Processing model
|
| 59 |
+
|
| 60 |
+
An implementation takes DSSL source text and a document, and produces styled output. The
|
| 61 |
+
model has six stages. A conforming implementation does not have to run them as separate
|
| 62 |
+
passes, but its results MUST be the same as if it had.
|
| 63 |
+
|
| 64 |
+
```
|
| 65 |
+
source text
|
| 66 |
+
| 1. decode, strip comments, split into logical lines
|
| 67 |
+
v
|
| 68 |
+
syntax tree (chapter 2)
|
| 69 |
+
| 2. classify headers, resolve values, expand semantic properties,
|
| 70 |
+
| flatten nesting, collect tokens and motions
|
| 71 |
+
v
|
| 72 |
+
resolved document (chapters 3 to 8, output defined in chapter 10)
|
| 73 |
+
| 3. for each element: match rules, apply conditions
|
| 74 |
+
v
|
| 75 |
+
matched rules
|
| 76 |
+
| 4. sort by (layer, order), last declaration per property wins
|
| 77 |
+
v
|
| 78 |
+
declared values (chapter 5)
|
| 79 |
+
| 5. compute: same as CSS from here
|
| 80 |
+
v
|
| 81 |
+
computed style + effect descriptors
|
| 82 |
+
| 6. layout and paint, supplied by the host
|
| 83 |
+
v
|
| 84 |
+
pixels
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
Stages 1 and 2 need no document. They are pure functions of the source text (and the tokens
|
| 88 |
+
and motions that earlier files defined, see 4.5). That is why they can be tested without a
|
| 89 |
+
browser, and why this repository tests them by comparing outputs.
|
| 90 |
+
|
| 91 |
+
## 1.4 Conformance levels
|
| 92 |
+
|
| 93 |
+
An implementation claims a level. Each level includes the one before it.
|
| 94 |
+
|
| 95 |
+
| Level | Name | What it must do |
|
| 96 |
+
|---|---|---|
|
| 97 |
+
| 1 | Parser | Stage 1. Produce the syntax tree and the syntax errors defined in chapter 2. |
|
| 98 |
+
| 2 | Resolver | Stages 1 and 2. Produce a resolved document equal to the reference output (chapter 10), including errors and warnings. |
|
| 99 |
+
| 3 | Style engine | Stages 1 to 5. Give every element the declared values chapter 5 defines. |
|
| 100 |
+
| 4 | Renderer | Stage 6 for the effects in chapter 8: texture, aura, slider, glass, tilt, deform. |
|
| 101 |
+
|
| 102 |
+
The reference crate in this repository aims at level 2 first, then 3 and 4. It is not there
|
| 103 |
+
yet: `native/README.md` says exactly where it stands.
|
| 104 |
+
|
| 105 |
+
## 1.5 Selectors are CSS selectors
|
| 106 |
+
|
| 107 |
+
DSSL does not define a selector language. Selectors are CSS selectors as defined by the
|
| 108 |
+
Selectors specification, and matching is done by the host. This is how the JavaScript engine
|
| 109 |
+
works too: it calls `Element.matches`.
|
| 110 |
+
|
| 111 |
+
Two things sit on top of that:
|
| 112 |
+
|
| 113 |
+
- **State words.** A block header that is exactly one of the state words (chapter 2) means
|
| 114 |
+
"the parent selector plus this pseudo-class". `hover { ... }` inside `.card` means
|
| 115 |
+
`.card:hover`.
|
| 116 |
+
- **`seen`.** `:seen` is not a CSS pseudo-class. It is defined in 5.7.
|
| 117 |
+
|
| 118 |
+
A selector goes through the resolver as text. The resolver only looks at it to find
|
| 119 |
+
pseudo-elements (5.8) and to scan states. It never rewrites one except to join nested
|
| 120 |
+
selectors (5.3).
|
| 121 |
+
|
| 122 |
+
## 1.6 Versioning
|
| 123 |
+
|
| 124 |
+
The spec has the same version as the language it describes. This draft describes DSSL 0.16.
|
| 125 |
+
A change that makes a previously valid source invalid, or changes what a valid source means,
|
| 126 |
+
is listed in the changelog of the language and raises the second number.
|
| 127 |
+
|
| 128 |
+
## 1.7 What is out of scope
|
| 129 |
+
|
| 130 |
+
- The selector language (see 1.5).
|
| 131 |
+
- Layout and paint for ordinary CSS properties. DSSL passes those through unchanged.
|
| 132 |
+
- The CSS value grammar. DSSL checks that a word is a known CSS word and gives numbers
|
| 133 |
+
their units. It does not check that a value is valid for its property. The host does that
|
| 134 |
+
when it computes the style.
|
| 135 |
+
- The editor extension, the designer and the build tools (`dssl check`, `dssl build`,
|
| 136 |
+
`dssl import`). Chapter 11 says how the build lane relates to native support.
|
|
@@ -0,0 +1,212 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 2. Syntax
|
| 2 |
+
|
| 3 |
+
This chapter turns source text into a syntax tree. It needs no tokens, no document and no
|
| 4 |
+
vocabulary except the lists in the appendices.
|
| 5 |
+
|
| 6 |
+
## 2.1 Source text
|
| 7 |
+
|
| 8 |
+
- **SYN-1.** Source is a sequence of Unicode characters. Line numbers start at 1 and count
|
| 9 |
+
`\n` characters. A parser that reads bytes MUST decode UTF-8 first. `\r` is not special: a
|
| 10 |
+
`\r\n` file leaves a `\r` at the end of each line, and values are trimmed, so it does no
|
| 11 |
+
harm.
|
| 12 |
+
- **SYN-2.** Every diagnostic carries the file name and a 1-based line number. For a
|
| 13 |
+
construct that spans several lines, the line is the one where the construct started.
|
| 14 |
+
|
| 15 |
+
## 2.2 Comments
|
| 16 |
+
|
| 17 |
+
There are two comment forms: `// to the end of the line` and `/* a block */`.
|
| 18 |
+
|
| 19 |
+
- **SYN-3.** Comments are removed before anything else is parsed, in one pass over the whole
|
| 20 |
+
source, left to right.
|
| 21 |
+
- **SYN-4.** A quote character (`"` or `'`) that is not inside a comment starts a string. A
|
| 22 |
+
string ends at the next occurrence of the same quote character that is not directly
|
| 23 |
+
preceded by a backslash. Comment markers inside a string are plain text.
|
| 24 |
+
- **SYN-5.** A line comment runs to, but not including, the next `\n`. A block comment runs
|
| 25 |
+
to the first `*/`, or to the end of the source if there is none. Inside a block comment,
|
| 26 |
+
every character except `\n` is replaced by a space and every `\n` is kept. Removing a
|
| 27 |
+
comment therefore never changes the line number of anything after it.
|
| 28 |
+
- **SYN-6.** An unquoted `url(` ... `)` is one token for the comment pass. When the letters
|
| 29 |
+
`url(` (any case) are not directly preceded by a letter, digit, `_` or `-`, and the first
|
| 30 |
+
character after the `(` and any white space is not a quote, the text through the closing `)`
|
| 31 |
+
is kept exactly as written, newlines included, so a `//` inside it (`url(https://x.com/a.png)`)
|
| 32 |
+
is not a comment. A `url(` with no closing `)` is not special. A quoted `url("...")` is
|
| 33 |
+
covered by SYN-4. (Before 0.16.3 the engine treated that `//` as a comment, see D-1.)
|
| 34 |
+
|
| 35 |
+
Comments are removed from everything else, including the body of `raw { }`.
|
| 36 |
+
|
| 37 |
+
```dssl
|
| 38 |
+
// a line comment
|
| 39 |
+
.card {
|
| 40 |
+
padding: 16 /* a block comment, even in the middle of a line */
|
| 41 |
+
}
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
## 2.3 Logical lines
|
| 45 |
+
|
| 46 |
+
The comment-free source is split on `\n` into physical lines. Physical lines are joined into
|
| 47 |
+
logical chunks, and each chunk is processed by 2.4.
|
| 48 |
+
|
| 49 |
+
- **SYN-7.** A blank physical line is skipped. (Inside a `raw { }` capture it is kept. See
|
| 50 |
+
2.7.)
|
| 51 |
+
- **SYN-8.** A chunk is *incomplete* when any of these holds:
|
| 52 |
+
1. its parentheses or square brackets are unbalanced (more opening than closing, counting
|
| 53 |
+
outside quoted strings), or
|
| 54 |
+
2. after trimming trailing white space, it ends in `,`, or
|
| 55 |
+
3. after trimming trailing white space, it ends in `:`.
|
| 56 |
+
- **SYN-9.** While the buffer is incomplete, the next non-blank physical line is trimmed and
|
| 57 |
+
appended to the buffer with one space between them. When the buffer becomes complete, it is
|
| 58 |
+
processed as one chunk, with the line number of the first physical line. A chunk that is
|
| 59 |
+
incomplete at the end of the file is processed as it stands.
|
| 60 |
+
|
| 61 |
+
Why: this is how multi-line values, multi-line selector lists and `prop:` followed by the
|
| 62 |
+
value on the next line all work with no semicolons.
|
| 63 |
+
|
| 64 |
+
```dssl
|
| 65 |
+
.card,
|
| 66 |
+
.panel {
|
| 67 |
+
background: linear-gradient(
|
| 68 |
+
to bottom, red, blue
|
| 69 |
+
)
|
| 70 |
+
color:
|
| 71 |
+
color.ink
|
| 72 |
+
}
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
## 2.4 Processing a chunk
|
| 76 |
+
|
| 77 |
+
A chunk is a string. The parser keeps a stack of open blocks. The root is always at the
|
| 78 |
+
bottom of the stack. It repeats the following on the chunk until nothing is left:
|
| 79 |
+
|
| 80 |
+
1. Trim the chunk. If it is empty, stop.
|
| 81 |
+
2. Find the first top-level `{` and the first top-level `}`. "Top-level" means not inside a
|
| 82 |
+
quoted string and not inside parentheses or square brackets.
|
| 83 |
+
3. If there is a `}` and either there is no `{` or the `}` comes first:
|
| 84 |
+
- treat the text before it as declarations (2.6) if it is not empty,
|
| 85 |
+
- if the stack holds only the root, report `unexpected "}"` (SYN-10); otherwise pop one
|
| 86 |
+
block,
|
| 87 |
+
- continue with the text after the `}`.
|
| 88 |
+
4. Else if there is a `{`: the text before it is the *header text*.
|
| 89 |
+
- **SYN-11.** If the header text contains a top-level `;`, everything before the last such
|
| 90 |
+
`;` is treated as declarations (2.6) and the header is the text after it. This is what
|
| 91 |
+
lets `.card { background: red; hover { background: blue } }` work on one line. If the
|
| 92 |
+
remaining header is empty, report `block is missing a header before "{"` and skip the
|
| 93 |
+
`{`.
|
| 94 |
+
- If the header text is empty, report the same error and skip the `{`.
|
| 95 |
+
- Otherwise classify the header (2.5), append a node to the block on top of the stack, and
|
| 96 |
+
run the block-open rule (2.7). If the block is not closed on this line, push it.
|
| 97 |
+
5. Else the whole chunk is declarations (2.6). Stop.
|
| 98 |
+
|
| 99 |
+
A node always carries the line number of its chunk.
|
| 100 |
+
|
| 101 |
+
## 2.5 Classifying a header
|
| 102 |
+
|
| 103 |
+
The header is trimmed. The first row that matches wins.
|
| 104 |
+
|
| 105 |
+
| Header | Node kind | Notes |
|
| 106 |
+
|---|---|---|
|
| 107 |
+
| exactly `tokens` | `tokens` | 4.1 |
|
| 108 |
+
| exactly `pin` | `pin` | the must-win layer, 5.2 |
|
| 109 |
+
| exactly `raw` or `@css` | `raw` | verbatim CSS, 2.7 |
|
| 110 |
+
| exactly `fonts` | `fonts` | 8.7 |
|
| 111 |
+
| starts with `behavior ` | `behavior`, name = rest, trimmed | 6.9 |
|
| 112 |
+
| starts with `motion ` | `motion`, name = rest, trimmed | chapter 7 |
|
| 113 |
+
| starts with `@layer ` | `layer`, name = rest, trimmed | 5.2 |
|
| 114 |
+
| starts with `@media ` | `media`, query = rest, trimmed | 5.5 |
|
| 115 |
+
| starts with `@container` | `container`, query = rest after the 10 characters, trimmed | 5.6 |
|
| 116 |
+
| starts with `@signal ` | `signal`, expr = rest, trimmed | 5.9 |
|
| 117 |
+
| starts with any other `@` | `bogus` | error `unknown at-rule "<first word>"`, the whole block is skipped (2.7) |
|
| 118 |
+
| starts with `::` | `pseudo`, name = text after `::` up to the first space or `(` | 5.8. If the name is not a pseudo-element name and not a vendor pseudo, error `unknown pseudo-element "::name"` and the block is skipped |
|
| 119 |
+
| exactly one of the state words | `state`, name = the word | 5.7 |
|
| 120 |
+
| anything else | `selector`, sel = the header | a CSS selector list |
|
| 121 |
+
|
| 122 |
+
The state words, the pseudo-element names and the vendor-pseudo pattern are in appendix A.
|
| 123 |
+
|
| 124 |
+
- **SYN-12.** Matching of `tokens`, `pin`, `raw`, `@css` and `fonts` is on the whole trimmed
|
| 125 |
+
header. `tokens foo {` is a selector. `@media(width>1)` (no space) is an unknown at-rule.
|
| 126 |
+
`@container` is the one at-rule that does not require a space.
|
| 127 |
+
|
| 128 |
+
Unknown at-rules are skipped whole, so nothing inside them leaks out. For verbatim CSS the
|
| 129 |
+
author writes `raw { }`.
|
| 130 |
+
|
| 131 |
+
```dssl
|
| 132 |
+
raw {
|
| 133 |
+
@supports (display: grid) {
|
| 134 |
+
.box { display: grid; }
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
```
|
| 138 |
+
|
| 139 |
+
## 2.6 Declarations
|
| 140 |
+
|
| 141 |
+
A declaration text is split on top-level `;`. Inside a `tokens` block (the block on top of
|
| 142 |
+
the stack, or any block below it is a `tokens` block), each piece is further split by the
|
| 143 |
+
token-pair rule (2.8). Each non-empty trimmed piece is one declaration:
|
| 144 |
+
|
| 145 |
+
- **SYN-13.** Find the first top-level `:` in the piece.
|
| 146 |
+
- **SYN-14.** If there is none:
|
| 147 |
+
- `use <name>` where `<name>` matches `[A-Za-z][\w-]*` is a declaration with property
|
| 148 |
+
`use` and value `<name>`.
|
| 149 |
+
- A bare word matching `[a-z][a-z0-9-]*` (case-insensitive) is a declaration with that word
|
| 150 |
+
lowercased as the property and an empty value. (This is how `truncate` and
|
| 151 |
+
`visually-hidden` are written.)
|
| 152 |
+
- Anything else is the error `expected ":" in "<first 40 characters>"` with the hint
|
| 153 |
+
`declarations look like prop: value`.
|
| 154 |
+
- **SYN-15.** The property is the text before the colon, trimmed and lowercased. The value is
|
| 155 |
+
the text after it, trimmed, with its case kept. An empty property is the error
|
| 156 |
+
`declaration is missing a property name`.
|
| 157 |
+
- **SYN-16.** A property that is all digits with an optional fraction (`9`, `2.5`) is legal
|
| 158 |
+
only when some block on the stack is a `tokens` block. Elsewhere it is the error
|
| 159 |
+
`"<prop>" is not a valid property name`, with a hint about token keys.
|
| 160 |
+
- **SYN-17.** Any other property MUST match
|
| 161 |
+
`^(-{1,2}[a-z][a-z0-9.-]*|[a-z][a-z0-9-]*)$` (case-insensitive), otherwise the error
|
| 162 |
+
`"<prop>" is not a valid property name` is reported and the declaration is dropped. Dotted
|
| 163 |
+
names are legal only after a leading `--` (`--color.accent`).
|
| 164 |
+
|
| 165 |
+
A valid declaration becomes a `decl` node `{ prop, value, line }` appended to the block on
|
| 166 |
+
top of the stack.
|
| 167 |
+
|
| 168 |
+
## 2.7 Block-open rule
|
| 169 |
+
|
| 170 |
+
After a header is classified and its node is appended:
|
| 171 |
+
|
| 172 |
+
- **`raw` and `fonts`.**
|
| 173 |
+
- **SYN-18.** They are legal only at the top level (the stack holds only the root).
|
| 174 |
+
Otherwise report `raw { } must be top-level` (or `fonts { } ...`) with the hint
|
| 175 |
+
`move it out of the enclosing block`, and skip the balanced block.
|
| 176 |
+
- **SYN-19.** The body is captured verbatim into `node.css`. If the matching `}` is on the
|
| 177 |
+
same line as the header, the body is the text between the braces. Otherwise capture
|
| 178 |
+
continues on following physical lines: each one is appended followed by `\n`, blank lines
|
| 179 |
+
included, until the braces balance. The first line contributes only the text after the
|
| 180 |
+
`{`. Brace matching ignores quoted strings. Text after the closing `}` is processed as a
|
| 181 |
+
new chunk. If the file ends first, report `the raw { } block was never closed with "}"`
|
| 182 |
+
and the CSS captured so far is discarded.
|
| 183 |
+
- **`bogus`.**
|
| 184 |
+
- **SYN-20.** The block is skipped: the parser finds the matching `}` (quote-aware) and
|
| 185 |
+
continues after it. If there is none, report
|
| 186 |
+
`the "<first 30 characters>" block was never closed with "}"` and discard the rest of the
|
| 187 |
+
chunk.
|
| 188 |
+
- **Everything else.** The node is pushed on the stack.
|
| 189 |
+
|
| 190 |
+
At the end of the file, if more than the root is on the stack, report
|
| 191 |
+
`<n> block(s) were never closed with "}"`.
|
| 192 |
+
|
| 193 |
+
## 2.8 Token pairs
|
| 194 |
+
|
| 195 |
+
- **SYN-21.** Inside a `tokens` block, `pill: 999 card: 22` on one line is two declarations.
|
| 196 |
+
A piece is split at a space when all of these hold: a top-level `:` (not part of `::`) has
|
| 197 |
+
already been seen in the piece, the space is outside strings, parentheses and brackets, and
|
| 198 |
+
the text after the space looks like `name:` where `name` matches `[A-Za-z0-9][\w.-]*`
|
| 199 |
+
followed by optional spaces and a `:` that is not `::`.
|
| 200 |
+
|
| 201 |
+
## 2.9 The syntax tree
|
| 202 |
+
|
| 203 |
+
```
|
| 204 |
+
root { kind: 'root', children: [...] }
|
| 205 |
+
node { kind, line, children: [...], ...extra }
|
| 206 |
+
decl { kind: 'decl', prop, value, line }
|
| 207 |
+
```
|
| 208 |
+
|
| 209 |
+
Extra fields by kind: `behavior` and `motion` have `name`, `layer` has `name`, `media` and
|
| 210 |
+
`container` have `query`, `signal` has `expr`, `selector` has `sel`, `state` and `pseudo`
|
| 211 |
+
have `name`, `raw` and `fonts` have `css`. Child order is source order. The tree is data: a
|
| 212 |
+
Level 1 parser is tested by comparing its tree and its errors with the reference.
|
|
@@ -0,0 +1,199 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 3. Values
|
| 2 |
+
|
| 3 |
+
This chapter fixes how a value string such as `0 2 4 color.ink/10` becomes CSS. The algorithm
|
| 4 |
+
is applied to the value of an ordinary declaration, to token values, and to the pieces that
|
| 5 |
+
semantic properties pass on (chapter 6).
|
| 6 |
+
|
| 7 |
+
## 3.1 The resolution context
|
| 8 |
+
|
| 9 |
+
Every value is resolved with a context:
|
| 10 |
+
|
| 11 |
+
| Field | Meaning |
|
| 12 |
+
|---|---|
|
| 13 |
+
| `prop` | the property name the value belongs to (a token key for token values) |
|
| 14 |
+
| `unitless` | when true, a bare number stays a bare number. When false, it gets a unit. |
|
| 15 |
+
| `bareIdents` | when true, an unknown identifier is allowed through (font names, counter names) |
|
| 16 |
+
| `tokens` | the current token map (chapter 4) |
|
| 17 |
+
|
| 18 |
+
- **VAL-1.** For an ordinary property, `unitless` is true exactly when the property is in the
|
| 19 |
+
unitless list (appendix A). A semantic property chooses its own context for each piece it
|
| 20 |
+
passes on (chapter 6).
|
| 21 |
+
- **VAL-2.** `bareIdents` is true for `font-family`, for any property whose name starts with
|
| 22 |
+
`counter-`, for custom properties (`--name`), and for tokens whose key starts with `font`.
|
| 23 |
+
It is also switched on inside `counter()`, `counters()`, `attr()`, `env()`, `format()`,
|
| 24 |
+
`local()`, `paint()` and `element()`.
|
| 25 |
+
|
| 26 |
+
## 3.2 The scan
|
| 27 |
+
|
| 28 |
+
The value is scanned left to right. At each position, the first of these rules that applies
|
| 29 |
+
is used.
|
| 30 |
+
|
| 31 |
+
1. **White space** is copied as it is.
|
| 32 |
+
2. **Strings.** `"` or `'` starts a string that runs to the next occurrence of the same
|
| 33 |
+
quote. A backslash makes the character after it part of the string, so `"a\"b"` is one
|
| 34 |
+
string. It is copied verbatim. The same applies to strings inside function arguments and in
|
| 35 |
+
layer lists. (Before 0.16.3 the backslash was ignored here, see D-5.)
|
| 36 |
+
3. **Numbers.** A number starts at a digit, at `.` followed by a digit, or at `-` or `+`
|
| 37 |
+
followed by a digit or `.`. It continues over digits and `.`. If letters or `%` follow,
|
| 38 |
+
they are the unit and are lowercased. The output is the number text plus:
|
| 39 |
+
- the unit, if there is one,
|
| 40 |
+
- otherwise nothing, if `unitless` is true,
|
| 41 |
+
- otherwise `ms`, if `prop` is a time property (appendix A),
|
| 42 |
+
- otherwise `px`.
|
| 43 |
+
4. **Identifiers.** An identifier matches
|
| 44 |
+
`^-?(?:[A-Za-z_]|--[A-Za-z_])[A-Za-z0-9_.\\-]*`. Note that `.` and `-` are part of an
|
| 45 |
+
identifier, so `color.ink` and `ease-out` are single identifiers, and so is `a-1`.
|
| 46 |
+
What happens next, in order:
|
| 47 |
+
1. A name starting `--` is copied as it is (a custom property).
|
| 48 |
+
2. If the next character is `(`, it is a **function call** (3.3).
|
| 49 |
+
3. If the identifier is a **token** (3.4), it is replaced by a variable reference.
|
| 50 |
+
4. If it is a known **keyword** (3.5), it is copied as it is.
|
| 51 |
+
5. If `bareIdents` is true and the identifier is plain letters, digits, `_` and `-`
|
| 52 |
+
starting with a letter, it is copied as it is.
|
| 53 |
+
6. Otherwise it is an error (3.6). The identifier is copied and scanning continues.
|
| 54 |
+
5. **Hex colors.** `#` followed by hex digits is copied. An alpha suffix follows the rules in
|
| 55 |
+
3.4.
|
| 56 |
+
6. **Anything else** (`/`, `,`, `+`, `*`, `%`, `(`, `)`, `->`) is copied one character at a
|
| 57 |
+
time.
|
| 58 |
+
|
| 59 |
+
- **VAL-3.** Rule 3 means `0` becomes `0px`, `margin: 0 auto` becomes `0px auto`, and
|
| 60 |
+
`opacity: 0.5` stays `0.5` because `opacity` is unitless.
|
| 61 |
+
- **VAL-4.** `--name` custom property values are resolved like any other, with
|
| 62 |
+
`unitless: false` and `bareIdents: true`.
|
| 63 |
+
|
| 64 |
+
```dssl
|
| 65 |
+
.a {
|
| 66 |
+
padding: 0
|
| 67 |
+
margin: 0 auto
|
| 68 |
+
opacity: 0.5
|
| 69 |
+
line-height: 1.5
|
| 70 |
+
transition-delay: 200
|
| 71 |
+
}
|
| 72 |
+
```
|
| 73 |
+
|
| 74 |
+
The five lines resolve to `0px`, `0px auto`, `0.5`, `1.5` and `200ms`.
|
| 75 |
+
|
| 76 |
+
## 3.3 Function calls
|
| 77 |
+
|
| 78 |
+
The text from the `(` to its matching `)` is the argument text. Matching counts nested
|
| 79 |
+
parentheses and skips quoted strings.
|
| 80 |
+
|
| 81 |
+
- **VAL-5.** `url( )` is atomic. The output is `url(` + the argument text trimmed + `)`. Nothing
|
| 82 |
+
inside is looked at.
|
| 83 |
+
- **VAL-6.** `repeat(N, tracks)`, when the first argument is a number, keeps `N` as it is
|
| 84 |
+
(never a length) and resolves the rest with the same context. When the first argument is
|
| 85 |
+
not a plain number (`auto-fill`, `auto-fit`), the call falls through to VAL-7.
|
| 86 |
+
- **VAL-7.** Any other call resolves its argument text recursively. The inner context is:
|
| 87 |
+
- `unitless: true` for the functions in the *unitless functions* list (colors, filters
|
| 88 |
+
that take numbers, `scale*`, `steps`, `cubic-bezier`, `linear`, `radial`, `conic`),
|
| 89 |
+
- `unitless: false` for the *length functions* list (`calc`, `min`, `max`, `clamp`, the
|
| 90 |
+
other math functions, `blur`, `drop-shadow`),
|
| 91 |
+
- the outer context's `unitless` for any other function.
|
| 92 |
+
Function names are matched lowercase. The output keeps the written name.
|
| 93 |
+
|
| 94 |
+
Both lists are in appendix A.
|
| 95 |
+
|
| 96 |
+
```dssl
|
| 97 |
+
.a {
|
| 98 |
+
width: calc(100% - 24)
|
| 99 |
+
background: oklch(62% 0.19 35)
|
| 100 |
+
grid-template-columns: repeat(4, 1fr)
|
| 101 |
+
transform: scale(1.2)
|
| 102 |
+
}
|
| 103 |
+
```
|
| 104 |
+
|
| 105 |
+
`calc(100% - 24)` becomes `calc(100% - 24px)`. The `oklch` numbers and the `scale` factor
|
| 106 |
+
stay bare. `repeat(4, 1fr)` keeps its `4`.
|
| 107 |
+
|
| 108 |
+
## 3.4 Tokens and alpha
|
| 109 |
+
|
| 110 |
+
A reference to a token is the token's key written as an identifier (`color.ink`, `space.4`).
|
| 111 |
+
How a key is found is in 4.4. A reference becomes `var(--dssl-<key>)`, where every `.` in
|
| 112 |
+
the key is replaced by `-`.
|
| 113 |
+
|
| 114 |
+
- **VAL-8.** *Alpha modifier.* A token reference, a named color, `currentcolor` or a hex
|
| 115 |
+
color may be followed by `/` and a number, with optional white space and an optional `%`:
|
| 116 |
+
`color.ink/20`, `white/12`, `#ff0000/50`. The whole thing becomes
|
| 117 |
+
`color-mix(in oklab, <color> N%, transparent)`, where `N` is the number text as written.
|
| 118 |
+
The number is always a percentage, with or without the `%` sign.
|
| 119 |
+
- **VAL-9.** A named color is a keyword for which the color table (appendix A) has an entry.
|
| 120 |
+
|
| 121 |
+
```dssl
|
| 122 |
+
tokens { color { x: #123456 } }
|
| 123 |
+
.a {
|
| 124 |
+
color: color.x/50
|
| 125 |
+
background: #ff0000/50
|
| 126 |
+
border-color: white/12
|
| 127 |
+
}
|
| 128 |
+
```
|
| 129 |
+
|
| 130 |
+
These three become `color-mix(in oklab, var(--dssl-color-x) 50%, transparent)`,
|
| 131 |
+
`color-mix(in oklab, #ff0000 50%, transparent)` and
|
| 132 |
+
`color-mix(in oklab, white 12%, transparent)`.
|
| 133 |
+
|
| 134 |
+
## 3.5 Keywords
|
| 135 |
+
|
| 136 |
+
The keyword set (appendix A) holds every word DSSL accepts as a bare CSS value: color names,
|
| 137 |
+
display values, easing names, units of measure words and everything the CSS property
|
| 138 |
+
definitions mention. It is generated from the engine's vocabulary module.
|
| 139 |
+
|
| 140 |
+
- **VAL-10.** A keyword matches if the identifier is in the set, or its lowercase form is.
|
| 141 |
+
|
| 142 |
+
Why: DSSL is loud about typos. An identifier that is not a token, not a keyword and not
|
| 143 |
+
allowed by `bareIdents` is a mistake, and 3.6 says so.
|
| 144 |
+
|
| 145 |
+
## 3.6 Unknown identifiers
|
| 146 |
+
|
| 147 |
+
- **VAL-11.** An unknown identifier is the error `unknown value "<id>" for property "<prop>"`.
|
| 148 |
+
The hint is the best did-you-mean (9.3) over the token keys followed by the keywords, or no
|
| 149 |
+
hint if nothing is close. The identifier is copied to the output, so the value still
|
| 150 |
+
resolves as far as it can.
|
| 151 |
+
|
| 152 |
+
```dssl error
|
| 153 |
+
.a { color: colour }
|
| 154 |
+
```
|
| 155 |
+
|
| 156 |
+
## 3.7 Fluid sizes
|
| 157 |
+
|
| 158 |
+
`fluid` is sugar for a `clamp()` that moves linearly between two viewport widths. It has two
|
| 159 |
+
spellings.
|
| 160 |
+
|
| 161 |
+
- `font-size: fluid 16 24`: the value is `fluid` followed by arguments. It is allowed on the
|
| 162 |
+
properties in the *fluid properties* list (appendix A).
|
| 163 |
+
- `fluid: 16, 24`: the semantic property `fluid` (6.4) writes `font-size`.
|
| 164 |
+
|
| 165 |
+
The arguments are, in order: the first size, the second size, the lower viewport width
|
| 166 |
+
(default `360`), the upper viewport width (default `1200`). Arguments are separated by
|
| 167 |
+
white space or commas.
|
| 168 |
+
|
| 169 |
+
- **VAL-12.** A size is a number with an optional unit of `px`, `rem` or `em`. A bare number
|
| 170 |
+
is `px`. A `%` is an error (`cannot be a percentage, use px, rem or em`). The two sizes
|
| 171 |
+
MUST have the same unit (`mixes units, give both sizes the same unit`). The viewport
|
| 172 |
+
widths are in `px` and the upper MUST be larger than the lower.
|
| 173 |
+
- **VAL-13.** Let `a`, `b` be the sizes, `v0`, `v1` the viewport widths, `f` = 1 for `px`
|
| 174 |
+
and 16 for `rem` and `em`. Then
|
| 175 |
+
`slope = ((b - a) * f) / (v1 - v0)`, `vw = slope * 100` and
|
| 176 |
+
`intercept = a - (slope * v0) / f`. The output is
|
| 177 |
+
`clamp(<min><unit>, calc(<intercept><unit> + <vw>vw), <max><unit>)`, where `min` and `max`
|
| 178 |
+
are the smaller and larger of `a` and `b`, and every number is written with at most three
|
| 179 |
+
decimal places and no trailing zeros.
|
| 180 |
+
- **VAL-14.** On an error the property gets the value `0px` and the error is reported.
|
| 181 |
+
|
| 182 |
+
```dssl
|
| 183 |
+
h1 { font-size: fluid 28 44 }
|
| 184 |
+
.stack { gap: fluid 8 16 }
|
| 185 |
+
.hero { font-size: fluid 16 24 400 800 }
|
| 186 |
+
```
|
| 187 |
+
|
| 188 |
+
For `fluid 16 24` the output is `clamp(16px, calc(12.571px + 0.952vw), 24px)`.
|
| 189 |
+
|
| 190 |
+
## 3.8 Important
|
| 191 |
+
|
| 192 |
+
- **VAL-15.** The text `!important` (any case, any space after `!`) outside a quoted string
|
| 193 |
+
is not valid DSSL. The declaration is dropped and the error
|
| 194 |
+
`!important does not exist in DSSL - "<prop>: <value>" was NOT applied` is reported, with
|
| 195 |
+
the hint to use `pin { }`.
|
| 196 |
+
|
| 197 |
+
```dssl error
|
| 198 |
+
.a { color: red !important }
|
| 199 |
+
```
|
|
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 4. Tokens
|
| 2 |
+
|
| 3 |
+
A token is a named design value: a color, a space, a radius, a shadow, a font stack. Tokens
|
| 4 |
+
become CSS custom properties, so they follow the page's normal inheritance and can be
|
| 5 |
+
re-declared in any subtree.
|
| 6 |
+
|
| 7 |
+
## 4.1 The tokens block
|
| 8 |
+
|
| 9 |
+
```dssl
|
| 10 |
+
tokens {
|
| 11 |
+
color {
|
| 12 |
+
ink: #16161d
|
| 13 |
+
accent: oklch(62% 0.19 35)
|
| 14 |
+
}
|
| 15 |
+
space { 1: 4 2: 8 9: 96 }
|
| 16 |
+
radius { md: 14 }
|
| 17 |
+
shadow { md: 0 2 4 color.ink/10, 0 4 12 color.ink/8 }
|
| 18 |
+
}
|
| 19 |
+
```
|
| 20 |
+
|
| 21 |
+
- **TOK-1.** A `tokens` block may appear at the top level, or inside `@media`, `@container`,
|
| 22 |
+
`@signal` and `@layer` blocks that themselves have no selector around them. Inside a
|
| 23 |
+
selector it is the error `tokens must be top-level or inside @media / @signal`, and the
|
| 24 |
+
block is ignored.
|
| 25 |
+
- **TOK-2.** Inside a `tokens` block, a declaration `name: value` defines the token whose key
|
| 26 |
+
is the path to that block plus the name. A nested block whose header is a plain word
|
| 27 |
+
(`color { ... }`) adds that word to the path. A nested `tokens` block does the same with
|
| 28 |
+
the header text `tokens`. Any other nested block kind is the error
|
| 29 |
+
`unexpected "<kind>" inside tokens`.
|
| 30 |
+
- **TOK-3.** Numeric names (`1`, `9`) are legal keys (SYN-16). `space { 9: 96 }` defines
|
| 31 |
+
`space.9`.
|
| 32 |
+
- **TOK-4.** The value of a token is kept as written. It is resolved (chapter 3) when the
|
| 33 |
+
token is emitted (4.3), with `prop` set to the token key and `unitless` false.
|
| 34 |
+
|
| 35 |
+
Why: tokens resolve late, so a token may refer to another token, to alpha, or to a function,
|
| 36 |
+
and each reference is checked in the place it is used.
|
| 37 |
+
|
| 38 |
+
## 4.2 Keys and variable names
|
| 39 |
+
|
| 40 |
+
- **TOK-5.** A token key is a dotted path such as `color.ink` or `shadow.md`.
|
| 41 |
+
- **TOK-6.** The variable name for a key is `--dssl-` followed by the key with each `.`
|
| 42 |
+
replaced by `-`. So `color.ink` is `--dssl-color-ink` and `space.9` is `--dssl-space-9`.
|
| 43 |
+
Two keys that differ only by `.` against `-` (`a.b-c` and `a.b.c`) therefore share a
|
| 44 |
+
variable. Authors SHOULD avoid that.
|
| 45 |
+
|
| 46 |
+
## 4.3 Emission
|
| 47 |
+
|
| 48 |
+
A token that is defined becomes a declaration on `:root` in the layer `tokens`.
|
| 49 |
+
|
| 50 |
+
- **TOK-7.** Before reading any rule, the resolver collects the tokens of every `tokens` block
|
| 51 |
+
in the file, however deeply nested in conditions, into one map. When the same key is
|
| 52 |
+
defined twice, the later definition in source order replaces the earlier one in that map.
|
| 53 |
+
The map is also seeded with the tokens the host passes in (4.5), starting from the
|
| 54 |
+
built-in defaults.
|
| 55 |
+
- **TOK-8.** Each `tokens` block, when it is reached during the walk (5.4), emits one rule
|
| 56 |
+
with selector `:root`, layer `tokens`, the media, containers and signals of the context it
|
| 57 |
+
is in, and one declaration per key it defines itself, in the order the keys were written.
|
| 58 |
+
The value of each declaration is the value that block wrote, not the final value in the
|
| 59 |
+
map.
|
| 60 |
+
- **TOK-9.** Before the walk, the resolver also builds the *registry rule*: selector `:root`,
|
| 61 |
+
layer `tokens`, no conditions, one declaration for every key in the map in map order. It
|
| 62 |
+
takes the first order number (0). It is returned beside the rules and is not part of the
|
| 63 |
+
rules list. Hosts install it first, so every token has a value even before its block is
|
| 64 |
+
reached. Because it is built from the map, it carries the last definition of each key.
|
| 65 |
+
- **TOK-10.** An error in a token value is reported at the line where the token was written,
|
| 66 |
+
and only by the file that defines it. A token that comes from the host (4.5) is not checked
|
| 67 |
+
again.
|
| 68 |
+
|
| 69 |
+
```dssl
|
| 70 |
+
tokens { color { bg: white } }
|
| 71 |
+
@media dark { tokens { color { bg: black } } }
|
| 72 |
+
.a { background: color.bg }
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
This yields one `:root` rule for `white` and one for `black` under the dark condition. Both
|
| 76 |
+
are in the layer `tokens`, and the second has a later order, so it wins when dark applies.
|
| 77 |
+
|
| 78 |
+
## 4.4 Looking up a token
|
| 79 |
+
|
| 80 |
+
- **TOK-11.** An identifier in a value is a token reference when its text is exactly a key in
|
| 81 |
+
the map.
|
| 82 |
+
- **TOK-12.** Only an exact key matches. `color.ink2.bogus` is not `color.ink2`: it is not a
|
| 83 |
+
token, so it falls through to the keyword rule and is the error `unknown value`. (Before
|
| 84 |
+
0.16.3 the engine shortened the path from the right and used the first prefix that was a
|
| 85 |
+
key, which hid typos, see D-2.)
|
| 86 |
+
|
| 87 |
+
## 4.5 Tokens across files
|
| 88 |
+
|
| 89 |
+
A page usually loads several DSSL files. The host keeps a *registry* of token values and a
|
| 90 |
+
registry of motions (7.3) and passes both into the resolver for each new file, in load order.
|
| 91 |
+
The registry starts as the built-in defaults.
|
| 92 |
+
|
| 93 |
+
- **TOK-13.** For a file, the starting map is the registry. The resolver adds the file's own
|
| 94 |
+
tokens on top. After the file, the host updates the registry from the file's final map.
|
| 95 |
+
- **TOK-14.** The built-in defaults are in appendix A. They are defined with ordinary token
|
| 96 |
+
syntax and can be replaced by any `tokens` block.
|
| 97 |
+
|
| 98 |
+
Why: this is how `tokens.dssl` can define a palette that every later file uses, and how a
|
| 99 |
+
later file can override one token from an earlier one.
|
| 100 |
+
|
| 101 |
+
## 4.6 Scoped tokens
|
| 102 |
+
|
| 103 |
+
A custom property with a dotted name re-declares a token for the element it is on.
|
| 104 |
+
|
| 105 |
+
```dssl
|
| 106 |
+
.danger { --color.accent: color.err }
|
| 107 |
+
```
|
| 108 |
+
|
| 109 |
+
- **TOK-15.** A declaration whose property starts with `--` and contains a `.` is written
|
| 110 |
+
with the property `--dssl-` followed by the rest of the name with dots replaced by dashes
|
| 111 |
+
(`--color.accent` becomes `--dssl-color-accent`). The value is resolved with
|
| 112 |
+
`bareIdents: true`. Custom properties inherit, so every `var()` in the subtree sees the new
|
| 113 |
+
value.
|
| 114 |
+
- **TOK-16.** A custom property without a dot (`--brand`) is passed through with only its
|
| 115 |
+
value resolved.
|
| 116 |
+
|
| 117 |
+
## 4.7 Token shortcuts
|
| 118 |
+
|
| 119 |
+
Three semantic properties take a token name as a word (chapter 6): `shadow:`, `radius:`.
|
| 120 |
+
|
| 121 |
+
- **TOK-17.** `shadow: sm|md|lg|xl` is `box-shadow: var(--dssl-shadow-<word>)` whether or not
|
| 122 |
+
that token exists. `shadow: none` is `box-shadow: none`. A word that matches
|
| 123 |
+
`[A-Za-z][\w-]*` and for which `shadow.<word>` is a key in the map becomes
|
| 124 |
+
`box-shadow: var(--dssl-shadow-<word>)`. Anything else is resolved as an ordinary value.
|
| 125 |
+
- **TOK-18.** `radius:` takes one to four words. Each of `sm`, `md`, `lg`, `full`, `xl` becomes
|
| 126 |
+
`var(--dssl-radius-<word>)` whether or not it exists. Any other word that matches
|
| 127 |
+
`[A-Za-z][\w-]*` and for which `radius.<word>` is a key becomes the same kind of reference.
|
| 128 |
+
Everything else is resolved as an ordinary value. The words are joined by spaces into
|
| 129 |
+
`border-radius`. When one of the five words is used and `radius.<word>` is not a key, the
|
| 130 |
+
reference is still written, and the warning is
|
| 131 |
+
`radius "<word>" is not defined, so it will not apply` with the hint
|
| 132 |
+
`add it with tokens { radius { <word>: 32 } }`. By default only `sm`, `md`, `lg` and `full`
|
| 133 |
+
exist, so `xl` warns until the author defines it (D-4).
|
|
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 5. Cascade
|
| 2 |
+
|
| 3 |
+
The resolver flattens the nested blocks of a file into a flat list of *rules*. The cascade
|
| 4 |
+
then decides, per element, which declaration of each property wins. This chapter defines both.
|
| 5 |
+
|
| 6 |
+
## 5.1 The rule record
|
| 7 |
+
|
| 8 |
+
A rule is a record with these fields.
|
| 9 |
+
|
| 10 |
+
| Field | Meaning |
|
| 11 |
+
|---|---|
|
| 12 |
+
| `id` | a number, unique inside the document, in creation order |
|
| 13 |
+
| `sel` | the full selector text, nesting already joined (5.3) |
|
| 14 |
+
| `media` | a list of normalized media conditions (5.5). All must hold. |
|
| 15 |
+
| `signals` | a list of signal conditions (5.9). All must hold. |
|
| 16 |
+
| `containers` | a list of container conditions (5.6). All must hold. |
|
| 17 |
+
| `layer` | one of `tokens`, `base`, `components`, `utilities`, `pin` |
|
| 18 |
+
| `order` | a number: this rule's place in the file, counted from 0 (5.4) |
|
| 19 |
+
| `decls` | a list of declarations: `{ prop, value, line }` plus extras |
|
| 20 |
+
| `file`, `line` | where the rule came from |
|
| 21 |
+
| `pseudo` | the pseudo-element name for a shadow rule, else null |
|
| 22 |
+
| `states` | the set of state words found in `sel` (5.7) |
|
| 23 |
+
|
| 24 |
+
A *shadow rule* has the same fields. It is a rule whose `sel` names a pseudo-element target
|
| 25 |
+
(5.8).
|
| 26 |
+
|
| 27 |
+
## 5.2 Layers
|
| 28 |
+
|
| 29 |
+
- **CAS-1.** The layers are ranked `tokens` (0), `base` (1), `components` (2), `utilities`
|
| 30 |
+
(3), `pin` (4).
|
| 31 |
+
- **CAS-2.** Rules outside any layer block are in `components`. `@layer <name> { }` puts the
|
| 32 |
+
rules inside it in layer `<name>` when that is one of the five names, and in `components`
|
| 33 |
+
for any other name, with the warning `unknown layer "<name>", treated as "components"`. The
|
| 34 |
+
hint is the did-you-mean over the five names, or
|
| 35 |
+
`the layers are tokens, base, components, utilities, pin` when none is close. (D-3)
|
| 36 |
+
- **CAS-3.** `pin { }` puts its rules in layer `pin`. Declarations in `pin` behave as if
|
| 37 |
+
`!important`: they beat declarations from every other layer, and they beat inline styles
|
| 38 |
+
that the page itself wrote (5.11).
|
| 39 |
+
- **CAS-4.** The layer `tokens` is used only for token rules (chapter 4).
|
| 40 |
+
- **CAS-5.** There is no specificity. For two matching rules, a lower layer rank loses to a
|
| 41 |
+
higher one. Within a layer, the later `order` wins.
|
| 42 |
+
|
| 43 |
+
```dssl
|
| 44 |
+
.a { color: red }
|
| 45 |
+
pin { .a { color: blue } }
|
| 46 |
+
@layer base { .a { color: green } }
|
| 47 |
+
```
|
| 48 |
+
|
| 49 |
+
All three match. `base` is below `components`, so `red` beats `green`, and `pin` beats both.
|
| 50 |
+
The element is blue.
|
| 51 |
+
|
| 52 |
+
## 5.3 Nesting
|
| 53 |
+
|
| 54 |
+
A selector block may contain declarations, other selector blocks, state blocks, pseudo-element
|
| 55 |
+
blocks, `@media`, `@container`, `@signal`, `@layer` and `pin` blocks, and `use` lines.
|
| 56 |
+
|
| 57 |
+
- **CAS-6.** Nested selectors are joined to the parent selector. If the child contains `&`,
|
| 58 |
+
each `&` is replaced by the parent selector. Otherwise the result is the parent, a space
|
| 59 |
+
and the child (a descendant selector). A block at the top level is used as written.
|
| 60 |
+
- **CAS-7.** Lists are split at top-level commas (not inside parentheses or brackets, so
|
| 61 |
+
`:is(.x, .y)` stays whole) on both sides. Every parent part is joined with every child part,
|
| 62 |
+
parent-major: for each parent part in order, each child part in order. The results are
|
| 63 |
+
joined with `, `. So `.a, .b { .c { } }` means `.a .c, .b .c`, `.a { .c, .d { } }` means
|
| 64 |
+
`.a .c, .a .d`, and `&` is replaced by each parent part in turn. With no commas on either
|
| 65 |
+
side the result is the plain join of CAS-6. (Before 0.16.3 the lists were joined as whole
|
| 66 |
+
text, giving `.a, .b .c`. That was D-7.)
|
| 67 |
+
- **CAS-8.** A nested block whose header is a single plain word that is close to a state word
|
| 68 |
+
but not equal to it (`hove`, `focs`) is still a selector, but the resolver reports a
|
| 69 |
+
warning: `"<word>" compiled as a descendant selector`, with the hint naming the state.
|
| 70 |
+
This applies only when the header is a bare word of letters, digits and dashes, and there is
|
| 71 |
+
a parent selector. "Close" is the did-you-mean rule (9.3). The warning never fires for a
|
| 72 |
+
word that is an HTML element name (`li`, `td`, `menu`, and the rest of the list in the
|
| 73 |
+
reference engine), because a nested element name is a descendant selector on purpose. (Before
|
| 74 |
+
0.16.3 `li` was warned about, being two edits from `link`. That was D-8.)
|
| 75 |
+
- **CAS-9.** Conditions nest. `@media`, `@container` and `@signal` add one entry to the
|
| 76 |
+
`media`, `containers` or `signals` list of everything inside. A layer block replaces the
|
| 77 |
+
layer of everything inside.
|
| 78 |
+
- **CAS-10.** A state block adds `:<state>` to the parent selector (5.7). A pseudo-element
|
| 79 |
+
block makes a shadow rule (5.8).
|
| 80 |
+
|
| 81 |
+
```dssl
|
| 82 |
+
.card {
|
| 83 |
+
background: color.card
|
| 84 |
+
hover { background: color.paper }
|
| 85 |
+
@media dark { background: color.ink }
|
| 86 |
+
&.on { background: color.accent }
|
| 87 |
+
}
|
| 88 |
+
```
|
| 89 |
+
|
| 90 |
+
## 5.4 Order
|
| 91 |
+
|
| 92 |
+
- **CAS-11.** Each rule, shadow rule and `raw` block gets the next order number at the moment
|
| 93 |
+
it is emitted. The registry rule (4.3) gets 0. Token rules get a number at the moment their
|
| 94 |
+
block is reached.
|
| 95 |
+
- **CAS-12.** A rule is emitted when its block ends, or when a nested block starts, if it has
|
| 96 |
+
declarations waiting. So a block with declarations before and after a nested block makes
|
| 97 |
+
two rules, one for each fragment, in source order:
|
| 98 |
+
|
| 99 |
+
```dssl
|
| 100 |
+
.a {
|
| 101 |
+
color: red
|
| 102 |
+
hover { color: blue }
|
| 103 |
+
padding: 4
|
| 104 |
+
}
|
| 105 |
+
```
|
| 106 |
+
|
| 107 |
+
This makes `.a { color }` (order 1), `.a:hover { color }` (order 2) and `.a { padding }`
|
| 108 |
+
(order 3). The hover rule beats the base rule because it comes later. Writing the hover block
|
| 109 |
+
before `color: red` would make `color: red` win while hovering.
|
| 110 |
+
|
| 111 |
+
- **CAS-13.** A nested block is fully walked, and its own rule is emitted, before the rest of
|
| 112 |
+
its parent. Blocks nested inside it are emitted first.
|
| 113 |
+
- **CAS-14.** A rule with no declarations after resolution is not emitted.
|
| 114 |
+
- **CAS-15.** Declarations that appear with no selector around them are the error
|
| 115 |
+
`declarations must live inside a selector`, at the line of the first (line 0 for the file
|
| 116 |
+
top level).
|
| 117 |
+
- **CAS-16.** `order` is local to a file. When the host loads several files, it MUST place
|
| 118 |
+
them in load order and give every rule one position in that single sequence: the numbers of
|
| 119 |
+
a later file continue after the largest number of the earlier one. A later file wins over
|
| 120 |
+
an earlier one for equal layers.
|
| 121 |
+
|
| 122 |
+
Why: before 0.8.2 each file counted from zero and the numbers were compared across files,
|
| 123 |
+
which made a later file lose to an earlier one for no visible reason.
|
| 124 |
+
|
| 125 |
+
## 5.5 Media conditions
|
| 126 |
+
|
| 127 |
+
`@media <query>` adds one normalized query to `media`.
|
| 128 |
+
|
| 129 |
+
- **CAS-17.** The query is trimmed. An empty query is the error `@media needs a condition`
|
| 130 |
+
and the query `(min-width: 0)`.
|
| 131 |
+
- **CAS-18.** The single words `dark`, `light` and `reduced-motion` (any case) become
|
| 132 |
+
`(prefers-color-scheme: dark)`, `(prefers-color-scheme: light)` and
|
| 133 |
+
`(prefers-reduced-motion: reduce)`.
|
| 134 |
+
- **CAS-19.** `N` or `>= N` becomes `(min-width: Npx)`. `<= N` becomes `(max-width: Npx)`.
|
| 135 |
+
`A..B` becomes `(min-width: Apx) and (max-width: Bpx)`. `N`, `A` and `B` are numbers.
|
| 136 |
+
- **CAS-20.** Any other query is kept, except that in any comparison, a bare number after
|
| 137 |
+
`>`, `<` or `=` that has no unit gets `px`: `(width >= 768)` becomes `(width >= 768px)`.
|
| 138 |
+
- **CAS-21.** A condition holds when the host's media query evaluation says it holds.
|
| 139 |
+
|
| 140 |
+
```dssl
|
| 141 |
+
.a {
|
| 142 |
+
@media 768 { padding: 24 }
|
| 143 |
+
@media <= 480 { padding: 12 }
|
| 144 |
+
@media 480..960 { gap: 4 }
|
| 145 |
+
}
|
| 146 |
+
```
|
| 147 |
+
|
| 148 |
+
## 5.6 Container conditions
|
| 149 |
+
|
| 150 |
+
- **CAS-22.** `@container <query>` adds one normalized query (same rules as 5.5, with the
|
| 151 |
+
empty case `(min-width: 0)`) to `containers`.
|
| 152 |
+
- **CAS-23.** A container condition holds for an element when the nearest ancestor (or the
|
| 153 |
+
element itself) that the page marked as a container has a content width that satisfies every
|
| 154 |
+
bound in the query. A bound is `(min-width: N)`, `(max-width: N)`, `(width >= N)` or
|
| 155 |
+
`(width <= N)`. If no ancestor is a container, the condition does not hold.
|
| 156 |
+
|
| 157 |
+
## 5.7 States
|
| 158 |
+
|
| 159 |
+
- **CAS-24.** A state block `name { ... }` in a block with selector `S` makes a rule with
|
| 160 |
+
selector `S:name`. When `S` is a list, the state is added to every part (`.a, .b` with
|
| 161 |
+
`hover` is `.a:hover, .b:hover`). The state words are in appendix A. State blocks can nest
|
| 162 |
+
(`hover { focus { } }` gives `S:hover:focus`).
|
| 163 |
+
- **CAS-25.** A state block with no selector around it is the error `"<name>" needs a
|
| 164 |
+
selector around it`.
|
| 165 |
+
- **CAS-26.** All state words except `seen` are the CSS pseudo-classes of the same name and
|
| 166 |
+
are matched by the host.
|
| 167 |
+
- **CAS-27.** `seen` is not a CSS pseudo-class. An element is *seen* once at least part of it
|
| 168 |
+
has been inside the viewport, and stays seen. A rule whose selector contains `:seen`
|
| 169 |
+
matches when the selector with `:seen` removed (or `*` if nothing is left) matches and the
|
| 170 |
+
element is seen. An implementation MUST re-evaluate the element when it becomes seen.
|
| 171 |
+
- **CAS-28.** Inside a `seen` block, a value that contains `->` is the error
|
| 172 |
+
`"<prop>: <value>" - the -> arrow is motion syntax and does nothing inside seen { }`. The
|
| 173 |
+
rule is still emitted.
|
| 174 |
+
- **CAS-29.** `states` is the set of state words found in `sel` as `:word`, from the list:
|
| 175 |
+
hover, focus-visible, focus, active, disabled, checked, empty, target, invalid, valid,
|
| 176 |
+
required, open, closed, read-only, read-write, placeholder-shown, first-child, last-child,
|
| 177 |
+
only-child, seen.
|
| 178 |
+
|
| 179 |
+
## 5.8 Pseudo-elements and shadow rules
|
| 180 |
+
|
| 181 |
+
Inline styles cannot reach pseudo-elements, so the reference engine puts them in a separate
|
| 182 |
+
stylesheet. A native implementation has no such limit, but the resolver output still keeps
|
| 183 |
+
them in `shadowRules`, so that results are comparable.
|
| 184 |
+
|
| 185 |
+
- **CAS-30.** A block `::name { }` inside a selector block `S` makes a shadow rule with
|
| 186 |
+
`sel` = `S` and `pseudo` = `name`. When `S` is a list, there is one shadow rule per part
|
| 187 |
+
(and per state block inside it), each with its own copy of the declarations. At the top
|
| 188 |
+
level (no selector), `sel` is `*`.
|
| 189 |
+
- **CAS-31.** Inside a pseudo-element block, only declarations and state blocks are allowed.
|
| 190 |
+
Anything else is the error
|
| 191 |
+
`only declarations and states (hover { }) may appear inside a pseudo-element block`. A
|
| 192 |
+
state block inside makes a second shadow rule with `sel` = `S:<state>`. `seen` there is
|
| 193 |
+
the error `"seen" is engine-native and has no meaning on a pseudo-element`.
|
| 194 |
+
- **CAS-32.** A bare `content:` (no value) inside a pseudo-element becomes `content: ""`.
|
| 195 |
+
- **CAS-33.** Engine-native declarations (the `@` ones in 6.8) are not allowed on a
|
| 196 |
+
pseudo-element, except `@animate`. Each is the error
|
| 197 |
+
`"<prop>" is engine-native and has no meaning on ::<name> - a pseudo-element has no DOM
|
| 198 |
+
handle`, and is dropped.
|
| 199 |
+
- **CAS-34.** The same applies when the pseudo-element is written in the selector itself
|
| 200 |
+
(`.card::before { }`). The selector is split at the first top-level `::`. If every part of
|
| 201 |
+
a selector list has a pseudo-element, the rule becomes one shadow rule per part. If only
|
| 202 |
+
some do, the error is `selector list mixes pseudo-element and plain selectors: "<sel>"`
|
| 203 |
+
and nothing is emitted.
|
| 204 |
+
- **CAS-35.** A pseudo-element name MUST be in the pseudo-element list or match the vendor
|
| 205 |
+
pseudo pattern (appendix A), otherwise: `unknown pseudo-element "::<name>"`. `::slotted()`
|
| 206 |
+
is the error `::slotted() only exists inside a shadow tree, and DSSL styles the light DOM`.
|
| 207 |
+
`:seen` combined with a pseudo-element is an error.
|
| 208 |
+
- **CAS-36.** If every declaration of a shadow rule was rejected, nothing is emitted.
|
| 209 |
+
|
| 210 |
+
```dssl
|
| 211 |
+
.btn {
|
| 212 |
+
::after {
|
| 213 |
+
content: ""
|
| 214 |
+
opacity: 0
|
| 215 |
+
hover { opacity: 1 }
|
| 216 |
+
}
|
| 217 |
+
}
|
| 218 |
+
```
|
| 219 |
+
|
| 220 |
+
## 5.9 Signals
|
| 221 |
+
|
| 222 |
+
A signal is a named value that the page sets. It is how DSSL reads state that CSS cannot see
|
| 223 |
+
(a theme chosen in a menu, a game screen). Chapter 11 says how a browser could expose it.
|
| 224 |
+
|
| 225 |
+
- **CAS-37.** `@signal <expr>` adds one condition to `signals`. The forms are:
|
| 226 |
+
|
| 227 |
+
| Form | Condition record |
|
| 228 |
+
|---|---|
|
| 229 |
+
| `name` | `{ name, op: 'truthy', value: null }` |
|
| 230 |
+
| `name == value` | `{ name, op: '==', value }` |
|
| 231 |
+
| `name != value` | `{ name, op: '!=', value }` |
|
| 232 |
+
| `name in (a, b)` | `{ name, op: 'in', value: 'a,b', values: ['a','b'] }` |
|
| 233 |
+
| `name not in (a, b)` | `{ name, op: 'notin', value: 'a,b', values: ['a','b'] }` |
|
| 234 |
+
|
| 235 |
+
A name matches `[A-Za-z_][\w-]*`. A value may be quoted with `"` or `'`, and the quotes are
|
| 236 |
+
removed. List values are trimmed, unquoted, and empty ones removed.
|
| 237 |
+
- **CAS-38.** An expression in none of these forms is the error
|
| 238 |
+
`bad @signal expression "<expr>"` and is treated as `truthy` on the whole text. An empty
|
| 239 |
+
list is the error `@signal <name> <in|not in> ( ) has no values`.
|
| 240 |
+
- **CAS-39.** A signal's value is looked up on the element, then on each ancestor, then at the
|
| 241 |
+
document level. The first place that has the name wins. Values are compared as strings.
|
| 242 |
+
- **CAS-40.** A signal condition holds when:
|
| 243 |
+
- `truthy`: the name has a value that is not `false`, `null`, the string `false`, `0` or
|
| 244 |
+
the string `0`,
|
| 245 |
+
- `==`: the name has a value and its string equals the condition's value,
|
| 246 |
+
- `!=`: the name has no value, or its string differs,
|
| 247 |
+
- `in`: the name has a value and it is in the list,
|
| 248 |
+
- `notin`: the name has no value, or it is not in the list.
|
| 249 |
+
|
| 250 |
+
## 5.10 Which rules apply to an element
|
| 251 |
+
|
| 252 |
+
- **CAS-41.** A rule applies to an element when all of these hold:
|
| 253 |
+
1. its selector matches the element. A rule with selector `:root` applies only to the
|
| 254 |
+
document's root element;
|
| 255 |
+
2. if the selector contains `:seen`, CAS-27 holds;
|
| 256 |
+
3. every `media` condition holds;
|
| 257 |
+
4. every `signals` condition holds;
|
| 258 |
+
5. every `containers` condition holds.
|
| 259 |
+
- **CAS-42.** Applicable rules are sorted by layer rank, then by `order` (both ascending). The
|
| 260 |
+
declarations of the sorted rules are flattened in that order, each rule's declarations in
|
| 261 |
+
their written order.
|
| 262 |
+
- **CAS-43.** For each property, the last declaration in that sequence wins. Engine-native
|
| 263 |
+
declarations (6.8) each have their own combination rule, given with their feature.
|
| 264 |
+
|
| 265 |
+
## 5.11 What else decides the value
|
| 266 |
+
|
| 267 |
+
These rules are about where DSSL meets the page.
|
| 268 |
+
|
| 269 |
+
- **CAS-44.** *Inline styles written by the page.* A declaration that the page itself put in
|
| 270 |
+
the element's `style` attribute, or set from a script, beats any rule that is not in `pin`.
|
| 271 |
+
A `pin` rule beats it. A property the page removes is free for rules again.
|
| 272 |
+
- **CAS-45.** *Shorthand and longhand.* A shorthand expands into its longhands in cascade
|
| 273 |
+
position. Of a shorthand and one of its longhands, the one that comes later in the
|
| 274 |
+
flattened sequence wins for that longhand. This holds for `border` and its `-color`,
|
| 275 |
+
`-width` and `-style` longhands, and for `padding`, `margin` and `gap` and their sides.
|
| 276 |
+
- **CAS-46.** *Handing back with yield.* After the sequence is flattened, properties named by
|
| 277 |
+
the last applicable `yield:` (6.7) are removed from the DSSL result, so ordinary CSS decides
|
| 278 |
+
them. `yield: none` clears the list.
|
| 279 |
+
- **CAS-47.** *Alignment makes a box.* If the winning declarations include any of
|
| 280 |
+
`place-items`, `place-content`, `align-items`, `justify-items`, `align-content` or
|
| 281 |
+
`justify-content`, and the element has no declared `display`, and the element's natural
|
| 282 |
+
`display` is not `flex`, `inline-flex`, `grid` or `inline-grid` (and is not `none` or
|
| 283 |
+
`contents`), then `display` is set to `inline-grid` when the natural `display` is `inline` or
|
| 284 |
+
starts with `inline-`, and to `grid` otherwise. An explicit `display` from any rule wins over
|
| 285 |
+
this.
|
| 286 |
+
|
| 287 |
+
Why: alignment properties do nothing on a plain `span` or `button`, and DSSL treats that as a
|
| 288 |
+
silent failure.
|
| 289 |
+
|
| 290 |
+
- **CAS-48.** *Border and positional shorthands in the inline lane.* A browser that computes
|
| 291 |
+
styles natively does not need extra rules for CAS-45: the CSS cascade already does it.
|
|
@@ -0,0 +1,261 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 6. Properties
|
| 2 |
+
|
| 3 |
+
A declaration `prop: value` becomes zero or more *output declarations*. An output declaration
|
| 4 |
+
is either an ordinary CSS declaration `{ prop, value }`, or an *engine-native declaration*
|
| 5 |
+
whose property starts with `@` (6.8).
|
| 6 |
+
|
| 7 |
+
## 6.1 Lookup order
|
| 8 |
+
|
| 9 |
+
- **PRP-1.** For each declaration, the resolver does the first of these that applies:
|
| 10 |
+
1. If the value contains `!important` (VAL-15): report the error, emit nothing.
|
| 11 |
+
2. If `prop` starts with `--`: it is a custom property (TOK-15, TOK-16).
|
| 12 |
+
3. If `prop` is a semantic property (the names in 6.2 to 6.7, and appendix A): call that
|
| 13 |
+
property's expansion. It returns its own output declarations.
|
| 14 |
+
4. If `prop` is `animation` or `animation-name`: resolve the value with `bareIdents: true`
|
| 15 |
+
and `unitless` per the unitless list. (Motion names are bare words, and must not be
|
| 16 |
+
reported as unknown values.)
|
| 17 |
+
5. If the value is `fluid ...` and `prop` is in the fluid list: VAL-12 to VAL-14.
|
| 18 |
+
6. If `prop` is not a known CSS property (appendix A): report
|
| 19 |
+
`unknown property "<prop>"`, hint = did-you-mean over the known properties and the
|
| 20 |
+
semantic property names. Emit nothing.
|
| 21 |
+
7. Otherwise: one output declaration with the same property and the value resolved by
|
| 22 |
+
chapter 3.
|
| 23 |
+
|
| 24 |
+
The known-property list holds every property that CSS defines, plus a few vendor ones. It is
|
| 25 |
+
generated from the engine's vocabulary module (appendix A).
|
| 26 |
+
|
| 27 |
+
Each output declaration also carries the `line` of the source declaration.
|
| 28 |
+
|
| 29 |
+
```dssl error
|
| 30 |
+
.a { colour: red }
|
| 31 |
+
```
|
| 32 |
+
|
| 33 |
+
## 6.2 Size and flow words
|
| 34 |
+
|
| 35 |
+
- **PRP-2.** `size: w [h]`. Two declarations `width` and `height`. The height defaults to the
|
| 36 |
+
width. Both are lengths.
|
| 37 |
+
- **PRP-3.** `circle: s`. `width: s`, `height: s`, `border-radius: 50%`.
|
| 38 |
+
- **PRP-4.** `z: n` is `z-index: n` (a plain number). `grow`, `shrink` are `flex-grow`,
|
| 39 |
+
`flex-shrink` (a plain number, default 1 when empty). `basis: l` is `flex-basis: l`.
|
| 40 |
+
- **PRP-5.** `cover [position]` is `position: <position or absolute>` and `inset: 0`.
|
| 41 |
+
`sticky [top]` is `position: sticky` and `top: <top or 0>`.
|
| 42 |
+
- **PRP-6.** `truncate` (no value) is `overflow: hidden`, `text-overflow: ellipsis`,
|
| 43 |
+
`white-space: nowrap`.
|
| 44 |
+
- **PRP-7.** `visually-hidden` (no value) is `position: absolute; width: 1px; height: 1px;
|
| 45 |
+
padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
|
| 46 |
+
border: 0`, in that order.
|
| 47 |
+
|
| 48 |
+
## 6.3 Row, column, grid, stack, place, center
|
| 49 |
+
|
| 50 |
+
*Place words* map to two values, `(cross, main)`:
|
| 51 |
+
|
| 52 |
+
| word | cross | main |
|
| 53 |
+
|---|---|---|
|
| 54 |
+
| `center` | `center` | `center` |
|
| 55 |
+
| `start` | `start` | `flex-start` |
|
| 56 |
+
| `end` | `end` | `flex-end` |
|
| 57 |
+
| `between` | `center` | `space-between` |
|
| 58 |
+
| `around` | `center` | `space-around` |
|
| 59 |
+
| `evenly` | `center` | `space-evenly` |
|
| 60 |
+
| `stretch` | `stretch` | `flex-start` |
|
| 61 |
+
| `baseline` | `baseline` | `flex-start` |
|
| 62 |
+
|
| 63 |
+
- **PRP-8.** `row: words` and `column: words` start with `display: flex` and
|
| 64 |
+
`flex-direction: row|column`, then read the words in order:
|
| 65 |
+
- `gap N`: `gap: N` (a length). Missing `N` is the error `gap needs a value`.
|
| 66 |
+
- `wrap` / `nowrap`: `flex-wrap`.
|
| 67 |
+
- `reverse`: the direction becomes `row-reverse` or `column-reverse`.
|
| 68 |
+
- `inline`: `display` becomes `inline-flex`.
|
| 69 |
+
- a place word: see PRP-9.
|
| 70 |
+
- anything else: error `unknown word "<w>" in <row|column>`, hint = did-you-mean over
|
| 71 |
+
`gap center start end between around evenly stretch baseline wrap nowrap reverse inline`.
|
| 72 |
+
- **PRP-9.** Each place word has an axis role. `between`, `around`, `evenly` are *main*
|
| 73 |
+
(they write `justify-content`). `stretch` and `baseline` are *cross* (they write
|
| 74 |
+
`align-items`). `center`, `start`, `end` are *both*: they write whichever axes have not been
|
| 75 |
+
written yet by an earlier word in this declaration.
|
| 76 |
+
- A word that writes an axis a second time overrides it, with a warning:
|
| 77 |
+
`two words in <dir> write <prop>: "<new>" overrides "<old>"`, or when the same word, `"<w>"
|
| 78 |
+
is written twice in <dir> - the second copy wins`.
|
| 79 |
+
- A *both* word with both axes already taken writes nothing and warns
|
| 80 |
+
`"<w>" has nowhere to go: justify-content came from "<a>", align-items came from "<b>"`
|
| 81 |
+
(or the "written twice" form when it is the same word).
|
| 82 |
+
- **PRP-10.** `grid: words`. Words `gap N` and `rows N` are taken out first. The rest are the
|
| 83 |
+
column spec:
|
| 84 |
+
- nothing: error `grid needs columns`, columns are `none`,
|
| 85 |
+
- one integer `N`: `repeat(N, 1fr)`,
|
| 86 |
+
- `auto-fill L` or `auto-fit L`: `repeat(auto-fill, minmax(L, 1fr))` with `L` a length,
|
| 87 |
+
- otherwise each word is a length, joined by spaces.
|
| 88 |
+
The output is `display: grid`, `grid-template-columns`, then `gap` if given, then
|
| 89 |
+
`grid-template-rows` if given (`repeat(N, 1fr)` for an integer, a length otherwise).
|
| 90 |
+
- **PRP-11.** `stack: word` (default `center`) is `display: grid`,
|
| 91 |
+
`place-items: <cross> <main>` and `@stack: "1"`. An unknown word is the error
|
| 92 |
+
`unknown place "<w>" in stack` and only `@stack` is emitted.
|
| 93 |
+
- **PRP-12.** `place: word` is `place-items` and `place-content`, both `<cross> <main>`.
|
| 94 |
+
Unknown: `unknown place "<w>"`.
|
| 95 |
+
- **PRP-13.** `center: both|x|y` (default `both`). `both`: `place-items: center center` and
|
| 96 |
+
`place-content: center center`. `x`: `justify-items: center`, `justify-content: center`.
|
| 97 |
+
`y`: `align-items: center`, `align-content: center`. Unknown:
|
| 98 |
+
`unknown center axis "<v>"`.
|
| 99 |
+
- **PRP-14.** `align: center|start|end|stretch|baseline` is `align-items` with that word.
|
| 100 |
+
Unknown: `unknown align "<v>"`.
|
| 101 |
+
|
| 102 |
+
```dssl
|
| 103 |
+
.toolbar { row: gap 8 between center }
|
| 104 |
+
.board { grid: 3 gap 12 }
|
| 105 |
+
.pane { stack: center }
|
| 106 |
+
.hero { center: both }
|
| 107 |
+
```
|
| 108 |
+
|
| 109 |
+
The first rule gives `display: flex; flex-direction: row; gap: 8px;
|
| 110 |
+
justify-content: space-between; align-items: center`.
|
| 111 |
+
|
| 112 |
+
## 6.4 Text and look
|
| 113 |
+
|
| 114 |
+
- **PRP-15.** `font: size[/line-height] [color]`. DSSL's `font:` is not the CSS shorthand.
|
| 115 |
+
It writes `font-size` (a length, default `16`), then `line-height` (a plain number) if a `/`
|
| 116 |
+
part is there, then `color` if more words follow.
|
| 117 |
+
If the value looks like the CSS shorthand (it contains `"`, `'` or `,`, or its first word is
|
| 118 |
+
one of `italic oblique bold bolder lighter normal small-caps condensed expanded caption icon
|
| 119 |
+
menu message-box small-caption status-bar system-ui serif sans-serif monospace`, or it is a
|
| 120 |
+
weight `100`..`900` followed by a sized word), the result is the error
|
| 121 |
+
`font: "<v>" looks like the CSS font shorthand, but DSSL's font: means size, line height and
|
| 122 |
+
colour` and nothing is emitted.
|
| 123 |
+
- **PRP-16.** `fluid: a, b[, v0, v1]` is `font-size` through VAL-12 to VAL-14.
|
| 124 |
+
- **PRP-17.** `shadow` and `radius`: TOK-17, TOK-18.
|
| 125 |
+
- **PRP-18.** `text-stroke: width [color] [inside]`, or `none`. It writes
|
| 126 |
+
`-webkit-text-stroke: <width> <color>` (width in px if bare, color default `currentcolor`),
|
| 127 |
+
and `paint-order: stroke fill` unless `inside` is given. `none` writes
|
| 128 |
+
`-webkit-text-stroke: 0` and `paint-order: normal`. A missing or non-numeric width is the
|
| 129 |
+
error `text-stroke needs a width first`.
|
| 130 |
+
- **PRP-19.** `outline-shape: width [color]`, or `none`. It writes one `filter` made of four
|
| 131 |
+
`drop-shadow(x y 0 color)` terms for `(w,0)`, `(-w,0)`, `(0,w)`, `(0,-w)`. `none` is
|
| 132 |
+
`filter: none`. A missing width is the error `outline-shape needs a width first`.
|
| 133 |
+
- **PRP-20.** `rotate: v`. A bare number `n` is `n` degrees. `x|y|z n` and four numbers also
|
| 134 |
+
get `deg`. Anything else is resolved as a unitless value.
|
| 135 |
+
|
| 136 |
+
## 6.5 transition
|
| 137 |
+
|
| 138 |
+
`transition: part, part, ...` or `none`. Each part is `duration [easing] [property]`.
|
| 139 |
+
|
| 140 |
+
- **PRP-21.** The duration is a number with an optional `ms` or `s` unit. A bare number is
|
| 141 |
+
milliseconds. The easing is an easing name (appendix A) or a `cubic-bezier(...)` or
|
| 142 |
+
`steps(...)` call. The property is a known CSS property, or one of the deform names
|
| 143 |
+
(`bend`, `bend-y`, `bend-up`, `fold`, `stretch`, which mean `transform`), and defaults to
|
| 144 |
+
`all`. The part becomes `<property> <duration> <easing>`, with the easing defaulting to
|
| 145 |
+
`ease`. Parts are joined by `, `.
|
| 146 |
+
- **PRP-22.** If a part does not start with a time but contains one (the CSS habit,
|
| 147 |
+
`color .2s ease`), the error is `transition: the CSS form (property first) is not DSSL`,
|
| 148 |
+
with a hint that rewrites the part in DSSL order. A part with no time at all is the error
|
| 149 |
+
`transition duration "<d>" is not a time`. An unknown property is
|
| 150 |
+
`unknown transition property "<p>"`. A part with an error is dropped. If no part survives,
|
| 151 |
+
nothing is emitted.
|
| 152 |
+
|
| 153 |
+
## 6.6 gradient
|
| 154 |
+
|
| 155 |
+
`gradient: layer + layer + ...`. The first layer is on top. Each layer is a *kind sentence*
|
| 156 |
+
optionally followed by *layer options*.
|
| 157 |
+
|
| 158 |
+
- **PRP-23.** Layers are split on a top-level `+` that has white space on both sides.
|
| 159 |
+
- **PRP-24.** Layer options may follow the sentence, in any order, each at the end of the text:
|
| 160 |
+
`tile W [H]` (background size, bare numbers are px, H defaults to W), `offset X Y`
|
| 161 |
+
(background position) and one of `no-repeat`, `repeat-x`, `repeat-y`.
|
| 162 |
+
- **PRP-25.** If the layer (after options) starts with a CSS gradient function, `url(`,
|
| 163 |
+
`image-set(` or `-webkit-`, it is resolved as an ordinary value. Otherwise it is a sentence.
|
| 164 |
+
- **PRP-26.** A sentence is `[repeating] linear|radial|conic <head> <stops>` or
|
| 165 |
+
`mesh <base>, <blob>, ...`. The output is the CSS function `linear-gradient(...)`,
|
| 166 |
+
`radial-gradient(...)`, `conic-gradient(...)` (with `repeating-` first when asked).
|
| 167 |
+
- **PRP-27.** Stops are separated by `->` or by commas. Each is a color (a token, hex, named
|
| 168 |
+
color, color function, alpha form) with up to two trailing positions, or a lone position
|
| 169 |
+
(a midpoint hint). Bare numbers in positions are px (degrees for `conic`), except `0`
|
| 170 |
+
which stays `0`. A stop word that is a plain word but not a color name is the error
|
| 171 |
+
`gradient stop "<s>" is not a color`.
|
| 172 |
+
- **PRP-28.** A *linear* head is an angle (a bare number is degrees, `45deg` also works) or
|
| 173 |
+
`to <side> [<side>]`. Default `180deg`. A *radial* head is made of `circle`, `ellipse`,
|
| 174 |
+
position words, lengths and `at`. A *conic* head is `from <angle>` and/or `at <position>`.
|
| 175 |
+
Anything else is an error saying what is not part of the gradient. An interpolation space
|
| 176 |
+
(`in oklch`, `in hsl longer hue`, ...) may end the head.
|
| 177 |
+
- **PRP-29.** `mesh` takes a base color first (an item without `at`), then blobs
|
| 178 |
+
`color at X Y [size S]` (size defaults to 60%). Each blob is
|
| 179 |
+
`radial-gradient(circle farthest-side at X Y, color, transparent S)`. The base is
|
| 180 |
+
`linear-gradient(base, base)`. The blobs come first, the base last.
|
| 181 |
+
- **PRP-30.** Errors: `gradient needs a kind: ...`, `gradient needs at least two stops`,
|
| 182 |
+
`"<s>" is a midpoint, so it has to sit between two colours`, `a gradient stop is missing its
|
| 183 |
+
color`, `mesh needs a base colour and at least one blob`, `mesh item "<i>" needs a position`,
|
| 184 |
+
`mesh needs a base colour first (an item without "at")`.
|
| 185 |
+
- **PRP-31.** `gradient:` writes `background-image` marked as coming from a gradient, plus
|
| 186 |
+
`background-size`, `background-position` and `background-repeat` only when some layer set
|
| 187 |
+
one (with `auto`, `0 0` and `repeat` for the layers that did not).
|
| 188 |
+
- **PRP-32.** `gradient-text: layers` writes the same image, then `background-clip: text`,
|
| 189 |
+
`-webkit-background-clip: text`, `color: transparent`, `-webkit-text-fill-color: transparent`.
|
| 190 |
+
- **PRP-33.** `gradient-flow: duration [easing] [alternate|alternate-reverse]` or `none`
|
| 191 |
+
writes `@gradient-flow` with `{ duration (ms), easing, direction }`. `none` and an empty
|
| 192 |
+
value write `@gradient-flow: null`. The easing default is `linear` and the direction
|
| 193 |
+
default is `normal`.
|
| 194 |
+
|
| 195 |
+
```dssl
|
| 196 |
+
.stripes { gradient: repeating linear 45, #fff 0 10, color.ink 10 20 }
|
| 197 |
+
.blend { gradient: linear 90 in oklch, #ff0055 -> #00d4ff }
|
| 198 |
+
.sheen { gradient: radial at top left, #fff/40 -> transparent + linear 135, #123 -> #456 }
|
| 199 |
+
```
|
| 200 |
+
|
| 201 |
+
## 6.7 yield
|
| 202 |
+
|
| 203 |
+
`yield: name name ...` hands properties back to ordinary CSS.
|
| 204 |
+
|
| 205 |
+
- **PRP-34.** The names are separated by spaces or commas and lowercased. Each MUST be a known
|
| 206 |
+
CSS property or a semantic property name, otherwise the error
|
| 207 |
+
`yield: "<n>" is not a CSS property` and nothing is emitted. An empty list is the error
|
| 208 |
+
`yield needs the properties to hand back`. `none` writes `@yield: null`. Otherwise it writes
|
| 209 |
+
`@yield` with the list of names.
|
| 210 |
+
- **PRP-35.** For a name that is a shorthand, its longhands are handed back too (`padding`
|
| 211 |
+
hands back `padding-top` and the rest).
|
| 212 |
+
|
| 213 |
+
## 6.8 Engine-native declarations
|
| 214 |
+
|
| 215 |
+
Declarations whose property starts with `@` are not CSS. They describe behavior that needs
|
| 216 |
+
more than a computed style. Each is produced by exactly one DSSL property and consumed by the
|
| 217 |
+
feature it belongs to.
|
| 218 |
+
|
| 219 |
+
| Output property | Produced by | Value | Chapter |
|
| 220 |
+
|---|---|---|---|
|
| 221 |
+
| `@animate` | `animate:` | a spec record, or null | 7 |
|
| 222 |
+
| `@stagger` | `stagger:` | milliseconds or null | 7 |
|
| 223 |
+
| `@overlap` | `overlap:` | `allow`, `deny`, `auto` | 8.6 |
|
| 224 |
+
| `@stack` | `stack:` | `"1"` | 6.3 |
|
| 225 |
+
| `@bend`, `@bend-y`, `@bend-up`, `@fold` | `bend`, `bend-y`, `bend-up`, `fold` | degrees | 8.5 |
|
| 226 |
+
| `@stretch` | `stretch:` | `{ factor, axis }` | 8.5 |
|
| 227 |
+
| `@bend-around` | `bend-around:` | degrees | 8.5 |
|
| 228 |
+
| `@gradient-flow` | `gradient-flow:` | spec record or null | 6.6 |
|
| 229 |
+
| `@texture` | `texture:` | list of layers or null | 8.1 |
|
| 230 |
+
| `@aura-glow`, `@aura-particles` | the aura family | list of layers or null | 8.2 |
|
| 231 |
+
| `@slider` | `slider:` | spec record | 8.3 |
|
| 232 |
+
| `@tilt` | `tilt:` | spec record or null | 8.4 |
|
| 233 |
+
| `@yield` | `yield:` | list of names or null | 6.7 |
|
| 234 |
+
|
| 235 |
+
- **PRP-36.** Engine-native declarations are not CSS and a host MUST NOT pass them to the
|
| 236 |
+
style system as properties. A Level 3 implementation combines them with the rule for each
|
| 237 |
+
feature. The default combination is the CSS one: for each name, the last in cascade order
|
| 238 |
+
wins. Exceptions are `@animate` (all of them are kept, 7.2) and `@yield` (names accumulate,
|
| 239 |
+
5.11).
|
| 240 |
+
|
| 241 |
+
## 6.9 behavior and use
|
| 242 |
+
|
| 243 |
+
```dssl
|
| 244 |
+
behavior focus-ring {
|
| 245 |
+
outline: 2 solid color.accent
|
| 246 |
+
outline-offset: 2
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
.btn { use focus-ring }
|
| 250 |
+
```
|
| 251 |
+
|
| 252 |
+
- **PRP-37.** A top-level `behavior name { ... }` defines a named block of declarations and
|
| 253 |
+
nested blocks. A second block with the same name is the error `behavior "<n>" is defined
|
| 254 |
+
twice`. Behaviors are collected before the walk, so a behavior may be used above its
|
| 255 |
+
definition. `behavior` is allowed only at the top level.
|
| 256 |
+
- **PRP-38.** `use name` inside a block replays the behavior's children there, as if they had
|
| 257 |
+
been written in that place, with the same context. An unknown name is
|
| 258 |
+
`unknown behavior "<n>"` with a did-you-mean over the defined names. A behavior that uses
|
| 259 |
+
itself, directly or through others, is `behavior cycle involving "<n>"`.
|
| 260 |
+
- **PRP-39.** The declarations of a behavior are resolved at the place they are used, so
|
| 261 |
+
tokens, conditions and layers there apply to them.
|
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 7. Motion
|
| 2 |
+
|
| 3 |
+
DSSL separates *defining* a motion from *running* it. `motion` defines keyframes. `animate:`
|
| 4 |
+
runs one on an element. `seen` and states decide when.
|
| 5 |
+
|
| 6 |
+
## 7.1 Defining a motion
|
| 7 |
+
|
| 8 |
+
```dssl
|
| 9 |
+
motion rise-in {
|
| 10 |
+
from { opacity: 0; translate: 0 18 }
|
| 11 |
+
to { opacity: 1; translate: 0 0 }
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
motion pulse {
|
| 15 |
+
essential
|
| 16 |
+
0% { opacity: 1 }
|
| 17 |
+
50% { opacity: 0.6 }
|
| 18 |
+
100% { opacity: 1 }
|
| 19 |
+
}
|
| 20 |
+
```
|
| 21 |
+
|
| 22 |
+
- **MOT-1.** `motion <name> { ... }` is allowed only at the top level. A motion block holds
|
| 23 |
+
keyframe blocks and the word `essential`. Any other declaration is the error `"<prop>" is
|
| 24 |
+
not allowed inside motion`, with the hint `motions take from/to/at blocks and essential`.
|
| 25 |
+
- **MOT-2.** A keyframe block header is one of `from` (0), `to` (100), `at N%` or `N%` or
|
| 26 |
+
`N`, or a comma list of these (`0%, 100%`). Every offset MUST be between 0 and 100. A bad
|
| 27 |
+
header is the error `bad keyframe selector "<h>"`.
|
| 28 |
+
- **MOT-3.** `essential` (alone, or as `essential: true`) marks the motion as one that keeps
|
| 29 |
+
playing under `prefers-reduced-motion`.
|
| 30 |
+
- **MOT-4.** Declarations inside a keyframe are resolved like any other declaration
|
| 31 |
+
(chapter 6) with `prop` set to the source property. Custom properties are dropped. Each
|
| 32 |
+
output property is named in camelCase (`background-color` becomes `backgroundColor`).
|
| 33 |
+
- **MOT-5.** In a keyframe, the deform words (`bend`, `bend-y`, `bend-up`, `fold`, `stretch`)
|
| 34 |
+
are not kept as properties. They are composed into one `transform` (8.5), with an extra
|
| 35 |
+
`transformOrigin` for the edge-pinned ones, because there is no box yet when keyframes are
|
| 36 |
+
built. A deform value of 0 is a real reset.
|
| 37 |
+
- **MOT-6.** A list header makes one frame per offset with the same properties. The frames of a
|
| 38 |
+
motion are sorted by offset (a stable sort).
|
| 39 |
+
- **MOT-7.** The result is `{ essential: bool, frames: [{ offset, props }] }`. A motion block
|
| 40 |
+
is parsed once, the first time it is needed.
|
| 41 |
+
|
| 42 |
+
## 7.2 Running a motion
|
| 43 |
+
|
| 44 |
+
`animate: part, part, ...` or `none`. Each part is `name [words]`.
|
| 45 |
+
|
| 46 |
+
- **MOT-8.** The spec record starts as
|
| 47 |
+
`{ motion: name, duration: 400, easing: smooth, fill: 'both', delay: 0 }`. `smooth` is the
|
| 48 |
+
`cubic-bezier(0.4, 0, 0.2, 1)` easing from appendix A.
|
| 49 |
+
- **MOT-9.** Words after the name are read in order:
|
| 50 |
+
- `delay N`, `jitter N`, `iterations N`: the next word is a number with an optional `ms` or
|
| 51 |
+
`s` unit (for `iterations` a plain count). Missing: error `<word> needs a number`.
|
| 52 |
+
- `essential`: sets `essentialHere`.
|
| 53 |
+
- a number with optional unit: the first word after the name is the duration (`s` means
|
| 54 |
+
seconds, otherwise ms); a later one is the delay.
|
| 55 |
+
- an easing name: sets the easing.
|
| 56 |
+
- `both`, `forwards`, `backwards`, `none`, `auto`: the fill mode.
|
| 57 |
+
- `infinite`: iterations is infinity.
|
| 58 |
+
- `alternate`, `alternate-reverse`, `reverse`, `normal`: the direction.
|
| 59 |
+
- anything else: error `unknown animate part "<w>"`, hint = did-you-mean over the easing
|
| 60 |
+
names and the words above.
|
| 61 |
+
- **MOT-10.** One part gives one `@animate` declaration. Several parts (a top-level comma)
|
| 62 |
+
give several, in order. `animate: none` gives `@animate: null`.
|
| 63 |
+
- **MOT-11.** After the whole file is walked, every `@animate` with a motion name is linked:
|
| 64 |
+
the motion is looked up in this file, then in the motions the host passed in (7.3). If
|
| 65 |
+
found, the spec gets `frames`, and `essential` is true when the motion or the spec says so.
|
| 66 |
+
If not found, the error is `unknown motion "<n>"`, with a did-you-mean over the file's
|
| 67 |
+
motions, or a hint showing how to define one, and the spec is marked `broken`.
|
| 68 |
+
- **MOT-12.** Several `@animate` declarations matched by one element all run, in cascade
|
| 69 |
+
order. `@animate: null` from a later rule cancels the ones before it.
|
| 70 |
+
|
| 71 |
+
## 7.3 Motions across files
|
| 72 |
+
|
| 73 |
+
- **MOT-13.** The host passes the already-built motions of earlier files to the resolver (the
|
| 74 |
+
motion registry). A motion defined in an earlier file can be used by a later one, like a
|
| 75 |
+
token. A motion in the current file shadows one in the registry.
|
| 76 |
+
- **MOT-14.** After resolving, every motion in the file is built (not only the referenced
|
| 77 |
+
ones) and returned as `motionFrames`, for any consumer that wants all of them (the static
|
| 78 |
+
emitter, 11.4).
|
| 79 |
+
|
| 80 |
+
## 7.4 The animation shorthand
|
| 81 |
+
|
| 82 |
+
- **MOT-15.** The plain CSS properties `animation` and `animation-name` pass through (PRP-1,
|
| 83 |
+
item 4), with a bare number meaning ms. If a rule has one whose words do not include the
|
| 84 |
+
name of any motion in this file or the registry, the warning is
|
| 85 |
+
`animation "<v>" references no motion defined in this sheet - it will not run`.
|
| 86 |
+
- **MOT-16.** `animation-delay`, `-duration`, `-iteration-count`, `-direction`, `-fill-mode`,
|
| 87 |
+
`-timing-function` and `-play-state` do nothing in a rule that has no `animation` or
|
| 88 |
+
`animation-name`. The warning is `<prop> does nothing here: this rule has no CSS animation
|
| 89 |
+
to tune`, with a hint to put the setting in the `animate:` line.
|
| 90 |
+
|
| 91 |
+
## 7.5 stagger
|
| 92 |
+
|
| 93 |
+
`stagger: N` on a parent offsets the delay of each element child's animations by
|
| 94 |
+
`index * N` ms, where `index` is the child's position among the parent's element children.
|
| 95 |
+
|
| 96 |
+
- **MOT-17.** The value is a number with optional `ms` or `s`, or `none`. Anything else is the
|
| 97 |
+
error `stagger needs a duration like "60" or "120ms", or "none"`. It writes `@stagger` with
|
| 98 |
+
milliseconds, or `@stagger: null`.
|
| 99 |
+
|
| 100 |
+
## 7.6 Reduced motion
|
| 101 |
+
|
| 102 |
+
- **MOT-18.** When the user prefers reduced motion, a motion plays only if it is `essential`
|
| 103 |
+
(by its own flag or by `essential` on the `animate:` line). Others do not run. Textures,
|
| 104 |
+
auras and tilt follow their own rules in chapter 8.
|
|
@@ -0,0 +1,279 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 8. Effects
|
| 2 |
+
|
| 3 |
+
Effects are the parts of DSSL that CSS has no equivalent for, or only a clumsy one. Each effect
|
| 4 |
+
has two halves:
|
| 5 |
+
|
| 6 |
+
- a **description**: the text the author writes and the record the resolver produces from it.
|
| 7 |
+
This half is fully specified here and a Level 2 implementation MUST produce the same records.
|
| 8 |
+
- a **rendering contract**: what a Level 4 renderer must draw. Where the contract depends on
|
| 9 |
+
generator code that is not yet written down as prose, this chapter says so. Those parts are
|
| 10 |
+
*defined by the reference implementation* (`public/dssl/texture.js`, `aura.js`, `slider.js`)
|
| 11 |
+
until a prose definition replaces them. They are marked **Pending**.
|
| 12 |
+
|
| 13 |
+
All vocabulary tables (setting names, ranges, presets) are generated into appendix A.
|
| 14 |
+
|
| 15 |
+
## 8.1 Texture
|
| 16 |
+
|
| 17 |
+
`texture:` lays a generated image on top of an element's own background.
|
| 18 |
+
|
| 19 |
+
```dssl
|
| 20 |
+
.card { background: #c9a66b; texture: wood }
|
| 21 |
+
.sheet { background: linear-gradient(135deg, #ff7a00, #7a1fff); texture: grain intensity 0.6 }
|
| 22 |
+
.poster { background: #e9e2d0; texture: paper, scanlines intensity 0.1 }
|
| 23 |
+
```
|
| 24 |
+
|
| 25 |
+
**Description.**
|
| 26 |
+
|
| 27 |
+
- **FX-1.** The value is `none`, or a comma-separated list of layers. `none` writes
|
| 28 |
+
`@texture: null`. An empty value is the error `texture needs a name`. Any error anywhere in
|
| 29 |
+
the value drops the whole declaration.
|
| 30 |
+
- **FX-2.** Each layer starts with a preset name or a generator name (appendix A). Otherwise
|
| 31 |
+
the error is `unknown texture "<w>"`, with a did-you-mean over presets and generators.
|
| 32 |
+
- **FX-3.** After the name come settings. A setting is a key from the texture settings table
|
| 33 |
+
(appendix A), followed by as many values as that key takes. A key has one *kind*:
|
| 34 |
+
`flag` (no value), `number`, `numbers` (several), `word` (one of a list) or `color`.
|
| 35 |
+
- A number outside the key's range is the error `texture "<key>" must be between <min> and
|
| 36 |
+
<max>`. A non-number is `texture setting "<key>" needs a number, got "<v>"`.
|
| 37 |
+
- A word not in the list is `unknown <key> "<w>"` with a did-you-mean.
|
| 38 |
+
- A missing value is `texture setting "<key>" needs a value` (or `N values`). A value that is
|
| 39 |
+
itself a setting key counts as missing.
|
| 40 |
+
- A color value is resolved by chapter 3 (tokens, alpha and all). A bad color drops the
|
| 41 |
+
declaration.
|
| 42 |
+
- An unknown key is `unknown texture setting "<key>"` with a did-you-mean.
|
| 43 |
+
- A key marked *optional* (`symmetrical`) may stand alone, and then takes its first listed
|
| 44 |
+
value.
|
| 45 |
+
- **FX-4.** A preset is a stored list of layers. Writing a preset name gives those layers.
|
| 46 |
+
Settings apply to every layer of the preset, except that `color` and `color2` apply only to
|
| 47 |
+
the first layer when the preset has several. A generator name gives one layer made of the
|
| 48 |
+
generator's defaults.
|
| 49 |
+
- **FX-5.** The output is `@texture` with the list of layer records, each being the preset or
|
| 50 |
+
generator layer with the author's overrides applied, and a `preset` field naming the preset
|
| 51 |
+
(null for a bare generator).
|
| 52 |
+
|
| 53 |
+
**Rendering contract.**
|
| 54 |
+
|
| 55 |
+
- **FX-6.** The texture is drawn above the element's own background and below its content. The
|
| 56 |
+
author's background (a color, a gradient, or several layers, written as `background` or
|
| 57 |
+
`background-image`) is never replaced, and removing the texture gives back exactly the
|
| 58 |
+
original.
|
| 59 |
+
- **FX-7.** A texture is deterministic. The same layer record, including `seed`, MUST give the
|
| 60 |
+
same pixels on every machine and every engine. The tile MUST repeat without a visible seam.
|
| 61 |
+
(Why: the reference implementation draws from `seed` and plain arithmetic only.)
|
| 62 |
+
- **FX-8.** `symmetrical` mirrors every other tile on the chosen axis (`x`, `y`, or both), so
|
| 63 |
+
the pattern repeats twice as far apart and each tile edge meets its own reflection. It applies
|
| 64 |
+
to textures made as images (noise, bump, rings, waves, hex) and is ignored by the pure
|
| 65 |
+
pattern generators (lines, dots, grid, checker, carbon).
|
| 66 |
+
- **FX-9.** `animate N` steps the texture every `N` ms. It stands still when the user prefers
|
| 67 |
+
reduced motion.
|
| 68 |
+
- **FX-10.** Colors given as tokens follow the token, including under a theme change.
|
| 69 |
+
|
| 70 |
+
**Pending.** The generators (`noise`, `bump`, `lines`, `dots`, `grid`, `checker`, `weave`,
|
| 71 |
+
`carbon`, `waves`, `hex`, `rings`) and the seeded random number generator are defined by
|
| 72 |
+
`texture.js`. A prose definition of each is the first item of the Level 4 work.
|
| 73 |
+
|
| 74 |
+
## 8.2 Aura
|
| 75 |
+
|
| 76 |
+
An aura is light and particles around an element. There are no presets. Fire, snow and sparks
|
| 77 |
+
are written by the author, usually as a `behavior`.
|
| 78 |
+
|
| 79 |
+
**Description.**
|
| 80 |
+
|
| 81 |
+
- **FX-11.** The properties are `aura`, `aura-glow`, `aura-particle` (and `aura-particles`),
|
| 82 |
+
`glow-particle` (and `-particles`), `aura-glow-particle` (and `-particles`). They write two
|
| 83 |
+
slots, `@aura-glow` and `@aura-particles`. A property that does not touch a slot leaves it
|
| 84 |
+
out of its output.
|
| 85 |
+
|
| 86 |
+
| Property | Writes |
|
| 87 |
+
|---|---|
|
| 88 |
+
| `aura` | both slots, as `glow ..., particles ...` clauses; it replaces both |
|
| 89 |
+
| `aura-glow` | the glow slot |
|
| 90 |
+
| `aura-particle(s)` | the particles slot |
|
| 91 |
+
| `glow-particle(s)` | the particles slot, with every particle glowing |
|
| 92 |
+
| `aura-glow-particle(s)` | both slots, with shared settings; both a glow and particles are required |
|
| 93 |
+
|
| 94 |
+
- **FX-12.** `none` clears exactly the slots the property owns (`aura-glow: none` leaves the
|
| 95 |
+
particles alone). An empty value is the error `<prop> needs a value`. An empty list writes
|
| 96 |
+
`null` for the slot.
|
| 97 |
+
- **FX-13.** A value is a comma-separated list of layers. In `aura`, each layer starts with
|
| 98 |
+
`glow`, `particles` or `particle`, otherwise the error
|
| 99 |
+
`an aura layer starts with glow or particles, not "<w>"`.
|
| 100 |
+
- **FX-14.** Inside a layer, the first color (or `->`-joined color list) and the first number
|
| 101 |
+
are positional: for a glow they are the color and the radius, for particles they are the
|
| 102 |
+
colors and the count. Everything else is a named setting from the glow or particle table
|
| 103 |
+
(appendix A). A leftover or unknown word is an error, with a did-you-mean.
|
| 104 |
+
- **FX-15.** The output is `@aura-glow` and/or `@aura-particles`, each a list of layer records
|
| 105 |
+
or `null`.
|
| 106 |
+
|
| 107 |
+
**Rendering contract.** (From the reference implementation. All of it is **Pending** as prose.)
|
| 108 |
+
|
| 109 |
+
- **FX-16.** The glow is drawn only outside the element's box. `behind` does the same for
|
| 110 |
+
particles.
|
| 111 |
+
- **FX-17.** An element that is off screen, hidden, clipped away by an overflow container, or
|
| 112 |
+
removed emits nothing. When no aura is active, the renderer stops its loop.
|
| 113 |
+
- **FX-18.** At most 1800 particles are alive across the page. When requests exceed that, every
|
| 114 |
+
emitter gets a fair share.
|
| 115 |
+
- **FX-19.** Under reduced motion, glows stand still and particles are not emitted, unless the
|
| 116 |
+
layer says `essential`.
|
| 117 |
+
- **FX-20.** A state block can change the aura. Leaving the state lets live particles finish,
|
| 118 |
+
then the emitter goes.
|
| 119 |
+
- **FX-21.** `from thumb` makes particles leave a range slider's thumb at the current value.
|
| 120 |
+
|
| 121 |
+
## 8.3 Slider
|
| 122 |
+
|
| 123 |
+
`slider:` styles `<input type="range">` from one description. Without it, every engine needs
|
| 124 |
+
its own vendor pseudo-elements.
|
| 125 |
+
|
| 126 |
+
```dssl
|
| 127 |
+
input.volume {
|
| 128 |
+
slider: track 6 color.line radius full, fill color.accent,
|
| 129 |
+
thumb 24 color.paper, ring 3 color.accent, glow color.accent 14,
|
| 130 |
+
ticks 10 color.muted
|
| 131 |
+
}
|
| 132 |
+
```
|
| 133 |
+
|
| 134 |
+
**Description.**
|
| 135 |
+
|
| 136 |
+
- **FX-22.** The value is a comma-separated list of clauses. A clause starts with one of
|
| 137 |
+
`track`, `fill`, `thumb`, `shape`, `ring`, `glow`, `ticks`, `graph`, `graph-height`,
|
| 138 |
+
`graph-gap`. An unknown head is `unknown slider setting "<w>"` with a did-you-mean. An empty
|
| 139 |
+
value is `slider needs a description`.
|
| 140 |
+
- **FX-23.** Every word after a clause's head MUST be used by that clause. A leftover is the
|
| 141 |
+
error `unexpected "<words>" in the <head> setting`, with a hint about the missing comma.
|
| 142 |
+
- **FX-24.** The default record is: track height 6, color `var(--dssl-color-line)`, radius
|
| 143 |
+
`full`; fill `var(--dssl-color-accent)`; thumb size 22, color `var(--dssl-color-accent)`;
|
| 144 |
+
shape `circle`; no ring, no glow, no ticks, no graph; graph height 40, graph gap 2. Clauses
|
| 145 |
+
change the record in order.
|
| 146 |
+
- **FX-25.** Clause forms and limits are in appendix A. The notable ones: `ticks` needs a count
|
| 147 |
+
of at least 2, `graph` needs 2 to 120 numbers each in 0 to 100, `graph-height` is at least 8,
|
| 148 |
+
`graph-gap` is not negative.
|
| 149 |
+
- **FX-26.** The output is `@slider` with the record. When the rule is emitted (5.4), the
|
| 150 |
+
resolver turns the record into CSS: base declarations on the element, put *first* in the rule
|
| 151 |
+
so the author's own declarations in the same rule win, plus one shadow rule per vendor
|
| 152 |
+
pseudo-element. That CSS is defined by `sliderCss`. **Pending.**
|
| 153 |
+
|
| 154 |
+
**Rendering contract.**
|
| 155 |
+
|
| 156 |
+
- **FX-27.** The fill and the graph bars follow the value, which CSS cannot know. The renderer
|
| 157 |
+
keeps `--dssl-p` (the value as 0 to 1) up to date on the input, for typing, dragging, arrow
|
| 158 |
+
keys and programmatic changes.
|
| 159 |
+
- **FX-28.** A native engine that styles the slider parts itself does not need the vendor
|
| 160 |
+
pseudo-elements. It MUST give the same appearance as the record describes.
|
| 161 |
+
|
| 162 |
+
## 8.4 Glass and tilt
|
| 163 |
+
|
| 164 |
+
```dssl
|
| 165 |
+
.pane {
|
| 166 |
+
glass: 18 saturate 1.6
|
| 167 |
+
tilt: 10 lift 1.04 glare
|
| 168 |
+
}
|
| 169 |
+
```
|
| 170 |
+
|
| 171 |
+
**Glass (plain CSS).**
|
| 172 |
+
|
| 173 |
+
- **FX-29.** `glass: words` or `none`. `none` writes `backdrop-filter: none`. Otherwise the
|
| 174 |
+
words are: a number (blur in px, default 16, not negative), `saturate N` (default 1.5),
|
| 175 |
+
`bright N`, `tint <color>` or `tint none`, and a bare color word counts as a tint. A word
|
| 176 |
+
that is none of these is `unknown glass setting "<w>"`. A missing number is
|
| 177 |
+
`<word> needs a number`. A color is recognised as a bare tint when it starts with `#`, `rgb`,
|
| 178 |
+
`hsl`, `oklch`, `oklab` or `color`, contains `/`, looks like `name.key`, or is `white`,
|
| 179 |
+
`black` or `transparent`.
|
| 180 |
+
- **FX-30.** The output is `backdrop-filter: blur(Bpx) saturate(S)` followed by
|
| 181 |
+
` brightness(R)` when given. Then `background-color: <tint>` unless the tint is `none`, where
|
| 182 |
+
the default tint is `color-mix(in srgb, currentColor 8%, transparent)`. The author's own
|
| 183 |
+
`background` written after `glass:` replaces the wash.
|
| 184 |
+
|
| 185 |
+
**Tilt (needs the pointer).**
|
| 186 |
+
|
| 187 |
+
- **FX-31.** `tilt: words` or `none`. The words are a number (max degrees, 0 to 45, default 8),
|
| 188 |
+
`lift N` (scale on hover, above 0), `perspective N` (px, at least 100, default 900),
|
| 189 |
+
`speed N` (0.02 to 1, default 0.18), `invert` and `glare`. The record is
|
| 190 |
+
`{ max, lift, perspective, speed, invert, glare }`. `none` writes `@tilt: null`. An empty value
|
| 191 |
+
is `tilt needs a number of degrees`. Out-of-range values are errors that name the range.
|
| 192 |
+
- **FX-32.** The renderer adds, after the element's own `transform`:
|
| 193 |
+
`perspective(<P>px) rotateX(var(--dssl-tx, 0deg)) rotateY(var(--dssl-ty, 0deg))
|
| 194 |
+
scale(var(--dssl-ts, 1))`, and updates the three variables from the pointer, so that moving
|
| 195 |
+
the pointer never triggers a restyle. With `glare`, it also keeps `--dssl-gx` and
|
| 196 |
+
`--dssl-gy` (0% to 100%) pointing at the pointer.
|
| 197 |
+
- **FX-33.** Tilt ignores touch, stays flat under reduced motion, and stops when the page is
|
| 198 |
+
frozen. It combines with `translate`, `scale` and `rotate`. It does not combine with `bend`
|
| 199 |
+
or `fold`, because both write `transform`.
|
| 200 |
+
|
| 201 |
+
## 8.5 Deform
|
| 202 |
+
|
| 203 |
+
`bend`, `bend-y`, `bend-up`, `fold`, `stretch` and `bend-around` deform an element, or for
|
| 204 |
+
`bend-around` its children.
|
| 205 |
+
|
| 206 |
+
- **FX-34.** `bend`, `bend-y`, `bend-up`, `fold` take a bare number of degrees (or `Ndeg`).
|
| 207 |
+
Anything else is `<name> takes a bare number of degrees`. They write `@bend`, `@bend-y`,
|
| 208 |
+
`@bend-up`, `@fold` with the number.
|
| 209 |
+
- **FX-35.** `stretch: F [horizontal|vertical|x|y]` with `F` above 0. It writes `@stretch`
|
| 210 |
+
`{ factor, axis }`, axis default `horizontal`. A bad value is
|
| 211 |
+
`stretch needs a positive factor, ...`; `F <= 0` is `stretch: F would flatten the element to
|
| 212 |
+
nothing`.
|
| 213 |
+
- **FX-36.** `bend-around: D` is a bare number of degrees between -170 and 170, otherwise
|
| 214 |
+
`bend-around caps at ±170° ...`. It writes `@bend-around`.
|
| 215 |
+
- **FX-37.** *Composition.* The deform parts of an element combine into one transform string,
|
| 216 |
+
in this order, followed by the element's own transform (when it is not `none`). `d` is the
|
| 217 |
+
record of numbers, `h` the element height in px (0 when there is no box yet):
|
| 218 |
+
1. if any of bend, bend-y, fold, bend-up is non-zero: `perspective(900px)`;
|
| 219 |
+
2. if bend: `rotateX(<bend>deg)`; if bend-y: `rotateY(<bend-y>deg)`;
|
| 220 |
+
3. if fold: with `h > 0`: `translateY(<-h/2>px) rotateX(<fold>deg) translateY(<h/2>px)`;
|
| 221 |
+
without a box: `rotateX(<fold>deg)` and the origin `50% 0%`;
|
| 222 |
+
4. if bend-up: with `h > 0`: `translateY(<h/2>px) rotateX(<up>deg) translateY(<-h/2>px)`;
|
| 223 |
+
without a box: `rotateX(<up>deg)` and the origin `50% 100%`;
|
| 224 |
+
5. if stretch is set and not 1: for the horizontal axis
|
| 225 |
+
`scaleX(<f>) scaleY(<1/f rounded to 4 places>)`, for vertical
|
| 226 |
+
`scaleY(<f>) scaleX(<1/f>)`.
|
| 227 |
+
|
| 228 |
+
Translations are rounded to 2 decimal places. The result is `none` when there are no parts.
|
| 229 |
+
In keyframes (7.1) there is no box, so the second form of fold and bend-up is used.
|
| 230 |
+
- **FX-38.** *Arc layout.* `bend-around: D` lays `n` children along an arc. It does nothing
|
| 231 |
+
when `n < 2`, the container has no width, or `|D|` is too small (`sin(|D|/2) < 0.0001`).
|
| 232 |
+
Otherwise let `half = |D|/2` in radians, `R = round2((width/2) / sin(half))`, and the angle of
|
| 233 |
+
child `i` (from 0) is `round2(-D/2 + D*i/(n-1))` degrees. `round2(v)` is
|
| 234 |
+
`round(v * 100) / 100`. A positive `D` makes a dome, negative a smile.
|
| 235 |
+
|
| 236 |
+
## 8.6 Overlap
|
| 237 |
+
|
| 238 |
+
- **FX-39.** `overlap: allow|none|deny|auto`. It writes `@overlap` with `allow` (for `none` too),
|
| 239 |
+
`deny` or `auto`. Anything else is `unknown overlap policy "<v>"`. The value inherits down the
|
| 240 |
+
tree.
|
| 241 |
+
- **FX-40.** `deny`: the element yields out of any overlap with other elements. `auto`: it
|
| 242 |
+
yields only while its opacity is below 100%. `allow` is the default. How an element yields is
|
| 243 |
+
defined by the reference engine's `overlapNudge`. **Pending.**
|
| 244 |
+
|
| 245 |
+
## 8.7 Fonts
|
| 246 |
+
|
| 247 |
+
`fonts { }` loads fonts. A font is a stylesheet link or an `@font-face`, and neither belongs
|
| 248 |
+
in a rule, so it has its own block.
|
| 249 |
+
|
| 250 |
+
```dssl
|
| 251 |
+
fonts {
|
| 252 |
+
Fraunces: 500 700 800
|
| 253 |
+
"Hanken Grotesk": 400 700 italic
|
| 254 |
+
Inter: 100..900 display optional
|
| 255 |
+
Brand: from "/fonts/brand.woff2" 400
|
| 256 |
+
}
|
| 257 |
+
```
|
| 258 |
+
|
| 259 |
+
- **FX-41.** The body is verbatim text (2.7). Block comments are blanked, and a `//` comment
|
| 260 |
+
that starts a line or follows white space is removed. Each remaining line has a trailing `;`
|
| 261 |
+
removed and is `Family: words`. The family is everything before the first colon outside
|
| 262 |
+
quotes, unquoted, with runs of white space collapsed to one space. A line with no colon is
|
| 263 |
+
`expected "Family: weights" in "<text>"`.
|
| 264 |
+
- **FX-42.** The words are: weights (`400`, or a range `100..900`, each from 1 to 1000, a range
|
| 265 |
+
rising), `italic`, `display <swap|block|fallback|optional|auto>`, `from "<file>"`. Anything
|
| 266 |
+
else is `unknown font setting "<w>"`.
|
| 267 |
+
- **FX-43.** Without `from`, the font is from Google Fonts. All Google families together make
|
| 268 |
+
one link:
|
| 269 |
+
`https://fonts.googleapis.com/css2?family=<parts>&display=<d>` where each part is
|
| 270 |
+
`Name:wght@400;700` (sorted by number, spaces in the name as `+`), or `Name:ital,wght@0,400;
|
| 271 |
+
0,700;1,400;1,700` with italics (all weights, upright first), or `Name` alone for no weights,
|
| 272 |
+
or `Name:ital@0;1` for italics with no weights. The `display` is the last one given on any
|
| 273 |
+
Google line, default `swap`. The link records the line of the `fonts` block.
|
| 274 |
+
- **FX-44.** With `from`, the line makes an `@font-face` block (as a `raw` entry, so it goes into
|
| 275 |
+
the page stylesheet) with `font-family`, `src: url("<file>")` plus `format("woff2"|"woff"|
|
| 276 |
+
"truetype"|"opentype")` by extension, `font-weight` (a range written with a space),
|
| 277 |
+
`font-style` and `font-display` (default `swap`). A `from` line takes at most one weight.
|
| 278 |
+
- **FX-45.** Google's servers see every visitor who loads one of their fonts. Authors who need
|
| 279 |
+
to avoid that use `from`.
|
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 9. Diagnostics
|
| 2 |
+
|
| 3 |
+
DSSL is loud. A mistake is an error with a place and a hint, not a silent no-op.
|
| 4 |
+
|
| 5 |
+
## 9.1 Records
|
| 6 |
+
|
| 7 |
+
- **DIA-1.** A diagnostic is `{ file, line, message, hint? }`. `hint` is omitted (not null)
|
| 8 |
+
when there is none. Messages and hints are English text and are compared exactly by the
|
| 9 |
+
conformance tests, so an implementation MUST use the wording in this spec.
|
| 10 |
+
- **DIA-2.** *Errors* mean something was wrong and was dropped or replaced. A source is `ok`
|
| 11 |
+
when it has no errors. *Warnings* mean the source compiles and runs but is probably not what
|
| 12 |
+
the author meant. Warnings never change `ok`.
|
| 13 |
+
- **DIA-3.** A tool may offer a strict mode that treats warnings as failures
|
| 14 |
+
(`dssl check --strict`). That is a tool choice, not part of resolving.
|
| 15 |
+
- **DIA-4.** Errors from the parser come first, then errors from the resolver, each in the
|
| 16 |
+
order found.
|
| 17 |
+
- **DIA-5.** *Deduplication.* At the end of resolving, errors with the same file, line and
|
| 18 |
+
message are reduced to one, keeping the last occurrence, and the order of the others is
|
| 19 |
+
unchanged.
|
| 20 |
+
- **DIA-6.** Unknown words are errors, never noise. A word that is left over after a construct
|
| 21 |
+
has used what it understands is an error, not ignored.
|
| 22 |
+
- **DIA-7.** A lint or any other helper MUST NOT be able to break a compile. If it fails, its
|
| 23 |
+
warnings are dropped and everything else stands.
|
| 24 |
+
|
| 25 |
+
## 9.2 Where each message is defined
|
| 26 |
+
|
| 27 |
+
Each message appears in the chapter that defines the construct it belongs to, in code font. The
|
| 28 |
+
conformance corpus (chapter 10) covers every message at least once. Appendix B is generated from
|
| 29 |
+
the reference implementation and lists every message template, so a gap between this spec and
|
| 30 |
+
the corpus shows up as a failing check.
|
| 31 |
+
|
| 32 |
+
## 9.3 Did-you-mean
|
| 33 |
+
|
| 34 |
+
- **DIA-8.** `didYouMean(word, candidates)` returns the best candidate, or nothing:
|
| 35 |
+
1. If the word or the candidate list is empty, return nothing.
|
| 36 |
+
2. Lowercase the word. For each candidate in order, skipping empty ones, compute the
|
| 37 |
+
Levenshtein distance (insert, delete, substitute, each cost 1) between the lowercase word
|
| 38 |
+
and the lowercase text of the candidate.
|
| 39 |
+
3. Keep the first candidate with the smallest distance. A later candidate with an equal
|
| 40 |
+
distance does not replace it.
|
| 41 |
+
4. The tolerance is `max(2, floor(length of the word / 3))`. If the smallest distance is
|
| 42 |
+
larger, return nothing. Otherwise return the candidate as text, in its original case.
|
| 43 |
+
- **DIA-9.** The order of the candidates is the order of the sets and lists in appendix A,
|
| 44 |
+
which is the insertion order in the reference implementation. A different order can change
|
| 45 |
+
which of two equally close words is suggested, so implementations MUST keep it.
|
| 46 |
+
|
| 47 |
+
## 9.4 Warnings the resolver emits
|
| 48 |
+
|
| 49 |
+
| Where | Message starts with |
|
| 50 |
+
|---|---|
|
| 51 |
+
| 5.3, nested word near a state word | `"<w>" compiled as a descendant selector` |
|
| 52 |
+
| 6.3, row and column words | `two words in ...`, `"<w>" is written twice in ...`, `"<w>" has nowhere to go ...` |
|
| 53 |
+
| 6.6, `gradient:` and another image | `"<sel>" sets the background image twice` |
|
| 54 |
+
| 7.4, animation shorthand | `animation "<v>" references no motion ...`, `<prop> does nothing here ...` |
|
| 55 |
+
| 2.7, `raw { }` | `raw { } is verbatim CSS, so this line needs a ";" at the end` |
|
| 56 |
+
| same-rule display clash | `"<prop>:" expands to display: <v>, which overrides the earlier ...` |
|
| 57 |
+
|
| 58 |
+
- **DIA-10.** *Display clash.* Inside one rule, when a semantic property that expands to
|
| 59 |
+
`display` (`row`, `column`, `grid`, `stack`) comes after an explicit `display:` with a
|
| 60 |
+
different value, the warning is
|
| 61 |
+
`"<via>:" expands to display: <new>, which overrides the earlier "display: <old>" (line <n>)
|
| 62 |
+
in the same rule - later wins, so the earlier one is dead`. At most 400 warnings of this kind
|
| 63 |
+
are kept per file. Overrides across different rules are the cascade at work and get no
|
| 64 |
+
warning.
|
| 65 |
+
- **DIA-11.** *Raw semicolons.* In a `raw { }` body (comments blanked), a line that looks like
|
| 66 |
+
`name: value`, does not end in `;`, `{`, `}` or `,`, and is followed by another declaration
|
| 67 |
+
line or a line starting with `}`, is a warning at the line of that declaration inside the
|
| 68 |
+
block.
|
| 69 |
+
|
| 70 |
+
## 9.5 Lint
|
| 71 |
+
|
| 72 |
+
A lint pass runs on the finished rules and adds warnings. It covers text contrast (WCAG ratio,
|
| 73 |
+
4.5 for body text, 3 for large text), an outline removed from something you can tab to with no
|
| 74 |
+
`focus-visible` replacement, and an explicit width or height under 24px on a button or link. It
|
| 75 |
+
looks only at unconditional rules, follows tokens, alpha and `color-mix`, and is defined by
|
| 76 |
+
`lint.js`.
|
| 77 |
+
|
| 78 |
+
- **DIA-12.** A Level 2 implementation MAY omit the lint pass. It then declares `lint: false`,
|
| 79 |
+
and conformance tests compare warnings with the lint warnings removed. A lint warning is one
|
| 80 |
+
whose message starts with `text contrast is`, starts with `the focus outline is removed`, or
|
| 81 |
+
ends with `the smallest target WCAG 2.2 allows`.
|
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 10. The resolved document
|
| 2 |
+
|
| 3 |
+
The resolver turns one source file into a *resolved document*. This chapter defines its exact
|
| 4 |
+
shape and how two implementations are compared. This is what makes Level 2 testable without a
|
| 5 |
+
browser.
|
| 6 |
+
|
| 7 |
+
## 10.1 Inputs
|
| 8 |
+
|
| 9 |
+
- **DOC-1.** The resolver takes: the source text, the file name, the token registry (4.5) and
|
| 10 |
+
the motion registry (7.3). The registry defaults are the built-in tokens and no motions.
|
| 11 |
+
|
| 12 |
+
## 10.2 The document
|
| 13 |
+
|
| 14 |
+
```
|
| 15 |
+
{
|
| 16 |
+
errors: [ { file, line, message, hint? } ], // parser errors, then resolver errors
|
| 17 |
+
warnings: [ { file, line, message, hint? } ],
|
| 18 |
+
rules: [ Rule ],
|
| 19 |
+
shadowRules: [ Rule ],
|
| 20 |
+
raws: [ { css, file, line, order } ],
|
| 21 |
+
fontLinks: [ { url, line, file } ],
|
| 22 |
+
motionNames: [ name ], // motions defined in this file, in source order
|
| 23 |
+
motionFrames: { name: { essential, frames: [ { offset, props } ] } },
|
| 24 |
+
mediaQueries: [ query ], // distinct, in first-use order
|
| 25 |
+
tokens: { key: value }, // the final token map
|
| 26 |
+
registryRule: Rule
|
| 27 |
+
}
|
| 28 |
+
Rule = { id, sel, media, signals, containers, layer, order, decls, file, line, pseudo, states }
|
| 29 |
+
decl = { prop, value, line, via?, fromGradient? }
|
| 30 |
+
```
|
| 31 |
+
|
| 32 |
+
- **DOC-2.** `rules` holds the ordinary rules and the token rules from `tokens` blocks, in the
|
| 33 |
+
order they were emitted. `shadowRules` holds pseudo-element rules (5.8). `raws` holds `raw`
|
| 34 |
+
and `fonts` font-face blocks in emission order. The registry rule is not in `rules`.
|
| 35 |
+
- **DOC-3.** `mediaQueries` lists every distinct entry of `media` found in `rules` and
|
| 36 |
+
`shadowRules`, in the order first seen, rules first.
|
| 37 |
+
- **DOC-4.** `tokens` is the final map of 4.3 (every key, with the last definition in source
|
| 38 |
+
order). Keys are compared as a set; the canonical form sorts them.
|
| 39 |
+
- **DOC-5.** A declaration may carry `via` (the semantic property that produced a `display`
|
| 40 |
+
value) and `fromGradient` (true for the `background-image` from `gradient:`). Both are part
|
| 41 |
+
of the record.
|
| 42 |
+
- **DOC-6.** `states` is a set of state words. It is written as a sorted array.
|
| 43 |
+
- **DOC-7.** `ok` is not stored. It is `errors.length == 0`.
|
| 44 |
+
|
| 45 |
+
## 10.3 Canonical form
|
| 46 |
+
|
| 47 |
+
To compare two documents they are written as JSON in this form.
|
| 48 |
+
|
| 49 |
+
- **DOC-8.** Object keys are sorted by code point. Arrays keep their order, except `states`
|
| 50 |
+
and the `tokens` object, which are sorted.
|
| 51 |
+
- **DOC-9.** Numbers are written as the shortest decimal that reads back to the same
|
| 52 |
+
double, with no exponent for values between 1e-6 and 1e21, and no `-0`. Infinity is the
|
| 53 |
+
string `"Infinity"` (an `iterations` of `infinite`).
|
| 54 |
+
- **DOC-10.** A field that is `undefined` is omitted. A field that is `null` is `null`.
|
| 55 |
+
- **DOC-11.** Strings are compared as UTF-8 text.
|
| 56 |
+
- **DOC-12.** Two implementations are equal on a source when their canonical JSON is
|
| 57 |
+
byte-identical, after removing lint warnings from implementations that declared `lint: false`
|
| 58 |
+
(DIA-12).
|
| 59 |
+
|
| 60 |
+
## 10.4 The corpus
|
| 61 |
+
|
| 62 |
+
The comparison needs inputs. The corpus is a folder of `.dssl` files:
|
| 63 |
+
|
| 64 |
+
- every stylesheet the site ships (`public/styles/*.dssl`),
|
| 65 |
+
- every fenced `dssl` block from the guide, the readme and this spec,
|
| 66 |
+
- the fixtures of the existing test suites,
|
| 67 |
+
- one file per diagnostic message, written to trigger it.
|
| 68 |
+
|
| 69 |
+
For each input, `scripts/native-dump.mjs` writes the canonical JSON of the reference engine's
|
| 70 |
+
output to `native/expected/`. The Rust test `native/tests/differential.rs` resolves the same
|
| 71 |
+
input and compares.
|
| 72 |
+
|
| 73 |
+
- **DOC-13.** The expected files are generated. They are committed so that a change in the
|
| 74 |
+
reference engine shows up in review as a change in expected output, and so the Rust tests run
|
| 75 |
+
without Node.
|
| 76 |
+
- **DOC-14.** A divergence (chapter 12) is excluded from the comparison by listing the input in
|
| 77 |
+
`native/corpus/EXCLUDED.md` with the divergence id. An excluded input is still run, and its
|
| 78 |
+
diff is printed, so a fix is noticed.
|
| 79 |
+
- **DOC-15.** Once the harness exists, `native/PARITY.md` lists, per chapter, how many corpus
|
| 80 |
+
inputs pass, fail and are excluded. It is generated by the test run and not written by hand.
|
| 81 |
+
|
| 82 |
+
## 10.5 What the document does not contain
|
| 83 |
+
|
| 84 |
+
- The syntax tree (Level 1 compares it separately, 2.9).
|
| 85 |
+
- Behaviors (they are expanded during the walk and do not appear in the output).
|
| 86 |
+
- Anything about a particular element. Matching is stage 3 and needs a document.
|
|
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 11. Browser integration
|
| 2 |
+
|
| 3 |
+
This chapter is informative. It says how a browser could host DSSL natively, stage by stage,
|
| 4 |
+
and which parts are cheap and which are real engineering. Nothing here is proposed to a
|
| 5 |
+
standards body, no browser implements it, and the reference crate has not been wired into any
|
| 6 |
+
engine. It is written so that a browser team can judge the size of the job.
|
| 7 |
+
|
| 8 |
+
## 11.1 Delivery
|
| 9 |
+
|
| 10 |
+
DSSL needs a way to reach the parser, the way CSS has `<link rel="stylesheet">` and `<style>`.
|
| 11 |
+
|
| 12 |
+
- **INT-1.** A DSSL stylesheet is text with the media type `text/dssl`. (No registration is
|
| 13 |
+
proposed. This is a placeholder name.)
|
| 14 |
+
- **INT-2.** `<link rel="stylesheet" type="text/dssl" href="...">` and
|
| 15 |
+
`<style type="text/dssl">...</style>` load DSSL. A browser that does not know the type does
|
| 16 |
+
not load it, which is how CSS has always been introduced.
|
| 17 |
+
- **INT-3.** Several stylesheets are one cascade in load order (CAS-16), the same as CSS.
|
| 18 |
+
Tokens and motions flow from earlier files to later ones (4.5, 7.3) in that order.
|
| 19 |
+
|
| 20 |
+
Authors who need a page to work in a browser with no DSSL support can ship the output of
|
| 21 |
+
`dssl build` as CSS. That is the *static lane*. It is an author's choice, not a part of native
|
| 22 |
+
support, and it is described in 11.5.
|
| 23 |
+
|
| 24 |
+
## 11.2 Where the parser sits
|
| 25 |
+
|
| 26 |
+
In every engine, a stylesheet becomes a list of rule objects, and nothing after that stage
|
| 27 |
+
cares what syntax the rules came from. A DSSL front end replaces the tokenizer and parser (CSS
|
| 28 |
+
stage 1) and produces the same kind of rule objects.
|
| 29 |
+
|
| 30 |
+
```
|
| 31 |
+
CSS text --> CSS tokenizer + parser --\
|
| 32 |
+
>--> rule objects --> style resolution --> layout --> paint
|
| 33 |
+
DSSL text --> DSSL parser + resolver --/
|
| 34 |
+
```
|
| 35 |
+
|
| 36 |
+
- **INT-4.** The resolved document (chapter 10) is the hand-off. Each rule record maps to an
|
| 37 |
+
engine rule: `sel` to the selector list, `decls` to the declaration block, `layer` to a
|
| 38 |
+
cascade layer, `media` and `containers` to conditional wrappers, and `order` to source order.
|
| 39 |
+
- **INT-5.** Engine-native declarations (`@...`, 6.8) are not properties. They go to the feature
|
| 40 |
+
that owns them (11.4), not to the style system's property table.
|
| 41 |
+
|
| 42 |
+
This is also how new CSS syntax has entered engines before. Nesting and cascade layers are
|
| 43 |
+
parsed into the same rule tree as everything else.
|
| 44 |
+
|
| 45 |
+
## 11.3 The part that lowers to CSS
|
| 46 |
+
|
| 47 |
+
A large part of DSSL is already expressible in CSS. The proof is `dssl build`, which does exactly
|
| 48 |
+
that. Here is real output, from the reference engine, for a small source:
|
| 49 |
+
|
| 50 |
+
```dssl
|
| 51 |
+
tokens { color { brand: #c2185b } }
|
| 52 |
+
.card {
|
| 53 |
+
background: color.brand
|
| 54 |
+
padding: 16
|
| 55 |
+
row: gap 8 between center
|
| 56 |
+
radius: md
|
| 57 |
+
hover { background: color.brand/80 }
|
| 58 |
+
@media dark { background: #181310 }
|
| 59 |
+
}
|
| 60 |
+
```
|
| 61 |
+
|
| 62 |
+
compiles to the following (reformatted, and without the built-in token declarations):
|
| 63 |
+
|
| 64 |
+
```css
|
| 65 |
+
@layer tokens, base, components, utilities, pin;
|
| 66 |
+
|
| 67 |
+
@layer tokens {
|
| 68 |
+
:where(:root) { --dssl-color-brand: #c2185b; }
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
@layer components {
|
| 72 |
+
:where(.card) {
|
| 73 |
+
background: var(--dssl-color-brand);
|
| 74 |
+
padding: 16px;
|
| 75 |
+
display: flex;
|
| 76 |
+
flex-direction: row;
|
| 77 |
+
gap: 8px;
|
| 78 |
+
justify-content: space-between;
|
| 79 |
+
align-items: center;
|
| 80 |
+
border-radius: var(--dssl-radius-md);
|
| 81 |
+
}
|
| 82 |
+
:where(.card:hover) {
|
| 83 |
+
background: color-mix(in oklab, var(--dssl-color-brand) 80%, transparent);
|
| 84 |
+
}
|
| 85 |
+
@media (prefers-color-scheme: dark) {
|
| 86 |
+
:where(.card) { background: #181310; }
|
| 87 |
+
}
|
| 88 |
+
}
|
| 89 |
+
```
|
| 90 |
+
|
| 91 |
+
The mapping:
|
| 92 |
+
|
| 93 |
+
| DSSL | CSS it lowers to |
|
| 94 |
+
|---|---|
|
| 95 |
+
| tokens | custom properties on `:root`, inside `@layer tokens` |
|
| 96 |
+
| layers and `pin` | `@layer`, with `!important` for `pin` |
|
| 97 |
+
| no specificity | every selector wrapped in `:where()` so order alone decides |
|
| 98 |
+
| states | pseudo-classes |
|
| 99 |
+
| `@media`, `@container` | the same at-rules |
|
| 100 |
+
| semantic properties (`row`, `grid`, `radius`, `fluid`, ...) | longhand properties and `clamp()` |
|
| 101 |
+
| alpha (`color.ink/20`) | `color-mix(in oklab, ..., transparent)` |
|
| 102 |
+
| `motion` | `@keyframes` |
|
| 103 |
+
| `raw` | verbatim |
|
| 104 |
+
| `glass` | `backdrop-filter` and a background color |
|
| 105 |
+
|
| 106 |
+
- **INT-6.** A native engine MAY implement this part by lowering to its own CSS rule objects.
|
| 107 |
+
The result must equal the cascade of chapter 5. In particular, the `:where()` wrapping is how
|
| 108 |
+
CSS reproduces "no specificity", and the layer ranks reproduce CAS-1.
|
| 109 |
+
|
| 110 |
+
## 11.4 The part that needs engine work
|
| 111 |
+
|
| 112 |
+
| Feature | What is missing from CSS | What a native engine adds |
|
| 113 |
+
|---|---|---|
|
| 114 |
+
| `@signal` | Named values set by the page, readable by the cascade | A page-visible store of named values, with ancestor lookup (CAS-39), invalidating style when one changes. The nearest CSS feature is a container style query on a custom property. Support differs between engines and must be checked before relying on it. |
|
| 115 |
+
| `seen` | A pseudo-class that matches once an element has been in view | An element flag set by the same machinery as intersection observation, and style invalidation when it flips (CAS-27). |
|
| 116 |
+
| `animate` | Per-element motion lists with `jitter`, `essential` and `stagger` | Mapping to the engine's keyframe animation, with a delay offset per child. `essential` and reduced motion are policy on top. |
|
| 117 |
+
| `texture` | A generated image layer that sits on the author's own background | A background image generator keyed by the layer record (FX-7), cached per tile. |
|
| 118 |
+
| `aura` | Glow and particles outside the box, over everything, with a particle budget | A page-level paint layer above content that does not take pointer events, with the budget of FX-18. |
|
| 119 |
+
| `slider` | One description for all engines' range-input parts | Direct styling of the control parts, plus a value-as-fraction the style can read (FX-27). |
|
| 120 |
+
| `tilt` | Pointer-driven 3D transform without restyling | A compositor-driven transform from pointer position (FX-32). |
|
| 121 |
+
| `bend`, `fold`, `bend-around` | Transforms that need the element's own box, or a container's children | These run during or after layout, because they need box sizes (FX-37, FX-38). |
|
| 122 |
+
| `overlap` | A rule that moves elements out of overlaps | Hook after layout (FX-40). This is the hardest item and is not specified yet. |
|
| 123 |
+
| alignment promotion | A box type chosen from an alignment word | Rule CAS-47 at computed-value time. |
|
| 124 |
+
|
| 125 |
+
- **INT-7.** For each row, the spec's description half (chapter 8) and corpus fixes what the
|
| 126 |
+
feature means. How the engine realises it is the engine's business, as long as the rendering
|
| 127 |
+
contract holds.
|
| 128 |
+
|
| 129 |
+
## 11.5 The static lane and native support
|
| 130 |
+
|
| 131 |
+
`dssl build` already exists. Today it is the exit lane for pages that need no JavaScript. With
|
| 132 |
+
native support, the rows of 11.3 stop needing it, because the browser lowers them itself. What
|
| 133 |
+
stays on the author's side is what 11.4 lists and nothing else.
|
| 134 |
+
|
| 135 |
+
The build report already counts those leftovers (`@signal` rules, engine-native declarations),
|
| 136 |
+
so it is a ready measure of how much of a given page is the cheap part and how much is the
|
| 137 |
+
engine-work part.
|
| 138 |
+
|
| 139 |
+
## 11.6 How a browser team would check their work
|
| 140 |
+
|
| 141 |
+
- Level 1 and 2: run the corpus (chapter 10). The expected JSON is committed. No browser
|
| 142 |
+
needed.
|
| 143 |
+
- Level 3: element-level tests, in the style of the web platform tests. A fixture is a small
|
| 144 |
+
HTML file, a DSSL file and the expected computed value of chosen properties on chosen
|
| 145 |
+
elements. These do not exist yet. They are the first thing to write after milestone 1.
|
| 146 |
+
- Level 4: reftests, comparing a rendering to a reference rendering, and pixel tests for the
|
| 147 |
+
effects (the repository already has pixel helpers in `scripts/lib/pixels.mjs`).
|
| 148 |
+
|
| 149 |
+
## 11.7 What is not claimed
|
| 150 |
+
|
| 151 |
+
- No browser supports DSSL natively today, and this repository does not change that.
|
| 152 |
+
- The reference crate does not exist yet beyond a stub (see `native/README.md`). When it does,
|
| 153 |
+
it will parse and resolve. It will not match elements, compute styles or paint.
|
| 154 |
+
- The lowering table in 11.3 is the claim of the existing build lane, checked by the repository's
|
| 155 |
+
static parity test. It has not been run in browsers other than Chromium.
|
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 12. Known divergences
|
| 2 |
+
|
| 3 |
+
Writing this spec from the reference engine and checking it against the engine turned up places
|
| 4 |
+
where the engine did not do what a careful reader of the language would expect. They were found
|
| 5 |
+
on 0.16.2. Seven are fixed in 0.16.3 and one is still open. This chapter keeps the record, so
|
| 6 |
+
that a second implementation knows which behavior is old and which is current.
|
| 7 |
+
|
| 8 |
+
| Id | Where | Summary | Status |
|
| 9 |
+
|---|---|---|---|
|
| 10 |
+
| D-1 | 2.2 | `//` inside an unquoted `url(...)` started a comment | fixed in 0.16.3 (SYN-6) |
|
| 11 |
+
| D-2 | 4.4 | A token path with a typo at the end resolved to its parent | fixed in 0.16.3 (TOK-12) |
|
| 12 |
+
| D-3 | 5.2 | An unknown `@layer` name was silently `components` | fixed in 0.16.3, now warns (CAS-2) |
|
| 13 |
+
| D-4 | 4.7 | `radius: xl` pointed at a token that does not exist | fixed in 0.16.3, now warns (TOK-18) |
|
| 14 |
+
| D-5 | 3.2 | A backslash did not escape a quote inside a value | fixed in 0.16.3 (VAL rule 2) |
|
| 15 |
+
| D-6 | 4.3 | The registry rule carries the last definition of a token | open, needs a browser test |
|
| 16 |
+
| D-7 | 5.3 | Nesting under a selector list joined the wrong way | fixed in 0.16.3 (CAS-7, CAS-24, CAS-30) |
|
| 17 |
+
| D-8 | 5.3 | A nested `li` got a "did you mean link" warning | fixed in 0.16.3 (CAS-8) |
|
| 18 |
+
|
| 19 |
+
A conformance corpus built from 0.16.3 or later has no exclusions for D-1 to D-5, D-7 and D-8.
|
| 20 |
+
Inputs produced by an older engine do.
|
| 21 |
+
|
| 22 |
+
## D-1: `//` in an unquoted url (fixed)
|
| 23 |
+
|
| 24 |
+
```dssl
|
| 25 |
+
.a { background: url(http://x.com/a.png) }
|
| 26 |
+
```
|
| 27 |
+
|
| 28 |
+
The comment stripper did not know about `url( )`, so `//x.com/a.png) }` was removed as a line
|
| 29 |
+
comment. The value became `url(http` and the file reported one unclosed block. Inside `raw { }`
|
| 30 |
+
the closing brace of the `raw` block was eaten too. Now an unquoted `url(` ... `)` is copied as
|
| 31 |
+
written, and a comment right after it still works.
|
| 32 |
+
|
| 33 |
+
## D-2: token path prefix match (fixed)
|
| 34 |
+
|
| 35 |
+
```dssl error
|
| 36 |
+
tokens { color { ink2: #111 } }
|
| 37 |
+
.a { color: color.ink2.bogus }
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
This used to resolve to `var(--dssl-color-ink2)` with no error, because the lookup shortened the
|
| 41 |
+
dotted path from the right and used the first prefix that was a token. A typo at the end of a
|
| 42 |
+
path is now the loud `unknown value` error, with a did-you-mean.
|
| 43 |
+
|
| 44 |
+
## D-3 and D-4: silent fallbacks (fixed, now warnings)
|
| 45 |
+
|
| 46 |
+
`@layer weird { .a { color: red } }` puts the rule in `components`, and now says so. `radius: xl`
|
| 47 |
+
becomes `var(--dssl-radius-xl)`, and now warns when no `radius.xl` token exists, because by
|
| 48 |
+
default only `sm`, `md`, `lg` and `full` do. Both are warnings, so `ok` stays true and the output
|
| 49 |
+
is the same as before.
|
| 50 |
+
|
| 51 |
+
## D-5: escaped quote in a value (fixed)
|
| 52 |
+
|
| 53 |
+
```dssl
|
| 54 |
+
.a { content: "a\"b" }
|
| 55 |
+
```
|
| 56 |
+
|
| 57 |
+
The parser's string scan honored the backslash, but the value resolver stopped the string at the
|
| 58 |
+
escaped quote and reported `unknown value "b"`. Strings in values, in function arguments and in
|
| 59 |
+
layer lists now skip the character after a backslash.
|
| 60 |
+
|
| 61 |
+
## D-6: the registry rule (open)
|
| 62 |
+
|
| 63 |
+
The registry rule is built from the final token map (TOK-9). When a token is defined once at the
|
| 64 |
+
top level and again, later in the file, inside `@media dark`, the map holds the dark value, so
|
| 65 |
+
the registry rule carries it as an unconditional value. Within one file this does no harm,
|
| 66 |
+
because the registry rule has the lowest order and the file's own token rules come after it.
|
| 67 |
+
Whether it can override an earlier file's unconditional value depends on where the host installs
|
| 68 |
+
that bundle in the cascade, and that has not been tested.
|
| 69 |
+
|
| 70 |
+
Action: write a two-file test (a base palette, then a second file with a dark override) and run
|
| 71 |
+
it in a browser before deciding whether this is a bug.
|
| 72 |
+
|
| 73 |
+
## D-7: nesting under a selector list (fixed)
|
| 74 |
+
|
| 75 |
+
```dssl
|
| 76 |
+
.a, .b { .c { color: red } }
|
| 77 |
+
```
|
| 78 |
+
|
| 79 |
+
used to produce `.a, .b .c`, which means `.a` and `.b .c`. The same applied to state blocks
|
| 80 |
+
(`.a, .b { hover { } }` gave `.a, .b:hover`, so only `.b` got the hover), to a child list
|
| 81 |
+
(`.a { .c, .d { } }` gave `.a .c, .d`) and to pseudo-element blocks. Parents and children are now
|
| 82 |
+
split at top-level commas and every parent part is joined with every child part, and a state is
|
| 83 |
+
added to every part. A selector with no commas is joined exactly as before.
|
| 84 |
+
|
| 85 |
+
## D-8: false "did you mean" warning on element names (fixed)
|
| 86 |
+
|
| 87 |
+
```dssl
|
| 88 |
+
.menu { li { color: red } }
|
| 89 |
+
```
|
| 90 |
+
|
| 91 |
+
compiled correctly to `.menu li` and also warned that the author may have meant `link`, because
|
| 92 |
+
`li` is two edits from it. A nested word that is an HTML element name no longer warns. A real typo
|
| 93 |
+
such as `hove` still does.
|
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# DSSL specification
|
| 2 |
+
|
| 3 |
+
Status: working draft, written against the reference engine 0.16.3 (the bugs of chapter 12 were found on 0.16.2).
|
| 4 |
+
This is not a standard. It is the document a browser team (or anyone writing a second
|
| 5 |
+
implementation) would read to build DSSL without reading the JavaScript engine.
|
| 6 |
+
|
| 7 |
+
## Why this exists
|
| 8 |
+
|
| 9 |
+
DSSL today is a JavaScript engine that writes inline styles. That is one way to run the
|
| 10 |
+
language. It is not the language. CSS is a language that browsers implement natively, and
|
| 11 |
+
this spec says what it would take to do the same for DSSL: what the text means, what every
|
| 12 |
+
stage produces, and what a correct implementation has to do.
|
| 13 |
+
|
| 14 |
+
The Rust crate next to this folder (`native/`) is the reference implementation of this spec
|
| 15 |
+
that does not use JavaScript. It is checked against the JavaScript engine by running both on
|
| 16 |
+
the same inputs and comparing the results.
|
| 17 |
+
|
| 18 |
+
## Chapters
|
| 19 |
+
|
| 20 |
+
| # | Chapter | What it fixes |
|
| 21 |
+
|---|---|---|
|
| 22 |
+
| 1 | [Overview](01-overview.md) | The processing model, conformance levels, what CSS actually does |
|
| 23 |
+
| 2 | [Syntax](02-syntax.md) | Text to syntax tree: comments, blocks, declarations, raw |
|
| 24 |
+
| 3 | [Values](03-values.md) | Bare numbers, identifiers, functions, colors, alpha |
|
| 25 |
+
| 4 | [Tokens](04-tokens.md) | Design tokens and how they become custom properties |
|
| 26 |
+
| 5 | [Cascade](05-cascade.md) | Layers, order, states, media, containers, signals |
|
| 27 |
+
| 6 | [Properties](06-properties.md) | The semantic properties and how each one expands |
|
| 28 |
+
| 7 | [Motion](07-motion.md) | `motion`, `animate`, `seen`, `stagger` |
|
| 29 |
+
| 8 | [Effects](08-effects.md) | Texture, aura, slider, glass, tilt, deform, fonts |
|
| 30 |
+
| 9 | [Diagnostics](09-diagnostics.md) | Errors, warnings, did-you-mean, lint |
|
| 31 |
+
| 10 | [Resolved document](10-resolved-document.md) | The exact output a resolver produces, and how conformance is tested |
|
| 32 |
+
| 11 | [Browser integration](11-browser-integration.md) | How a browser would host this, stage by stage |
|
| 33 |
+
| 12 | [Known divergences](12-known-divergences.md) | Places where the JavaScript engine does not yet match this spec |
|
| 34 |
+
|
| 35 |
+
## Conventions
|
| 36 |
+
|
| 37 |
+
- MUST, MUST NOT, SHOULD and MAY are used the way RFC 2119 uses them.
|
| 38 |
+
- Every testable rule has an id such as `SYN-4` or `CAS-7`. Conformance tests name the ids
|
| 39 |
+
they cover.
|
| 40 |
+
- Prose in the margin of a rule that starts with "Why:" is informative.
|
| 41 |
+
- Examples are executed. Every fenced `dssl` block is compiled by
|
| 42 |
+
`scripts/test-native-spec.mjs` against the JavaScript engine, and must produce no errors.
|
| 43 |
+
A block fenced as `dssl error` must produce at least one.
|
| 44 |
+
- The tables in the appendices are generated from the engine's own vocabulary modules by
|
| 45 |
+
`scripts/gen-native-vocab.mjs`. They are not edited by hand, so they cannot drift.
|
| 46 |
+
|
| 47 |
+
## Normative and informative
|
| 48 |
+
|
| 49 |
+
Chapters 2 to 10 are normative. Chapters 1 and 11 are informative apart from the
|
| 50 |
+
conformance levels defined in 1.4. Chapter 12 is a list of bugs, and is informative.
|
| 51 |
+
|
| 52 |
+
Where this spec and the JavaScript engine disagree, chapter 12 says which one is wrong and
|
| 53 |
+
what the fix is. Until the engine is fixed, conformance tests for those cases are excluded
|
| 54 |
+
from the comparison and listed by id.
|
|
@@ -0,0 +1,265 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Appendix A: vocabulary
|
| 2 |
+
|
| 3 |
+
Generated by `scripts/gen-native-vocab.mjs` from the engine. Not edited by hand.
|
| 4 |
+
The full word lists, in the engine's own order, are in `native/data/vocabulary.json`.
|
| 5 |
+
|
| 6 |
+
## A.1 State words
|
| 7 |
+
|
| 8 |
+
`hover`, `focus`, `focus-visible`, `active`, `disabled`, `checked`, `empty`, `target`, `required`, `invalid`, `valid`, `open`, `closed`, `placeholder-shown`, `read-only`, `read-write`, `enabled`, `indeterminate`, `first-child`, `last-child`, `only-child`, `first-of-type`, `last-of-type`, `link`, `visited`, `seen`
|
| 9 |
+
|
| 10 |
+
## A.2 Pseudo-elements
|
| 11 |
+
|
| 12 |
+
`before`, `after`, `placeholder`, `selection`, `marker`, `first-line`, `first-letter`, `backdrop`, `file-selector-button`, `part`, `slotted`
|
| 13 |
+
|
| 14 |
+
A vendor pseudo-element name matches `^-(webkit|moz|ms)-`.
|
| 15 |
+
|
| 16 |
+
## A.3 Unitless and time properties
|
| 17 |
+
|
| 18 |
+
Unitless (a bare number stays bare):
|
| 19 |
+
|
| 20 |
+
`opacity`, `line-height`, `z-index`, `font-weight`, `flex-grow`, `flex-shrink`, `flex`, `order`, `scale`, `widows`, `orphans`, `column-count`, `aspect-ratio`, `animation-iteration-count`, `flood-opacity`, `fill-opacity`, `stop-opacity`, `shape-image-threshold`, `counter-reset`, `counter-increment`, `counter-set`, `grid-row`, `grid-column`, `grid-area`, `font-feature-settings`, `font-variation-settings`, `tab-size`, `-webkit-line-clamp`, `line-clamp`, `stroke-miterlimit`, `stroke-opacity`, `initial-letter`, `font-size-adjust`
|
| 21 |
+
|
| 22 |
+
Time (a bare number is milliseconds):
|
| 23 |
+
|
| 24 |
+
`transition-delay`, `transition-duration`, `animation-delay`, `animation-duration`, `animation`
|
| 25 |
+
|
| 26 |
+
## A.4 Functions
|
| 27 |
+
|
| 28 |
+
Unitless functions (numbers inside stay bare):
|
| 29 |
+
|
| 30 |
+
`oklch`, `oklab`, `lab`, `lch`, `hsl`, `hsla`, `rgb`, `rgba`, `hwb`, `color`, `color-mix`, `light-dark`, `brightness`, `saturate`, `contrast`, `grayscale`, `sepia`, `invert`, `opacity`, `scale`, `scalex`, `scaley`, `scalez`, `scale3d`, `steps`, `cubic-bezier`, `linear`, `radial`, `conic`
|
| 31 |
+
|
| 32 |
+
Length functions (bare numbers inside are px):
|
| 33 |
+
|
| 34 |
+
`calc`, `min`, `max`, `clamp`, `round`, `mod`, `rem`, `abs`, `sign`, `hypot`, `pow`, `sqrt`, `log`, `exp`, `blur`, `drop-shadow`
|
| 35 |
+
|
| 36 |
+
## A.5 Fluid properties
|
| 37 |
+
|
| 38 |
+
`font-size`, `width`, `height`, `inline-size`, `block-size`, `min-width`, `max-width`, `min-height`, `max-height`, `gap`, `row-gap`, `column-gap`, `padding`, `margin`, `inset`, `top`, `right`, `bottom`, `left`, `padding-top`, `padding-right`, `padding-bottom`, `padding-left`, `padding-inline`, `padding-block`, `margin-top`, `margin-right`, `margin-bottom`, `margin-left`, `margin-inline`, `margin-block`, `letter-spacing`, `border-radius`
|
| 39 |
+
|
| 40 |
+
## A.6 Place words
|
| 41 |
+
|
| 42 |
+
| word | cross | main |
|
| 43 |
+
|---|---|---|
|
| 44 |
+
| `center` | `center` | `center` |
|
| 45 |
+
| `start` | `start` | `flex-start` |
|
| 46 |
+
| `end` | `end` | `flex-end` |
|
| 47 |
+
| `between` | `center` | `space-between` |
|
| 48 |
+
| `around` | `center` | `space-around` |
|
| 49 |
+
| `evenly` | `center` | `space-evenly` |
|
| 50 |
+
| `stretch` | `stretch` | `flex-start` |
|
| 51 |
+
| `baseline` | `baseline` | `flex-start` |
|
| 52 |
+
|
| 53 |
+
## A.7 Easings
|
| 54 |
+
|
| 55 |
+
| name | CSS |
|
| 56 |
+
|---|---|
|
| 57 |
+
| `snap` | `cubic-bezier(0.2, 0.9, 0.3, 1)` |
|
| 58 |
+
| `smooth` | `cubic-bezier(0.4, 0, 0.2, 1)` |
|
| 59 |
+
| `bounce` | `cubic-bezier(0.34, 1.56, 0.64, 1)` |
|
| 60 |
+
| `linear` | `linear` |
|
| 61 |
+
| `ease` | `ease` |
|
| 62 |
+
| `ease-in` | `ease-in` |
|
| 63 |
+
| `ease-out` | `ease-out` |
|
| 64 |
+
| `ease-in-out` | `ease-in-out` |
|
| 65 |
+
|
| 66 |
+
## A.8 Built-in tokens
|
| 67 |
+
|
| 68 |
+
| key | value |
|
| 69 |
+
|---|---|
|
| 70 |
+
| `color.ink` | `#16161d` |
|
| 71 |
+
| `color.paper` | `#faf7f2` |
|
| 72 |
+
| `color.card` | `#ffffff` |
|
| 73 |
+
| `color.muted` | `#6f6a7a` |
|
| 74 |
+
| `color.line` | `#e5ded2` |
|
| 75 |
+
| `color.accent` | `oklch(62% 0.19 35)` |
|
| 76 |
+
| `color.accent-ink` | `#fff6ee` |
|
| 77 |
+
| `color.ok` | `#2e7d4f` |
|
| 78 |
+
| `color.err` | `#b3372e` |
|
| 79 |
+
| `space.1` | `4` |
|
| 80 |
+
| `space.2` | `8` |
|
| 81 |
+
| `space.3` | `12` |
|
| 82 |
+
| `space.4` | `16` |
|
| 83 |
+
| `space.5` | `24` |
|
| 84 |
+
| `space.6` | `32` |
|
| 85 |
+
| `space.7` | `48` |
|
| 86 |
+
| `space.8` | `64` |
|
| 87 |
+
| `radius.sm` | `8` |
|
| 88 |
+
| `radius.md` | `14` |
|
| 89 |
+
| `radius.lg` | `22` |
|
| 90 |
+
| `radius.full` | `999` |
|
| 91 |
+
| `shadow.sm` | `0 1 2 color.ink/8, 0 1 3 color.ink/6` |
|
| 92 |
+
| `shadow.md` | `0 2 4 color.ink/10, 0 4 12 color.ink/8` |
|
| 93 |
+
| `shadow.lg` | `0 4 8 color.ink/12, 0 12 32 color.ink/12` |
|
| 94 |
+
| `shadow.xl` | `0 8 16 color.ink/14, 0 24 64 color.ink/16` |
|
| 95 |
+
| `font.sans` | `system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif` |
|
| 96 |
+
| `font.mono` | `ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace` |
|
| 97 |
+
|
| 98 |
+
## A.9 Semantic properties
|
| 99 |
+
|
| 100 |
+
`size`, `row`, `column`, `grid`, `stack`, `place`, `center`, `cover`, `sticky`, `font`, `fluid`, `shadow`, `radius`, `circle`, `align`, `z`, `grow`, `shrink`, `basis`, `truncate`, `visually-hidden`, `transition`, `animate`, `stagger`, `overlap`, `bend`, `bend-y`, `bend-up`, `fold`, `bend-around`, `stretch`, `gradient`, `text-stroke`, `yield`, `outline-shape`, `rotate`, `gradient-text`, `gradient-flow`, `texture`, `aura`, `aura-glow`, `aura-particle`, `aura-particles`, `glow-particle`, `glow-particles`, `aura-glow-particle`, `aura-glow-particles`, `glass`, `tilt`, `slider`
|
| 101 |
+
|
| 102 |
+
## A.10 Big sets
|
| 103 |
+
|
| 104 |
+
| set | count | where |
|
| 105 |
+
|---|---|---|
|
| 106 |
+
| CSS keywords | 1095 | `cssKeywords` in the data file |
|
| 107 |
+
| known CSS properties | 669 | `knownProps` |
|
| 108 |
+
| named colors | 148 | `namedColors` |
|
| 109 |
+
|
| 110 |
+
Color words allowed as gradient stops:
|
| 111 |
+
|
| 112 |
+
`black`, `silver`, `gray`, `white`, `maroon`, `red`, `purple`, `fuchsia`, `green`, `lime`, `olive`, `yellow`, `navy`, `blue`, `teal`, `aqua`, `orange`, `gold`, `pink`, `brown`, `violet`, `cyan`, `magenta`, `indigo`, `crimson`, `coral`, `tomato`, `goldenrod`, `khaki`, `slategray`, `slategrey`, `dimgray`, `dimgrey`, `lightgray`, `lightgrey`, `darkgray`, `darkgrey`, `gainsboro`, `whitesmoke`, `ghostwhite`, `ivory`, `beige`, `linen`, `seashell`, `snow`, `honeydew`, `mintcream`, `azure`, `aliceblue`, `lavender`, `canvas`, `canvastext`, `linktext`, `visitedtext`, `activetext`, `buttonface`, `buttontext`, `buttonborder`, `field`, `fieldtext`, `highlight`, `highlighttext`, `currentcolor`, `transparent`
|
| 113 |
+
|
| 114 |
+
## A.11 Texture
|
| 115 |
+
|
| 116 |
+
Generators: `noise`, `bump`, `lines`, `dots`, `grid`, `checker`, `weave`, `carbon`, `waves`, `hex`, `rings`, `bricks`, `herringbone`, `plaid`, `scales`, `chevron`, `diamonds`, `triangles`, `starfield`, `terrazzo`
|
| 117 |
+
|
| 118 |
+
Blend modes: `normal`, `multiply`, `screen`, `overlay`, `soft-light`, `hard-light`, `color-burn`, `color-dodge`, `darken`, `lighten`, `difference`, `exclusion`
|
| 119 |
+
|
| 120 |
+
Presets (73): `grain`, `noise`, `rough`, `sand`, `paper`, `cloud`, `concrete`, `stone`, `crumpled`, `glitter`, `frost`, `marble`, `wood`, `oak`, `walnut`, `cherry`, `maple`, `pine`, `mahogany`, `ebony`, `birch`, `oak-planks`, `walnut-planks`, `bark`, `leather`, `brushed`, `canvas`, `linen`, `denim`, `carbon`, `scanlines`, `halftone`, `dots`, `lines`, `grid`, `checker`, `crosshatch`, `stripes`, `waves`, `hex`, `bricks`, `bricks-old`, `herringbone`, `plaid`, `tartan`, `gingham`, `scales`, `mermaid`, `shingles`, `chevron`, `argyle`, `lowpoly`, `tiles`, `blueprint`, `granite`, `slate`, `sandstone`, `terrazzo`, `confetti`, `rust`, `corrugated`, `cork`, `kraft`, `felt`, `burlap`, `stucco`, `starfield`, `snow`, `grass`, `water`, `rain`, `lava`, `topo`
|
| 121 |
+
|
| 122 |
+
Settings:
|
| 123 |
+
|
| 124 |
+
| key | kind | values | range | what it does |
|
| 125 |
+
|---|---|---|---|---|
|
| 126 |
+
| `scale` | number | 1 | 0.1 to 2000 | feature size in px: how big the grains, cells or lines are |
|
| 127 |
+
| `intensity` | number | 1 | 0 to 2 | how strong the layer is, 0 to 1 (more than 1 over-drives it) |
|
| 128 |
+
| `contrast` | number | 1 | 0 to 40 | noise contrast: 1 is as generated, higher is harsher |
|
| 129 |
+
| `threshold` | number | 1 | 0 to 1 | noise cut-off: only values above it show (glitter uses a high one) |
|
| 130 |
+
| `contour` | number | 1 | 0.005 to 0.5 | draw thin lines where the noise crosses the threshold, instead of a plain cut: veins, rings, contours |
|
| 131 |
+
| `octaves` | number | 1 | 1 to 8 | noise detail layers, 1 is smooth, 5 is rough |
|
| 132 |
+
| `seed` | number | 1 | 0 to 99999 | a different random pattern with the same look |
|
| 133 |
+
| `stretch` | numbers | 2 | 0.1 to 200 | stretch noise features along x and y, e.g. stretch 40 1 for wood grain |
|
| 134 |
+
| `depth` | number | 1 | 0 to 30 | bump height: how deep the relief looks |
|
| 135 |
+
| `light` | number | 1 | -360 to 360 | bump light direction in degrees |
|
| 136 |
+
| `angle` | number | 1 | -360 to 360 | direction of lines and patterns, in degrees |
|
| 137 |
+
| `thickness` | number | 1 | 0.1 to 500 | line or grid-line width in px |
|
| 138 |
+
| `radius` | number | 1 | 0.02 to 1 | dot size as a fraction of the cell (plaid: how wide the bands are as a fraction of the repeat) |
|
| 139 |
+
| `softness` | number | 1 | 0 to 1 | how soft the edges of dots and lines are |
|
| 140 |
+
| `animate` | number | 1 | 0 to 60000 | milliseconds per shimmer step (film-grain flicker); 0 is still |
|
| 141 |
+
| `type` | word | 1 | `fractal`, `turbulence` | noise flavour: fractal is clouds, turbulence is veins |
|
| 142 |
+
| `blend` | word | 1 | `normal`, `multiply`, `screen`, `overlay`, `soft-light`, `hard-light`, `color-burn`, `color-dodge`, `darken`, `lighten`, `difference`, `exclusion` | how the layer mixes with what is under it |
|
| 143 |
+
| `color` | color | 1 | | the main colour (dark end of noise, ink of lines and dots) |
|
| 144 |
+
| `color2` | color | 1 | | the second colour (light end of noise, background cell of patterns) |
|
| 145 |
+
| `figure` | number | 1 | 0 to 1 | rings generator: how strongly the growth rings arch into a cathedral figure, 0 is straight grain |
|
| 146 |
+
| `warp` | number | 1 | 0 to 1 | rings generator: how much each ring wobbles along its length |
|
| 147 |
+
| `pores` | number | 1 | 0 to 1 | rings generator: fine fibre and pore streaks between the rings |
|
| 148 |
+
| `knots` | number | 1 | 0 to 8 | rings generator: how many knots in one tile (the pattern repeats, so keep it small) |
|
| 149 |
+
| `planks` | number | 1 | 24 to 1200 | rings generator: lay it out as planks this many px tall, with a seam and a slightly different board each |
|
| 150 |
+
| `symmetrical` | word | 1 | `both`, `x`, `y` | mirror every other tile, so each edge meets its own reflection: no seam, and the repeat is twice as far apart. x mirrors left to right, y top to bottom, both (the default) does both. Works on the image-based textures (noise, bump, rings, waves, hex). |
|
| 151 |
+
| `density` | number | 1 | 0.05 to 20 | starfield and terrazzo: how many stars or chips in a tile, 1 is normal |
|
| 152 |
+
| `invert` | flag | 0 | | swap the two colours |
|
| 153 |
+
|
| 154 |
+
## A.12 Aura
|
| 155 |
+
|
| 156 |
+
From words: `edge`, `outline`, `bottom`, `top`, `left`, `right`, `center`, `corners`, `thumb`
|
| 157 |
+
|
| 158 |
+
Shapes: `circle`, `spark`, `square`, `ring`, `star`, `flame`, `smoke`, `line`, `heart`, `diamond`, `triangle`, `plus`, `drop`, `bubble`, `snowflake`, `confetti`, `leaf`
|
| 159 |
+
|
| 160 |
+
Direction words: `up`, `down`, `left`, `right`, `out`, `in`
|
| 161 |
+
|
| 162 |
+
Blends: `add`, `normal`
|
| 163 |
+
|
| 164 |
+
Around shapes: `follow`, `box`, `round`, `pill`, `alpha`, `diamond`, `triangle`, `hexagon`, `octagon`, `pentagon`, `star`, `star4`, `star6`, `cross`, `heart`, `drop`, `bolt`
|
| 165 |
+
|
| 166 |
+
Glow settings:
|
| 167 |
+
|
| 168 |
+
| key | kind | range | what it does |
|
| 169 |
+
|---|---|---|---|
|
| 170 |
+
| `color` | color | | the light colour (default: the element's text colour) |
|
| 171 |
+
| `radius` | number | 1 to 400 | how far the glow reaches, in px |
|
| 172 |
+
| `intensity` | number | 0 to 4 | brightness, 1 is normal |
|
| 173 |
+
| `pulse` | number | 0 to 60000 | milliseconds for one breath in and out; 0 is steady |
|
| 174 |
+
| `depth` | number | 0 to 1 | how deep the pulse goes, 0 to 1 |
|
| 175 |
+
| `flicker` | number | 0 to 1 | random flicker, like a flame: 0 is steady, 1 is wild |
|
| 176 |
+
| `seed` | number | 0 to 99999 | a different random flicker with the same look |
|
| 177 |
+
| `texture` | texture | | texture(grain scale 2): break the light up with a texture |
|
| 178 |
+
| `essential` | flag | | keep animating even when the visitor prefers reduced motion |
|
| 179 |
+
| `unclipped` | flag | | let the light spill out of a parent that clips (overflow: hidden, auto, scroll). Without it the aura is cut at that edge, like the element itself |
|
| 180 |
+
| `around` | around | | the shape the light follows: follow (the default: the element's clip-path or rounded corners), box, round, pill, diamond, triangle, hexagon, octagon, pentagon, star, star4, star6, cross, heart, drop, bolt, alpha (an <img> or <canvas>'s visible pixels), or polygon(50% 0, 100% 50%, 50% 100%, 0 50%) |
|
| 181 |
+
| `inner` | flag | | light inside the edge (a rim) instead of outside it |
|
| 182 |
+
| `rays` | number | 1 to 64 | that many beams of light from the middle, slowly turning (see spin) |
|
| 183 |
+
| `spin` | number | -3600 to 3600 | rays turn this many degrees a second (default 10); on particles, how fast each one tumbles |
|
| 184 |
+
| `ripple` | number | 200 to 60000 | rings that spread out from the shape and fade, one every this many milliseconds |
|
| 185 |
+
| `nohalo` | flag | | only the rays and ripples, without the soft halo |
|
| 186 |
+
| `always` | flag | | keep emitting even when the element cannot be seen (opacity 0, display: none, visibility: hidden, on it or an ancestor): for an invisible anchor that smoke or sparks come out of |
|
| 187 |
+
| `z` | number | -1000000 to 2147483000 | the z-index of the layer this light is drawn on: `z 5` puts it under a hill with z-index 10. It meets elements in the page's root stacking context |
|
| 188 |
+
|
| 189 |
+
Glow defaults: `{"radius":24,"intensity":1,"pulse":0,"depth":0.35,"flicker":0,"seed":1}`
|
| 190 |
+
|
| 191 |
+
Particle settings:
|
| 192 |
+
|
| 193 |
+
| key | kind | range | what it does |
|
| 194 |
+
|---|---|---|---|
|
| 195 |
+
| `color` | colors | | colours over a particle's life: color #ff0 -> #f60 -> transparent |
|
| 196 |
+
| `count` | number | 1 to 600 | how many particles are alive at once |
|
| 197 |
+
| `size` | range | 0.5 to 300 | diameter in px: size 4, or size 10 4 (start and end of a random range) |
|
| 198 |
+
| `life` | range | 50 to 60000 | how long one lives, in ms: life 900, or life 600 1200 |
|
| 199 |
+
| `speed` | range | 0 to 3000 | px per second: speed 60, or speed 30 90 |
|
| 200 |
+
| `dir` | dir | | where they head: up, down, left, right, out, in, or degrees (-90 is up) |
|
| 201 |
+
| `spread` | number | 0 to 360 | how wide the fan of directions is, in degrees |
|
| 202 |
+
| `gravity` | number | -2000 to 2000 | px/s squared; negative pulls up (flames), positive down (snow) |
|
| 203 |
+
| `drag` | number | 0 to 10 | air resistance: how fast particles slow down |
|
| 204 |
+
| `turbulence` | number | 0 to 1000 | random sideways wobble, px/s |
|
| 205 |
+
| `from` | word | `edge`, `outline`, `bottom`, `top`, `left`, `right`, `center`, `corners`, `thumb` | where they are born: edge or outline (along the element's real outline, see around), bottom, top, left, right, center, corners, thumb (range sliders) |
|
| 206 |
+
| `shape` | word | `circle`, `spark`, `square`, `ring`, `star`, `flame`, `smoke`, `line`, `heart`, `diamond`, `triangle`, `plus`, `drop`, `bubble`, `snowflake`, `confetti`, `leaf` | circle, spark, square, ring, star, flame, smoke, line, heart, diamond, triangle, plus, drop, bubble, snowflake, confetti or leaf |
|
| 207 |
+
| `grow` | number | 0 to 10 | size at the end of life as a multiple of the start: 0.2 shrinks, 3 swells |
|
| 208 |
+
| `blend` | word | `add`, `normal` | add makes overlapping particles brighter, normal just stacks them |
|
| 209 |
+
| `glowing` | flag | | soft glowing particles that add light |
|
| 210 |
+
| `behind` | flag | | draw only outside the element's box, as if the element hid them |
|
| 211 |
+
| `seed` | number | 0 to 99999 | a different random pattern with the same look |
|
| 212 |
+
| `texture` | texture | | texture(grain): grainy particles |
|
| 213 |
+
| `essential` | flag | | keep animating even when the visitor prefers reduced motion |
|
| 214 |
+
| `unclipped` | flag | | let the particles leave a parent that clips (overflow: hidden, auto, scroll). Without it they are cut at that edge |
|
| 215 |
+
| `around` | around | | the shape `from edge` and `from outline` follow: follow (the default), box, round, pill, diamond, triangle, hexagon, octagon, pentagon, star, star4, star6, cross, heart, drop, bolt, or polygon(...) |
|
| 216 |
+
| `palette` | flag | | each particle takes ONE of the colours (confetti) instead of fading through them |
|
| 217 |
+
| `spin` | number | -3600 to 3600 | how fast each particle tumbles, in degrees a second (random direction) |
|
| 218 |
+
| `wind` | number | -3000 to 3000 | a sideways push, px/s squared; negative pushes left |
|
| 219 |
+
| `orbit` | number | -3600 to 3600 | the particles circle the middle of the element, this many degrees a second |
|
| 220 |
+
| `always` | flag | | keep emitting even when the element cannot be seen (opacity 0, display: none, visibility: hidden, on it or an ancestor): for an invisible anchor that smoke or sparks come out of |
|
| 221 |
+
| `z` | number | -1000000 to 2147483000 | the z-index of the layer these particles are drawn on: `z 5` puts them under a hill with z-index 10. It meets elements in the page's root stacking context |
|
| 222 |
+
|
| 223 |
+
Particle defaults: `{"count":40,"size":[4,4],"life":[900,900],"speed":[40,40],"dir":-90,"spread":30,"gravity":0,"drag":0,"turbulence":0,"from":"edge","shape":"circle","grow":0.3,"blend":null,"glowing":false,"seed":1}`
|
| 224 |
+
|
| 225 |
+
## A.13 Slider
|
| 226 |
+
|
| 227 |
+
| clause | form |
|
| 228 |
+
|---|---|
|
| 229 |
+
| `track` | `track [height] [color] [radius <n>\|full]` |
|
| 230 |
+
| `fill` | `fill <color> \| fill none` |
|
| 231 |
+
| `thumb` | `thumb <size> [color]` |
|
| 232 |
+
| `shape` | `shape circle \| square \| diamond \| pill \| bar` |
|
| 233 |
+
| `ring` | `ring <width> <color>` |
|
| 234 |
+
| `glow` | `glow <color> <radius>` |
|
| 235 |
+
| `ticks` | `ticks <count> [color] [length]` |
|
| 236 |
+
| `graph` | `graph <v1> <v2> ... (each 0 to 100)` |
|
| 237 |
+
| `graph-height` | `graph-height <px>` |
|
| 238 |
+
| `graph-gap` | `graph-gap <px>` |
|
| 239 |
+
|
| 240 |
+
Thumb shapes: `circle`, `square`, `diamond`, `pill`, `bar`
|
| 241 |
+
|
| 242 |
+
## A.14 Glass and tilt
|
| 243 |
+
|
| 244 |
+
| word | meaning |
|
| 245 |
+
|---|---|
|
| 246 |
+
| `blur` | a number: how many px to blur what is behind the element (default 16) |
|
| 247 |
+
| `saturate` | saturate <n>: colour boost for what shows through, 1 is unchanged (default 1.5) |
|
| 248 |
+
| `bright` | bright <n>: brightness of what shows through, 1 is unchanged |
|
| 249 |
+
| `tint` | tint <color> \| tint none: the milky layer on top (default: a faint wash of the text colour) |
|
| 250 |
+
| `max` | a number: the largest tilt in degrees (default 8) |
|
| 251 |
+
| `lift` | lift <n>: scale while the pointer is over it, e.g. 1.04 |
|
| 252 |
+
| `perspective` | perspective <px>: how strong the 3D depth looks (default 900) |
|
| 253 |
+
| `speed` | speed <0.05 to 1>: how quickly it follows (default 0.18) |
|
| 254 |
+
| `invert` | invert: tilt away from the pointer instead of toward it |
|
| 255 |
+
| `glare` | glare: also keep --dssl-gx and --dssl-gy (0% to 100%) pointing at the pointer, for your own highlight |
|
| 256 |
+
|
| 257 |
+
## A.15 Fonts
|
| 258 |
+
|
| 259 |
+
| word | meaning |
|
| 260 |
+
|---|---|
|
| 261 |
+
| `weights` | a weight (400), several (400 700), or a variable range (100..900) |
|
| 262 |
+
| `italic` | also load the italic of each weight |
|
| 263 |
+
| `display` | display <swap\|block\|fallback\|optional>: how the text behaves while the font loads (default swap) |
|
| 264 |
+
| `from` | from "/path/to/file.woff2": use your own file instead of Google Fonts |
|
| 265 |
+
|
|
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Appendix B: message templates
|
| 2 |
+
|
| 3 |
+
Generated by `scripts/gen-native-vocab.mjs`. Every error and warning template found in the engine
|
| 4 |
+
source, by file and line. `${...}` marks a value filled in at run time. The extraction is by pattern,
|
| 5 |
+
so it can include a string that is not a message and can miss one built in an unusual way. It is a
|
| 6 |
+
checklist for the corpus, not the definition: the definition is in the chapters.
|
| 7 |
+
|
| 8 |
+
## parser.js
|
| 9 |
+
|
| 10 |
+
| line | template |
|
| 11 |
+
|---|---|
|
| 12 |
+
| 177 | `unknown at-rule "${h.split(' ')[0]}"` |
|
| 13 |
+
| 183 | `unknown pseudo-element "::${name}"` |
|
| 14 |
+
| 205 | `unexpected "}"` |
|
| 15 |
+
| 224 | `block is missing a header before "{"` |
|
| 16 |
+
| 261 | `${meta.kind} { } must be top-level` |
|
| 17 |
+
| 282 | `the "${(meta.sel \|\| '').slice(0, 30) \|\| 'block'}" block was never closed with "}"` |
|
| 18 |
+
| 350 | `expected ":" in "${part.slice(0, 40)}"` |
|
| 19 |
+
| 356 | `declaration is missing a property name` |
|
| 20 |
+
| 367 | `"${prop}" is not a valid property name` |
|
| 21 |
+
|
| 22 |
+
## resolver.js
|
| 23 |
+
|
| 24 |
+
| line | template |
|
| 25 |
+
|---|---|
|
| 26 |
+
| 415 | `${what} takes a bare number of degrees` |
|
| 27 |
+
| 500 | `mesh needs a base colour and at least one blob` |
|
| 28 |
+
| 504 | `mesh item "${it}" needs a position` |
|
| 29 |
+
| 509 | `mesh needs a base colour first (an item without "at")` |
|
| 30 |
+
| 521 | `gradient needs a kind: "linear", "radial", "conic" or "mesh" (any of them can be "repeating")` |
|
| 31 |
+
| 558 | `gradient needs at least two stops` |
|
| 32 |
+
| 576 | `"${head}" is not a linear gradient direction` |
|
| 33 |
+
| 587 | `"${a}" is not part of a radial gradient shape` |
|
| 34 |
+
| 602 | `"${head}" is not a conic gradient prefix` |
|
| 35 |
+
| 617 | `"${s}" is a midpoint, so it has to sit between two colours` |
|
| 36 |
+
| 626 | `a gradient stop is missing its color (got "${s}")` |
|
| 37 |
+
| 633 | `gradient stop "${s}" is not a color` |
|
| 38 |
+
| 666 | `gap needs a value` |
|
| 39 |
+
| 680 | `"${a}" is written twice in ${dir} - the second copy wins` |
|
| 40 |
+
| 681 | `two words in ${dir} write ${prop}: "${a}" overrides "${prev}"` |
|
| 41 |
+
| 706 | `unknown word "${a}" in ${dir}` |
|
| 42 |
+
| 728 | `${a} needs a number` |
|
| 43 |
+
| 745 | `unknown animate part "${a}"` |
|
| 44 |
+
| 773 | `grid needs columns` |
|
| 45 |
+
| 791 | `unknown place "${word}" in stack` |
|
| 46 |
+
| 799 | `unknown place "${v}"` |
|
| 47 |
+
| 819 | `unknown center axis "${v}"` |
|
| 48 |
+
| 840 | `font: "${v.trim()}" looks like the CSS font shorthand, but DSSL's font: means size, line height and colour` |
|
| 49 |
+
| 870 | `radius "${a}" is not defined, so it will not apply` |
|
| 50 |
+
| 891 | `unknown align "${v}"` |
|
| 51 |
+
| 947 | `transition: the CSS form (property first) is not DSSL` |
|
| 52 |
+
| 952 | `transition duration "${dur}" is not a time` |
|
| 53 |
+
| 968 | `unknown transition property "${raw}"` |
|
| 54 |
+
| 997 | `stagger needs a duration like "60" or "120ms", or "none"` |
|
| 55 |
+
| 1016 | `unknown overlap policy "${(v \|\| '').trim()}"` |
|
| 56 |
+
| 1040 | `bend-around caps at ±170° - past that the arc folds back on itself` |
|
| 57 |
+
| 1053 | `stretch needs a positive factor, like "stretch: 1.2" or "stretch: 1.4 vertical"` |
|
| 58 |
+
| 1062 | `stretch: ${m[1]} would flatten the element to nothing` |
|
| 59 |
+
| 1095 | `text-stroke needs a width first` |
|
| 60 |
+
| 1112 | `yield needs the properties to hand back` |
|
| 61 |
+
| 1115 | `yield: "${n}" is not a CSS property` |
|
| 62 |
+
| 1128 | `outline-shape needs a width first` |
|
| 63 |
+
| 1166 | `gradient-flow takes a duration like "6s" or "6000ms", or "none"` |
|
| 64 |
+
| 1179 | `unknown gradient-flow part "${a}"` |
|
| 65 |
+
| 1202 | `fluid: "${s}" ${why}` |
|
| 66 |
+
| 1216 | `${parts[0]} ${parts[1]}` |
|
| 67 |
+
| 1217 | `${parts[2]} ${parts[3]}` |
|
| 68 |
+
| 1306 | `!important does not exist in DSSL - "${prop}: ${String(value).replace(/\s*!\s*important\s*/i, '')}" was NOT applied` |
|
| 69 |
+
| 1346 | `unknown property "${prop}"` |
|
| 70 |
+
| 1374 | `@media needs a condition` |
|
| 71 |
+
| 1402 | `@signal ${list[1]} ${list[2]} ( ) has no values` |
|
| 72 |
+
| 1412 | `bad @signal expression "${expr}"` |
|
| 73 |
+
| 1451 | `unexpected "${child.kind}" inside tokens` |
|
| 74 |
+
| 1460 | `behavior "${node.name}" is defined twice` |
|
| 75 |
+
| 1503 | `"${child.prop}" is not allowed inside motion` |
|
| 76 |
+
| 1509 | `bad keyframe selector "${child.sel}"` |
|
| 77 |
+
| 1601 | `unknown behavior "${name}"` |
|
| 78 |
+
| 1604 | `behavior cycle involving "${name}"` |
|
| 79 |
+
| 1623 | `"${node.sel}" compiled as a descendant selector ("${combine(ctx.sel, node.sel)}")` |
|
| 80 |
+
| 1635 | `"${node.name}" needs a selector around it` |
|
| 81 |
+
| 1647 | `"${d.prop}: ${d.value}" - the -> arrow is motion syntax and does nothing inside seen { }` |
|
| 82 |
+
| 1688 | `unknown layer "${node.name}", treated as "components"` |
|
| 83 |
+
| 1710 | `"seen" is engine-native and has no meaning on a pseudo-element` |
|
| 84 |
+
| 1716 | `only declarations and states (hover { }) may appear inside a pseudo-element block` |
|
| 85 |
+
| 1725 | `"${d.prop}" is engine-native and has no meaning on ::${node.name} - a pseudo-element has no DOM handle` |
|
| 86 |
+
| 1750 | `tokens must be top-level or inside @media / @signal` |
|
| 87 |
+
| 1789 | `raw { } is verbatim CSS, so this line needs a ";" at the end ("${t.slice(0, 40)}")` |
|
| 88 |
+
| 1797 | `${node.kind} "${node.name}" must be top-level` |
|
| 89 |
+
| 1808 | `declarations must live inside a selector` |
|
| 90 |
+
| 1824 | `"${d.prop}" is engine-native and has no meaning on ::${ps.parts[0].pseudo.split(/[\s:(]/)[0]} - a pseudo-element has no DOM handle` |
|
| 91 |
+
| 1834 | `unknown pseudo-element "::${pseudo}"` |
|
| 92 |
+
| 1842 | `::slotted() only exists inside a shadow tree, and DSSL styles the light DOM` |
|
| 93 |
+
| 1850 | `the engine-native "seen" state can't combine with "::${name}" in shadow CSS` |
|
| 94 |
+
| 1868 | `selector list mixes pseudo-element and plain selectors: "${ctx.sel}"` |
|
| 95 |
+
| 1913 | `"${d.via}:" expands to display: ${d.value}, which overrides the earlier "display: ${explicit.value}" (line ${explicit.line}) in the same rule - later wins, so the earlier one is dead` |
|
| 96 |
+
| 1937 | `"${r.sel}" sets the background image twice (gradient: and ${other.prop}): the later one replaces the earlier, so one of them never shows` |
|
| 97 |
+
| 1953 | `${x.prop} does nothing here: this rule has no CSS animation to tune${usesAnimate ? ', it runs its motion through animate:' : ''}` |
|
| 98 |
+
| 1965 | `unknown motion "${d.value.motion}"` |
|
| 99 |
+
| 1984 | `animation "${d.value}" references no motion defined in this sheet - it will not run` |
|
| 100 |
+
|
| 101 |
+
## texture.js
|
| 102 |
+
|
| 103 |
+
| line | template |
|
| 104 |
+
|---|---|
|
| 105 |
+
| 380 | `texture needs a name` |
|
| 106 |
+
| 390 | `unknown texture "${first}"` |
|
| 107 |
+
| 398 | `unknown texture setting "${key}"` |
|
| 108 |
+
| 406 | `texture setting "${key}" needs ${def.words === 1 ? 'a value' : def.words + ' values'}` |
|
| 109 |
+
| 412 | `texture setting "${key}" needs a number, got "${vals.join(' ')}"` |
|
| 110 |
+
| 413 | `texture "${key}" must be between ${def.min} and ${def.max}` |
|
| 111 |
+
| 417 | `unknown ${key} "${vals[0]}"` |
|
| 112 |
+
|
| 113 |
+
## aura.js
|
| 114 |
+
|
| 115 |
+
| line | template |
|
| 116 |
+
|---|---|
|
| 117 |
+
| 84 | `unknown around "${w}"` |
|
| 118 |
+
| 89 | `polygon needs "x y" pairs in percent, got "${part.trim()}"` |
|
| 119 |
+
| 92 | `a polygon needs at least 3 points` |
|
| 120 |
+
| 325 | `${prop} needs a value` |
|
| 121 |
+
| 342 | `an aura layer starts with glow or particles, not "${head}"` |
|
| 122 |
+
| 377 | `unknown aura property "${prop}"` |
|
| 123 |
+
|
| 124 |
+
## slider.js
|
| 125 |
+
|
| 126 |
+
| line | template |
|
| 127 |
+
|---|---|
|
| 128 |
+
| 69 | `slider needs a description` |
|
| 129 |
+
| 78 | `unknown slider setting "${head}"` |
|
| 130 |
+
| 92 | `track radius needs a number or "full"` |
|
| 131 |
+
| 102 | `thumb needs a size in px` |
|
| 132 |
+
| 107 | `unknown thumb shape "${rest[0] ?? ''}"` |
|
| 133 |
+
| 111 | `ring needs a width and a colour` |
|
| 134 |
+
| 116 | `glow needs a colour and a radius` |
|
| 135 |
+
| 121 | `ticks needs a count of at least 2` |
|
| 136 |
+
| 127 | `graph needs at least two numbers` |
|
| 137 |
+
| 128 | `graph values are 0 to 100` |
|
| 138 |
+
| 129 | `graph is limited to 120 bars` |
|
| 139 |
+
| 132 | `graph-height needs a number of px, at least 8` |
|
| 140 |
+
| 136 | `graph-gap needs a number of px` |
|
| 141 |
+
| 141 | `unexpected "${rest.slice(used).join(' ')}" in the ${head} setting` |
|
| 142 |
+
|
| 143 |
+
## effects.js
|
| 144 |
+
|
| 145 |
+
| line | template |
|
| 146 |
+
|---|---|
|
| 147 |
+
| 43 | `${x} needs a number` |
|
| 148 |
+
| 49 | `tint needs a color or "none"` |
|
| 149 |
+
| 58 | `unknown glass setting "${x}"` |
|
| 150 |
+
| 60 | `glass blur cannot be negative` |
|
| 151 |
+
| 72 | `tilt needs a number of degrees` |
|
| 152 |
+
| 87 | `unknown tilt setting "${x}"` |
|
| 153 |
+
| 89 | `tilt degrees should be between 0 and 45` |
|
| 154 |
+
| 90 | `lift must be above 0` |
|
| 155 |
+
| 91 | `perspective must be at least 100px` |
|
| 156 |
+
| 92 | `speed must be between 0.02 and 1` |
|
| 157 |
+
|
| 158 |
+
## fonts.js
|
| 159 |
+
|
| 160 |
+
| line | template |
|
| 161 |
+
|---|---|
|
| 162 |
+
|
| 163 |
+
## lint.js
|
| 164 |
+
|
| 165 |
+
| line | template |
|
| 166 |
+
|---|---|
|
| 167 |
+
| 119 | `text contrast is ${ratio.toFixed(1)}:1 (${toHex(fgSolid)} on ${toHex(bg)}), below the ${need}:1 that readers need${large ? ' for large text' : ''}` |
|
| 168 |
+
| 147 | `${dim}: ${px}px on "${r.sel}" is below 24px, the smallest target WCAG 2.2 allows` |
|
| 169 |
+
| 160 | `the focus outline is removed from "${k.sel}" and nothing replaces it, so keyboard users lose their place` |
|
| 170 |
+
| 269 | `${p.a.props.join(', ')} in "${p.a.sel}" can never apply: "${p.b.sel}" (${p.b.file \|\| ''}${p.b.file ? ':' : ''}${p.b.line}) comes later, matches every element this rule matches, and sets ${p.a.props.length > 1 ? 'the same properties' : 'the same property'}` |
|
| 171 |
+
|
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
pub fn hello() -> &'static str { "dssl" }
|
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
fn main() { println!("{}", dssl::hello()); }
|
|
@@ -1,6 +1,6 @@
|
|
| 1 |
{
|
| 2 |
"name": "dssl",
|
| 3 |
-
"version": "0.16.
|
| 4 |
"private": true,
|
| 5 |
"description": "The DSSL style language and the website that is written in it.",
|
| 6 |
"scripts": {
|
|
|
|
| 1 |
{
|
| 2 |
"name": "dssl",
|
| 3 |
+
"version": "0.16.3",
|
| 4 |
"private": true,
|
| 5 |
"description": "The DSSL style language and the website that is written in it.",
|
| 6 |
"scripts": {
|
|
@@ -19,7 +19,7 @@ import { resolve, DEFAULT_TOKENS, EASINGS } from './resolver.js';
|
|
| 19 |
import { toCSS as docToCSS } from './static.js';
|
| 20 |
import { DsslEngine } from './engine.js';
|
| 21 |
|
| 22 |
-
export const VERSION = '0.16.
|
| 23 |
|
| 24 |
let counter = 0;
|
| 25 |
const loadedUrls = new Set(); // every .dssl file fetched by load(), so DSSL.watch() knows what to follow
|
|
|
|
| 19 |
import { toCSS as docToCSS } from './static.js';
|
| 20 |
import { DsslEngine } from './engine.js';
|
| 21 |
|
| 22 |
+
export const VERSION = '0.16.3';
|
| 23 |
|
| 24 |
let counter = 0;
|
| 25 |
const loadedUrls = new Set(); // every .dssl file fetched by load(), so DSSL.watch() knows what to follow
|
|
@@ -111,6 +111,17 @@ function stripComments(src) {
|
|
| 111 |
continue;
|
| 112 |
}
|
| 113 |
if (c === '"' || c === "'") { q = c; out += c; continue; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
if (c === '/' && n === '/') {
|
| 115 |
// v0.7.1 bugfix: this handler used to emit its own '\n' AND rewind so
|
| 116 |
// the main loop emitted the same newline again - every // comment
|
|
|
|
| 111 |
continue;
|
| 112 |
}
|
| 113 |
if (c === '"' || c === "'") { q = c; out += c; continue; }
|
| 114 |
+
// An unquoted url(...) is one token: the // in http://x.com/a.png is not a comment. Copy it through the
|
| 115 |
+
// closing paren untouched (newlines included, so line numbers hold). A quoted url is handled by the string rule above.
|
| 116 |
+
if ((c === 'u' || c === 'U') && /^url\(/i.test(src.slice(i, i + 4)) && !/[\w-]/.test(src[i - 1] || '')) {
|
| 117 |
+
let k = i + 4;
|
| 118 |
+
while (k < src.length && /\s/.test(src[k])) k++;
|
| 119 |
+
if (src[k] !== '"' && src[k] !== "'") {
|
| 120 |
+
let e = k;
|
| 121 |
+
while (e < src.length && src[e] !== ')') e += src[e] === '\\' ? 2 : 1;
|
| 122 |
+
if (e < src.length) { out += src.slice(i, e + 1); i = e; continue; }
|
| 123 |
+
}
|
| 124 |
+
}
|
| 125 |
if (c === '/' && n === '/') {
|
| 126 |
// v0.7.1 bugfix: this handler used to emit its own '\n' AND rewind so
|
| 127 |
// the main loop emitted the same newline again - every // comment
|
|
@@ -182,6 +182,13 @@ const LENGTH_FN = new Set('calc,min,max,clamp,round,mod,rem,abs,sign,hypot,pow,s
|
|
| 182 |
* - token references become var(--dssl-…), `token/NN` becomes color-mix
|
| 183 |
* - unknown identifiers are errors (with did-you-mean)
|
| 184 |
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 185 |
/** split a selector list at top-level commas (not inside :is(...) and friends) */
|
| 186 |
function splitTopLevel(sel) {
|
| 187 |
const out = []; let depth = 0, cur = '';
|
|
@@ -209,7 +216,7 @@ function resolveValue(raw, ctx) {
|
|
| 209 |
|
| 210 |
if (c === '"' || c === "'") {
|
| 211 |
let j = i + 1;
|
| 212 |
-
while (j < n && raw[j] !== c) j+
|
| 213 |
out += raw.slice(i, j + 1);
|
| 214 |
i = j + 1;
|
| 215 |
continue;
|
|
@@ -247,7 +254,7 @@ function resolveValue(raw, ctx) {
|
|
| 247 |
if (raw[j] === ')') depth--;
|
| 248 |
if (depth > 0 && (raw[j] === '"' || raw[j] === "'")) {
|
| 249 |
const q = raw[j]; j++;
|
| 250 |
-
while (j < n && raw[j] !== q) j+
|
| 251 |
}
|
| 252 |
j++;
|
| 253 |
}
|
|
@@ -386,16 +393,8 @@ function topSplit(str, sep) {
|
|
| 386 |
}
|
| 387 |
|
| 388 |
function findToken(tokens, ident) {
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
if (ident.includes('.')) {
|
| 392 |
-
const parts = ident.split('.');
|
| 393 |
-
for (let k = parts.length - 1; k > 0; k--) {
|
| 394 |
-
const key = parts.slice(0, k).join('.');
|
| 395 |
-
if (tokens.has(key)) return key; // hmm - partial match would change meaning; require exact
|
| 396 |
-
}
|
| 397 |
-
}
|
| 398 |
-
return null;
|
| 399 |
}
|
| 400 |
|
| 401 |
/* ------------------------------------------------------------------ *
|
|
@@ -438,7 +437,7 @@ function splitLayers(s) {
|
|
| 438 |
const out = []; let depth = 0, q = null, cur = '';
|
| 439 |
for (let i = 0; i < s.length; i++) {
|
| 440 |
const c = s[i];
|
| 441 |
-
if (q) { cur += c; if (c === q) q = null; continue; }
|
| 442 |
if (c === '"' || c === "'") { q = c; cur += c; continue; }
|
| 443 |
if (c === '(' || c === '[') depth++;
|
| 444 |
else if (c === ')' || c === ']') depth = Math.max(0, depth - 1);
|
|
@@ -866,7 +865,12 @@ const SEMANTIC = {
|
|
| 866 |
radius(v, ctx) {
|
| 867 |
const atoms = v.trim().split(/\s+/).filter(Boolean);
|
| 868 |
const out = atoms.map(a => {
|
| 869 |
-
if (['sm', 'md', 'lg', 'full', 'xl'].includes(a))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 870 |
if (/^[A-Za-z][\w-]*$/.test(a) && ctx.tokens && ctx.tokens.has('radius.' + a)) return `var(--dssl-radius-${a})`; // 0.14.0: radius { pill: 99 } then radius: pill
|
| 871 |
return resolveValue(a, ctx);
|
| 872 |
});
|
|
@@ -1614,7 +1618,7 @@ export function resolve(ast, file = 'inline.dssl', baseTokens = null, baseMotion
|
|
| 1614 |
break;
|
| 1615 |
}
|
| 1616 |
case 'selector': {
|
| 1617 |
-
if (/^[a-zA-Z][a-zA-Z0-9-]*$/.test(node.sel) && ctx.sel) {
|
| 1618 |
const near = didYouMean(node.sel.toLowerCase(), [...STATE_WORDS]);
|
| 1619 |
if (near) warnings.push({ file, line: node.line, message: `"${node.sel}" compiled as a descendant selector ("${combine(ctx.sel, node.sel)}")`, hint: `if you meant the state, it is spelled "${near}" - this block currently styles descendants called <${node.sel}>` });
|
| 1620 |
}
|
|
@@ -1632,7 +1636,7 @@ export function resolve(ast, file = 'inline.dssl', baseTokens = null, baseMotion
|
|
| 1632 |
break;
|
| 1633 |
}
|
| 1634 |
flushPending(node.line);
|
| 1635 |
-
const childCtx = { ...ctx, sel: ctx.sel
|
| 1636 |
// v0.7.2 - the arrow is motion/gradient-stop syntax; inside a seen
|
| 1637 |
// block it compiled into an inline style the browser rejects, so the
|
| 1638 |
// element just sat at its base style forever. Say so, loudly, and
|
|
@@ -1678,7 +1682,11 @@ export function resolve(ast, file = 'inline.dssl', baseTokens = null, baseMotion
|
|
| 1678 |
}
|
| 1679 |
case 'layer':
|
| 1680 |
case 'pin': {
|
| 1681 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1682 |
flushPending(node.line);
|
| 1683 |
const childCtx = { ...ctx, layer };
|
| 1684 |
const sub = { decls: [] };
|
|
@@ -1688,6 +1696,7 @@ export function resolve(ast, file = 'inline.dssl', baseTokens = null, baseMotion
|
|
| 1688 |
}
|
| 1689 |
case 'pseudo': {
|
| 1690 |
const base = ctx.sel || '*'; // top-level ::selection etc. means every element
|
|
|
|
| 1691 |
const srule = {
|
| 1692 |
id: ruleId++, sel: base, pseudo: node.name,
|
| 1693 |
media: ctx.media, signals: ctx.signals, containers: ctx.containers,
|
|
@@ -1724,6 +1733,17 @@ export function resolve(ast, file = 'inline.dssl', baseTokens = null, baseMotion
|
|
| 1724 |
fill(srule, node.children);
|
| 1725 |
if (srule.decls.length) shadowRules.push(srule);
|
| 1726 |
for (const st of stateRules) if (st.decls.length) shadowRules.push(st);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1727 |
break;
|
| 1728 |
}
|
| 1729 |
case 'tokens': {
|
|
@@ -1994,10 +2014,24 @@ export function resolve(ast, file = 'inline.dssl', baseTokens = null, baseMotion
|
|
| 1994 |
return { rules, shadowRules, raws, fontLinks, motions, motionFrames, errors, warnings, mediaQueries: [...mediaQueries], tokens: Object.fromEntries(tokenMap), registryRule };
|
| 1995 |
}
|
| 1996 |
|
| 1997 |
-
/**
|
|
|
|
| 1998 |
function combine(parent, child) {
|
| 1999 |
-
|
| 2000 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2001 |
}
|
| 2002 |
|
| 2003 |
/* v0.5.0 - where does a selector carry a pseudo-element?
|
|
|
|
| 182 |
* - token references become var(--dssl-…), `token/NN` becomes color-mix
|
| 183 |
* - unknown identifiers are errors (with did-you-mean)
|
| 184 |
*/
|
| 185 |
+
/** HTML element names: a bare one nested in a rule is a descendant selector on purpose, never a mistyped state word */
|
| 186 |
+
const HTML_ELEMENTS = new Set(('a,abbr,acronym,address,area,article,aside,audio,b,base,bdi,bdo,big,blockquote,body,br,button,canvas,caption,center,cite,code,col,colgroup,' +
|
| 187 |
+
'data,datalist,dd,del,details,dfn,dialog,dir,div,dl,dt,em,embed,fieldset,figcaption,figure,font,footer,form,frame,frameset,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,' +
|
| 188 |
+
'i,iframe,img,input,ins,kbd,label,legend,li,link,main,map,mark,marquee,menu,meta,meter,nav,nobr,noscript,object,ol,optgroup,option,output,p,param,picture,pre,progress,q,' +
|
| 189 |
+
'rp,rt,ruby,s,samp,script,search,section,select,slot,small,source,span,strike,strong,style,sub,summary,sup,table,tbody,td,template,textarea,tfoot,th,thead,time,title,tr,' +
|
| 190 |
+
'track,tt,u,ul,var,video,wbr,svg,math').split(','));
|
| 191 |
+
|
| 192 |
/** split a selector list at top-level commas (not inside :is(...) and friends) */
|
| 193 |
function splitTopLevel(sel) {
|
| 194 |
const out = []; let depth = 0, cur = '';
|
|
|
|
| 216 |
|
| 217 |
if (c === '"' || c === "'") {
|
| 218 |
let j = i + 1;
|
| 219 |
+
while (j < n && raw[j] !== c) j += raw[j] === '\\' ? 2 : 1; // a backslash escapes the next character
|
| 220 |
out += raw.slice(i, j + 1);
|
| 221 |
i = j + 1;
|
| 222 |
continue;
|
|
|
|
| 254 |
if (raw[j] === ')') depth--;
|
| 255 |
if (depth > 0 && (raw[j] === '"' || raw[j] === "'")) {
|
| 256 |
const q = raw[j]; j++;
|
| 257 |
+
while (j < n && raw[j] !== q) j += raw[j] === '\\' ? 2 : 1;
|
| 258 |
}
|
| 259 |
j++;
|
| 260 |
}
|
|
|
|
| 393 |
}
|
| 394 |
|
| 395 |
function findToken(tokens, ident) {
|
| 396 |
+
// exact key only: color.ink2.bogus must not quietly become color.ink2, it falls through to "unknown value"
|
| 397 |
+
return tokens.has(ident) ? ident : null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 398 |
}
|
| 399 |
|
| 400 |
/* ------------------------------------------------------------------ *
|
|
|
|
| 437 |
const out = []; let depth = 0, q = null, cur = '';
|
| 438 |
for (let i = 0; i < s.length; i++) {
|
| 439 |
const c = s[i];
|
| 440 |
+
if (q) { cur += c; if (c === q && s[i - 1] !== '\\') q = null; continue; }
|
| 441 |
if (c === '"' || c === "'") { q = c; cur += c; continue; }
|
| 442 |
if (c === '(' || c === '[') depth++;
|
| 443 |
else if (c === ')' || c === ']') depth = Math.max(0, depth - 1);
|
|
|
|
| 865 |
radius(v, ctx) {
|
| 866 |
const atoms = v.trim().split(/\s+/).filter(Boolean);
|
| 867 |
const out = atoms.map(a => {
|
| 868 |
+
if (['sm', 'md', 'lg', 'full', 'xl'].includes(a)) {
|
| 869 |
+
if (ctx.tokens && !ctx.tokens.has('radius.' + a) && ctx.warnings) {
|
| 870 |
+
ctx.warnings.push({ file: ctx.file, line: ctx.line, message: `radius "${a}" is not defined, so it will not apply`, hint: `add it with tokens { radius { ${a}: 32 } }` });
|
| 871 |
+
}
|
| 872 |
+
return `var(--dssl-radius-${a})`;
|
| 873 |
+
}
|
| 874 |
if (/^[A-Za-z][\w-]*$/.test(a) && ctx.tokens && ctx.tokens.has('radius.' + a)) return `var(--dssl-radius-${a})`; // 0.14.0: radius { pill: 99 } then radius: pill
|
| 875 |
return resolveValue(a, ctx);
|
| 876 |
});
|
|
|
|
| 1618 |
break;
|
| 1619 |
}
|
| 1620 |
case 'selector': {
|
| 1621 |
+
if (/^[a-zA-Z][a-zA-Z0-9-]*$/.test(node.sel) && ctx.sel && !HTML_ELEMENTS.has(node.sel.toLowerCase())) {
|
| 1622 |
const near = didYouMean(node.sel.toLowerCase(), [...STATE_WORDS]);
|
| 1623 |
if (near) warnings.push({ file, line: node.line, message: `"${node.sel}" compiled as a descendant selector ("${combine(ctx.sel, node.sel)}")`, hint: `if you meant the state, it is spelled "${near}" - this block currently styles descendants called <${node.sel}>` });
|
| 1624 |
}
|
|
|
|
| 1636 |
break;
|
| 1637 |
}
|
| 1638 |
flushPending(node.line);
|
| 1639 |
+
const childCtx = { ...ctx, sel: withState(ctx.sel, node.name) };
|
| 1640 |
// v0.7.2 - the arrow is motion/gradient-stop syntax; inside a seen
|
| 1641 |
// block it compiled into an inline style the browser rejects, so the
|
| 1642 |
// element just sat at its base style forever. Say so, loudly, and
|
|
|
|
| 1682 |
}
|
| 1683 |
case 'layer':
|
| 1684 |
case 'pin': {
|
| 1685 |
+
const LAYERS = ['tokens', 'base', 'components', 'utilities', 'pin'];
|
| 1686 |
+
const layer = node.kind === 'pin' ? 'pin' : (LAYERS.includes(node.name) ? node.name : 'components');
|
| 1687 |
+
if (node.kind === 'layer' && !LAYERS.includes(node.name)) {
|
| 1688 |
+
warnings.push({ file, line: node.line, message: `unknown layer "${node.name}", treated as "components"`, hint: didYouMean(node.name, LAYERS) || 'the layers are tokens, base, components, utilities, pin' });
|
| 1689 |
+
}
|
| 1690 |
flushPending(node.line);
|
| 1691 |
const childCtx = { ...ctx, layer };
|
| 1692 |
const sub = { decls: [] };
|
|
|
|
| 1696 |
}
|
| 1697 |
case 'pseudo': {
|
| 1698 |
const base = ctx.sel || '*'; // top-level ::selection etc. means every element
|
| 1699 |
+
const parts = splitTopLevel(base);
|
| 1700 |
const srule = {
|
| 1701 |
id: ruleId++, sel: base, pseudo: node.name,
|
| 1702 |
media: ctx.media, signals: ctx.signals, containers: ctx.containers,
|
|
|
|
| 1733 |
fill(srule, node.children);
|
| 1734 |
if (srule.decls.length) shadowRules.push(srule);
|
| 1735 |
for (const st of stateRules) if (st.decls.length) shadowRules.push(st);
|
| 1736 |
+
// a selector list in front of the block (.a, .b { ::before { } }): the rules above were built on the whole
|
| 1737 |
+
// list; give every further part its own copy so each gets its own pseudo-element rule
|
| 1738 |
+
if (parts.length > 1) {
|
| 1739 |
+
const built = [srule, ...stateRules].filter((r) => r.decls.length);
|
| 1740 |
+
for (const part of parts.slice(1)) {
|
| 1741 |
+
for (const r of built) {
|
| 1742 |
+
shadowRules.push({ ...r, decls: r.decls.map((d) => ({ ...d })), id: ruleId++, order: order++, sel: part + r.sel.slice(base.length) });
|
| 1743 |
+
}
|
| 1744 |
+
}
|
| 1745 |
+
for (const r of built) r.sel = parts[0] + r.sel.slice(base.length);
|
| 1746 |
+
}
|
| 1747 |
break;
|
| 1748 |
}
|
| 1749 |
case 'tokens': {
|
|
|
|
| 2014 |
return { rules, shadowRules, raws, fontLinks, motions, motionFrames, errors, warnings, mediaQueries: [...mediaQueries], tokens: Object.fromEntries(tokenMap), registryRule };
|
| 2015 |
}
|
| 2016 |
|
| 2017 |
+
/** `&` substitution + descendant join. Lists are split at top-level commas and every parent part is joined with
|
| 2018 |
+
* every child part (parent-major), so `.a, .b { .c { } }` is `.a .c, .b .c`. Commas inside :is( ) or [ ] stay put. */
|
| 2019 |
function combine(parent, child) {
|
| 2020 |
+
const pp = splitTopLevel(parent), cp = splitTopLevel(child);
|
| 2021 |
+
if (pp.length <= 1 && cp.length <= 1) {
|
| 2022 |
+
if (child.includes('&')) return child.split('&').join(parent);
|
| 2023 |
+
return parent + ' ' + child;
|
| 2024 |
+
}
|
| 2025 |
+
const out = [];
|
| 2026 |
+
for (const p of pp) for (const c of cp) out.push(c.includes('&') ? c.split('&').join(p) : p + ' ' + c);
|
| 2027 |
+
return out.join(', ');
|
| 2028 |
+
}
|
| 2029 |
+
|
| 2030 |
+
/** append a state to every part of a selector list: `.a, .b` + hover is `.a:hover, .b:hover` */
|
| 2031 |
+
function withState(sel, name) {
|
| 2032 |
+
const parts = splitTopLevel(sel);
|
| 2033 |
+
if (parts.length <= 1) return sel + ':' + name;
|
| 2034 |
+
return parts.map((p) => p + ':' + name).join(', ');
|
| 2035 |
}
|
| 2036 |
|
| 2037 |
/* v0.5.0 - where does a selector carry a pseudo-element?
|
|
@@ -5,7 +5,7 @@
|
|
| 5 |
- Site (docs, playground, changelog, bench): https://dssl-sable.vercel.app
|
| 6 |
- Repo + full docs in the README: https://huggingface.co/EHS-Studio/dssl
|
| 7 |
- Install: `curl -fsSL https://dssl-sable.vercel.app/install.sh | sh` (or the zip: https://dssl-sable.vercel.app/dssl-engine.zip)
|
| 8 |
-
- Version: 0.16.
|
| 9 |
- Feature matrix vs CSS: see PARITY.md in the repo
|
| 10 |
- For agents working ON the codebase: see AGENTS.md in the repo
|
| 11 |
|
|
@@ -64,6 +64,10 @@ DSSL.replay(sel) / DSSL.refresh([el]) / DSSL.errors() (a function) / DSSL.versio
|
|
| 64 |
- Alpha on a named colour works: `white/12`, `currentColor/20`. It used to compile to `white/12px`.
|
| 65 |
- The playground has a canvas.html tab, `?example=` links, lint warnings and an "as CSS" tab. The canvas keeps a short allow-list of tags and drops scripts, handlers, styles and ids.
|
| 66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
## 0.16.2
|
| 68 |
- `DSSL.lint`'s `css-loses` no longer judges the output of `dssl build` (its reset is built to sit under the engine), and ignores a rule whose value is the same as what DSSL wrote inline. On this site's docs page it reported 4,314 findings in 0.16.0; it now reports none from the site's own CSS.
|
| 69 |
|
|
@@ -132,4 +136,4 @@ Wait for the `dssl-ready` event on `window` before measuring layout: the engine
|
|
| 132 |
|
| 133 |
## Editor support
|
| 134 |
|
| 135 |
-
The official extension (VS Code and VSCodium, same .vsix) bundles the real parser and resolver: diagnostics identical to the browser console, completions from the workspace token registry, hover docs for the semantic vocabulary. In VSCodium, search "DSSL" in the Extensions tab (it is on Open VSX: https://open-vsx.org/extension/ehs-studio/dssl-vscode). In VS Code, download `dssl-vscode/dssl-vscode-0.16.
|
|
|
|
| 5 |
- Site (docs, playground, changelog, bench): https://dssl-sable.vercel.app
|
| 6 |
- Repo + full docs in the README: https://huggingface.co/EHS-Studio/dssl
|
| 7 |
- Install: `curl -fsSL https://dssl-sable.vercel.app/install.sh | sh` (or the zip: https://dssl-sable.vercel.app/dssl-engine.zip)
|
| 8 |
+
- Version: 0.16.3 (engine), MIT license
|
| 9 |
- Feature matrix vs CSS: see PARITY.md in the repo
|
| 10 |
- For agents working ON the codebase: see AGENTS.md in the repo
|
| 11 |
|
|
|
|
| 64 |
- Alpha on a named colour works: `white/12`, `currentColor/20`. It used to compile to `white/12px`.
|
| 65 |
- The playground has a canvas.html tab, `?example=` links, lint warnings and an "as CSS" tab. The canvas keeps a short allow-list of tags and drops scripts, handlers, styles and ids.
|
| 66 |
|
| 67 |
+
## 0.16.3
|
| 68 |
+
- Seven bugs found by writing the native spec (`native/spec/`) are fixed. An unquoted `url(http://x.com/a.png)` no longer loses the rest of the line to the comment stripper (also inside `raw { }`). A typo at the end of a token path (`color.ink.bogus`) is an `unknown value` error instead of quietly becoming `color.ink`. Nesting under a selector list joins every part: `.a, .b { .c { } }` is `.a .c, .b .c`, `hover { }` gives `.a:hover, .b:hover`, `.c, .d { }` under `.a` gives `.a .c, .a .d`, and `::before { }` gets one rule per part. A backslash escapes a quote in a value (`content: "a\"b"`). A nested `li` or any other HTML element name no longer gets a "did you mean link" warning.
|
| 69 |
+
- Two new warnings, both compile fine: an unknown `@layer` name (it is treated as `components`) and `radius: xl` when no `radius.xl` token exists.
|
| 70 |
+
|
| 71 |
## 0.16.2
|
| 72 |
- `DSSL.lint`'s `css-loses` no longer judges the output of `dssl build` (its reset is built to sit under the engine), and ignores a rule whose value is the same as what DSSL wrote inline. On this site's docs page it reported 4,314 findings in 0.16.0; it now reports none from the site's own CSS.
|
| 73 |
|
|
|
|
| 136 |
|
| 137 |
## Editor support
|
| 138 |
|
| 139 |
+
The official extension (VS Code and VSCodium, same .vsix) bundles the real parser and resolver: diagnostics identical to the browser console, completions from the workspace token registry, hover docs for the semantic vocabulary. In VSCodium, search "DSSL" in the Extensions tab (it is on Open VSX: https://open-vsx.org/extension/ehs-studio/dssl-vscode). In VS Code, download `dssl-vscode/dssl-vscode-0.16.3.vsix` from the repo files, then Extensions panel -> ... -> Install from VSIX. Source lives in `dssl-vscode/` in the repo.
|
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
/* generated by dssl build from tokens.dssl + static.dssl - the static subset of DSSL v0.16.
|
| 2 |
@signal rules and engine-native properties (animate, aura, tilt, ...) stay in the runtime.
|
| 3 |
Textures are baked in as background images when their colours are known at build time. */
|
| 4 |
@import url("https://fonts.googleapis.com/css2?family=Fraunces:wght@500;700;800&family=Hanken+Grotesk:wght@400;500;700&display=swap");
|
|
|
|
| 1 |
+
/* generated by dssl build from tokens.dssl + static.dssl - the static subset of DSSL v0.16.3.
|
| 2 |
@signal rules and engine-native properties (animate, aura, tilt, ...) stay in the runtime.
|
| 3 |
Textures are baked in as background images when their colours are known at build time. */
|
| 4 |
@import url("https://fonts.googleapis.com/css2?family=Fraunces:wght@500;700;800&family=Hanken+Grotesk:wght@400;500;700&display=swap");
|
|
@@ -0,0 +1,178 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
/* gen-native-vocab.mjs: write the vocabulary the native crate and the spec appendices share.
|
| 3 |
+
*
|
| 4 |
+
* node scripts/gen-native-vocab.mjs write the files
|
| 5 |
+
* node scripts/gen-native-vocab.mjs --check fail if a file on disk is out of date
|
| 6 |
+
*
|
| 7 |
+
* Outputs:
|
| 8 |
+
* native/data/vocabulary.json every word list, in the engine's own order (order decides did-you-mean ties)
|
| 9 |
+
* native/spec/appendix-a-vocabulary.md the small tables, in prose form
|
| 10 |
+
* native/spec/appendix-b-messages.md every error and warning template found in the engine source
|
| 11 |
+
*
|
| 12 |
+
* The resolver keeps several tables private. Rather than touch the engine, this reads resolver.js as text,
|
| 13 |
+
* appends one export line to a temporary copy, and imports that. Nothing in public/dssl is changed. */
|
| 14 |
+
import { readFileSync, writeFileSync, mkdirSync, mkdtempSync, existsSync } from 'node:fs';
|
| 15 |
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
| 16 |
+
import { tmpdir } from 'node:os';
|
| 17 |
+
import { join, dirname } from 'node:path';
|
| 18 |
+
|
| 19 |
+
const root = fileURLToPath(new URL('../', import.meta.url));
|
| 20 |
+
const engineDir = join(root, 'public/dssl');
|
| 21 |
+
const check = process.argv.includes('--check');
|
| 22 |
+
|
| 23 |
+
async function loadResolverInternals() {
|
| 24 |
+
let src = readFileSync(join(engineDir, 'resolver.js'), 'utf8');
|
| 25 |
+
const base = pathToFileURL(engineDir).href + '/';
|
| 26 |
+
src = src.replace(/from '\.\//g, `from '${base}`);
|
| 27 |
+
src += '\nexport const __VOCAB = { TIME_PROPS, UNITLESS_FN, LENGTH_FN, COLOR_WORDS, FLUID_PROPS, PLACE_WORDS, SEMANTIC_NAMES: Object.keys(SEMANTIC) };\n';
|
| 28 |
+
const dir = mkdtempSync(join(tmpdir(), 'dssl-vocab-'));
|
| 29 |
+
const file = join(dir, 'resolver-vocab.mjs');
|
| 30 |
+
writeFileSync(file, src);
|
| 31 |
+
return import(pathToFileURL(file).href);
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
const R = await loadResolverInternals();
|
| 35 |
+
const P = await import(pathToFileURL(join(engineDir, 'parser.js')).href);
|
| 36 |
+
const C = await import(pathToFileURL(join(engineDir, 'color.js')).href);
|
| 37 |
+
const T = await import(pathToFileURL(join(engineDir, 'texture.js')).href);
|
| 38 |
+
const A = await import(pathToFileURL(join(engineDir, 'aura.js')).href);
|
| 39 |
+
const S = await import(pathToFileURL(join(engineDir, 'slider.js')).href);
|
| 40 |
+
const E = await import(pathToFileURL(join(engineDir, 'effects.js')).href);
|
| 41 |
+
const F = await import(pathToFileURL(join(engineDir, 'fonts.js')).href);
|
| 42 |
+
|
| 43 |
+
const V = R.__VOCAB;
|
| 44 |
+
const vocab = {
|
| 45 |
+
_about: 'Generated by scripts/gen-native-vocab.mjs from public/dssl. Do not edit by hand. Array order is the engine\'s insertion order.',
|
| 46 |
+
version: (/export const VERSION = '([^']+)'/.exec(readFileSync(join(engineDir, 'index.js'), 'utf8')) || [])[1] || 'unknown',
|
| 47 |
+
stateWords: [...P.STATE_WORDS],
|
| 48 |
+
pseudoElements: [...P.PSEUDO_ELEMENTS],
|
| 49 |
+
vendorPseudoSource: P.VENDOR_PSEUDO.source,
|
| 50 |
+
cssKeywords: [...R.CSS_KEYWORDS],
|
| 51 |
+
knownProps: [...R.KNOWN_PROPS],
|
| 52 |
+
unitlessProps: [...R.UNITLESS_PROPS],
|
| 53 |
+
timeProps: [...V.TIME_PROPS],
|
| 54 |
+
unitlessFns: [...V.UNITLESS_FN],
|
| 55 |
+
lengthFns: [...V.LENGTH_FN],
|
| 56 |
+
colorWords: [...V.COLOR_WORDS],
|
| 57 |
+
fluidProps: [...V.FLUID_PROPS],
|
| 58 |
+
placeWords: V.PLACE_WORDS,
|
| 59 |
+
easings: R.EASINGS,
|
| 60 |
+
defaultTokens: R.DEFAULT_TOKENS,
|
| 61 |
+
semanticNames: V.SEMANTIC_NAMES,
|
| 62 |
+
namedColors: C.NAMED,
|
| 63 |
+
texture: { generators: T.GENERATORS, blendModes: T.BLEND_MODES, keys: T.TEXTURE_KEYS, presetNames: T.PRESET_NAMES, presets: T.PRESETS },
|
| 64 |
+
aura: { fromWords: A.FROM_WORDS, shapes: A.SHAPES, dirWords: A.DIR_WORDS, blends: A.AURA_BLENDS, glowKeys: A.GLOW_KEYS, particleKeys: A.PARTICLE_KEYS, glowDefaults: A.GLOW_DEFAULTS, particleDefaults: A.PARTICLE_DEFAULTS, aroundNames: A.AROUND_NAMES },
|
| 65 |
+
slider: { clauses: S.SLIDER_CLAUSES, thumbShapes: S.THUMB_SHAPES },
|
| 66 |
+
effects: { glassWords: E.GLASS_WORDS, tiltWords: E.TILT_WORDS },
|
| 67 |
+
fonts: { words: F.FONT_WORDS },
|
| 68 |
+
};
|
| 69 |
+
|
| 70 |
+
/* ---------------- appendix A ---------------- */
|
| 71 |
+
|
| 72 |
+
const code = (x) => '`' + x + '`';
|
| 73 |
+
const list = (a) => a.map(code).join(', ');
|
| 74 |
+
const table = (head, rows) => [`| ${head.join(' | ')} |`, `|${head.map(() => '---').join('|')}|`, ...rows.map((r) => `| ${r.join(' | ')} |`)].join('\n');
|
| 75 |
+
const esc = (s) => String(s).replace(/\|/g, '\\|');
|
| 76 |
+
|
| 77 |
+
function appendixA() {
|
| 78 |
+
const o = [];
|
| 79 |
+
o.push('# Appendix A: vocabulary', '',
|
| 80 |
+
'Generated by `scripts/gen-native-vocab.mjs` from the engine. Not edited by hand.',
|
| 81 |
+
`The full word lists, in the engine's own order, are in \`native/data/vocabulary.json\`.`, '');
|
| 82 |
+
o.push('## A.1 State words', '', list(vocab.stateWords), '');
|
| 83 |
+
o.push('## A.2 Pseudo-elements', '', list(vocab.pseudoElements), '',
|
| 84 |
+
`A vendor pseudo-element name matches \`${vocab.vendorPseudoSource}\`.`, '');
|
| 85 |
+
o.push('## A.3 Unitless and time properties', '',
|
| 86 |
+
'Unitless (a bare number stays bare):', '', list(vocab.unitlessProps), '',
|
| 87 |
+
'Time (a bare number is milliseconds):', '', list(vocab.timeProps), '');
|
| 88 |
+
o.push('## A.4 Functions', '',
|
| 89 |
+
'Unitless functions (numbers inside stay bare):', '', list(vocab.unitlessFns), '',
|
| 90 |
+
'Length functions (bare numbers inside are px):', '', list(vocab.lengthFns), '');
|
| 91 |
+
o.push('## A.5 Fluid properties', '', list(vocab.fluidProps), '');
|
| 92 |
+
o.push('## A.6 Place words', '', table(['word', 'cross', 'main'], Object.entries(vocab.placeWords).map(([k, v]) => [code(k), code(v[0]), code(v[1])])), '');
|
| 93 |
+
o.push('## A.7 Easings', '', table(['name', 'CSS'], Object.entries(vocab.easings).map(([k, v]) => [code(k), code(v)])), '');
|
| 94 |
+
o.push('## A.8 Built-in tokens', '', table(['key', 'value'], Object.entries(vocab.defaultTokens).map(([k, v]) => [code(k), code(esc(v))])), '');
|
| 95 |
+
o.push('## A.9 Semantic properties', '', list(vocab.semanticNames), '');
|
| 96 |
+
o.push('## A.10 Big sets', '', table(['set', 'count', 'where'], [
|
| 97 |
+
['CSS keywords', vocab.cssKeywords.length, '`cssKeywords` in the data file'],
|
| 98 |
+
['known CSS properties', vocab.knownProps.length, '`knownProps`'],
|
| 99 |
+
['named colors', Object.keys(vocab.namedColors).length, '`namedColors`'],
|
| 100 |
+
]), '', 'Color words allowed as gradient stops:', '', list(vocab.colorWords), '');
|
| 101 |
+
o.push('## A.11 Texture', '',
|
| 102 |
+
`Generators: ${list(vocab.texture.generators)}`, '',
|
| 103 |
+
`Blend modes: ${list(vocab.texture.blendModes)}`, '',
|
| 104 |
+
`Presets (${vocab.texture.presetNames.length}): ${list(vocab.texture.presetNames)}`, '',
|
| 105 |
+
'Settings:', '',
|
| 106 |
+
table(['key', 'kind', 'values', 'range', 'what it does'], Object.entries(vocab.texture.keys).map(([k, d]) => [
|
| 107 |
+
code(k), d.kind, d.words ?? '', d.values ? list(d.values) : (d.min !== undefined ? `${d.min} to ${d.max}` : ''), esc(d.doc || ''),
|
| 108 |
+
])), '');
|
| 109 |
+
o.push('## A.12 Aura', '',
|
| 110 |
+
`From words: ${list(vocab.aura.fromWords)}`, '',
|
| 111 |
+
`Shapes: ${list(vocab.aura.shapes)}`, '',
|
| 112 |
+
`Direction words: ${list(Object.keys(vocab.aura.dirWords))}`, '',
|
| 113 |
+
`Blends: ${list(vocab.aura.blends)}`, '',
|
| 114 |
+
`Around shapes: ${list(vocab.aura.aroundNames)}`, '',
|
| 115 |
+
'Glow settings:', '',
|
| 116 |
+
table(['key', 'kind', 'range', 'what it does'], Object.entries(vocab.aura.glowKeys).map(([k, d]) => [code(k), d.kind, d.min !== undefined ? `${d.min} to ${d.max}` : (d.values ? list(d.values) : ''), esc(d.doc || '')])), '',
|
| 117 |
+
`Glow defaults: ${code(JSON.stringify(vocab.aura.glowDefaults))}`, '',
|
| 118 |
+
'Particle settings:', '',
|
| 119 |
+
table(['key', 'kind', 'range', 'what it does'], Object.entries(vocab.aura.particleKeys).map(([k, d]) => [code(k), d.kind, d.min !== undefined ? `${d.min} to ${d.max}` : (d.values ? list(d.values) : ''), esc(d.doc || '')])), '',
|
| 120 |
+
`Particle defaults: ${code(JSON.stringify(vocab.aura.particleDefaults))}`, '');
|
| 121 |
+
o.push('## A.13 Slider', '', table(['clause', 'form'], Object.entries(vocab.slider.clauses).map(([k, v]) => [code(k), code(esc(v))])), '',
|
| 122 |
+
`Thumb shapes: ${list(vocab.slider.thumbShapes)}`, '');
|
| 123 |
+
o.push('## A.14 Glass and tilt', '',
|
| 124 |
+
table(['word', 'meaning'], [...Object.entries(vocab.effects.glassWords), ...Object.entries(vocab.effects.tiltWords)].map(([k, v]) => [code(k), esc(v)])), '');
|
| 125 |
+
o.push('## A.15 Fonts', '', table(['word', 'meaning'], Object.entries(vocab.fonts.words).map(([k, v]) => [code(k), esc(v)])), '');
|
| 126 |
+
return o.join('\n') + '\n';
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
/* ---------------- appendix B ---------------- */
|
| 130 |
+
|
| 131 |
+
function appendixB() {
|
| 132 |
+
const files = ['parser.js', 'resolver.js', 'texture.js', 'aura.js', 'slider.js', 'effects.js', 'fonts.js', 'lint.js'];
|
| 133 |
+
const re = /(?:\bmessage:\s*|\berr\(\s*\w+\s*,\s*|\b(?:bad|hooks\.error)\(\s*)(`(?:[^`\\]|\\.)*`|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*")/g;
|
| 134 |
+
const o = ['# Appendix B: message templates', '',
|
| 135 |
+
'Generated by `scripts/gen-native-vocab.mjs`. Every error and warning template found in the engine',
|
| 136 |
+
'source, by file and line. `${...}` marks a value filled in at run time. The extraction is by pattern,',
|
| 137 |
+
'so it can include a string that is not a message and can miss one built in an unusual way. It is a',
|
| 138 |
+
'checklist for the corpus, not the definition: the definition is in the chapters.', ''];
|
| 139 |
+
for (const f of files) {
|
| 140 |
+
const text = readFileSync(join(engineDir, f), 'utf8');
|
| 141 |
+
const seen = new Set();
|
| 142 |
+
const rows = [];
|
| 143 |
+
for (const m of text.matchAll(re)) {
|
| 144 |
+
const raw = m[1].slice(1, -1).replace(/\\n/g, ' ').replace(/\\(['"`])/g, '$1');
|
| 145 |
+
if (raw.length < 6 || seen.has(raw)) continue;
|
| 146 |
+
seen.add(raw);
|
| 147 |
+
const line = text.slice(0, m.index).split('\n').length;
|
| 148 |
+
rows.push([String(line), code(esc(raw).replace(/`/g, "'"))]);
|
| 149 |
+
}
|
| 150 |
+
o.push(`## ${f}`, '', table(['line', 'template'], rows), '');
|
| 151 |
+
}
|
| 152 |
+
return o.join('\n') + '\n';
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
/* ---------------- write or check ---------------- */
|
| 156 |
+
|
| 157 |
+
const outputs = [
|
| 158 |
+
['native/data/vocabulary.json', JSON.stringify(vocab, null, 1) + '\n'],
|
| 159 |
+
['native/spec/appendix-a-vocabulary.md', appendixA()],
|
| 160 |
+
['native/spec/appendix-b-messages.md', appendixB()],
|
| 161 |
+
];
|
| 162 |
+
|
| 163 |
+
let stale = 0;
|
| 164 |
+
for (const [rel, text] of outputs) {
|
| 165 |
+
const path = join(root, rel);
|
| 166 |
+
if (check) {
|
| 167 |
+
const now = existsSync(path) ? readFileSync(path, 'utf8') : null;
|
| 168 |
+
if (now !== text) { console.error('STALE ' + rel + ' (run node scripts/gen-native-vocab.mjs)'); stale++; }
|
| 169 |
+
continue;
|
| 170 |
+
}
|
| 171 |
+
mkdirSync(dirname(path), { recursive: true });
|
| 172 |
+
writeFileSync(path, text);
|
| 173 |
+
console.log('wrote ' + rel + ' (' + text.length + ' bytes)');
|
| 174 |
+
}
|
| 175 |
+
if (check) {
|
| 176 |
+
if (stale) process.exit(1);
|
| 177 |
+
console.log('vocabulary files are up to date');
|
| 178 |
+
}
|
|
@@ -15,7 +15,7 @@ const SUITES = [
|
|
| 15 |
['engine 0.5', 'test-v050.mjs'], ['engine 0.6', 'test-v060.mjs'], ['engine 0.7', 'test-v070.mjs'], ['parser lines 0.7.1', 'test-v071.mjs'],
|
| 16 |
['review fixes 0.7.2', 'test-v072.mjs'], ['exit lane 0.8.0', 'test-v073.mjs'], ['follow-up 0.8.1', 'test-v081.mjs'], ['cascade 0.8.2', 'test-v082.mjs'],
|
| 17 |
['color, texture, aura, slider, lint, import, share 0.9.0', 'test-v090.mjs'], ['editor extension', 'test-extension-lib.mjs'],
|
| 18 |
-
['site stylesheets compile', 'dssl-styles-check.mjs'], ['guide examples compile', 'test-guide-examples.mjs'],
|
| 19 |
['designer: state to DSSL and back', 'test-designer.mjs'], ['designer: editor wiring (fake vscode)', 'test-designer-host.mjs'],
|
| 20 |
['guide examples in a browser', 'test-guide-browser.mjs', true], ['0.9.0 in a browser', 'test-browser-v090.mjs', true], ['designer panel in a browser', 'test-designer-browser.mjs', true], ['glass, tilt, wood, baked textures, counters 0.10-0.11', 'test-v0100.mjs', true], ['symmetrical, fonts, gradients, inspector, hot reload 0.12', 'test-v0120.mjs', true], ['build fidelity, source maps, strict CSP, server rendering 0.13', 'test-v0130.mjs', true], ['made for games, docs match the code 0.14', 'test-v0140.mjs', true], ['the second game review 0.15', 'test-v0150.mjs', true], ['round three: yield, shapes, textures 0.16', 'test-v0160.mjs', true], ['built CSS with JavaScript off vs the engine, every page', 'test-static-parity.mjs', true],
|
| 21 |
];
|
|
|
|
| 15 |
['engine 0.5', 'test-v050.mjs'], ['engine 0.6', 'test-v060.mjs'], ['engine 0.7', 'test-v070.mjs'], ['parser lines 0.7.1', 'test-v071.mjs'],
|
| 16 |
['review fixes 0.7.2', 'test-v072.mjs'], ['exit lane 0.8.0', 'test-v073.mjs'], ['follow-up 0.8.1', 'test-v081.mjs'], ['cascade 0.8.2', 'test-v082.mjs'],
|
| 17 |
['color, texture, aura, slider, lint, import, share 0.9.0', 'test-v090.mjs'], ['editor extension', 'test-extension-lib.mjs'],
|
| 18 |
+
['site stylesheets compile', 'dssl-styles-check.mjs'], ['guide examples compile', 'test-guide-examples.mjs'], ['native spec: examples, prose, known bugs', 'test-native-spec.mjs'], ['known divergences fixed 0.16.3', 'test-v0163.mjs'],
|
| 19 |
['designer: state to DSSL and back', 'test-designer.mjs'], ['designer: editor wiring (fake vscode)', 'test-designer-host.mjs'],
|
| 20 |
['guide examples in a browser', 'test-guide-browser.mjs', true], ['0.9.0 in a browser', 'test-browser-v090.mjs', true], ['designer panel in a browser', 'test-designer-browser.mjs', true], ['glass, tilt, wood, baked textures, counters 0.10-0.11', 'test-v0100.mjs', true], ['symmetrical, fonts, gradients, inspector, hot reload 0.12', 'test-v0120.mjs', true], ['build fidelity, source maps, strict CSP, server rendering 0.13', 'test-v0130.mjs', true], ['made for games, docs match the code 0.14', 'test-v0140.mjs', true], ['the second game review 0.15', 'test-v0150.mjs', true], ['round three: yield, shapes, textures 0.16', 'test-v0160.mjs', true], ['built CSS with JavaScript off vs the engine, every page', 'test-static-parity.mjs', true],
|
| 21 |
];
|
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
/* test-native-spec.mjs: keep native/spec honest.
|
| 3 |
+
*
|
| 4 |
+
* 1. every ```dssl block in the spec compiles with no errors, and every ```dssl error block has at least one
|
| 5 |
+
* 2. the numbers and strings the prose promises are what the engine produces
|
| 6 |
+
* 3. the divergences of chapter 12 stay fixed
|
| 7 |
+
* 4. the generated appendices and data file are up to date
|
| 8 |
+
*
|
| 9 |
+
* Exit code is 0 only when every check passed. */
|
| 10 |
+
import { readFileSync, readdirSync } from 'node:fs';
|
| 11 |
+
import { spawnSync } from 'node:child_process';
|
| 12 |
+
import { fileURLToPath } from 'node:url';
|
| 13 |
+
import { join } from 'node:path';
|
| 14 |
+
import { parse } from '../public/dssl/parser.js';
|
| 15 |
+
import { resolve, DEFAULT_TOKENS } from '../public/dssl/resolver.js';
|
| 16 |
+
|
| 17 |
+
const root = fileURLToPath(new URL('../', import.meta.url));
|
| 18 |
+
const specDir = join(root, 'native/spec');
|
| 19 |
+
|
| 20 |
+
let pass = 0, fail = 0;
|
| 21 |
+
const ok = (name) => { pass++; };
|
| 22 |
+
const bad = (name, why) => { fail++; console.error('FAIL ' + name + (why ? '\n ' + why : '')); };
|
| 23 |
+
|
| 24 |
+
function run(src, file = 'spec.dssl') {
|
| 25 |
+
const p = parse(src, file);
|
| 26 |
+
const d = resolve(p.ast, file, { ...DEFAULT_TOKENS });
|
| 27 |
+
return { doc: d, errors: [...p.errors, ...d.errors], warnings: d.warnings || [] };
|
| 28 |
+
}
|
| 29 |
+
const rule = (doc, sel) => doc.rules.find((r) => r.sel === sel);
|
| 30 |
+
const val = (doc, sel, prop) => { const r = rule(doc, sel); const d = r && r.decls.find((x) => x.prop === prop); return d ? d.value : undefined; };
|
| 31 |
+
|
| 32 |
+
/* 1. fenced examples */
|
| 33 |
+
const chapters = readdirSync(specDir).filter((f) => /^\d\d-.*\.md$/.test(f)).sort();
|
| 34 |
+
let blocks = 0;
|
| 35 |
+
for (const f of chapters) {
|
| 36 |
+
const text = readFileSync(join(specDir, f), 'utf8');
|
| 37 |
+
let i = 0;
|
| 38 |
+
for (const m of text.matchAll(/```dssl( error)?\n([\s\S]*?)```/g)) {
|
| 39 |
+
i++; blocks++;
|
| 40 |
+
const expectError = !!m[1];
|
| 41 |
+
const { errors } = run(m[2], `${f} block ${i}`);
|
| 42 |
+
if (expectError && errors.length) ok();
|
| 43 |
+
else if (expectError) bad(`${f} block ${i}`, 'is marked "error" but compiled cleanly');
|
| 44 |
+
else if (errors.length) bad(`${f} block ${i}`, errors.map((e) => `line ${e.line}: ${e.message}`).join('; '));
|
| 45 |
+
else ok();
|
| 46 |
+
}
|
| 47 |
+
}
|
| 48 |
+
if (blocks < 20) bad('spec examples', `only ${blocks} fenced blocks found, expected the chapters to carry many more`);
|
| 49 |
+
|
| 50 |
+
/* 2. promises made in the prose */
|
| 51 |
+
const eq = (name, got, want) => (JSON.stringify(got) === JSON.stringify(want) ? ok() : bad(name, `got ${JSON.stringify(got)}, wanted ${JSON.stringify(want)}`));
|
| 52 |
+
|
| 53 |
+
{ // 3.2 numbers
|
| 54 |
+
const { doc } = run('.a { padding: 0; margin: 0 auto; opacity: 0.5; line-height: 1.5; transition-delay: 200 }');
|
| 55 |
+
eq('VAL-3 padding', val(doc, '.a', 'padding'), '0px');
|
| 56 |
+
eq('VAL-3 margin', val(doc, '.a', 'margin'), '0px auto');
|
| 57 |
+
eq('VAL-3 opacity', val(doc, '.a', 'opacity'), '0.5');
|
| 58 |
+
eq('VAL-3 line-height', val(doc, '.a', 'line-height'), '1.5');
|
| 59 |
+
eq('3.2 time prop', val(doc, '.a', 'transition-delay'), '200ms');
|
| 60 |
+
}
|
| 61 |
+
{ // 3.3 functions
|
| 62 |
+
const { doc } = run('.a { width: calc(100% - 24); background: oklch(62% 0.19 35); grid-template-columns: repeat(4, 1fr); transform: scale(1.2) }');
|
| 63 |
+
eq('VAL-7 calc', val(doc, '.a', 'width'), 'calc(100% - 24px)');
|
| 64 |
+
eq('VAL-7 oklch', val(doc, '.a', 'background'), 'oklch(62% 0.19 35)');
|
| 65 |
+
eq('VAL-6 repeat', val(doc, '.a', 'grid-template-columns'), 'repeat(4, 1fr)');
|
| 66 |
+
eq('VAL-7 scale', val(doc, '.a', 'transform'), 'scale(1.2)');
|
| 67 |
+
}
|
| 68 |
+
{ // 3.4 alpha
|
| 69 |
+
const { doc } = run('tokens { color { x: #123456 } }\n.a { color: color.x/50; background: #ff0000/50; border-color: white/12 }');
|
| 70 |
+
eq('VAL-8 token alpha', val(doc, '.a', 'color'), 'color-mix(in oklab, var(--dssl-color-x) 50%, transparent)');
|
| 71 |
+
eq('VAL-8 hex alpha', val(doc, '.a', 'background'), 'color-mix(in oklab, #ff0000 50%, transparent)');
|
| 72 |
+
eq('VAL-8 named alpha', val(doc, '.a', 'border-color'), 'color-mix(in oklab, white 12%, transparent)');
|
| 73 |
+
}
|
| 74 |
+
{ // 3.7 fluid
|
| 75 |
+
const { doc } = run('h1 { font-size: fluid 16 24 }');
|
| 76 |
+
eq('VAL-13 fluid', val(doc, 'h1', 'font-size'), 'clamp(16px, calc(12.571px + 0.952vw), 24px)');
|
| 77 |
+
}
|
| 78 |
+
{ // 5.2 layers
|
| 79 |
+
const { doc } = run('.a { color: red }\npin { .a { color: blue } }\n@layer base { .a { color: green } }');
|
| 80 |
+
eq('CAS-2/5 layer ranks', doc.rules.filter((r) => r.sel === '.a').map((r) => [r.layer, val(doc.rules.length ? { rules: [r] } : doc, '.a', 'color')]), [['components', 'red'], ['pin', 'blue'], ['base', 'green']]);
|
| 81 |
+
}
|
| 82 |
+
{ // 5.4 fragments
|
| 83 |
+
const { doc } = run('.a {\n color: red\n hover { color: blue }\n padding: 4\n}');
|
| 84 |
+
eq('CAS-12 fragments', doc.rules.filter((r) => r.sel.startsWith('.a')).map((r) => [r.sel, r.decls[0].prop]), [['.a', 'color'], ['.a:hover', 'color'], ['.a', 'padding']]);
|
| 85 |
+
const orders = doc.rules.filter((r) => r.sel.startsWith('.a')).map((r) => r.order);
|
| 86 |
+
eq('CAS-11 orders 1,2,3', orders, [1, 2, 3]);
|
| 87 |
+
eq('TOK-9 registry order 0', doc.registryRule.order, 0);
|
| 88 |
+
}
|
| 89 |
+
{ // 5.5 media
|
| 90 |
+
const { doc } = run('.a { @media 768 { padding: 24 } @media <= 480 { padding: 12 } @media 480..960 { gap: 4 } @media dark { gap: 1 } }');
|
| 91 |
+
eq('CAS-19 media', doc.rules.filter((r) => r.sel === '.a').map((r) => r.media), [['(min-width: 768px)'], ['(max-width: 480px)'], ['(min-width: 480px) and (max-width: 960px)'], ['(prefers-color-scheme: dark)']]);
|
| 92 |
+
}
|
| 93 |
+
{ // 5.9 signals
|
| 94 |
+
const { doc } = run('.a { @signal theme == dark { color: red } @signal screen in (a, b) { color: blue } @signal on { color: green } }');
|
| 95 |
+
eq('CAS-37 signals', doc.rules.filter((r) => r.sel === '.a').map((r) => r.signals[0]), [
|
| 96 |
+
{ name: 'theme', op: '==', value: 'dark' }, { name: 'screen', op: 'in', value: 'a,b', values: ['a', 'b'] }, { name: 'on', op: 'truthy', value: null }]);
|
| 97 |
+
}
|
| 98 |
+
{ // 6.3 row
|
| 99 |
+
const { doc } = run('.toolbar { row: gap 8 between center }');
|
| 100 |
+
eq('PRP-8 row', rule(doc, '.toolbar').decls.map((d) => d.prop + ':' + d.value), ['display:flex', 'flex-direction:row', 'gap:8px', 'justify-content:space-between', 'align-items:center']);
|
| 101 |
+
}
|
| 102 |
+
{ // 4.3 conditional tokens
|
| 103 |
+
const { doc } = run('tokens { color { bg: white } }\n@media dark { tokens { color { bg: black } } }\n.a { background: color.bg }');
|
| 104 |
+
const toks = doc.rules.filter((r) => r.layer === 'tokens');
|
| 105 |
+
eq('TOK-8 two token rules', toks.map((r) => [r.media, r.decls[0].value]), [[[], 'white'], [['(prefers-color-scheme: dark)'], 'black']]);
|
| 106 |
+
eq('TOK-9 registry carries the last definition', doc.registryRule.decls.find((d) => d.prop === '--dssl-color-bg').value, 'black');
|
| 107 |
+
}
|
| 108 |
+
{ // 3.8, 6.1
|
| 109 |
+
const { errors } = run('.a { color: red !important }');
|
| 110 |
+
eq('VAL-15 important', errors.length === 1 && /^!important does not exist in DSSL/.test(errors[0].message), true);
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
/* 3. the divergences of chapter 12 stay fixed (0.16.3). D-6 is open and needs a browser test, so it is not checked here. */
|
| 114 |
+
{ // D-1, SYN-6
|
| 115 |
+
const { errors, doc } = run('.a { background: url(http://x.com/a.png) }');
|
| 116 |
+
eq('D-1 unquoted url keeps its //', [errors.length, val(doc, '.a', 'background')], [0, 'url(http://x.com/a.png)']);
|
| 117 |
+
}
|
| 118 |
+
{ // D-2, TOK-12
|
| 119 |
+
const { errors } = run('tokens { color { ink2: #111 } }\n.a { color: color.ink2.bogus }');
|
| 120 |
+
eq('D-2 a typo in a token path is an error', errors.some((e) => /unknown value "color.ink2.bogus"/.test(e.message)), true);
|
| 121 |
+
}
|
| 122 |
+
{ // D-3, CAS-2
|
| 123 |
+
const { errors, warnings } = run('@layer weird { .a { color: red } }');
|
| 124 |
+
eq('D-3 unknown layer warns', [errors.length, warnings.some((w) => /^unknown layer "weird", treated as "components"/.test(w.message))], [0, true]);
|
| 125 |
+
}
|
| 126 |
+
{ // D-4, TOK-18
|
| 127 |
+
const { doc, errors, warnings } = run('.a { radius: xl }');
|
| 128 |
+
eq('D-4 radius xl warns, same output', [errors.length, warnings.some((w) => /^radius "xl" is not defined/.test(w.message)), val(doc, '.a', 'border-radius')], [0, true, 'var(--dssl-radius-xl)']);
|
| 129 |
+
}
|
| 130 |
+
{ // D-5, VAL string rule
|
| 131 |
+
const { errors } = run('.a { content: "a\\"b" }');
|
| 132 |
+
eq('D-5 an escaped quote stays inside the string', errors.length, 0);
|
| 133 |
+
}
|
| 134 |
+
{ // D-7, CAS-7, CAS-24
|
| 135 |
+
const sels = (src, hit) => run(src).doc.rules.filter((r) => hit.test(r.sel)).map((r) => r.sel);
|
| 136 |
+
eq('D-7 parent list', sels('.a, .b { .c { color: red } }', /\.c/), ['.a .c, .b .c']);
|
| 137 |
+
eq('D-7 state on a list', sels('.a, .b { hover { color: red } }', /hover/), ['.a:hover, .b:hover']);
|
| 138 |
+
eq('D-7 child list', sels('.a { .c, .d { color: red } }', /\.c/), ['.a .c, .a .d']);
|
| 139 |
+
}
|
| 140 |
+
{ // D-8, CAS-8
|
| 141 |
+
const { warnings } = run('.menu { li { color: red } hove { color: red } }');
|
| 142 |
+
eq('D-8 li is quiet, hove still warns', [warnings.some((w) => /"li" compiled/.test(w.message)), warnings.some((w) => /"hove" compiled/.test(w.message))], [false, true]);
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
/* 4. generated files */
|
| 146 |
+
{
|
| 147 |
+
const r = spawnSync(process.execPath, ['--no-warnings', join(root, 'scripts/gen-native-vocab.mjs'), '--check'], { encoding: 'utf8' });
|
| 148 |
+
if (r.status === 0) ok(); else bad('generated vocabulary files are up to date', (r.stderr || r.stdout || '').trim());
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
console.log(`${blocks} spec examples checked`);
|
| 152 |
+
console.log(`${pass} passed, ${fail} failed`);
|
| 153 |
+
process.exit(fail ? 1 : 0);
|
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
/* test-v0163.mjs: seven known divergences fixed (D-1 to D-5, D-7, D-8): unquoted url() with //, token prefix matching,
|
| 3 |
+
* unknown @layer, undefined radius word, escaped quotes in values, selector lists when nesting, HTML element names
|
| 4 |
+
* that look like state typos. Pure Node, no browser. */
|
| 5 |
+
import { compile } from '../public/dssl/index.js';
|
| 6 |
+
|
| 7 |
+
let pass = 0, fail = 0;
|
| 8 |
+
const ok = (name, cond, extra) => { if (cond) { pass++; console.log(` ok ${name}`); } else { fail++; console.log(`FAIL ${name}${extra !== undefined ? '; ' + extra : ''}`); } };
|
| 9 |
+
const section = (t) => console.log(`\n== ${t}`);
|
| 10 |
+
const run = (src) => compile(src, 't.dssl');
|
| 11 |
+
const sels = (src) => run(src).doc.rules.filter((r) => r.layer !== 'tokens').map((r) => r.sel);
|
| 12 |
+
const shadow = (src) => run(src).doc.shadowRules.map((r) => `${r.sel}::${r.pseudo}`);
|
| 13 |
+
const decl = (src, prop) => { for (const r of run(src).doc.rules) for (const d of r.decls) if (d.prop === prop) return d.value; return undefined; };
|
| 14 |
+
const J = JSON.stringify;
|
| 15 |
+
|
| 16 |
+
section('D-1. // inside an unquoted url()');
|
| 17 |
+
{
|
| 18 |
+
const r = run('.a { background: url(http://x.com/a.png) }');
|
| 19 |
+
ok('unquoted url with // compiles clean', r.errors.length === 0 && r.ok, J(r.errors));
|
| 20 |
+
ok('and keeps the whole url', decl('.a { background: url(http://x.com/a.png) }', 'background') === 'url(http://x.com/a.png)');
|
| 21 |
+
ok('a declaration after it on the next line survives', decl('.a { background: url(http://x.com/a.png)\n color: red }', 'color') === 'red');
|
| 22 |
+
ok('upper case URL( with spaces', run('.a { background: URL( http://x.com/a.png ) }').errors.length === 0);
|
| 23 |
+
ok('inside raw { } the closing brace is kept', run('raw { .a { background: url(http://x.com/a.png) } }\n.b { color: red }').errors.length === 0);
|
| 24 |
+
ok('quoted url still fine', run('.a { background: url("http://x.com/a.png") }').errors.length === 0 && decl('.a { background: url("http://x.com/a.png") }', 'background') === 'url("http://x.com/a.png")');
|
| 25 |
+
ok('a real comment after the url still works', decl('.a { background: url(a.png) // note\n color: red }', 'color') === 'red' && run('.a { background: url(a.png) // note\n color: red }').errors.length === 0);
|
| 26 |
+
ok('a // comment elsewhere still strips', run('.a { color: red } // trailing\n.b { color: blue }').errors.length === 0);
|
| 27 |
+
const e = run('.a { background: url(http://x.com/a.png)\n color: nonsense }').errors;
|
| 28 |
+
ok('line numbers do not drift after the url', e.length === 1 && e[0].line === 2, J(e));
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
section('D-2. token lookup is exact');
|
| 32 |
+
{
|
| 33 |
+
const src = 'tokens { color { ink2: #111 } }\n.a { color: color.ink2.bogus }';
|
| 34 |
+
const r = run(src);
|
| 35 |
+
ok('color.ink2.bogus is an unknown value', r.errors.length === 1 && /unknown value "color\.ink2\.bogus"/.test(r.errors[0].message), J(r.errors));
|
| 36 |
+
ok('the error carries file, line, message, hint keys', r.errors[0] && ['file', 'line', 'message', 'hint'].every((k) => k in r.errors[0]));
|
| 37 |
+
ok('color.ink2 itself still resolves', decl('tokens { color { ink2: #111 } }\n.a { color: color.ink2 }', 'color') === 'var(--dssl-color-ink2)');
|
| 38 |
+
ok('alpha on an exact token still works', /color-mix/.test(decl('tokens { color { ink2: #111 } }\n.a { color: color.ink2/50 }', 'color')));
|
| 39 |
+
ok('built-in tokens still resolve', run('.a { color: color.ink }').errors.length === 0);
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
section('D-3. unknown @layer warns');
|
| 43 |
+
{
|
| 44 |
+
const r = run('@layer weird { .a { color: red } }');
|
| 45 |
+
ok('warns, never errors', r.errors.length === 0 && r.ok && r.warnings.length === 1, J(r.warnings));
|
| 46 |
+
ok('message and hint', r.warnings[0].message === 'unknown layer "weird", treated as "components"' && r.warnings[0].hint === 'the layers are tokens, base, components, utilities, pin', J(r.warnings));
|
| 47 |
+
ok('warning has the usual shape', ['file', 'line', 'message', 'hint'].every((k) => k in r.warnings[0]) && r.warnings[0].line === 1);
|
| 48 |
+
ok('still compiled as components', r.doc.rules.find((x) => x.sel === '.a').layer === 'components');
|
| 49 |
+
const t = run('@layer compnents { .a { color: red } }');
|
| 50 |
+
ok('a near miss gets a did-you-mean', t.warnings.length === 1 && t.warnings[0].hint === 'components', J(t.warnings));
|
| 51 |
+
ok('known layers are silent', ['tokens', 'base', 'components', 'utilities', 'pin'].every((l) => run(`@layer ${l} { .a { color: red } }`).warnings.length === 0));
|
| 52 |
+
ok('pin { } is silent', run('pin { .a { color: red } }').warnings.length === 0);
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
section('D-4. radius word with no token');
|
| 56 |
+
{
|
| 57 |
+
const r = run('.a { radius: xl }');
|
| 58 |
+
ok('radius: xl warns', r.errors.length === 0 && r.ok && r.warnings.some((w) => w.message === 'radius "xl" is not defined, so it will not apply' && w.hint === 'add it with tokens { radius { xl: 32 } }'), J(r.warnings));
|
| 59 |
+
ok('same declaration is still emitted', decl('.a { radius: xl }', 'border-radius') === 'var(--dssl-radius-xl)');
|
| 60 |
+
ok('no default token was added', !('radius.xl' in run('.a { radius: xl }').doc.tokens));
|
| 61 |
+
ok('defining it silences the warning', run('tokens { radius { xl: 32 } }\n.a { radius: xl }').warnings.length === 0);
|
| 62 |
+
ok('sm, md, lg, full are silent', ['sm', 'md', 'lg', 'full'].every((w) => run(`.a { radius: ${w} }`).warnings.length === 0));
|
| 63 |
+
ok('a number is silent', run('.a { radius: 8 }').warnings.length === 0);
|
| 64 |
+
ok('a custom radius token is silent', run('tokens { radius { pill: 99 } }\n.a { radius: pill }').warnings.length === 0);
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
section('D-5. a backslash escapes a quote in a value');
|
| 68 |
+
{
|
| 69 |
+
const r = run('.a { content: "a\\"b" }');
|
| 70 |
+
ok('content: "a\\"b" has no error', r.errors.length === 0, J(r.errors));
|
| 71 |
+
ok('and is passed through', decl('.a { content: "a\\"b" }', 'content') === '"a\\"b"');
|
| 72 |
+
ok('single quotes too', run(".a { content: 'it\\'s' }").errors.length === 0);
|
| 73 |
+
ok('inside a function', run('.a { content: attr(x) "q\\"r" }').errors.length === 0 && run('.a { background: image-set("a\\"b.png" 1x) }').errors.length === 0);
|
| 74 |
+
ok('a plain string is unchanged', decl('.a { content: "ab" }', 'content') === '"ab"');
|
| 75 |
+
ok('an unknown word after an escaped string is still an error', run('.a { content: "a\\"b" nonsense }').errors.length === 1);
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
section('D-7. nesting under selector lists');
|
| 79 |
+
{
|
| 80 |
+
ok('.a, .b { .c { } }', J(sels('.a, .b { .c { color: red } }')) === J(['.a .c, .b .c']), J(sels('.a, .b { .c { color: red } }')));
|
| 81 |
+
ok('.a, .b { hover { } }', J(sels('.a, .b { hover { color: red } }')) === J(['.a:hover, .b:hover']), J(sels('.a, .b { hover { color: red } }')));
|
| 82 |
+
ok('.a { .c, .d { } }', J(sels('.a { .c, .d { color: red } }')) === J(['.a .c, .a .d']), J(sels('.a { .c, .d { color: red } }')));
|
| 83 |
+
ok('.a, .b { .c, .d { } } is parent-major', J(sels('.a, .b { .c, .d { color: red } }')) === J(['.a .c, .a .d, .b .c, .b .d']), J(sels('.a, .b { .c, .d { color: red } }')));
|
| 84 |
+
ok('.a, .b { &.on { } }', J(sels('.a, .b { &.on { color: red } }')) === J(['.a.on, .b.on']), J(sels('.a, .b { &.on { color: red } }')));
|
| 85 |
+
ok('.a, .b { & > .c { } }', J(sels('.a, .b { & > .c { color: red } }')) === J(['.a > .c, .b > .c']));
|
| 86 |
+
ok('.a { .x &, & + & { } } substitutes every &', J(sels('.a { .x &, & + & { color: red } }')) === J(['.x .a, .a + .a']), J(sels('.a { .x &, & + & { color: red } }')));
|
| 87 |
+
ok('state inside a nested list child', J(sels('.a, .b { .c { hover { color: red } } }')) === J(['.a .c:hover, .b .c:hover']));
|
| 88 |
+
ok('a comma inside :is( ) is NOT split (parent)', J(sels('.a:is(.x, .y) { .c { color: red } }')) === J(['.a:is(.x, .y) .c']));
|
| 89 |
+
ok('a comma inside :is( ) is NOT split (child)', J(sels('.a { .c:is(.x, .y) { color: red } }')) === J(['.a .c:is(.x, .y)']));
|
| 90 |
+
ok('a comma inside [ ] is NOT split', J(sels('.a { [data-x="1,2"] { color: red } }')) === J(['.a [data-x="1,2"]']));
|
| 91 |
+
ok('a state on :is( ) parent', J(sels('.a:is(.x, .y) { hover { color: red } }')) === J(['.a:is(.x, .y):hover']));
|
| 92 |
+
ok('plain .a { .b { } } is unchanged', J(sels('.a { .b { color: red } }')) === J(['.a .b']));
|
| 93 |
+
ok('plain & is unchanged', J(sels('.a { &.on { color: red } }')) === J(['.a.on']));
|
| 94 |
+
ok('plain state is unchanged', J(sels('.a { hover { color: red } }')) === J(['.a:hover']));
|
| 95 |
+
ok('deep plain nesting is unchanged', J(sels('.a { .b { .c { color: red } } }')) === J(['.a .b .c']));
|
| 96 |
+
ok('no errors for any of it', run('.a, .b { .c, .d { hover { color: red } } }').errors.length === 0);
|
| 97 |
+
const sh = shadow('.a, .b { ::before { content: ""\n color: red } }');
|
| 98 |
+
ok('.a, .b { ::before { } } gives one shadow rule per part', J(sh) === J(['.a::before', '.b::before']), J(sh));
|
| 99 |
+
const sh2 = shadow('.a, .b { ::before { content: ""\n hover { color: red } } }');
|
| 100 |
+
ok('and a state inside it follows each part', J(sh2) === J(['.a::before', '.a:hover::before', '.b::before', '.b:hover::before']), J(sh2));
|
| 101 |
+
ok('plain .a { ::before { } } is unchanged', J(shadow('.a { ::before { content: "" } }')) === J(['.a::before']));
|
| 102 |
+
ok('the shadow rules do not share declaration objects', (() => { const r = run('.a, .b { ::before { content: "" } }').doc.shadowRules; return r.length === 2 && r[0].decls !== r[1].decls && r[0].id !== r[1].id; })());
|
| 103 |
+
ok('a top-level list of pseudo-elements is unchanged', J(shadow('.a::before, .b::before { content: "" }')) === J(['.a::before', '.b::before']));
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
section('D-8. HTML element names are not state typos');
|
| 107 |
+
{
|
| 108 |
+
const w = (src) => run(src).warnings.filter((x) => /compiled as a descendant selector/.test(x.message));
|
| 109 |
+
ok('li under a rule does not warn', w('.menu { li { color: red } }').length === 0);
|
| 110 |
+
const names = 'a abbr address article aside audio b blockquote body br button canvas caption code col details dialog div em fieldset figure footer form h1 h2 h3 h4 h5 h6 header hr html i iframe img input label legend li main mark menu nav ol optgroup option p pre section select small span strong sub summary sup table tbody td textarea tfoot th thead time tr u ul video'.split(' ');
|
| 111 |
+
const noisy = names.filter((n) => w(`.x { ${n} { color: red } }`).length);
|
| 112 |
+
ok(`none of ${names.length} element names warn`, noisy.length === 0, noisy.join(','));
|
| 113 |
+
ok('and they still compile as descendants', J(sels('.menu { li { color: red } }')) === J(['.menu li']));
|
| 114 |
+
ok('hove still warns', w('.a { hove { color: red } }').length === 1 && /"hover"/.test(w('.a { hove { color: red } }')[0].hint));
|
| 115 |
+
ok('focs still warns', w('.a { focs { color: red } }').length === 1 && /"focus"/.test(w('.a { focs { color: red } }')[0].hint));
|
| 116 |
+
ok('warnings never become errors', run('.a { hove { color: red } }').errors.length === 0 && run('.a { hove { color: red } }').ok);
|
| 117 |
+
ok('a custom word far from any state is silent', w('.a { widget { color: red } }').length === 0);
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
console.log(`\n${pass} passed, ${fail} failed`);
|
| 121 |
+
process.exit(fail ? 1 : 0);
|
|
@@ -11,6 +11,14 @@ const ENTRIES: {
|
|
| 11 |
code?: string;
|
| 12 |
kind?: "spec" | "vote" | "add";
|
| 13 |
}[] = [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
{
|
| 15 |
version: "v0.16.2",
|
| 16 |
date: "growth phase \u00b7 a second small fix",
|
|
|
|
| 11 |
code?: string;
|
| 12 |
kind?: "spec" | "vote" | "add";
|
| 13 |
}[] = [
|
| 14 |
+
{
|
| 15 |
+
version: "v0.16.3",
|
| 16 |
+
date: "growth phase \u00b7 the spec found seven bugs",
|
| 17 |
+
title: "Writing the native spec found seven bugs. They are fixed.",
|
| 18 |
+
why: "a language a browser could implement needs a spec that can be checked against the engine, and checking it showed where the engine and the language disagreed.",
|
| 19 |
+
kind: "add",
|
| 20 |
+
body: "An unquoted url(http://...) no longer loses the rest of the line. A typo at the end of a token path is an error instead of quietly becoming its parent. Nesting under a selector list (.a, .b { .c { } }, hover { }) now joins every part. A backslash escapes a quote in a value. A nested li no longer gets a did you mean link warning. An unknown @layer name and radius: xl with no token now warn instead of failing silently.",
|
| 21 |
+
},
|
| 22 |
{
|
| 23 |
version: "v0.16.2",
|
| 24 |
date: "growth phase \u00b7 a second small fix",
|