kaloko 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/schemas/config.v1.json +2 -0
- package/schemas/revision.v1.json +11 -0
- package/schemas/run.v1.json +12 -3
- package/schemas/scenario.v1.json +14 -0
- package/skills/kaloko/reference/design.md +93 -1
- package/skills/kaloko/reference/execution.md +6 -0
- package/skills/kaloko/reference/portable-html.md +12 -3
- package/skills/kaloko/reference/stacks.md +6 -0
- package/src/cli.mjs +99 -33
- package/src/lib/assertions.mjs +3 -1
- package/src/lib/browser-daemon.mjs +3 -1
- package/src/lib/browser.mjs +79 -10
- package/src/lib/build.mjs +9 -46
- package/src/lib/capture.mjs +1 -1
- package/src/lib/design-cli.mjs +121 -47
- package/src/lib/design-core.mjs +26 -4
- package/src/lib/design-export.mjs +26 -6
- package/src/lib/design-lint.mjs +45 -11
- package/src/lib/design-origins.mjs +86 -0
- package/src/lib/design.mjs +112 -8
- package/src/lib/dimensions.mjs +66 -12
- package/src/lib/doctor.mjs +4 -2
- package/src/lib/drift.mjs +1 -1
- package/src/lib/evaluate.mjs +6 -2
- package/src/lib/manifest-core.mjs +90 -5
- package/src/lib/spec-cli.mjs +7 -4
- package/src/lib/stack.mjs +5 -8
- package/src/lib/tokens.mjs +16 -0
- package/src/lib/walk-dimensions.mjs +31 -6
- package/viewer/index.html +142 -35
package/package.json
CHANGED
package/schemas/config.v1.json
CHANGED
|
@@ -193,7 +193,9 @@
|
|
|
193
193
|
"kind": { "enum": ["app", "design"], "default": "app", "description": "app: the application under test (a web app at base_url, or a native app in the app block). design: a folder of live HTML steps served locally by the CLI (serve); its runs are published as design versions (#42)." },
|
|
194
194
|
"serve": { "type": "string", "description": "kind: design. Folder with one sub-folder per step (<step>/index.html, optional <step>/<locale>/index.html) and shared files in _shared/; relative to the config." },
|
|
195
195
|
"fixtures": { "type": "string", "description": "kind: design. Folder of JSON fixtures live steps may fetch instead of real APIs; relative to the config." },
|
|
196
|
+
"origins": { "type": "array", "maxItems": 20, "items": { "type": "string", "pattern": "^https://(\\*\\.)?[A-Za-z0-9.-]+(:[0-9]{1,5})?/?$" }, "description": "kind: design. Origins the design loads fonts, stylesheets and images from (https://fonts.googleapis.com, https://*.cdn.example.com). The organization allows them in Settings → Security; kaloko design lint warns about one it does not allow. Scripts never load from them." },
|
|
196
197
|
"tokens_mode": { "type": "string", "description": "kind: design. Token mode (e.g. light, dark) steps are rendered in; default: the token set's first mode." },
|
|
198
|
+
"token_modes": { "oneOf": [{ "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]{0,39}$" } }, { "const": false }], "description": "kind: design. Token modes of the token set to render every step in, one capture per mode (keys <viewport>.mode-<name>); tokens_mode is the default and has the plain key. Not set: every mode of the set when it has two or more, except a set of only light and dark (left to color_schemes). false: only tokens_mode." },
|
|
197
199
|
"html_view": { "type": "boolean", "default": false, "description": "Experimental (#42): keep a static HTML view of every capture (assets rehosted, scripts removed, secrets scrubbed). Refused on production unless the environment is readonly." },
|
|
198
200
|
"base_url": {
|
|
199
201
|
"oneOf": [
|
package/schemas/revision.v1.json
CHANGED
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
"state": { "type": "string", "default": "default", "description": "default, a design state (empty, error, …) or view:<viewport> for an HTML view." },
|
|
13
13
|
"kind": { "enum": ["design", "html_view"], "default": "design" },
|
|
14
14
|
"entry": { "type": "string" },
|
|
15
|
+
"items": {
|
|
16
|
+
"type": ["array", "null"],
|
|
17
|
+
"description": "Stack steps (#61): the variants of the step, each a folder of the step with its own page (<step>/<id>/index.html). The revision covers the whole step folder; its entry is the overview page or the first variant's.",
|
|
18
|
+
"maxItems": 200,
|
|
19
|
+
"items": { "type": "object", "required": ["id", "entry"], "properties": { "id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$" }, "entry": { "type": "string" } } }
|
|
20
|
+
},
|
|
15
21
|
"files": { "$ref": "bundle.v1.json#/properties/files" },
|
|
16
22
|
"tokens": { "type": ["object", "null"], "properties": { "project": { "type": ["string", "null"] }, "version": { "type": ["integer", "null"] }, "hash": { "type": ["string", "null"] } } },
|
|
17
23
|
"based_on": { "type": ["string", "null"], "description": "The revision this one changed (a canvas edit, a sync on top of the draft)." },
|
|
@@ -31,6 +37,11 @@
|
|
|
31
37
|
"mode": { "type": "string" }
|
|
32
38
|
}
|
|
33
39
|
}
|
|
40
|
+
},
|
|
41
|
+
"item_captures": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"description": "Stack steps (#61): item id → viewport → rendered capture of that variant, shaped like captures.",
|
|
44
|
+
"additionalProperties": { "type": "object", "additionalProperties": { "$ref": "#/properties/captures/additionalProperties" } }
|
|
34
45
|
}
|
|
35
46
|
}
|
|
36
47
|
}
|
package/schemas/run.v1.json
CHANGED
|
@@ -156,11 +156,11 @@
|
|
|
156
156
|
},
|
|
157
157
|
"viewports": {
|
|
158
158
|
"type": "object",
|
|
159
|
-
"description": "Capture key -> [width, height]. A key is the viewport name plus the dimension values that differ from the default, joined by dots (mobile, mobile.webkit, iphone-15.webkit.dark.reduce)."
|
|
159
|
+
"description": "Capture key -> [width, height]. A key is the viewport name plus the dimension values that differ from the default, joined by dots (mobile, mobile.webkit, iphone-15.webkit.dark.reduce). Token modes of a design add mode-<name>, step states state-<name> as the last part (mobile.mode-brand-b, mobile.dark.state-empty)."
|
|
160
160
|
},
|
|
161
161
|
"variants": {
|
|
162
162
|
"type": "object",
|
|
163
|
-
"description": "Capture key -> { viewport, browser, color_scheme?, reduced_motion?, forced_colors?, display_mode?, device? }. Absent in runs without dimensions: every key is then a plain viewport in Chromium.",
|
|
163
|
+
"description": "Capture key -> { viewport, browser, color_scheme?, reduced_motion?, forced_colors?, display_mode?, token_mode?, step_state?, device? }. Absent in runs without dimensions: every key is then a plain viewport in Chromium.",
|
|
164
164
|
"additionalProperties": {
|
|
165
165
|
"type": "object",
|
|
166
166
|
"properties": {
|
|
@@ -170,13 +170,15 @@
|
|
|
170
170
|
"reduced_motion": { "enum": ["no-preference", "reduce"] },
|
|
171
171
|
"forced_colors": { "enum": ["none", "active"] },
|
|
172
172
|
"display_mode": { "enum": ["browser", "standalone"] },
|
|
173
|
+
"token_mode": { "type": "string", "description": "Token mode of the design's token set the key was rendered in." },
|
|
174
|
+
"step_state": { "type": "string", "description": "Step state (default, empty, error, loading…) of the key." },
|
|
173
175
|
"device": { "type": "string" }
|
|
174
176
|
}
|
|
175
177
|
}
|
|
176
178
|
},
|
|
177
179
|
"dimensions": {
|
|
178
180
|
"type": "object",
|
|
179
|
-
"description": "Values of each dimension the run walked (browsers, color_schemes, reduced_motion, forced_colors, display_modes) for the canvas switchers."
|
|
181
|
+
"description": "Values of each dimension the run walked (browsers, color_schemes, reduced_motion, forced_colors, display_modes, token_modes with the default mode first, states with default first) for the canvas switchers. A step that has no such state has no captures under its keys."
|
|
180
182
|
},
|
|
181
183
|
"devices": {
|
|
182
184
|
"type": "object",
|
|
@@ -463,6 +465,8 @@
|
|
|
463
465
|
"reduced_motion": { "type": "string" },
|
|
464
466
|
"forced_colors": { "type": "string" },
|
|
465
467
|
"display_mode": { "type": "string" },
|
|
468
|
+
"token_mode": { "type": "string", "description": "Token mode a design capture was rendered in." },
|
|
469
|
+
"step_state": { "type": "string", "description": "Step state of the capture (default, empty, error…)." },
|
|
466
470
|
"device_preset": { "type": "string", "description": "Viewport name of the device preset the capture emulated." },
|
|
467
471
|
"device": { "type": ["string", "null"] },
|
|
468
472
|
"tree": { "type": ["string", "null"], "description": "UI tree of an app capture (qawalk.tree.v1)." },
|
|
@@ -562,6 +566,11 @@
|
|
|
562
566
|
"type": "object",
|
|
563
567
|
"description": "Page metadata per locale (meta, links, JSON-LD, microdata, headings)."
|
|
564
568
|
},
|
|
569
|
+
"states": {
|
|
570
|
+
"type": "array",
|
|
571
|
+
"items": { "type": "string" },
|
|
572
|
+
"description": "Step states the step is captured in (default first), when its scenario step lists states."
|
|
573
|
+
},
|
|
565
574
|
"session": {
|
|
566
575
|
"type": [
|
|
567
576
|
"string",
|
package/schemas/scenario.v1.json
CHANGED
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"reduced_motion": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "enum": ["no-preference", "reduce"] }, "description": "prefers-reduced-motion values (keys <viewport>.reduce)." },
|
|
69
69
|
"forced_colors": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "enum": ["none", "active"] }, "description": "forced-colors (Windows high contrast) values (keys <viewport>.forced)." },
|
|
70
70
|
"display_modes": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "enum": ["browser", "standalone"] }, "description": "PWA display modes: standalone captures the page as an installed app (display-mode media rules and matchMedia; the whole screen of a device preset)." },
|
|
71
|
+
"token_modes": { "oneOf": [{ "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]{0,39}$" } }, { "const": false }], "description": "Design environments: token modes of the token set to render every step in (keys <viewport>.mode-<name>). Not set: every mode of the set (see the environment's token_modes). false: only the environment's tokens_mode." },
|
|
71
72
|
"devices": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$" }, "description": "App scenarios: devices to walk on, e.g. pixel-8-api-34, iphone-15-ios-18 (emulators, simulators or real devices named in the environment's app.<platform>.devices). One capture key per device." },
|
|
72
73
|
"environments": {
|
|
73
74
|
"type": "array",
|
|
@@ -311,6 +312,13 @@
|
|
|
311
312
|
],
|
|
312
313
|
"description": "For `kaloko walk --affected`: globs of repository files (relative to the config) that shape this step, next to the routes and imports Kaloko finds itself; `always` walks the step on every affected walk (sign-in, consent)."
|
|
313
314
|
},
|
|
315
|
+
"states": {
|
|
316
|
+
"type": "array",
|
|
317
|
+
"minItems": 1,
|
|
318
|
+
"uniqueItems": true,
|
|
319
|
+
"items": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]{0,39}$", "not": { "enum": ["index"] } },
|
|
320
|
+
"description": "States this step is captured in besides the default one, e.g. [empty, error, loading]; any name works. Each state is one more capture per viewport (keys <viewport>.state-<name>) and a value of the State switcher on the canvas. Design steps render <step>/<state>.html (or <step>/<locale>/<state>.html), else <step>/index.html?state=<name>; walks of web and app steps run the step script once more per state with the argument state. `default` may be listed; it is always captured."
|
|
321
|
+
},
|
|
314
322
|
"page": {
|
|
315
323
|
"enum": ["landing", "work", "list", "settings", "form", "doc"],
|
|
316
324
|
"description": "What kind of page this step is (see the scenario's page); the usability pack asks per type, e.g. one primary call to action only on landing pages."
|
|
@@ -542,6 +550,12 @@
|
|
|
542
550
|
"minItems": 1,
|
|
543
551
|
"items": { "type": "string" },
|
|
544
552
|
"description": "Environments where this criterion applies, e.g. [production] for hreflang to the live domain, the live demo or the sitemap. On any other environment the walk reports it as not applicable (not_evaluated with na: environment) and it does not make the step partial."
|
|
553
|
+
},
|
|
554
|
+
"states": {
|
|
555
|
+
"type": "array",
|
|
556
|
+
"minItems": 1,
|
|
557
|
+
"items": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]{0,39}$" },
|
|
558
|
+
"description": "Step states this criterion applies to, e.g. [empty] for \"says the cart is empty\". Captures of other states report it as not applicable (na: state). Not set: every state of the step."
|
|
545
559
|
}
|
|
546
560
|
}
|
|
547
561
|
},
|
|
@@ -37,6 +37,11 @@ design/
|
|
|
37
37
|
images, fonts, module imports, `fetch('./fixtures/x.json')`). Links to other steps are not files it needs.
|
|
38
38
|
- Live steps run sandboxed on their own origin with `connect-src 'self'`: no real APIs. Use JSON fixtures in
|
|
39
39
|
the bundle.
|
|
40
|
+
- Web fonts and images from a service (Google Fonts, Adobe Fonts, the company CDN) load only from origins an
|
|
41
|
+
organization admin allows in Settings → Security. List the ones the design uses on the environment
|
|
42
|
+
(`design: { kind: design, serve: design, origins: [https://fonts.googleapis.com, https://fonts.gstatic.com] }`);
|
|
43
|
+
`kaloko design lint` warns about each the organization does not allow yet, so tell the person to ask an admin.
|
|
44
|
+
Scripts never load from those origins.
|
|
40
45
|
- Links between steps are plain relative links to the page: `<a href="../payment/index.html">`. The canvas
|
|
41
46
|
follows them; `data-kaloko-go="payment"` (or `data-qawalk-go`) moves to that step whatever the `href` says.
|
|
42
47
|
- Reference token values as CSS custom properties named after the token path (`color.accent` →
|
|
@@ -48,6 +53,40 @@ design/
|
|
|
48
53
|
`kaloko design lint` checks the folder; `kaloko sync` runs it first and stops on errors (things that break on
|
|
49
54
|
the live step), warnings are printed.
|
|
50
55
|
|
|
56
|
+
## Variants of one template (stack steps)
|
|
57
|
+
|
|
58
|
+
A step that comes in variants of one template (an e-mail per reason support can pick, a landing per city, a card per
|
|
59
|
+
plan) is one stack step ([stacks.md](stacks.md)), not one step per variant in a lane of its own:
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
- id: credit
|
|
63
|
+
kind: stack
|
|
64
|
+
title: Credit from support
|
|
65
|
+
items: { urls: [refund, late, damaged] } # folders of the step; without folder names: every subfolder with a page
|
|
66
|
+
fields: [{ id: reason, label: Reason, from: .reason }]
|
|
67
|
+
criteria: [...] # every variant meets them
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
design/credit/index.html optional overview (the step's entry; links into the variants)
|
|
72
|
+
design/credit/refund/index.html one folder per variant: its page and the files next to it
|
|
73
|
+
design/credit/refund/cs/index.html a locale override of one variant
|
|
74
|
+
design/credit/late/index.html
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- `items.urls` that name folders (`refund`, `./refund/`, `refund/index.html`) list the variants in that order. App
|
|
78
|
+
paths (`/credit?reason=refund`), other sources or no list: every subfolder with an `index.html` is a variant,
|
|
79
|
+
sorted by name. Locale folders, `dark/` and folders starting with `_` are never variants.
|
|
80
|
+
- One revision covers the whole step folder; changing a variant is a new revision of the step. The walk captures
|
|
81
|
+
every variant in every viewport (`items.viewports` narrows it) with the index fields and criteria, and reuses
|
|
82
|
+
captures per revision and variant.
|
|
83
|
+
- `kaloko sync` sends the variants' captures with the step; the published version shows the stack index with every
|
|
84
|
+
variant and its verdict, and each variant opens live in the lightbox.
|
|
85
|
+
- `kaloko design lint` reports a variant folder without its `index.html` as an error.
|
|
86
|
+
- `kaloko export --live` and `export --design` write the variant folders; the design export adds
|
|
87
|
+
`screenshots/<step>/<variant>/<locale>/<viewport>.webp`.
|
|
88
|
+
- Not for steps whose variants are different screens of a flow: those stay separate steps.
|
|
89
|
+
|
|
51
90
|
## Devices, dark mode and app screens
|
|
52
91
|
|
|
53
92
|
Design steps can target device presets and colour schemes like any run ([devices.md](devices.md)):
|
|
@@ -68,6 +107,30 @@ color_schemes: [light, dark]
|
|
|
68
107
|
step spec and the token check of a dark capture name the dark tokens, and drift compares dark with dark.
|
|
69
108
|
- Browsers: design steps render in Chromium. Check the implementation in WebKit and Firefox instead.
|
|
70
109
|
|
|
110
|
+
## Step states and token modes
|
|
111
|
+
|
|
112
|
+
A step lists its other states in the scenario (`states: [empty, error, loading]`; any name of letters, digits, `-`
|
|
113
|
+
and `_` works). Draw each one so it can be reviewed and built:
|
|
114
|
+
|
|
115
|
+
- A state is a page next to the step's page: `<step>/<state>.html`, per locale `<step>/<locale>/<state>.html`. It
|
|
116
|
+
travels with the step's revision like the dark page; give it its own fixtures (`<step>/empty.json`, or a literal
|
|
117
|
+
`fetch('./fixtures/cart-empty.json')`) so the closure finds them.
|
|
118
|
+
- Without that page the walk opens `<step>/index.html?state=<name>` and says so. Use it when one page switches its
|
|
119
|
+
states in JS (`new URLSearchParams(location.search).get('state')`); the fixture must still be next to the page or
|
|
120
|
+
fetched by a literal path.
|
|
121
|
+
- Captures of a state are keyed `<viewport>.state-<name>` (`mobile.dark.state-empty`). Criteria with
|
|
122
|
+
`states: [empty]` are judged on that state only; other criteria on every state.
|
|
123
|
+
- The canvas shows a State switcher next to the language; review mode and the grid follow it. A step without the
|
|
124
|
+
state shows its default capture with a note.
|
|
125
|
+
|
|
126
|
+
Token modes: when the token set has two or more modes (resolver contexts or mode groups), every step renders in each
|
|
127
|
+
mode. The walk sets the mode's tokens as custom properties on `:root` after the page's own styles and
|
|
128
|
+
`data-kaloko-mode="<mode>"` on `<html>`; a page that switches themes by class can read the attribute. Captures are
|
|
129
|
+
keyed `<viewport>.mode-<name>`; the environment's `tokens_mode` (else the first mode) is the default with the plain
|
|
130
|
+
key, and the canvas switches modes like colour schemes. A set with only `light`/`dark` modes follows the colour
|
|
131
|
+
scheme instead (`color_schemes: [light, dark]`), unless `token_modes` names them. `token_modes: [brand-a, brand-b]` (environment, scenario or `kaloko start
|
|
132
|
+
--token-modes`) picks modes; `false` turns it off. Live view shows the default mode; other modes are screenshots.
|
|
133
|
+
|
|
71
134
|
**Native app screens as portable HTML.** A mockup of an iOS or Android screen is a full-screen page:
|
|
72
135
|
|
|
73
136
|
- Size it to the screen, not to a document: `html, body { height: 100% }` and the main area `min-height: 100dvh`.
|
|
@@ -121,7 +184,36 @@ opens straight into the presentation of that step: share it with the person who
|
|
|
121
184
|
without it, a step never rendered live) the presentation shows the screenshots.
|
|
122
185
|
- From the local preview and an offline export, the steps open from the run's merged folder (`live/site/`), so plain
|
|
123
186
|
relative links click through there too.
|
|
124
|
-
- A link's query and hash travel to the next step (`../payment/index.html?plan=pro#card`):
|
|
187
|
+
- A link's query and hash travel to the next step (`../payment/index.html?plan=pro#card`): enough for one value.
|
|
188
|
+
For more, use the prototype state below.
|
|
189
|
+
|
|
190
|
+
### Prototype state
|
|
191
|
+
|
|
192
|
+
Steps of a prototype share a small store, so a cart filled on one step shows on the next. The frame helper of the
|
|
193
|
+
live step provides `window.kaloko.state`; the canvas keeps it for the viewer in their browser tab, per draft or
|
|
194
|
+
version, and never sends it to the service. *Start over* in the presentation clears it.
|
|
195
|
+
|
|
196
|
+
```html
|
|
197
|
+
<!-- payment/index.html: the seeds are what the step shows when nothing set it yet -->
|
|
198
|
+
<script type="application/json" id="seed" data-kaloko-state>{ "cart": [{ "name": "Tea", "price": 120 }] }</script>
|
|
199
|
+
<script>
|
|
200
|
+
const render = (s) => { /* draw s.cart */ }
|
|
201
|
+
// first the step's own seeds, so it looks right alone (from disk, in a capture, in an export)
|
|
202
|
+
render(JSON.parse(document.getElementById('seed').textContent))
|
|
203
|
+
// then what the prototype remembers: the helper loads after the page's scripts and the state comes a moment later
|
|
204
|
+
addEventListener('kaloko:state', (e) => render(e.detail.state))
|
|
205
|
+
</script>
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
- `kaloko.state.get(key)`, `set(key, value)` (JSON, up to 64 kB; `null` removes the key), `update(key, fn)`,
|
|
209
|
+
`subscribe(fn)` (called with the whole state now and on every change; returns an unsubscribe function), `reset()`,
|
|
210
|
+
`ready` (a promise of the first state). The `kaloko:state` event on `window` carries the same state; scripts that
|
|
211
|
+
run before the helper use it.
|
|
212
|
+
- The seeds in `<script type="application/json" data-kaloko-state>` fill keys that nothing has set yet. Give every
|
|
213
|
+
step that reads state seeds that make it look right on its own: reviewers open steps directly, captures render
|
|
214
|
+
each step alone, and the local preview and exports have no helper, so `window.kaloko` is missing there.
|
|
215
|
+
- Write with `set` or `update` on the step where the person acts (`update('cart', (c) => [...(c || []), item])`),
|
|
216
|
+
read on the next. Keep it small: ids, counts and form values, not page markup.
|
|
125
217
|
|
|
126
218
|
## What changed in a version
|
|
127
219
|
|
|
@@ -34,6 +34,12 @@ call `kaloko session reset` themselves when the plan starts as a new visitor.
|
|
|
34
34
|
to the node's person (`session.key`, `title`, `mailbox`, `account`, and
|
|
35
35
|
`credentials` for that account in the run's environment; see
|
|
36
36
|
[environments.md](environments.md#accounts-and-sign-in)).
|
|
37
|
+
- Step states: a step with `states: [empty, error]` runs its script once
|
|
38
|
+
more per state with `state` (`'default'` first, then `'empty'`, …); bring
|
|
39
|
+
the page into that state (route a mocked API response with `page.route`,
|
|
40
|
+
empty the cart) before the capture. Each run captures that state's keys
|
|
41
|
+
(`mobile.state-empty`). For a step an agent walks:
|
|
42
|
+
`kaloko capture --step <id> --state empty`. App scripts get `state` too.
|
|
37
43
|
- `agent` — steps that need judgement or change often. Follow
|
|
38
44
|
`execution.instructions`, then `kaloko capture --step <id>`.
|
|
39
45
|
- `manual` — a person does it; you capture afterwards.
|
|
@@ -19,7 +19,14 @@ warnings, `--json` gives every finding with file, line, rule and fix.
|
|
|
19
19
|
`https://`, no protocol-relative `//cdn…`, no paths starting with `/` (on the live origin `/` is the origin root, from
|
|
20
20
|
disk it is the disk root). Errors: `external-url`, `root-relative`, `outside-folder`, `missing-file`.
|
|
21
21
|
- **No CDNs.** Download libraries into `_shared/` and link them relatively. Fonts are bundled as **woff2**, subset to
|
|
22
|
-
the characters used, with `@font-face` in the shared CSS
|
|
22
|
+
the characters used, with `@font-face` in the shared CSS.
|
|
23
|
+
- **Font and asset origins** are the one exception, for stylesheets, fonts and images only: an organization admin
|
|
24
|
+
allows origins such as `https://fonts.googleapis.com`, `https://fonts.gstatic.com`, `https://use.typekit.net` or
|
|
25
|
+
the company CDN in Settings → Security, and live steps load them. Declare the ones the design uses on the design
|
|
26
|
+
environment (`origins: [https://fonts.googleapis.com, https://fonts.gstatic.com]`); `kaloko design lint` then
|
|
27
|
+
takes them instead of an `external-url` error and warns (`origin-not-allowed`) about each the organization does
|
|
28
|
+
not allow yet. Scripts, module imports, `fetch` and video never load from them. A bundled font still works from
|
|
29
|
+
disk and from an export; prefer it when you can.
|
|
23
30
|
- Only bundle file types (html, css, js, mjs, json, svg, woff2, woff, png, jpg, webp, avif, gif, mp4, webm, txt).
|
|
24
31
|
Convert TTF/OTF fonts and other formats (`file-type`).
|
|
25
32
|
- **Size budget:** a file over 1 MB or a step over 5 MB (with the shared files) warns (`large-file`); 10 MB per file
|
|
@@ -40,8 +47,10 @@ warnings, `--json` gives every finding with file, line, rule and fix.
|
|
|
40
47
|
|
|
41
48
|
## State and data
|
|
42
49
|
|
|
43
|
-
- **State lives in the URL**, not in storage: `localStorage`,
|
|
44
|
-
sandboxed frame and are empty for every other viewer
|
|
50
|
+
- **State between steps lives in `window.kaloko.state` or the URL**, not in storage: `localStorage`,
|
|
51
|
+
`sessionStorage`, IndexedDB and cookies throw in the sandboxed frame and are empty for every other viewer
|
|
52
|
+
(`storage`). For a cart, a chosen plan or details filled in on an earlier step use the prototype state
|
|
53
|
+
([design.md → Prototype state](design.md#prototype-state)); for a single value the query and hash do
|
|
45
54
|
(`?plan=pro#card`): a link's query and hash travel to the next step in the presentation, and work from disk.
|
|
46
55
|
Wrap any storage access you keep in `try/catch` with a fallback.
|
|
47
56
|
- **No network:** real APIs, `XMLHttpRequest`, `WebSocket`, `EventSource` do not connect (`websocket`). Put data in
|
|
@@ -126,5 +126,11 @@ two or three example paths), whether the limit cut the list, and that
|
|
|
126
126
|
semantic criteria covered only the sample. Put the full list in the CSV or
|
|
127
127
|
the MCP result rather than in the issue.
|
|
128
128
|
|
|
129
|
+
## Design environments
|
|
130
|
+
|
|
131
|
+
On a design environment a stack step is a template with its variants: each variant is a folder of the step,
|
|
132
|
+
`design/<step>/<variant>/index.html`, listed by `items.urls` or discovered from subfolders, and every variant is
|
|
133
|
+
captured in every viewport. See [design.md](design.md#variants-of-one-template-stack-steps).
|
|
134
|
+
|
|
129
135
|
Not yet supported for stacks: comparison with a baseline run per page and
|
|
130
136
|
the documentation layer (latest captures per step).
|