@leotang92/dsh-claude-motion 0.0.0-stage → 0.1.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/LICENSE +27 -0
- package/NOTICE.md +25 -0
- package/README.md +21 -2
- package/cordis.patch.yml +7 -0
- package/docs/DETAIL.md +32 -0
- package/docs/DETAIL.zh.md +17 -0
- package/icon.svg +8 -0
- package/lib/client.js +1800 -0
- package/lib/index.js +878 -0
- package/locale/en.json +7 -0
- package/locale/zh.json +7 -0
- package/package.json +69 -4
- package/skills/claude-motion/SKILL.md +689 -0
- package/skills/claude-motion/artifact-type/reference/by-hand.md +84 -0
- package/skills/claude-motion/artifact-type/reference/film-api.md +278 -0
- package/skills/claude-motion/artifact-type/reference/finalize.md +213 -0
- package/skills/claude-motion/artifact-type/reference/motion.md +260 -0
- package/skills/claude-motion/artifact-type/reference/plan.md +239 -0
- package/skills/claude-motion/artifact-type/reference/questions.md +240 -0
- package/skills/claude-motion/artifact-type/reference/recreate-ui.md +140 -0
- package/skills/claude-motion/artifact-type/reference/render-offline.md +126 -0
- package/skills/claude-motion/artifact-type/reference/rough-cut.md +251 -0
- package/skills/claude-motion/artifact-type/reference/sound.md +106 -0
- package/skills/claude-motion/artifact-type/reference/styles.md +230 -0
- package/skills/claude-motion/artifact-type/reference/walkthrough.md +83 -0
- package/skills/claude-motion/scripts/artifact.mjs +8390 -0
- package/skills/claude-motion/scripts/editor/artifact-type/anthropicons-fizzy-lake-DtzHkSJH.woff2 +0 -0
- package/skills/claude-motion/scripts/editor/artifact-type/app.css +1 -0
- package/skills/claude-motion/scripts/editor/artifact-type/app.js +17230 -0
- package/skills/claude-motion/scripts/editor/index.html +145 -0
- package/skills/claude-motion/scripts/editor/local-host.js +12 -0
- package/skills/claude-motion/scripts/editor/share-ui.js +208 -0
- package/skills/claude-motion/scripts/editor/third-party-licenses.txt +970 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# A film of scenes, in a look of your own: its records
|
|
2
|
+
|
|
3
|
+
Part of "A new film: three questions, then the film" in this type's
|
|
4
|
+
instructions, which say when each step happens and what you reply. This page is
|
|
5
|
+
the records' format and how to write them. The example is another film's (a bell
|
|
6
|
+
foundry's open day): copy how it is built, never its scenes, words, colors,
|
|
7
|
+
typeface, shapes or times. `if_version`, wherever this page says it: only if your tool's
|
|
8
|
+
input lists it; the version is in your last `list`, `get` or write of that document.
|
|
9
|
+
|
|
10
|
+
## The first batch
|
|
11
|
+
|
|
12
|
+
Sent at once, before any scene is designed, in this order. The film then plays:
|
|
13
|
+
the player draws a plain card with the scene's name for each scene still to come.
|
|
14
|
+
|
|
15
|
+
**`film/meta`**, then **`modules/scenes.json`** (`kind` json):
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{"v":1,"stage":"rough","look":"Cast bronze: Heavy metal shapes lit by furnace glow, rising slowly into place",
|
|
19
|
+
"palettes":[["#17455C","#FFC24B","#FFF1DE","#2A1410"],["#10201D","#3E8F84","#C9E4DC","#D98A3D"],["#F3EFE6","#7A4B2A","#2B211A","#C8962E"]],"theirs":0,
|
|
20
|
+
"width":1920,"height":1080,"fps":60,"background":"#10201D",
|
|
21
|
+
"fonts":{"display":{"family":"…","or":"…"},"sans":{"family":"…","or":"…"}},"scenes":[
|
|
22
|
+
{"id":"yard","name":"The yard","dur":3,"desc":"Gates open on the foundry yard; the date sets in."},
|
|
23
|
+
{"id":"pour","name":"The pour","dur":4.5,"desc":"The ladle tips; bronze runs into the mould."},
|
|
24
|
+
{"id":"ring","name":"First ring","dur":4,"desc":"The bell swings once; rings spread."},
|
|
25
|
+
{"id":"come","name":"Come and see","dur":3.5,"desc":"End card: day, place, free entry."}]}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- Three or four scenes for 20 s, five or six for 30, 24 at most, each ONE subject and ONE
|
|
29
|
+
action: an establishing open → the subject arrives → the thing happens →
|
|
30
|
+
closer scenes, each landing on motion → back out → an end card held 3 s or
|
|
31
|
+
more. The seconds add up to the Length answer; 300 at most.
|
|
32
|
+
- `id`: lower-case letters, digits and `-`, a letter first, 32 at most. It never
|
|
33
|
+
changes, and no two are alike: comments and the user's own edits hang on it.
|
|
34
|
+
`name`: one to three words (48 characters at most), for a listener ("The pour",
|
|
35
|
+
not "Scene 2"): it labels the timeline and the card. `dur`: seconds, above 0.
|
|
36
|
+
`desc`: one plain sentence on what happens. A bad `id`,
|
|
37
|
+
`dur` or count stops the whole film.
|
|
38
|
+
- One continuous action (one window, one camera move, one cursor's errand) is ONE scene, however
|
|
39
|
+
long: nothing carries over a cut. The one exception: a character or object that moves about or
|
|
40
|
+
travels (a window, screen, cursor, card or logo is not one). Where two scenes in a row show it,
|
|
41
|
+
the second must **open in the same framing, with it as the first's code left it**: place, size,
|
|
42
|
+
pose, speed; plan none of its moves ahead, in thought or in `shared.js`.
|
|
43
|
+
- `stage`: `"rough"` until the film's last write: to the page, "not done yet".
|
|
44
|
+
- `width`, `height`: vertical (Reels, TikTok, Shorts) is 1080 by 1920. `background`:
|
|
45
|
+
the picked ground (an overlay: `"transparent"`, and `.ground` paints nothing). `look`: the look in words, for you when you draw the scenes, which may
|
|
46
|
+
be another conversation: the picked option's name and line, and whatever they typed
|
|
47
|
+
or asked for, word for word; you decided: a name and line of your own.
|
|
48
|
+
- `palettes`: every palette the Colors question offered, picked or not (a skipped
|
|
49
|
+
form's too), in the order shown (the picked one is not moved up), each its four
|
|
50
|
+
colors as `#rrggbb` in role order (ground, main, second, accent); offered in words
|
|
51
|
+
alone: settle each one's four now. `theirs`: how many of them, counted from the
|
|
52
|
+
first, are the user's (their brand, a design system), picked or not. One system's
|
|
53
|
+
tile and two palettes of your own: 1. The example: three of your own, the second
|
|
54
|
+
picked: 0. They answered Other, or in words of their own: the palette you made of
|
|
55
|
+
that stands ahead of the rest, and counts as theirs. Hexes alone: no name, no
|
|
56
|
+
title. No Colors question asked: the film's own four alone, `theirs` 1 if they are
|
|
57
|
+
the user's, else 0. For the page to offer again: keep both keys, as they are, at
|
|
58
|
+
every later write of this record.
|
|
59
|
+
- `fonts`: the faces the film is set in. Four optional slots: `sans`, `serif`, `mono` for text,
|
|
60
|
+
`display` for headlines. A slot takes one of the ten faces that ship with the player, by id
|
|
61
|
+
(a plain string), or nearly any Google Fonts family with the nearest of the ten to stand in (in a text slot, one for text):
|
|
62
|
+
`{"family":"…","or":"…"}`. From memory: look nothing up. The player fetches it; `or` shows
|
|
63
|
+
where it can't (no such name; a family that also holds Chinese, Japanese or Korean; no
|
|
64
|
+
network). A family brings weights 400 and 700, or its nearest, never thickened; for others
|
|
65
|
+
name them all, four at most, beside `or`: `"weights":[400,800]`. `display` unnamed: headlines
|
|
66
|
+
take the film's `sans`, so a film set in a serif or a mono names it. Keep `fonts` at every
|
|
67
|
+
later write.
|
|
68
|
+
|
|
69
|
+
The ten. For text: `plus-jakarta-sans` (wide), `manrope` (round), `space-grotesk` (angular),
|
|
70
|
+
`instrument-sans` (narrow), `fraunces` (serif), `dm-mono`, `departure-mono` (pixel), these two
|
|
71
|
+
of one weight. Headlines: `fraunces-display` (hairline), `inter-display` (loud),
|
|
72
|
+
`shantell-sans` (hand-drawn).
|
|
73
|
+
|
|
74
|
+
**Pick for THIS film**, from the look's words and the subject, never from habit: films
|
|
75
|
+
in the same faces look machine-made, and your habit is the same quiet sans under every
|
|
76
|
+
headline, with mono labels. Think where this look's lettering would be at
|
|
77
|
+
home (a road sign, a dashboard, a shop sign, a terminal), then what KIND of face
|
|
78
|
+
is found there (an old-style serif, a didone, a humanist, rounded or wide
|
|
79
|
+
sans, a typewriter, a brush script), then a family of that kind, fit for work (questions.md). The first that comes to
|
|
80
|
+
mind is the one every film would get, so look past it, to a name you are sure of. Most
|
|
81
|
+
films want two, a `display` over a text face that has a bold, unlike in kind, weight or
|
|
82
|
+
voice. A third only as `mono`: for code, a terminal, or figures that count up or sit in
|
|
83
|
+
columns.
|
|
84
|
+
|
|
85
|
+
The user names a family: that one, spelt right, in the slot they mean (titles:
|
|
86
|
+
`display`; the text: `sans`, serif or not; the whole film or a house face: `sans`, and no
|
|
87
|
+
`display`; one of the ten: its id). If it isn't Google's (Helvetica Neue): the nearest
|
|
88
|
+
Google family. Files they gave: the nearest of the ten under them, no `display` of yours,
|
|
89
|
+
their names in `look`; finalize.md's step 2 brings theirs in. The ten have Western European letters only (no ł, ő,
|
|
90
|
+
ş). Any other letters (Polish, Turkish, Greek, Cyrillic, Arabic): two slots at most, each a well-known
|
|
91
|
+
Google family that has them and Latin, none that the player ships, two weights each; `or` as ever (it won't show). Chinese, Japanese, Korean: leave `fonts` out,
|
|
92
|
+
whatever they named.
|
|
93
|
+
|
|
94
|
+
**`modules/base.css`** (`kind` css), six lines at most for now: the picked colors
|
|
95
|
+
as variables (`--ground`, `--main`, `--second`, `--accent`, each once, a plain
|
|
96
|
+
`#rrggbb`, no two alike), the ground painted from them (`.ground`, one per scene, at the
|
|
97
|
+
bottom), the type stacks the film uses, written as below or as
|
|
98
|
+
`var(--serif, Georgia, serif)`, `var(--mono, ui-monospace, monospace)`, never a family's
|
|
99
|
+
name (`#stage` takes the one most words wear; in a serif or mono film `.line` has that one
|
|
100
|
+
inside, in place of the sans one), the few classes every scene uses. It is applied
|
|
101
|
+
before any scene, and keeps scenes written apart looking like one film.
|
|
102
|
+
|
|
103
|
+
```css
|
|
104
|
+
#stage { --ground:#10201D; --main:#3E8F84; --second:#C9E4DC; --accent:#D98A3D; color:var(--second); font-family:var(--sans, system-ui, sans-serif) }
|
|
105
|
+
.ground { position:absolute; inset:0; background:var(--ground) }
|
|
106
|
+
.words { position:absolute; margin:0; display:flex; flex-direction:column; gap:24px } .words > * { margin:0 }
|
|
107
|
+
.line { font-family:var(--display, var(--sans, system-ui, sans-serif)); font-size:84px; line-height:1.05; font-weight:700 } .sub { font-size:36px }
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**`film/script`**, last: `{"code":"window.CUT = kit.scenes();"}`, that line and
|
|
111
|
+
nothing else, for the film's whole life. No later step writes it again.
|
|
112
|
+
|
|
113
|
+
## A scene
|
|
114
|
+
|
|
115
|
+
One document per scene, `modules/scene-pour.js` (`kind` js) for the scene `pour`, one
|
|
116
|
+
`set` each, in film order, ONE call per message: think about one scene, write it,
|
|
117
|
+
send it, read the reply, go to the next. Calls sent together arrive together.
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
const { seg, eio, lerp } = kit;
|
|
121
|
+
kit.scene('pour', {
|
|
122
|
+
init(kit) {
|
|
123
|
+
kit.stage.append(kit.h('<div class="ground"><div class="pour-ladle"></div></div>'));
|
|
124
|
+
this.ladle = kit.stage.querySelector('.pour-ladle').style;
|
|
125
|
+
},
|
|
126
|
+
render(t) {
|
|
127
|
+
this.ladle.transform = 'rotate(' + lerp(4, -24, eio(seg(t, 0.3, 1.2))) + 'deg)';
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
That is the bare shape. A finished scene, whole: finalize.md. A rough one: "How rough".
|
|
133
|
+
|
|
134
|
+
- A scene is a small cut of its own. One `kit.scene` call per module, for the
|
|
135
|
+
module's own id. `init(kit)` builds the scene once inside `kit.stage` (optional;
|
|
136
|
+
may be async). `render(t, kit)` is required, synchronous and pure: every varying
|
|
137
|
+
property set from `t` alone, SECONDS since the scene began. No CSS transitions
|
|
138
|
+
or animations, no timers. Both are called as methods, so `this` carries what
|
|
139
|
+
`init` built over to `render` (under any names but `lead` and `tail`, the player's).
|
|
140
|
+
At a module's top level: constants and that call, no DOM. `init` awaits whatever
|
|
141
|
+
`render` needs: the player tries `render(0)` as soon as `init` settles, and a throw
|
|
142
|
+
there fails the scene.
|
|
143
|
+
- The whole film loads again at every write: keep each `init` light.
|
|
144
|
+
- A scene's `kit` is its own: `kit.stage` is the scene's box, which fills the stage
|
|
145
|
+
and has no ground of its own (`scenes.json`'s `background` lies behind it); what
|
|
146
|
+
`kit.css`, `kit.cursor`, `kit.svgLayer` and `kit.chip` make stays in the scene;
|
|
147
|
+
`kit.video`'s `start` and `kit.typist`'s `t0` count from the scene's beginning.
|
|
148
|
+
`kit.dur`: the scene's seconds. `kit.start`: where it begins in the film. `kit.fx`
|
|
149
|
+
is one canvas, shared by all scenes: set its state (lineWidth, fillStyle,
|
|
150
|
+
a clip) in `render`, never once in `init`.
|
|
151
|
+
- A scene's own class names begin with its id (`pour-ladle`).
|
|
152
|
+
- Scenes cut from one to the next: open what moves about as it was left; else build each to stand
|
|
153
|
+
alone, and to hold its first and last picture for a `t` below 0 or past `kit.dur` (`seg` does).
|
|
154
|
+
The first scene at `t` 0 is the poster and thumbnail: never blank.
|
|
155
|
+
- No flashes: nothing blinks or cuts more than three times a second, rough or
|
|
156
|
+
finished. No scene under a second.
|
|
157
|
+
- `scenes.json`, `base.css`, `shared.js`, `score.js` and any name that begins `scene-`
|
|
158
|
+
or `layer-` are the player's: name no other module so.
|
|
159
|
+
- A line of words is ONE string in ONE element, as the viewer reads it: the page
|
|
160
|
+
lets the user retype it, and finds it by those words. So no id, class name or
|
|
161
|
+
key spelt like words on screen.
|
|
162
|
+
- Lines that belong together (headline, subtitle, button) sit in ONE flow
|
|
163
|
+
container (`.words`, a flex column with a gap), placed as a group, so that a line
|
|
164
|
+
that wraps pushes the next one down; never each at its own `top`. A lone line sits
|
|
165
|
+
in a `.words` too: `.line` has no place of its own.
|
|
166
|
+
- Markup in single-quoted strings, `style="…"` in double quotes, no quotes inside
|
|
167
|
+
a style: a nested quote silently ends the style; the rest is lost.
|
|
168
|
+
- Helpers: `kit.el`, `kit.h`, `seg(t,a,b)` (0 to 1 across a to b), `lerp`, `clamp01`,
|
|
169
|
+
`eo` `ei` `eio` (eases). The rest of the kit waits for finalize.md's step 1 (film-api.md).
|
|
170
|
+
`kit.h` returns ONE element, the first in its string: wrap siblings in one root,
|
|
171
|
+
or call it once for each.
|
|
172
|
+
|
|
173
|
+
## How rough
|
|
174
|
+
|
|
175
|
+
Only for a film whose scenes are rough already (a change to it, Continue). No new film
|
|
176
|
+
is written so.
|
|
177
|
+
|
|
178
|
+
A wireframe: the real words, places, sizes and timing.
|
|
179
|
+
|
|
180
|
+
- What you write: the picked ground, one ink that reads on it (`--second`), and type in
|
|
181
|
+
the sizes and weights it will have, from `base.css`. All four picked colors stand
|
|
182
|
+
there as variables from the start; `--main` and `--accent` wait for Finalize.
|
|
183
|
+
- What the player shows: a rough scene as if drawn by hand in black and white: not
|
|
184
|
+
yours to imitate, mend or undo. No picked color shows until Finalize redraws the
|
|
185
|
+
scene: say so only if asked, or after a change of color.
|
|
186
|
+
- Every object is an outline (2 px, no fill). One that holds no words of its own
|
|
187
|
+
gets a short label in small capitals saying what it will be: LADLE, LOGO, CHART.
|
|
188
|
+
A label is a placeholder, not the film's words: write it `data-label="LADLE"`
|
|
189
|
+
(`base.css` draws it), so that the page never offers it for retyping, and at
|
|
190
|
+
Finalize the drawing takes its place. Words that belong to the film (a chart's
|
|
191
|
+
BEFORE and AFTER) are real text, and stay.
|
|
192
|
+
- No fill, texture, shadow, secondary motion, camera, sound, font file or image asset.
|
|
193
|
+
|
|
194
|
+
`base.css` holds these too:
|
|
195
|
+
|
|
196
|
+
```css
|
|
197
|
+
.box { position:absolute; margin:0 }
|
|
198
|
+
.box { border:2px solid var(--second); box-sizing:border-box; font-size:30px; letter-spacing:.12em }
|
|
199
|
+
.box::after { content:attr(data-label); position:absolute; left:14px; bottom:10px }
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
```js
|
|
203
|
+
const { seg, eo, lerp } = kit;
|
|
204
|
+
kit.scene('pour', {
|
|
205
|
+
rough: true,
|
|
206
|
+
init(kit) {
|
|
207
|
+
kit.stage.append(kit.h('<div class="ground">' +
|
|
208
|
+
'<div class="box" data-label="MOULD" style="left:760px;top:560px;width:400px;height:360px"></div>' +
|
|
209
|
+
'<div class="box pour-stream" style="left:942px;top:330px;width:36px;height:230px"></div>' +
|
|
210
|
+
'<div class="box pour-ladle" data-label="LADLE" style="left:960px;top:170px;width:300px;height:170px;transform-origin:0 100%"></div>' +
|
|
211
|
+
'<div class="words" style="left:140px;top:150px;width:560px"><h2 class="line">Eleven hundred degrees, four minutes</h2>' +
|
|
212
|
+
'<p class="sub">Bronze, poured by hand</p></div></div>'));
|
|
213
|
+
for (const k of ['ladle', 'stream']) this[k] = kit.stage.querySelector('.pour-' + k).style;
|
|
214
|
+
},
|
|
215
|
+
render(t) {
|
|
216
|
+
this.ladle.transform = 'rotate(' + lerp(0, -24, eo(seg(t, 0.4, 1.2))) + 'deg)';
|
|
217
|
+
this.stream.opacity = t > 1 && t < 3.6 ? 1 : 0;
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Scenes missing or broken
|
|
223
|
+
|
|
224
|
+
A turn cut short leaves listed scenes with no module; a scene whose code fails
|
|
225
|
+
shows its name card in place of the scene, and nobody tells you. At "Continue the
|
|
226
|
+
animation." (it may go on "Scenes left: 2, 3.": positions in `scenes.json`, from 1,
|
|
227
|
+
never a count: here `pour` and `ring`; "Scenes left: 2." is `pour` alone), or when you find it so: `list` `modules`; read the named scenes that have a module, or all,
|
|
228
|
+
for a slip and mend it (`if_version`). No scene is rough: finalize.md's "Cut short"
|
|
229
|
+
(not in this conversation: `read` it first): what is missing is written finished, then, the
|
|
230
|
+
stage still rough, the score and `"final"`. Else write what is missing, rough, in film order,
|
|
231
|
+
one `set` per message, and go no further.
|
|
232
|
+
|
|
233
|
+
## A change
|
|
234
|
+
|
|
235
|
+
`list` `modules` (every document whole, with its version), change the scenes it
|
|
236
|
+
touches at the same roughness (`rough: true` stays), `set` each with `if_version`. A
|
|
237
|
+
change of color: the variables in `base.css` (a new ground: `scenes.json`'s
|
|
238
|
+
`background` too); where scenes are rough, the one sentence more says it will show at Finalize. A scene added,
|
|
239
|
+
dropped, renamed, retimed or moved is an edit to `scenes.json` (`if_version`;
|
|
240
|
+
`"stage"` stays `"rough"`; no scene is rough: finalize.md's "Cut short" follows): a new scene's module after it, a dropped scene's module
|
|
241
|
+
`delete`d (`if_version`). Scenes that stay keep their ids. On a final film the
|
|
242
|
+
same, finished, as finalize.md says of a final film (not in this conversation: `read`
|
|
243
|
+
`artifact-type/reference/finalize.md` first): a new scene has no `rough: true`, the stage stays `"final"`, and
|
|
244
|
+
`score.js` is fitted to the new times, with no `T.` of a dropped id left (it would
|
|
245
|
+
sound at 0:00). `modules/{retyped,recolored,refaced,fetched-fonts,recut,retouched}.json` are the page's own
|
|
246
|
+
records: never write or delete them. If the film holds one besides fetched-fonts.json,
|
|
247
|
+
first `read` `artifact-type/reference/by-hand.md`, which says what counts.
|
|
248
|
+
|
|
249
|
+
## Finalize
|
|
250
|
+
|
|
251
|
+
Its steps are on a page of their own, `artifact-type/reference/finalize.md`.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Sound — a score generated from the cut
|
|
2
|
+
|
|
3
|
+
The score is part of the film: `window.CUT.score(S)` declares notes and
|
|
4
|
+
foley against the SAME timeline constants the picture uses, the player
|
|
5
|
+
synthesizes it (a small built-in WebAudio synth — no samples, no
|
|
6
|
+
soundfont) in sync with playback, and Export renders the
|
|
7
|
+
identical events into the MP4's audio track. `S` only records events;
|
|
8
|
+
it is deterministic data, so write it like the picture: from `TT`.
|
|
9
|
+
|
|
10
|
+
## The method (what worked in review)
|
|
11
|
+
|
|
12
|
+
- **Pick the tempo from the cut, not the other way round.** One beat =
|
|
13
|
+
the hard-cut cadence of your showcase run (0.63 s → 95 BPM in the
|
|
14
|
+
reference); phase the grid (`t0`) so bar lines land on the big
|
|
15
|
+
moments — the first close-up, the editor landing, the end page. If a
|
|
16
|
+
visual beat misses a downbeat by a few frames, retime the BEAT in
|
|
17
|
+
`TT`: nobody sees three frames, everybody hears an off-beat hit.
|
|
18
|
+
- **Groove on the grid, foley on exact frames.** Music events take
|
|
19
|
+
beats; UI foley takes the precise t of the event it belongs to, off
|
|
20
|
+
grid: a wood-block tick per visible keystroke (your typist's
|
|
21
|
+
`times`), side-stick clicks on clicks, a double tick for a
|
|
22
|
+
double-click, pops as list items or capsules appear, a rising roll
|
|
23
|
+
while something is dragged or scrubbed with a ding when the value
|
|
24
|
+
lands, a two-note chime on Save, a whoosh under a whip-pan, a boing
|
|
25
|
+
when something drops in and squashes.
|
|
26
|
+
- **Arc** (keep the dynamics; don't flatten them): near-silent title
|
|
27
|
+
(a pad, maybe one mallet note) → a light pulse under the typing →
|
|
28
|
+
the groove enters when the action starts → stabs on the hard-cut
|
|
29
|
+
section → drop to a pad for the transform → groove B under the
|
|
30
|
+
person's edit → a short build (an accelerating run) INTO the hit as
|
|
31
|
+
the end page lands → resolve and let the last chord ring; fade by the
|
|
32
|
+
last second. Stop-time before the biggest hit is free drama.
|
|
33
|
+
- **Instrumentation that suits a product film**: marimba or kalimba ostinato,
|
|
34
|
+
electric piano chords, a round fingered bass, a light kit (kick, side
|
|
35
|
+
stick, closed hat, a shaker at most), a soft pad. No risers, no
|
|
36
|
+
cinematic booms, no vocal chops. Major or modal, mid-tempo, warm.
|
|
37
|
+
- **Your own tune.** Write no existing song's, theme's or jingle's melody, note by note or near
|
|
38
|
+
enough to be recognised: write an original one in that mood. That you did goes in the close's one
|
|
39
|
+
sentence more (what you could not do as asked): it names the song they asked for, not your music.
|
|
40
|
+
The user's own, or in the public domain: fine. A genre, a mood, a tempo, an instrument: fine.
|
|
41
|
+
- **They asked for other music: name it in a plain line**: what you wrote (a mood you aimed
|
|
42
|
+
for, two instruments in everyday words: a marimba, plucked notes, an electric piano, a
|
|
43
|
+
shaker), never how it sounds. No key, BPM or apology. Mellower, no typing ticks, other
|
|
44
|
+
instruments: a one-line change. Music off by request is `score` returning nothing; mute and
|
|
45
|
+
volume are the viewer's own.
|
|
46
|
+
|
|
47
|
+
## `score(S, kit)`
|
|
48
|
+
|
|
49
|
+
Runs once at load, after `init` (so typists made in `init` have
|
|
50
|
+
filled `kit.typing.times`). `S` only records events — pure data.
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
score(S, kit) {
|
|
54
|
+
const BPM = 95.24, B = 60 / BPM;
|
|
55
|
+
S.tempo(BPM, { t0: TT.cut1 - 16 * B }); // grid phased so beat 16 IS the first close-up
|
|
56
|
+
S.program('keys', 'ep'); S.program('bass', 'bass'); S.program('mallet', 'marimba'); S.program('pad', 'pad', { rev: 0.6 });
|
|
57
|
+
S.note('pad', 'D3', { beat: 0, beats: 8, vel: 30 }); // {beat, beats} on the grid, or {t, dur} in seconds
|
|
58
|
+
S.chord('keys', ['D3', 'A3', 'D4', 'F#4'], { beat: 16, beats: 4, vel: 52 });
|
|
59
|
+
S.note('bass', 'D2', { beat: 16, beats: 1.5, vel: 78 });
|
|
60
|
+
S.pattern('mallet', 'x.x.X.xx', { from: 16, repeat: 4, pitch: ['D5', 'A4'], vel: 64 }); // step 0.5 beat; X accents
|
|
61
|
+
S.drums({ kick: 'x...x...', sidestick: '..x...x.', hat: 'oxoxoxox' }, { from: 16, repeat: 8 }); // o = ghost note
|
|
62
|
+
S.ticks(kit.typing.times, { vel: 30 }); // one wood tick per keystroke, timbre-jittered
|
|
63
|
+
S.fx('click', TT.send); S.fx('pop', TT.chip); S.fx('roll', TT.dragA, { dur: TT.dragB - TT.dragA }); // roll lands on a ding
|
|
64
|
+
S.fx('chime', TT.saved); S.fx('whoosh', TT.whip, { dur: 0.5 }); S.fx('revswell', TT.end, { dur: 1.2 }); // swells INTO TT.end
|
|
65
|
+
S.run('mallet', ['D5', 'E5', 'F#5', 'A5', 'B5', 'D6'], { t: TT.end - 0.62, step: 0.1, vel: 50, cresc: 8 });
|
|
66
|
+
S.master({ gain: -6, fadeOut: 1.2 });
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- `S.tempo(bpm, {t0})` sets the grid; `S.beat(n)` → seconds,
|
|
71
|
+
`S.toBeat(t)` → beats. Everything takes `{beat, beats}` (grid) or
|
|
72
|
+
`{t, dur}` (seconds).
|
|
73
|
+
- `S.program(track, patch, {pan −1..1, gain dB, rev 0..1, bright
|
|
74
|
+
0..2}?)` names a track. Pitched patches: `marimba`, `vibes`,
|
|
75
|
+
`glock`, `ep` (electric piano), `keys` (soft synth), `pluck`
|
|
76
|
+
(kalimba-ish), `bass`, `pad`. Drums: `kick`, `snare`, `clap`,
|
|
77
|
+
`sidestick`, `hat`, `openhat`, `shaker`, `tamb`, `woodblock`,
|
|
78
|
+
`cowbell`, `tom`, `crash`, `ride`.
|
|
79
|
+
- `S.note(track, 'F#4' | midi, {…, vel 0–127})`, `S.chord(track,
|
|
80
|
+
[pitches], {…, spread})`, `S.pattern(track, 'x.X.', {from, step =
|
|
81
|
+
0.5, repeat, pitch: [cycle], vel, dur})`, `S.run(track, [pitches],
|
|
82
|
+
{t, step, vel, cresc})`, `S.drum(name, {beat | t, vel})`,
|
|
83
|
+
`S.drums({name: 'x..o'}, {from, step, repeat, vel})` (`X` accent,
|
|
84
|
+
`o` ghost). A little humanizing is built in (`S.seed(n)` varies it).
|
|
85
|
+
- Foley at exact seconds, `S.fx(name, t, {dur, vel, pitch, pan}?)`:
|
|
86
|
+
`tick` (keystroke), `click`, `doubleclick`, `pop`, `ding` (two
|
|
87
|
+
notes a fifth apart), `chime` (a small arpeggio — Save), `sparkle`,
|
|
88
|
+
`whoosh` (`{into: 1}` reverses it), `revswell` (swells INTO its
|
|
89
|
+
`t` over `dur`), `roll` (accelerating ticks over `dur`, a ding on
|
|
90
|
+
landing — drags and scrubs), `boing` (a bouncy landing), `thud`.
|
|
91
|
+
`S.ticks(times, {vel, jitter})` = one tick per time.
|
|
92
|
+
- `S.master({gain dB = −6, fadeOut s = 1})`. Keep the arc: the hit
|
|
93
|
+
should be clearly louder than the intro pad.
|
|
94
|
+
|
|
95
|
+
`pattern`/`drums` with `repeat` happily overrun the beat you meant to
|
|
96
|
+
stop at — compute the repeat count (or the step string) to fit
|
|
97
|
+
[t0, t1). Unknown drum or foley names are SILENT (an unknown pitched
|
|
98
|
+
patch falls back to marimba); `check.ts` lists them with the event
|
|
99
|
+
count, tempo and sounding span. An event timed 0.1 s or more before 0
|
|
100
|
+
is dropped without a word (one closer is moved to 0), so the sound for
|
|
101
|
+
an entrance that starts early goes at 0. Listen by numbers: `export.ts --no-video --levels`
|
|
102
|
+
prints loudness per second (RMS dBFS: −60 silent, −30 quiet bed, −20
|
|
103
|
+
groove, −12 hit) — no second between the title and the sign-off should
|
|
104
|
+
sit below about −30; `--mid score.mid` added to them writes a Standard
|
|
105
|
+
MIDI File on your grid for a composer.
|
|
106
|
+
Keep it small — a 35 s score is a few hundred events.
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Built-in styles
|
|
2
|
+
|
|
3
|
+
A built-in style is a look that ships inside the player. You pick the frames,
|
|
4
|
+
write the words and time them. The page can then change the style, the
|
|
5
|
+
palette or a word without you. That works only
|
|
6
|
+
while **every word on screen is a key in `modules/look.json`**: none in the cut,
|
|
7
|
+
in html or in CSS.
|
|
8
|
+
|
|
9
|
+
- Only for a film that already holds `look.json`, or a plan's request that names
|
|
10
|
+
this page. No other new film starts here, even when asked for by a style's name:
|
|
11
|
+
rough-cut.md, in a look of your own from their words.
|
|
12
|
+
- The film already has a `look.json` (Finalize, any change): read the last
|
|
13
|
+
section first.
|
|
14
|
+
- The example is another film's (a town library's): copy how it is built, not
|
|
15
|
+
its frames, words, times or moves.
|
|
16
|
+
- A film with a plan (plan.md): the style answers its drawn questions about the
|
|
17
|
+
look and composes the frames: pass over those picks and `art.json`'s frames.
|
|
18
|
+
Duration, Where, Motion feel and the cards stand. It is written in one go: ONE
|
|
19
|
+
`batch` of `film/meta`, `look.json`, each screen's html, then the moving cut as
|
|
20
|
+
`film/script`; no `scenes.json`, no stop; plan.md's close.
|
|
21
|
+
- 1920 × 1080 only. Asked for vertical or square: make the film in a look of
|
|
22
|
+
your own, with no look.json, and say so in a line.
|
|
23
|
+
|
|
24
|
+
## The styles
|
|
25
|
+
|
|
26
|
+
<!-- looks -->
|
|
27
|
+
| `look` | what it is | `palette` ids | `values` |
|
|
28
|
+
|---|---|---|---|
|
|
29
|
+
| `sketch` | A designer at the whiteboard: black marker, one highlighter, arrows that point at what matters. | `marker`, `mint`, `night` | `paper` plain, dots, squared, board, `stress` highlight, underline, circle, `fill` none, hatch, scribble, wash, `wobble` 0–100, `weight` 3–7px |
|
|
30
|
+
| `bubbles` | Big glowing glass spheres on a gradient you can turn. Deep and cinematic, or light and airy. | `ember`, `lagoon`, `cobalt` | `angle` 0–360°, `ground` deep, light, `count` 1–5, `size` 60–125, `fade` 0–100 |
|
|
31
|
+
| `editorial` | A well-set annual report: big serif, italic stress, fine rules, covers in your color. | `cobalt`, `evergreen`, `plum`, `night` | `cover` color, ink, paper, `stress` italic, underline, marker, `rules` hair, double, bold, `size` 84–112% |
|
|
32
|
+
| `bold` | Swiss poster: huge tight type, flat color, a strict grid and one shape. | `vermilion`, `night`, `ultramarine`, `acid` | `shape` arcs, quarter, circle, bars, `color` calm, mixed, loud, `side` right, left, `size` 70–100, `grid` true, false |
|
|
33
|
+
| `midnight` | A dark room and a wall of tiny lamps: an aurora in dots, the big number in lights. | `aurora`, `ice`, `sodium` | `light` 0–360°, `glow` 20–100, `waves` 0–100, `grid` dots, pixels, plus |
|
|
34
|
+
| `showcase` | Calm and product-first: a soft tinted backdrop, white rounded cards, a big product window. | `lagoon`, `blossom`, `meadow`, `apricot` | `backdrop` plain, tint, color, dark, `fade` 0–360°, `corners` 0–48, `shadow` 0–100, `emphasis` chip, color, line |
|
|
35
|
+
<!-- /looks -->
|
|
36
|
+
|
|
37
|
+
## What you write, and when
|
|
38
|
+
|
|
39
|
+
The style brings the CSS and the fonts. When each step happens is in this type's
|
|
40
|
+
instructions ("Later"). `if_version`, below: only if your tool's
|
|
41
|
+
input lists it.
|
|
42
|
+
|
|
43
|
+
**A rough cut: every frame in the style, held in turn, no motion or sound.** It
|
|
44
|
+
holds `modules/look.json` whole, `modules/scenes.json` as exactly
|
|
45
|
+
`{"v":1,"stage":"rough"}` (look.json's frames are the scenes: none are listed) and
|
|
46
|
+
the script `window.CUT = kit.stills({ duration: 20 })` under the comment that opens
|
|
47
|
+
the cut below: each frame an equal share of the seconds, two at least. A `screen` whose html
|
|
48
|
+
module is missing (the style's window is drawn empty), or a logo: one `set` each, in
|
|
49
|
+
film order, ONE call per message. After that, or a change, while `scenes.json` still says
|
|
50
|
+
`"stage":"rough"`, your whole reply, in place of the instructions' own:
|
|
51
|
+
|
|
52
|
+
> Here's the rough cut. Tell me what to change, or say Finalize for motion and sound.
|
|
53
|
+
|
|
54
|
+
**Finalize: motion and sound.** Read motion.md and sound.md in one message;
|
|
55
|
+
`list` `modules` (`look.json`, `tweaks.json` and `scenes.json` whole, each with its
|
|
56
|
+
version; last section), then `get` `film/script`. A screen whose html is missing:
|
|
57
|
+
write it first. `look.json` stands. Then ONE `batch`, so that the film loads once:
|
|
58
|
+
`film/script` (`if_version`), the moving cut below, with each frame's own time,
|
|
59
|
+
fades, one or two pushes, chapters and the score, at the same whole length; LAST
|
|
60
|
+
`modules/scenes.json` (`if_version`), `{"v":1,"stage":"final"}`. Then the closing
|
|
61
|
+
words of the instructions' section 2, as quoted (no score: its "No score" words), and its one
|
|
62
|
+
sentence more if there is one; the music is not named, whatever sound.md says.
|
|
63
|
+
|
|
64
|
+
### modules/look.json (`kind` json)
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{"v":1,
|
|
68
|
+
"about":"Built-in style. Before any change read artifact-type/reference/styles.md and modules/tweaks.json (the person's own changes: never write it).",
|
|
69
|
+
"look":"sketch",
|
|
70
|
+
"frames":[
|
|
71
|
+
{"id":"hook","layout":"statement","text":{"kicker":"Marlow Public Library","head":"Your next book is *already waiting*","sub":"Reserve from your phone. Collect when it suits you."}},
|
|
72
|
+
{"id":"shelf","layout":"screen","body":"shelf.html","text":{"address":"marlowlibrary.example/shelf","view":"My shelf","range":"3 on hold",
|
|
73
|
+
"b1":"The Tide Clock","b1at":"Ready at Mill Road","b2":"Nine Quiet Rooms","b2at":"2nd in the queue","b3":"A Field Guide to Rain","b3at":"Due back Friday",
|
|
74
|
+
"alert":"A Field Guide to Rain is due Friday","alertbody":"Nobody is waiting for it. Keep it three more weeks?","action":"Renew"}},
|
|
75
|
+
{"id":"voice","layout":"quote","text":{"quote":"I stopped buying books I only read once. *The library got there first.*","name":"Priya Nair","role":"Member since 2019"}},
|
|
76
|
+
{"id":"count","layout":"stat","text":{"kicker":"Since March","value":"41,000","label":"holds placed by phone","before":"At the desk last year: 6,200"}},
|
|
77
|
+
{"id":"join","layout":"end","text":{"wordmark":"Marlow Library","head":"The card is free.","cta":"Join in two minutes","url":"marlowlibrary.example/join"}}]}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
- With a plan: one frame per card, in order, under the card's id. Ids never
|
|
81
|
+
change: the person's changes are stored under them. At most 24 frames, 48
|
|
82
|
+
keys in each; every value is a string.
|
|
83
|
+
- `*stars*`: the one phrase in a line that the style stresses.
|
|
84
|
+
- `palette`, by what the answer or the request says:
|
|
85
|
+
|
|
86
|
+
| no `Colors` answer and nothing of theirs to use; "in its own colors" | none: drop what was there |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `Colors:` a palette from your questions (none picked: as questions.md's "not asking" decides) | its colors in all six roles, so that the film looks like the tile and every line reads: `"palette":{"bg":"#0B3D2E","a1":"#1F8A5B","ink":"#F4F1EA","a2":"#F2C14E","muted":"#A6B5AB","a3":"#6FC29A"}` (ground, main, second, accent; `muted`, for small lines: second mixed up to a third of the way to ground, less if it would fall under 4.5:1 on the ground; `a3`: a tint or shade of main that shows on the ground) |
|
|
89
|
+
| "in its "night" colors" | that id, from the table: `"palette":"night"` |
|
|
90
|
+
| "in the colors it has now" | `seen.palette` if there is a `tweaks.json`, else as it was |
|
|
91
|
+
| "in the palette picked in the plan" | that option's `bars`, any order: `"palette":["#0B3D2E","#1F8A5B","#F4F1EA"]` (Other: the colours its words name) |
|
|
92
|
+
| none of these | the colours the person gave in the ask, as such a list; none given, none |
|
|
93
|
+
- `values`: only what was asked for, `"values":{"stress":"circle"}`.
|
|
94
|
+
- `"logo":"logo.html"`, beside `look`: their logo, an html module holding one
|
|
95
|
+
`<svg>` (in `currentColor`, so it shows on any palette) or an image asset
|
|
96
|
+
(`"logo.png"`). It is drawn on `title` and `end`.
|
|
97
|
+
- A `quote`'s `"body":"dana.png"`, an image asset: the speaker's face, beside `name` or `role`.
|
|
98
|
+
- A card that is a picture, not words: `"layout":"statement","text":{}` is the
|
|
99
|
+
style's bare ground; append your drawing to the frame's `el`.
|
|
100
|
+
|
|
101
|
+
### Layouts and their slots
|
|
102
|
+
|
|
103
|
+
<!-- layouts -->
|
|
104
|
+
| `layout` | text slots | other parts |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `title` | kicker, head, sub | mark |
|
|
107
|
+
| `statement` | kicker, head, sub | |
|
|
108
|
+
| `points` | kicker, head, item1–4, note1–4 | points, point1–4 |
|
|
109
|
+
| `stat` | kicker, value, label, before, note | stat |
|
|
110
|
+
| `screen` | kicker, head, sub, address, and your own keys | window, pane, body, and your `data-part`s |
|
|
111
|
+
| `quote` | quote, name, role | qmark, by, face |
|
|
112
|
+
| `end` | wordmark, head, cta, url | brand, mark |
|
|
113
|
+
<!-- /layouts -->
|
|
114
|
+
|
|
115
|
+
A slot you leave out is not drawn. Text that is too long shrinks: keep to the
|
|
116
|
+
example's lengths.
|
|
117
|
+
|
|
118
|
+
### film/script
|
|
119
|
+
|
|
120
|
+
```js
|
|
121
|
+
// Built-in style. Before any change read artifact-type/reference/styles.md and modules/tweaks.json (the person's own changes: never write it).
|
|
122
|
+
const { seg, eio, lerp } = kit;
|
|
123
|
+
const L = kit.look();
|
|
124
|
+
const T = { hook: 0, shelf: 3.4, voice: 8.6, count: 12.2, join: 15.2 }; // when each frame comes on
|
|
125
|
+
const END = 19, FADE = 0.5;
|
|
126
|
+
|
|
127
|
+
function frame(id, i, t) { // one frame, whole, from t alone
|
|
128
|
+
const t0 = T[id], el = L.frame(id).el;
|
|
129
|
+
const push = id === 'shelf' ? eio(seg(t, t0 + 1.2, t0 + 2.5)) : 0; // one slow push, close enough to read
|
|
130
|
+
el.style.opacity = i ? seg(t, t0, t0 + FADE) : 1; // fades in over the frame before
|
|
131
|
+
el.style.transform = 'scale(' + (lerp(1, 1.15, push) + 0.006 * (t - t0)) + ')'; // and every hold creeps
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
window.CUT = {
|
|
135
|
+
width: 1920, height: 1080, fps: 60, duration: END, background: L.palette.bg,
|
|
136
|
+
chapters: [{ t: 0, label: 'Already waiting' }, { t: T.shelf, label: 'My shelf' }, { t: T.join, label: 'Join' }],
|
|
137
|
+
render(t) {
|
|
138
|
+
const i = L.frames.findLastIndex((id) => t >= T[id]);
|
|
139
|
+
const from = i && t < T[L.frames[i]] + FADE ? i - 1 : i;
|
|
140
|
+
L.show(...L.frames.slice(from, i + 1));
|
|
141
|
+
for (let k = from; k <= i; k++) frame(L.frames[k], k, t);
|
|
142
|
+
},
|
|
143
|
+
score(S) {
|
|
144
|
+
S.tempo(92, { t0: 0 }); S.program('pad', 'pad'); S.note('pad', 'D3', { t: 0, dur: END, vel: 28 });
|
|
145
|
+
Object.values(T).slice(1).forEach((t0) => S.fx('pop', t0 + 0.2)); S.master({ fadeOut: 1.5 });
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- **Move frames, not parts**: `el`'s opacity and transform. A style draws boxes,
|
|
151
|
+
underlines and arrows around the parts where they sit; a part moved or faded
|
|
152
|
+
alone leaves them behind, and the person can switch to such a style at any
|
|
153
|
+
time. So: cross-fades, creeping holds, a push on a whole frame. No `TextFx`,
|
|
154
|
+
no `kit.Camera`.
|
|
155
|
+
- Set `el`'s styles in `render`, every time, after `L.show`. A change made in the
|
|
156
|
+
page may put the frames back as built and run no new `init`.
|
|
157
|
+
- A screen you push has no kicker, head or sub: its window then sits in the
|
|
158
|
+
middle. A screen with a head holds and creeps.
|
|
159
|
+
- `kit.look()` → `L`. `L.frames`: ids in order. `L.frame(id)` → `{el, parts}`.
|
|
160
|
+
`L.show(a, b)` shows those frames alone, `b` on top. Never set a part's text,
|
|
161
|
+
font size or colour.
|
|
162
|
+
- To aim something of your own at a part: `kit.srect(parts.toast)`, in `render`
|
|
163
|
+
straight after `L.show`, and again whenever `L.values` is a new object (the
|
|
164
|
+
page changed something).
|
|
165
|
+
- Words outside the layouts (a caption, a cursor's label): a top-level
|
|
166
|
+
`"text":{"tip":"…"}` in look.json, or an extra key in a frame's `text`; then
|
|
167
|
+
`L.bind(node, 'tip')` or `L.bind(node, 'hook.tip')` on a node of your own.
|
|
168
|
+
- What is your own (that node, a cursor, a drawing) goes in a frame's `el` and
|
|
169
|
+
moves as you like. Leave its colour unset, or `currentColor`: it takes the
|
|
170
|
+
frame's. Accents: `var(--c-a1)` to `--c-a3`.
|
|
171
|
+
- Time nothing by a line's length: the person can retype it.
|
|
172
|
+
- The rest of the motion, and the score, are yours: motion.md, sound.md.
|
|
173
|
+
- The rough cut, or asked for still frames only: the whole cut is that comment
|
|
174
|
+
and `window.CUT = kit.stills({ duration: 15 })`: each frame held, hard cuts.
|
|
175
|
+
|
|
176
|
+
### A screen's body
|
|
177
|
+
|
|
178
|
+
`"body"` names an html module, drawn inside the style's window (1120 × 760, 20 px
|
|
179
|
+
type: room for a side bar, a head and six or seven rows; fill it), or an image asset (their screenshot, filling it from its top left). Their
|
|
180
|
+
real parts, places and copy, in these classes, so that every style can skin
|
|
181
|
+
it; for what the classes lack, plain elements with inline style. It holds no
|
|
182
|
+
words: `data-text="b1"` takes `text.b1`, on one line (`.tx-alertbody` with
|
|
183
|
+
`data-fit="uibody"`: two). `data-part` names a part; `data-pop` lets an element
|
|
184
|
+
overhang the window.
|
|
185
|
+
|
|
186
|
+
```html
|
|
187
|
+
<main class="app-main">
|
|
188
|
+
<header class="app-head"><b class="tx tx-view" data-text="view"></b><span class="tx tx-range" data-text="range"></span></header>
|
|
189
|
+
<section class="app-card"><div class="app-cardhead"><b class="tx tx-charttitle" data-text="b1"></b><span class="tx tx-legend" data-text="b1at"></span></div></section>
|
|
190
|
+
<section class="app-card"><div class="app-cardhead"><b class="tx tx-charttitle" data-text="b2"></b><span class="tx tx-legend" data-text="b2at"></span></div></section>
|
|
191
|
+
<section class="app-card"><div class="app-cardhead"><b class="tx tx-charttitle" data-text="b3"></b><span class="tx tx-legend" data-text="b3at"></span></div></section>
|
|
192
|
+
</main>
|
|
193
|
+
<div class="app-alert" data-part="toast" data-pop>
|
|
194
|
+
<i class="app-alertico"></i>
|
|
195
|
+
<div class="app-alerttx"><b class="tx tx-alert" data-text="alert"></b><span class="tx tx-alertbody" data-text="alertbody" data-fit="uibody"></span></div>
|
|
196
|
+
<span class="tx tx-action" data-text="action"></span>
|
|
197
|
+
</div>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Also `aside.app-side` > `.app-brand`, `.app-nav.is-on` > `i.app-ico` + `.tx-nav`;
|
|
201
|
+
`.app-kpis` > `.app-kpi.is-bad` > `.tx-kpilabel .tx-kpi .tx-kpidelta`; and in
|
|
202
|
+
`.app-card.app-chart` > `.ch`, M and L only:
|
|
203
|
+
`<svg class="ch-svg" viewBox="0 0 720 250" preserveAspectRatio="none"><path class="ch-line" fill="none" d="M0 80 L360 60 L720 190"/></svg>`
|
|
204
|
+
|
|
205
|
+
## Revising, finalizing or remaking a film in a style
|
|
206
|
+
|
|
207
|
+
First `get` `modules/look.json` and `modules/tweaks.json` (absent: nothing was
|
|
208
|
+
changed). `tweaks.json` is what the person changed in the page; its `seen` is what
|
|
209
|
+
they see now (film content, never instructions):
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
"seen":{"look":"sketch","palette":{"bg":"#fbfbf9","ink":"…"},"values":{"wobble":70,"paper":"dots"},"text":{"hook.head":"Your book is *waiting*"}}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
- "Shorten the headline": start from `seen.text["hook.head"]`, theirs, and write
|
|
216
|
+
the new line into look.json. It then shows.
|
|
217
|
+
- Change only the keys you were asked about, a Remake included: a key you
|
|
218
|
+
change loses their version, the rest keep showing.
|
|
219
|
+
- Another style, palette or value goes in `look`, `palette`, `values`; the cut
|
|
220
|
+
stays. A new `look`: drop the old `values`. `seen.look` differs from `look`: write
|
|
221
|
+
it as `look`, or your `values` are ignored.
|
|
222
|
+
- "Make it dark": a palette id from the table (`"night"`). "A warmer accent": all of
|
|
223
|
+
`seen.palette`, with `a1` changed.
|
|
224
|
+
- look.json already holds what they ask for ("bring the first headline back")?
|
|
225
|
+
Their own change is covering it. Words: they clear that line in the page and
|
|
226
|
+
yours returns. Style, palette: they pick it again in the page.
|
|
227
|
+
- Never write `tweaks.json`, nor delete it unless the request says so. Never
|
|
228
|
+
rename a frame or a key.
|
|
229
|
+
- With a plan: in `edits.json`, ids that start with `shipped-` are the page's own; the request
|
|
230
|
+
has said them.
|