@navipartner/demo-video 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -100
- package/bin/demo-video.mjs +101 -30
- package/bin/init.d.mts +2 -0
- package/bin/init.mjs +21 -22
- package/bin/pick.d.mts +0 -4
- package/bin/pick.mjs +0 -39
- package/dist/{adapter-CDOXdUZI.d.ts → adapter-bOi1ZBRa.d.ts} +36 -7
- package/dist/{chunk-D7UYGNSF.js → chunk-RMBVQL2J.js} +199 -48
- package/dist/index.d.ts +119 -20
- package/dist/index.js +1 -1
- package/dist/runner/index.d.ts +1 -1
- package/dist/runner/index.js +527 -180
- package/package.json +1 -1
- package/skills/np-demo-video/SKILL.md +213 -230
- package/skills/np-demo-video/look.md +169 -79
- package/skills/np-demo-video/reference.md +81 -30
package/package.json
CHANGED
|
@@ -1,35 +1,43 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: np-demo-video
|
|
3
|
-
description:
|
|
3
|
+
description: Use when asked for a product demo video, a showcase of a flow, or a marketing or SoMe clip of a NaviPartner app (retail self-checkout, food-order kiosk, NP Passes, or any app with a demo/ folder); for a story in another language; to re-record a demo after UI changes; or for a video requested in Linear, including one in a customer's branding.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# NaviPartner demo video
|
|
7
7
|
|
|
8
8
|
You direct; the engine (`@navipartner/demo-video`) films. You write a story
|
|
9
|
-
(JSON)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
(JSON) and the engine performs it on the app's own e2e setup. Never write
|
|
10
|
+
Playwright code for a video and never edit the app or its mocks to make a
|
|
11
|
+
video pass.
|
|
12
|
+
|
|
13
|
+
Each file has one job:
|
|
14
|
+
- **[look.md](look.md):** what a video looks like and its tempo. Read it
|
|
15
|
+
first.
|
|
16
|
+
- **This file:** the workflow, and the judgment calls the engine can't make.
|
|
17
|
+
- **[reference.md](reference.md):** every field and every limit `check`
|
|
18
|
+
enforces. Look things up there.
|
|
19
|
+
- **[linear.md](linear.md):** a video asked for in Linear. Follow it, and
|
|
20
|
+
nothing else here, when that's the request.
|
|
15
21
|
|
|
16
22
|
## 1. Understand the request
|
|
17
23
|
|
|
18
|
-
|
|
24
|
+
Take from it:
|
|
25
|
+
- **Kind:** a **showcase** (the app's main journey, 45–90 s, for buyers) or
|
|
26
|
+
a **feature clip** (one feature, 15–30 s, for news). "A video of the QR
|
|
27
|
+
app" is a showcase; "a video of the new split-bill button" is a feature
|
|
28
|
+
clip. look.md has the shape of each.
|
|
19
29
|
- **Product:** which app.
|
|
20
|
-
- **Chapters:** the
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- **Data:** the products, names and amounts the request mentions ("two
|
|
24
|
-
waters").
|
|
30
|
+
- **Chapters:** the 2–4 ideas a showcase shows, or the one feature a clip
|
|
31
|
+
shows.
|
|
32
|
+
- **Data:** the products, names and amounts it mentions ("two waters").
|
|
25
33
|
|
|
26
34
|
Card text defaults to English. Ask only for what you cannot infer.
|
|
27
35
|
|
|
28
36
|
### The primary story
|
|
29
37
|
|
|
30
38
|
Every app has one **primary story**: the journey the app exists for, from
|
|
31
|
-
start to the moment of value. It is
|
|
32
|
-
|
|
39
|
+
start to the moment of value. It is filmed when a request names no feature
|
|
40
|
+
("make a video of the QR app").
|
|
33
41
|
|
|
34
42
|
| App | Primary story | Ends on |
|
|
35
43
|
|---|---|---|
|
|
@@ -38,267 +46,242 @@ when a request names no feature ("make a video of the QR app").
|
|
|
38
46
|
| Retail self-checkout | scan and pay | paid, receipt |
|
|
39
47
|
| NP Passes | create a pass | the pass is created |
|
|
40
48
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
- **The app's purpose.** Its README, routes and package description say what
|
|
46
|
-
it is for. If they disagree with the happy-path spec, ask.
|
|
49
|
+
In a new app, find it in **the e2e suite's happy path**: the spec that walks
|
|
50
|
+
the whole flow (`complete-order-flow.spec.ts`). Follow it and end where it
|
|
51
|
+
asserts success. If the app's README or routes say it is for something
|
|
52
|
+
else, ask.
|
|
47
53
|
|
|
48
54
|
Name the story for that job (`checkout`, `create-pass`) and mark it
|
|
49
|
-
`"primary": true
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
55
|
+
`"primary": true` (one per app). The primary story is a showcase. In the
|
|
56
|
+
PR, say which spec it follows.
|
|
57
|
+
|
|
58
|
+
A feature clip is named for its feature (`split-bill`), with
|
|
59
|
+
`"kind": "feature"`. Find the spec that tests the feature and film from
|
|
60
|
+
where it starts; everything needed to get there goes behind the card.
|
|
61
|
+
|
|
62
|
+
Run `pnpm --dir <app> exec demo-video list` first. If a primary story exists
|
|
63
|
+
and the request names no feature, render it instead of writing a new one.
|
|
64
|
+
In a repo with several apps and none named, ask which, or offer each app's
|
|
65
|
+
primary story.
|
|
66
|
+
|
|
67
|
+
## 2. Choose what to film
|
|
68
|
+
|
|
69
|
+
The e2e spec does everything; the video shows only what sells. For each
|
|
70
|
+
step of the spec, decide:
|
|
71
|
+
|
|
72
|
+
| The step is… | In the video |
|
|
73
|
+
|---|---|
|
|
74
|
+
| The idea itself (scan, pay, the preview changing) | On screen, pushed in |
|
|
75
|
+
| Needed, but not the idea (a language dialog, a cookie banner, a tab, a login) | `"behindCard": true` right after the chapter's card: done while the card covers the app |
|
|
76
|
+
| Filling a form | One or two short values, in fields whose effect shows on screen (the preview, the total). The rest stays as the mocks have it |
|
|
77
|
+
| Proof (a total, a confirmation) | `expectText`, framed and held |
|
|
78
|
+
|
|
79
|
+
A showcase chapter is 10–20 seconds of app; a feature clip's one chapter
|
|
80
|
+
8–15. If yours is longer, it is two ideas or it shows setup. Brisk is not
|
|
81
|
+
rushed: a result the viewer must read gets its hold.
|
|
82
|
+
|
|
83
|
+
## 3. Plan on paper first
|
|
84
|
+
|
|
85
|
+
Before any JSON, write the plan. For each chapter, in this order:
|
|
86
|
+
1. **Sees:** one plain sentence with the chapter's verb: "the shopper pays
|
|
87
|
+
by card and the payment goes through".
|
|
88
|
+
2. **Behind the card:** the setup it needs, if any.
|
|
89
|
+
3. **Actions** (2–4), each with **what it changes and where** (a row at the
|
|
90
|
+
top, the total at the bottom, a new screen).
|
|
91
|
+
4. **Shots:** the chapter opens on its first push-in: one shot on the area
|
|
92
|
+
that holds a control *and* what it changes. It ends framing the result.
|
|
93
|
+
5. **The card:** statement + benefit, written last (below), and the
|
|
94
|
+
snapshot (`show`) of the result it ends on, if that result is visual.
|
|
95
|
+
6. **Proof:** the value the app shows, checked with `expectText`.
|
|
96
|
+
|
|
97
|
+
Check the plan: is it clear on mute? Does each card describe exactly what
|
|
98
|
+
follows? Do the open card's logo and snapshot show the product in the
|
|
99
|
+
first seconds?
|
|
100
|
+
|
|
101
|
+
Example, a showcase of retail self-checkout:
|
|
82
102
|
|
|
83
103
|
```
|
|
84
|
-
open Introducing · NaviPartner logo · sub "Self-checkout"
|
|
104
|
+
open Introducing · NaviPartner logo · sub "Self-checkout that pays its way."
|
|
105
|
+
show: receipt (the result the story ends on)
|
|
85
106
|
ch1 sees: a guest scans two waters and they land in the basket
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
card: "Scan *and go*."
|
|
107
|
+
behind: —
|
|
108
|
+
shots: frame scan area + basket rows; hold on the rows
|
|
109
|
+
card: "Scan *and go*." / "Every item lands in the basket as you scan."
|
|
110
|
+
show: basket
|
|
89
111
|
ch2 sees: the guest pays by card and the payment goes through
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
112
|
+
behind: —
|
|
113
|
+
shots: frame "Go to payment" + total; pull out when payment opens;
|
|
114
|
+
end framing the receipt
|
|
115
|
+
card: "Pay *by card*." / "Tap, insert or phone: the terminal takes it."
|
|
116
|
+
show: receipt
|
|
93
117
|
payoff "Paid *in seconds*." · sub "64,50 kr. by card." (expectText on the total)
|
|
94
|
-
end NaviPartner logo · "
|
|
118
|
+
end NaviPartner logo · "Book a demo at navipartner.com."
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Example, a feature clip (`"kind": "feature"`):
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
open New · NaviPartner logo · sub "Split the bill in two taps."
|
|
125
|
+
show: split-summary
|
|
126
|
+
ch1 sees: a waiter splits a table's bill between three guests
|
|
127
|
+
behind: open the table, open the bill
|
|
128
|
+
shots: frame split button + guest shares; end framing the shares
|
|
129
|
+
card: "Split *the bill*." / "Each guest pays their own share, by card or cash."
|
|
130
|
+
end NaviPartner logo · "Now in NP Restaurant."
|
|
95
131
|
```
|
|
96
132
|
|
|
97
|
-
##
|
|
133
|
+
## 4. Learn the app
|
|
98
134
|
|
|
99
|
-
1. **Adapter:** `<app>/demo/demo.config.ts
|
|
100
|
-
|
|
101
|
-
|
|
135
|
+
1. **Adapter:** `<app>/demo/demo.config.ts`: how the app runs offline
|
|
136
|
+
(`setup` → the e2e mocks), its `ready` testid and any `actions` (e.g.
|
|
137
|
+
retail's `scan`). No adapter yet: see "A new app".
|
|
102
138
|
2. **Testids:** read the components for every screen in the plan and collect
|
|
103
|
-
their `data-testid`s.
|
|
104
|
-
3. **Data:**
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
- Never add fixtures or change the mocks or the app for a video.
|
|
109
|
-
- Skip the test edge cases the mocks contain on purpose, such as a product
|
|
110
|
-
with an absurdly long name or an error item.
|
|
111
|
-
- If the request needs data the e2e tests don't have, say so instead of
|
|
112
|
-
inventing it.
|
|
113
|
-
- One exception: a pitch draft's brand may rename the mock's products
|
|
114
|
-
in `config.demoData`, when the adapter takes it (a `brandNeeds` entry).
|
|
115
|
-
It gives them names only, never new barcodes, prices or flows.
|
|
139
|
+
their `data-testid`s, including the element the snapshot shows.
|
|
140
|
+
3. **Data:** only what the e2e tests already have: their mocks, logins and
|
|
141
|
+
data. Never add fixtures or change mocks. Skip the edge cases the mocks
|
|
142
|
+
hold on purpose (an absurdly long name, an error item). If the request
|
|
143
|
+
needs data the tests don't have, say so instead of inventing it.
|
|
116
144
|
|
|
117
145
|
### A new app
|
|
118
146
|
|
|
119
147
|
1. From the repo root: `npx --ignore-scripts @navipartner/demo-video init`,
|
|
120
|
-
then `pnpm install`.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
and writes a `demo.config.ts` skeleton with the dev server from
|
|
125
|
-
`playwright.config`.
|
|
126
|
-
2. Finish the skeleton from the app's **current** code and e2e tests, not
|
|
127
|
-
from notes or an older adapter:
|
|
148
|
+
then `pnpm install`. With several apps it prints one `init --app <folder>`
|
|
149
|
+
line per app: run the one you need.
|
|
150
|
+
2. Finish the `demo.config.ts` skeleton from the app's **current** code and
|
|
151
|
+
e2e tests (fields in reference.md):
|
|
128
152
|
- `appPath` and `ready`: what the e2e helpers open and wait for.
|
|
129
|
-
- `setup`: the e2e mocks exactly as the tests call them
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
A developer writes stories locally (VS Code, with this skill) and a PR
|
|
146
|
-
confirms them. A `/demo-video` PR comment, the Run workflow form and a
|
|
147
|
-
request to @Linear only pick an existing story and a brand: they never
|
|
148
|
-
write one. A story is
|
|
149
|
-
`<app>/demo/stories/<name>.json`, named for what it shows (`checkout`,
|
|
150
|
-
`settings`), and holds no brand: it films in NaviPartner's brand, or in a
|
|
151
|
-
customer's that @Linear researches for one video. A translation is a story
|
|
152
|
-
of its own (below).
|
|
153
|
+
- `setup`: the e2e mocks exactly as the tests call them, then the brand
|
|
154
|
+
laid over the response that carries the app's branding
|
|
155
|
+
(`overlayResponse`), using only keys the app's parser accepts.
|
|
156
|
+
- `brandNeeds`: every `config` key and asset slot `setup` uses, each with
|
|
157
|
+
what it is and where it shows. Be specific: a pitch's research fills
|
|
158
|
+
exactly these.
|
|
159
|
+
- `actions` for what a test does through code (a scanner bridge), and
|
|
160
|
+
`idleTimeoutSeconds` if the app resets when idle.
|
|
161
|
+
3. Write the primary story, then `check` it.
|
|
162
|
+
|
|
163
|
+
## 5. Write the story
|
|
164
|
+
|
|
165
|
+
A story is `<app>/demo/stories/<name>.json`, named for what it shows. It
|
|
166
|
+
holds no brand: it films in NaviPartner's, or in a customer's that @Linear
|
|
167
|
+
researches for one video. A developer writes stories locally; a
|
|
168
|
+
`/demo-video` PR comment or a request to @Linear only picks an existing one.
|
|
153
169
|
|
|
154
170
|
{ "app": "<adapter app>",
|
|
155
171
|
"description": "One sentence: what the story shows. Follows e2e/<spec>.",
|
|
156
172
|
"primary": true,
|
|
157
|
-
"title": { "eyebrow": "Introducing", "logo": true, "sub": "…" },
|
|
173
|
+
"title": { "eyebrow": "Introducing", "logo": true, "sub": "…", "show": "<result testid>" },
|
|
158
174
|
"closing": { "logo": true, "sub": "…" },
|
|
159
175
|
"steps": [ … ] }
|
|
160
176
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
change
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
before acting, lingers on a chapter's result before its card, and opens
|
|
190
|
-
every chapter wide with the cursor at rest. Don't add holds for those.
|
|
191
|
-
- **Works with any brand:** a pitch draft films the same story in a
|
|
192
|
-
customer's brand. Never target text a brand can change (renamed products,
|
|
193
|
-
an order number): pick products by testid and `nth`, the mock's order.
|
|
194
|
-
- **Safety:** after each navigation, `waitFor` the next screen's testid. Put
|
|
195
|
-
`expectText` on prices and confirmations so the video fails if the copy is
|
|
196
|
-
wrong, and so a card may quote them.
|
|
177
|
+
A chapter in steps:
|
|
178
|
+
|
|
179
|
+
{ "do": "card", "heading": "Pay *by card*.",
|
|
180
|
+
"sub": "Tap, insert or phone: the terminal takes it.", "show": "receipt" },
|
|
181
|
+
{ "do": "click", "target": "accept-terms", "behindCard": true },
|
|
182
|
+
{ "do": "frame", "targets": ["pay-button", "order-total"] },
|
|
183
|
+
{ "do": "expectText", "target": "order-total", "text": "64,50 kr." },
|
|
184
|
+
{ "do": "click", "target": "pay-button" },
|
|
185
|
+
{ "do": "zoomOut" },
|
|
186
|
+
{ "do": "waitFor", "target": "receipt" },
|
|
187
|
+
{ "do": "frame", "targets": ["receipt", "receipt-total"] },
|
|
188
|
+
{ "do": "hold", "seconds": 2 }
|
|
189
|
+
|
|
190
|
+
- **Shots:** prefer `frame` (2–4 targets, pushed in as far as they fit) to
|
|
191
|
+
guessing one `zoom` target. The chapter's first shot is set behind its
|
|
192
|
+
card. When a click changes something outside the shot, `zoomOut` right
|
|
193
|
+
after it. End the chapter framing its result.
|
|
194
|
+
- **Typing:** `"replace": true` clears what the field holds first. Type
|
|
195
|
+
short, believable values that change something on screen.
|
|
196
|
+
- **Leave the beats to the engine.** It pauses around every click, settles
|
|
197
|
+
the camera, lingers on a chapter's result and holds each card long enough
|
|
198
|
+
to read. Add a `hold` only on something the viewer must read (1.5–3 s).
|
|
199
|
+
- **Works with any brand:** a pitch films the same story in a customer's
|
|
200
|
+
brand. Never target text a brand can change (renamed products, an order
|
|
201
|
+
number): pick by testid and `nth`.
|
|
202
|
+
- **Safety:** after each navigation, `waitFor` the next screen. Put
|
|
203
|
+
`expectText` on prices and confirmations, so the video fails if the copy
|
|
204
|
+
is wrong, and so a card may quote them.
|
|
197
205
|
|
|
198
206
|
### Writing the cards
|
|
199
207
|
|
|
200
|
-
The words are what the viewer remembers; write them with care.
|
|
208
|
+
The words are what the viewer remembers; write them with care. A chapter
|
|
209
|
+
card is a **statement** and a **benefit**, beside a **snapshot** of the
|
|
210
|
+
result when it is visual. No eyebrow: chapter labels don't help in a
|
|
211
|
+
one-minute film.
|
|
201
212
|
|
|
202
|
-
- **
|
|
213
|
+
- **Statement:** names what the chapter shows, in the chapter's own verb,
|
|
203
214
|
before it happens: a scan chapter is "Scan *and go*.", not "Shopping made
|
|
204
215
|
easy." If the viewer couldn't point at it in the next ten seconds, rewrite
|
|
205
|
-
it.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
216
|
+
it. The italic word is the action or its result ("*scan*", "*by card*"),
|
|
217
|
+
never filler.
|
|
218
|
+
- **Benefit:** why it matters to the customer, as something the chapter then
|
|
219
|
+
shows: "Every item lands in the basket as you scan." Not a slogan, not a
|
|
220
|
+
claim the video can't back.
|
|
221
|
+
- **Snapshot (`show`):** the element the chapter ends on (the pass preview,
|
|
222
|
+
the receipt). The engine captures it as it last looks in that chapter. On
|
|
223
|
+
a payoff, it is the result as the payoff comes up.
|
|
224
|
+
- **Payoff:** the result just shown, with the app's real values from an
|
|
225
|
+
`expectText`: "64,50 kr. by card." No durations, counts or claims the
|
|
226
|
+
video doesn't show.
|
|
227
|
+
- **Open card:** its sub-line says what the product does for the buyer
|
|
228
|
+
("Self-checkout that pays its way."), or for a clip, the feature ("Split
|
|
229
|
+
the bill in two taps."). Its `show` is the result the story ends on, or
|
|
230
|
+
the feature itself.
|
|
231
|
+
- **End card:** one short line, the promise or the next step ("Book a demo
|
|
232
|
+
at navipartner.com.", "Now in NP Restaurant.").
|
|
213
233
|
- **Never on a card:** testids, barcodes, internal names, "demo", "test",
|
|
214
234
|
exclamation marks, "seamless", "effortless", "revolutionary".
|
|
215
|
-
- Statements ≤ 7 words, subs ≤ 16 (`check` stops at 8 and 16), sentence
|
|
216
|
-
case, ending with a full stop.
|
|
217
|
-
|
|
218
|
-
### Brands
|
|
219
|
-
|
|
220
|
-
Repos keep no brands. NaviPartner's ships with the engine, and every video
|
|
221
|
-
in a repo is in it. Never create `demo/brands/`: `check` refuses it.
|
|
222
|
-
|
|
223
|
-
A video in a customer's branding is asked for in Linear: @Linear researches
|
|
224
|
-
their brand for that one video and keeps nothing (follow
|
|
225
|
-
[linear.md](linear.md), and nothing else here, when that's the request).
|
|
226
235
|
|
|
227
236
|
### A translation
|
|
228
237
|
|
|
229
238
|
A story in another language is a story of its own, named for its language:
|
|
230
|
-
`checkout-da.json` beside `checkout.json`.
|
|
239
|
+
`checkout-da.json` beside `checkout.json`. Same flow, plus what switches the
|
|
240
|
+
app's language (as the e2e tests do it, usually `behindCard`); its cards in
|
|
241
|
+
that language; a `description` that says the language; never `primary`.
|
|
242
|
+
`/demo-video checkout in danish` picks it. Check it again when you change
|
|
243
|
+
the base story.
|
|
231
244
|
|
|
232
|
-
|
|
233
|
-
language (its language button, as the e2e tests do it).
|
|
234
|
-
- Its title, cards and closing in that language, the same rules as any card.
|
|
235
|
-
- `description` says the language ("The checkout, in Danish."). It is never
|
|
236
|
-
`primary`.
|
|
237
|
-
- `/demo-video checkout in danish` (or `checkout da`, `checkout på dansk`)
|
|
238
|
-
picks it.
|
|
239
|
-
- `check --story checkout-da` before the PR, and again when you change the
|
|
240
|
-
base story.
|
|
245
|
+
Videos are silent: they must work on mute.
|
|
241
246
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
There's no music bed. Videos are silent, so they must work on mute.
|
|
245
|
-
|
|
246
|
-
## 5. Check, then render
|
|
247
|
+
## 6. Check, then render
|
|
247
248
|
|
|
248
249
|
pnpm --dir <app> exec demo-video check [--story <name>] --json
|
|
249
250
|
|
|
250
251
|
Without `--story`, commands use the primary story. `check` performs every
|
|
251
|
-
step for real
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
| `N camera push-ins in one chapter` | Push in once on the chapter's area and hold steady |
|
|
258
|
-
| `… only fit in the wide shot` | `frame` things that sit together, or stay wide |
|
|
259
|
-
| `… names a brand or extends a story` | Remove it: a customer's branding is @Linear's, a translation is a story of its own |
|
|
260
|
-
| `…/demo/brands isn't used` | Delete the folder: repos keep no brands |
|
|
261
|
-
| `a zoom with nothing in its shot` | Remove it, or act or read something in it |
|
|
262
|
-
| `zoom 2.4; use 1.3–2` | Zoom less: context reads better and stays sharp |
|
|
263
|
-
| `"…" looks like a testid-like name / barcode / code` | Cards are for people: say it in words |
|
|
264
|
-
| `"38" isn't shown by an expectText` | Quote only values an `expectText` checks |
|
|
265
|
-
| `the card announces a chapter in which nothing is done` | Follow it with the steps it describes |
|
|
266
|
-
|
|
267
|
-
Fix what the report names. Its `visible` list shows what is on screen at the
|
|
268
|
-
failing step. Repeat until it passes, at most 3 rounds; a story that still
|
|
269
|
-
fails is reported as "couldn't show this", with the last report. Then:
|
|
252
|
+
step for real, fails on anything that would film badly, and prints about
|
|
253
|
+
how long the video will run against its kind's range. Its error names
|
|
254
|
+
the fix; reference.md lists them all. Its `visible` list shows what is on
|
|
255
|
+
screen at the failing step. Repeat until it passes, at most 3 rounds; a
|
|
256
|
+
story that still fails is reported as "couldn't show this", with the last
|
|
257
|
+
report. Then:
|
|
270
258
|
|
|
271
259
|
pnpm --dir <app> exec demo-video render [--story <name>]
|
|
272
260
|
|
|
273
|
-
Rendering films every frame (60 fps,
|
|
274
|
-
|
|
275
|
-
30 fps in about half the time
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
- **
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
important is cut off; the cursor rests out of the way.
|
|
291
|
-
- **Pacing:** each chapter is one idea; nothing rushed, nothing lingering.
|
|
261
|
+
Rendering films every frame (60 fps), about 15× the video's length, and
|
|
262
|
+
runs a check first when cards show snapshots, to capture them. While tuning,
|
|
263
|
+
`render --draft` films at 30 fps in about half the time. Playwright starts
|
|
264
|
+
the app's dev server from the adapter's `webServer`; if it can't on this
|
|
265
|
+
machine, start it yourself with the same command and env, and it is reused.
|
|
266
|
+
|
|
267
|
+
## 7. Review like a viewer
|
|
268
|
+
|
|
269
|
+
Open `<app>/demo/out/review/sheet.jpg` first (one frame a second), then the
|
|
270
|
+
stills beside it. Judge against look.md:
|
|
271
|
+
- **Story:** each card is followed by exactly what it says; each snapshot
|
|
272
|
+
shows the chapter's result.
|
|
273
|
+
- **Pace:** no stretch where nothing changes and no setup on screen, yet
|
|
274
|
+
every result and card stays long enough to read. A showcase 45–90 s, a
|
|
275
|
+
clip 15–30 s.
|
|
276
|
+
- **Camera:** every shot reads on a phone; each click's result is on
|
|
277
|
+
screen; chapters end on their result.
|
|
292
278
|
- **Truth:** every word is true of what's on screen.
|
|
293
279
|
|
|
294
|
-
Adjust the JSON and re-render. Two rounds of tuning is normal;
|
|
295
|
-
|
|
280
|
+
Adjust the JSON and re-render. Two rounds of tuning is normal; more means
|
|
281
|
+
the plan from step 3 is the problem.
|
|
296
282
|
|
|
297
283
|
## Report
|
|
298
284
|
|
|
299
|
-
Give
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
- the contact sheet and stills
|
|
303
|
-
- anything the video could not show truthfully (it shows demo fixture data,
|
|
304
|
-
not a real tenant's)
|
|
285
|
+
Give the MP4 path and duration, the chapter plan, the contact sheet, and
|
|
286
|
+
anything the video could not show truthfully (it shows demo fixture data,
|
|
287
|
+
not a real tenant's).
|