@navipartner/demo-video 0.7.0 → 0.7.2
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 +13 -9
- package/bin/demo-video.mjs +98 -17
- package/bin/init.d.mts +2 -0
- package/bin/init.mjs +17 -6
- package/dist/{adapter-CDOXdUZI.d.ts → adapter-DxZmb-QU.d.ts} +47 -8
- package/dist/{chunk-D7UYGNSF.js → chunk-XMOGUZJU.js} +211 -50
- 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 +753 -217
- package/package.json +1 -1
- package/skills/np-demo-video/SKILL.md +242 -230
- package/skills/np-demo-video/look.md +182 -82
- package/skills/np-demo-video/reference.md +89 -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,266 +46,270 @@ 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: wide when it reads, pushed in only when it's too small |
|
|
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 wide, on the whole window. Push in only
|
|
92
|
+
where the text is too small to read wide, framing the control *and* what
|
|
93
|
+
it changes (a live preview included); the engine shows the whole window
|
|
94
|
+
first. End on the result, framed if it needs reading.
|
|
95
|
+
5. **The card:** statement + benefit, written last (below), and the
|
|
96
|
+
snapshot (`show`) of the result it ends on, if that result is visual.
|
|
97
|
+
6. **Proof:** the value the app shows, checked with `expectText`.
|
|
98
|
+
|
|
99
|
+
Check the plan: is it clear on mute? Does each card describe exactly what
|
|
100
|
+
follows? Do the open card's logo and snapshot show the product in the
|
|
101
|
+
first seconds?
|
|
102
|
+
|
|
103
|
+
Example, a showcase of retail self-checkout:
|
|
82
104
|
|
|
83
105
|
```
|
|
84
|
-
open Introducing · NaviPartner logo · sub "Self-checkout"
|
|
106
|
+
open Introducing · NaviPartner logo · sub "Self-checkout that pays its way."
|
|
107
|
+
show: receipt (the result the story ends on)
|
|
85
108
|
ch1 sees: a guest scans two waters and they land in the basket
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
card: "Scan *and go*."
|
|
109
|
+
behind: —
|
|
110
|
+
shots: frame scan area + basket rows; hold on the rows
|
|
111
|
+
card: "Scan *and go*." / "Every item lands in the basket as you scan."
|
|
112
|
+
show: basket
|
|
89
113
|
ch2 sees: the guest pays by card and the payment goes through
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
114
|
+
behind: —
|
|
115
|
+
shots: frame "Go to payment" + total; pull out when payment opens;
|
|
116
|
+
end framing the receipt
|
|
117
|
+
card: "Pay *by card*." / "Tap, insert or phone: the terminal takes it."
|
|
118
|
+
show: receipt
|
|
93
119
|
payoff "Paid *in seconds*." · sub "64,50 kr. by card." (expectText on the total)
|
|
94
|
-
end NaviPartner logo · "
|
|
120
|
+
end NaviPartner logo · "Book a demo at navipartner.com."
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Example, a feature clip (`"kind": "feature"`):
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
open New · NaviPartner logo · sub "Split the bill in two taps."
|
|
127
|
+
show: split-summary
|
|
128
|
+
ch1 sees: a waiter splits a table's bill between three guests
|
|
129
|
+
behind: open the table, open the bill
|
|
130
|
+
shots: frame split button + guest shares; end framing the shares
|
|
131
|
+
card: "Split *the bill*." / "Each guest pays their own share, by card or cash."
|
|
132
|
+
end NaviPartner logo · "Now in NP Restaurant."
|
|
95
133
|
```
|
|
96
134
|
|
|
97
|
-
##
|
|
135
|
+
## 4. Learn the app
|
|
98
136
|
|
|
99
|
-
1. **Adapter:** `<app>/demo/demo.config.ts
|
|
100
|
-
|
|
101
|
-
|
|
137
|
+
1. **Adapter:** `<app>/demo/demo.config.ts`: how the app runs offline
|
|
138
|
+
(`setup` → the e2e mocks), its `ready` testid and any `actions` (e.g.
|
|
139
|
+
retail's `scan`). No adapter yet: see "A new app".
|
|
102
140
|
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.
|
|
141
|
+
their `data-testid`s, including the element the snapshot shows.
|
|
142
|
+
3. **Data:** only what the e2e tests already have: their mocks, logins and
|
|
143
|
+
data. Never add fixtures or change mocks. Skip the edge cases the mocks
|
|
144
|
+
hold on purpose (an absurdly long name, an error item). If the request
|
|
145
|
+
needs data the tests don't have, say so instead of inventing it.
|
|
116
146
|
|
|
117
147
|
### A new app
|
|
118
148
|
|
|
119
149
|
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:
|
|
150
|
+
then `pnpm install`. With several apps it prints one `init --app <folder>`
|
|
151
|
+
line per app: run the one you need.
|
|
152
|
+
2. Finish the `demo.config.ts` skeleton from the app's **current** code and
|
|
153
|
+
e2e tests (fields in reference.md):
|
|
128
154
|
- `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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
`<app>/demo/stories/<name>.json`, named for what it shows (`checkout`,
|
|
149
|
-
`settings`), and holds no brand: it films in NaviPartner's brand, or in a
|
|
150
|
-
customer's that @Linear researches for one video. A translation is a story
|
|
151
|
-
of its own (below).
|
|
155
|
+
- `setup`: the e2e mocks exactly as the tests call them, then the brand
|
|
156
|
+
laid over the response that carries the app's branding
|
|
157
|
+
(`overlayResponse`), using only keys the app's parser accepts.
|
|
158
|
+
- `brandNeeds`: every `config` key and asset slot `setup` uses, each with
|
|
159
|
+
what it is and where it shows. Be specific: a pitch's research fills
|
|
160
|
+
exactly these.
|
|
161
|
+
- `actions` for what a test does through code (a scanner bridge, a
|
|
162
|
+
colour picker, a file upload). An action the viewer sees names its
|
|
163
|
+
control (`target`), so the cursor goes there and the camera rules
|
|
164
|
+
apply; don't add holds to make up for a missing one. Also
|
|
165
|
+
`idleTimeoutSeconds` if the app resets when idle.
|
|
166
|
+
3. Write the primary story, then `check` it.
|
|
167
|
+
|
|
168
|
+
## 5. Write the story
|
|
169
|
+
|
|
170
|
+
A story is `<app>/demo/stories/<name>.json`, named for what it shows. It
|
|
171
|
+
holds no brand: it films in NaviPartner's, or in a customer's that @Linear
|
|
172
|
+
researches for one video. A developer writes stories locally; a
|
|
173
|
+
`/demo-video` PR comment or a request to @Linear only picks an existing one.
|
|
152
174
|
|
|
153
175
|
{ "app": "<adapter app>",
|
|
154
176
|
"description": "One sentence: what the story shows. Follows e2e/<spec>.",
|
|
155
177
|
"primary": true,
|
|
156
|
-
"title": { "eyebrow": "Introducing", "logo": true, "sub": "…" },
|
|
178
|
+
"title": { "eyebrow": "Introducing", "logo": true, "sub": "…", "show": "<result testid>" },
|
|
157
179
|
"closing": { "logo": true, "sub": "…" },
|
|
158
180
|
"steps": [ … ] }
|
|
159
181
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
`
|
|
176
|
-
|
|
177
|
-
`
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
- **
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
customer's brand. Never target text a brand can change (renamed products,
|
|
192
|
-
an order number): pick products by testid and `nth`, the mock's order.
|
|
193
|
-
- **Safety:** after each navigation, `waitFor` the next screen's testid. Put
|
|
194
|
-
`expectText` on prices and confirmations so the video fails if the copy is
|
|
195
|
-
wrong, and so a card may quote them.
|
|
182
|
+
A chapter in steps:
|
|
183
|
+
|
|
184
|
+
{ "do": "card", "heading": "Pay *by card*.",
|
|
185
|
+
"sub": "Tap, insert or phone: the terminal takes it.", "show": "receipt" },
|
|
186
|
+
{ "do": "click", "target": "accept-terms", "behindCard": true },
|
|
187
|
+
{ "do": "frame", "targets": ["pay-button", "order-total"] },
|
|
188
|
+
{ "do": "expectText", "target": "order-total", "text": "64,50 kr." },
|
|
189
|
+
{ "do": "click", "target": "pay-button" },
|
|
190
|
+
{ "do": "zoomOut" },
|
|
191
|
+
{ "do": "waitFor", "target": "receipt" },
|
|
192
|
+
{ "do": "frame", "targets": ["receipt", "receipt-total"] },
|
|
193
|
+
{ "do": "hold", "seconds": 2 }
|
|
194
|
+
|
|
195
|
+
- **Shots:** stay wide while the shot reads. When a push-in is needed,
|
|
196
|
+
prefer `frame` (2–4 targets: the control and what it changes) to guessing
|
|
197
|
+
one `zoom` target, and keep the live preview in it; use `maxScale` to
|
|
198
|
+
stay looser. When an action changes something outside the shot,
|
|
199
|
+
`zoomOut` right after it. When `check` asks for a shot, question the shot
|
|
200
|
+
before adding a frame: staying wide, or framing the result, is often the
|
|
201
|
+
better fix.
|
|
202
|
+
- **Typing:** `"replace": true` clears what the field holds first. Type
|
|
203
|
+
short, believable values that change something on screen.
|
|
204
|
+
- **Leave the beats to the engine.** It pauses around every click, settles
|
|
205
|
+
the camera, lingers on a chapter's result and holds each card long enough
|
|
206
|
+
to read. Add a `hold` only on something the viewer must read (1.5–3 s).
|
|
207
|
+
- **Works with any brand:** a pitch films the same story in a customer's
|
|
208
|
+
brand. Never target text a brand can change (renamed products, an order
|
|
209
|
+
number): pick by testid and `nth`.
|
|
210
|
+
- **Safety:** after each navigation, `waitFor` the next screen. Put
|
|
211
|
+
`expectText` on prices and confirmations, so the video fails if the copy
|
|
212
|
+
is wrong, and so a card may quote them.
|
|
196
213
|
|
|
197
214
|
### Writing the cards
|
|
198
215
|
|
|
199
|
-
The words are what the viewer remembers; write them with care.
|
|
216
|
+
The words are what the viewer remembers; write them with care. A chapter
|
|
217
|
+
card is a **statement** and a **benefit**, beside a **snapshot** of the
|
|
218
|
+
result when it is visual. No eyebrow: chapter labels don't help in a
|
|
219
|
+
one-minute film.
|
|
200
220
|
|
|
201
|
-
- **
|
|
221
|
+
- **Statement:** names what the chapter shows, in the chapter's own verb,
|
|
202
222
|
before it happens: a scan chapter is "Scan *and go*.", not "Shopping made
|
|
203
223
|
easy." If the viewer couldn't point at it in the next ten seconds, rewrite
|
|
204
|
-
it.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
224
|
+
it. The italic word is the action or its result ("*scan*", "*by card*"),
|
|
225
|
+
never filler.
|
|
226
|
+
- **Benefit:** why it matters to the customer, as something the chapter then
|
|
227
|
+
shows: "Every item lands in the basket as you scan." Not a slogan, not a
|
|
228
|
+
claim the video can't back.
|
|
229
|
+
- **Snapshot (`show`):** the element the chapter ends on (the pass preview,
|
|
230
|
+
the receipt). The engine captures it as it last looks in that chapter. On
|
|
231
|
+
a payoff, it is the result as the payoff comes up.
|
|
232
|
+
- **Payoff:** the result just shown, with the app's real values from an
|
|
233
|
+
`expectText`: "64,50 kr. by card." No durations, counts or claims the
|
|
234
|
+
video doesn't show.
|
|
235
|
+
- **Open card:** its sub-line says what the product does for the buyer
|
|
236
|
+
("Self-checkout that pays its way."), or for a clip, the feature ("Split
|
|
237
|
+
the bill in two taps."). Its `show` is the result the story ends on, or
|
|
238
|
+
the feature itself.
|
|
239
|
+
- **End card:** one short line, the promise or the next step ("Book a demo
|
|
240
|
+
at navipartner.com.", "Now in NP Restaurant.").
|
|
212
241
|
- **Never on a card:** testids, barcodes, internal names, "demo", "test",
|
|
213
242
|
exclamation marks, "seamless", "effortless", "revolutionary".
|
|
214
|
-
- Statements ≤ 7 words, subs ≤ 16 (`check` stops at 8 and 16), sentence
|
|
215
|
-
case, ending with a full stop.
|
|
216
|
-
|
|
217
|
-
### Brands
|
|
218
|
-
|
|
219
|
-
Repos keep no brands. NaviPartner's ships with the engine, and every video
|
|
220
|
-
in a repo is in it. Never create `demo/brands/`: `check` refuses it.
|
|
221
|
-
|
|
222
|
-
A video in a customer's branding is asked for in Linear: @Linear researches
|
|
223
|
-
their brand for that one video and keeps nothing (follow
|
|
224
|
-
[linear.md](linear.md), and nothing else here, when that's the request).
|
|
225
243
|
|
|
226
244
|
### A translation
|
|
227
245
|
|
|
228
246
|
A story in another language is a story of its own, named for its language:
|
|
229
|
-
`checkout-da.json` beside `checkout.json`.
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
- `description` says the language ("The checkout, in Danish."). It is never
|
|
235
|
-
`primary`.
|
|
236
|
-
- `/demo-video checkout in danish` (or `checkout da`, `checkout på dansk`)
|
|
237
|
-
picks it.
|
|
238
|
-
- `check --story checkout-da` before the PR, and again when you change the
|
|
239
|
-
base story.
|
|
247
|
+
`checkout-da.json` beside `checkout.json`. Same flow, plus what switches the
|
|
248
|
+
app's language (as the e2e tests do it, usually `behindCard`); its cards in
|
|
249
|
+
that language; a `description` that says the language; never `primary`.
|
|
250
|
+
`/demo-video checkout in danish` picks it. Check it again when you change
|
|
251
|
+
the base story.
|
|
240
252
|
|
|
241
|
-
|
|
253
|
+
Videos are silent: they must work on mute.
|
|
242
254
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
## 5. Check, then render
|
|
255
|
+
## 6. Check, then film a draft
|
|
246
256
|
|
|
247
257
|
pnpm --dir <app> exec demo-video check [--story <name>] --json
|
|
248
258
|
|
|
249
259
|
Without `--story`, commands use the primary story. `check` performs every
|
|
250
|
-
step for real
|
|
260
|
+
step for real, fails on anything that would film badly, and prints about
|
|
261
|
+
how long the video will run against its kind's range. Its error names
|
|
262
|
+
the fix; reference.md lists them all. Its `visible` list shows what is on
|
|
263
|
+
screen at the failing step. Repeat until it passes, at most 3 rounds; a
|
|
264
|
+
story that still fails is reported as "couldn't show this", with the last
|
|
265
|
+
report. Then film a draft:
|
|
266
|
+
|
|
267
|
+
pnpm --dir <app> exec demo-video render --draft [--story <name>]
|
|
268
|
+
|
|
269
|
+
A draft films at 30 fps, in about half the time of the final (which is
|
|
270
|
+
about 15× the video's length). It runs a check first when cards show
|
|
271
|
+
snapshots, to capture them. Playwright starts the app's dev server from the
|
|
272
|
+
adapter's `webServer`; if it can't on this machine, start it yourself with
|
|
273
|
+
the same command and env, and it is reused.
|
|
274
|
+
|
|
275
|
+
## 7. Review like a viewer
|
|
276
|
+
|
|
277
|
+
Open `<app>/demo/out/review/sheet.jpg` first (one frame a second), then the
|
|
278
|
+
stills beside it. Judge against look.md:
|
|
279
|
+
- **Story:** each card is followed by exactly what it says; each snapshot
|
|
280
|
+
shows the chapter's result.
|
|
281
|
+
- **Pace:** no stretch where nothing changes and no setup on screen, yet
|
|
282
|
+
every result and card stays long enough to read. A showcase 45–90 s, a
|
|
283
|
+
clip 15–30 s.
|
|
284
|
+
- **Camera:** every shot reads on a phone; each click's result is on
|
|
285
|
+
screen; chapters end on their result.
|
|
286
|
+
- **Truth:** every word is true of what's on screen.
|
|
251
287
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
| `"x" is outside the shot …` | The zoom frames the wrong area: zoom on what this shot clicks, or `zoomOut` first |
|
|
255
|
-
| `clicking "x" changes y, which is outside the shot …` | Frame what the click changes, or `zoomOut` right after the click |
|
|
256
|
-
| `N camera push-ins in one chapter` | Push in once on the chapter's area and hold steady |
|
|
257
|
-
| `… only fit in the wide shot` | `frame` things that sit together, or stay wide |
|
|
258
|
-
| `… names a brand or extends a story` | Remove it: a customer's branding is @Linear's, a translation is a story of its own |
|
|
259
|
-
| `…/demo/brands isn't used` | Delete the folder: repos keep no brands |
|
|
260
|
-
| `a zoom with nothing in its shot` | Remove it, or act or read something in it |
|
|
261
|
-
| `zoom 2.4; use 1.3–2` | Zoom less: context reads better and stays sharp |
|
|
262
|
-
| `"…" looks like a testid-like name / barcode / code` | Cards are for people: say it in words |
|
|
263
|
-
| `"38" isn't shown by an expectText` | Quote only values an `expectText` checks |
|
|
264
|
-
| `the card announces a chapter in which nothing is done` | Follow it with the steps it describes |
|
|
265
|
-
|
|
266
|
-
Fix what the report names. Its `visible` list shows what is on screen at the
|
|
267
|
-
failing step. Repeat until it passes, at most 3 rounds; a story that still
|
|
268
|
-
fails is reported as "couldn't show this", with the last report. Then:
|
|
288
|
+
Adjust the JSON and film another draft. Two rounds of tuning is normal;
|
|
289
|
+
more means the plan from step 3 is the problem.
|
|
269
290
|
|
|
270
|
-
|
|
291
|
+
## 8. The final, only on the developer's go-ahead
|
|
271
292
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
look.md:
|
|
284
|
-
- **Story:** each statement card is followed by exactly what it says, and
|
|
285
|
-
the payoff by the result it states.
|
|
286
|
-
- **Camera:** every push-in lands where something then happens; no shot is
|
|
287
|
-
mostly empty space; each click's result is on screen.
|
|
288
|
-
- **Framing:** pushed-in shots fill the frame and read on a phone; nothing
|
|
289
|
-
important is cut off; the cursor rests out of the way.
|
|
290
|
-
- **Pacing:** each chapter is one idea; nothing rushed, nothing lingering.
|
|
291
|
-
- **Truth:** every word is true of what's on screen.
|
|
293
|
+
Give the developer the draft (its MP4 and contact sheet) and **stop**. Film
|
|
294
|
+
the final 60 fps video only when the developer has watched the latest draft
|
|
295
|
+
and says, specifically, that they are satisfied with the whole flow and want
|
|
296
|
+
the final: "the flow is right, render the final", "go ahead at 60".
|
|
297
|
+
|
|
298
|
+
These are not a go-ahead, so ask instead ("Happy with the whole flow? Say
|
|
299
|
+
so and I'll render the final at 60 fps."):
|
|
300
|
+
- "looks good" or praise of one part, without asking for the final;
|
|
301
|
+
- approval of an earlier draft;
|
|
302
|
+
- a request for changes, however small;
|
|
303
|
+
- no answer.
|
|
292
304
|
|
|
293
|
-
|
|
294
|
-
|
|
305
|
+
A go-ahead covers the draft it was given for. After any change to the
|
|
306
|
+
story, film a new draft and wait for a new go-ahead. Then:
|
|
307
|
+
|
|
308
|
+
pnpm --dir <app> exec demo-video render [--story <name>]
|
|
295
309
|
|
|
296
310
|
## Report
|
|
297
311
|
|
|
298
|
-
Give
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
- anything the video could not show truthfully (it shows demo fixture data,
|
|
303
|
-
not a real tenant's)
|
|
312
|
+
Give the MP4 path and duration (the draft's, or the final's), the chapter
|
|
313
|
+
plan, the contact sheet, and anything the video could not show truthfully
|
|
314
|
+
(it shows demo fixture data, not a real tenant's). After a draft, say that
|
|
315
|
+
the final waits for their go-ahead.
|