@bitmagic/cli 0.1.65-dev.24 → 0.1.65-dev.4

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.
Files changed (62) hide show
  1. package/README.md +18 -106
  2. package/dist/assets/materials.d.ts +0 -9
  3. package/dist/assets/materials.js +2 -10
  4. package/dist/assets/materials.js.map +1 -1
  5. package/dist/cli.d.ts +0 -1
  6. package/dist/cli.js +0 -2
  7. package/dist/cli.js.map +1 -1
  8. package/dist/commands/forge.js +23 -39
  9. package/dist/commands/forge.js.map +1 -1
  10. package/dist/commands/generate.d.ts +13 -31
  11. package/dist/commands/generate.js +56 -48
  12. package/dist/commands/generate.js.map +1 -1
  13. package/dist/commands/trailer.js +1 -1
  14. package/dist/commands/trailer.js.map +1 -1
  15. package/dist/editor/animation-preview-page.js +1 -88
  16. package/dist/editor/animation-preview-page.js.map +1 -1
  17. package/dist/editor/asset-detail-panel.d.ts +2 -2
  18. package/dist/editor/asset-detail-panel.js +0 -21
  19. package/dist/editor/asset-detail-panel.js.map +1 -1
  20. package/dist/editor/asset-viewer.js +8 -31
  21. package/dist/editor/asset-viewer.js.map +1 -1
  22. package/dist/editor/shell-page.js +1 -63
  23. package/dist/editor/shell-page.js.map +1 -1
  24. package/dist/mobile/asset-hosts.d.ts +9 -7
  25. package/dist/mobile/asset-hosts.js +16 -7
  26. package/dist/mobile/asset-hosts.js.map +1 -1
  27. package/dist/scaffold/blender-level-skill-files.js +2 -3
  28. package/dist/scaffold/blender-level-skill-files.js.map +1 -1
  29. package/dist/scaffold/claude-settings.js +0 -4
  30. package/dist/scaffold/claude-settings.js.map +1 -1
  31. package/dist/scaffold/project-files.js +12 -18
  32. package/dist/scaffold/project-files.js.map +1 -1
  33. package/dist/scaffold/project.js +1 -4
  34. package/dist/scaffold/project.js.map +1 -1
  35. package/dist/scaffold/skill-files.d.ts +5 -32
  36. package/dist/scaffold/skill-files.js +63 -102
  37. package/dist/scaffold/skill-files.js.map +1 -1
  38. package/dist/telemetry/creator-prompt.d.ts +2 -18
  39. package/dist/telemetry/creator-prompt.js +3 -24
  40. package/dist/telemetry/creator-prompt.js.map +1 -1
  41. package/dist/telemetry/report.js +16 -31
  42. package/dist/telemetry/report.js.map +1 -1
  43. package/package.json +4 -4
  44. package/assets/skills/trailer-craft.md +0 -180
  45. package/dist/commands/character.d.ts +0 -18
  46. package/dist/commands/character.js +0 -268
  47. package/dist/commands/character.js.map +0 -1
  48. package/dist/forge/prune-store.d.ts +0 -46
  49. package/dist/forge/prune-store.js +0 -86
  50. package/dist/forge/prune-store.js.map +0 -1
  51. package/dist/forge/remote-store.d.ts +0 -36
  52. package/dist/forge/remote-store.js +0 -113
  53. package/dist/forge/remote-store.js.map +0 -1
  54. package/dist/generate/character-body.d.ts +0 -79
  55. package/dist/generate/character-body.js +0 -100
  56. package/dist/generate/character-body.js.map +0 -1
  57. package/dist/project/character-search.d.ts +0 -30
  58. package/dist/project/character-search.js +0 -82
  59. package/dist/project/character-search.js.map +0 -1
  60. package/dist/scaffold/asset-pipeline-skill-files.d.ts +0 -42
  61. package/dist/scaffold/asset-pipeline-skill-files.js +0 -207
  62. package/dist/scaffold/asset-pipeline-skill-files.js.map +0 -1
@@ -40,9 +40,8 @@ export declare function creatorPromptField(override?: unknown): {
40
40
  /** `body` plus the creator's own words, when the flag was given and telemetry is on. */
41
41
  export declare function withParent(body: Record<string, unknown>): Record<string, unknown>;
42
42
  /**
43
- * The creator's ask as an opaque, stable dedupe key — what a game's "Built with N prompts" is
44
- * counted on, so the COUNT never depends on storing anybody's words. (The beacon also carries the
45
- * words themselves in {@link creatorAskText}, for a channel that shows them and stores nothing.)
43
+ * The creator's ask as an opaque, stable dedupe key — what the command beacon sends so
44
+ * api-server can count "prompts this game was built with" without ever being told the text.
46
45
  *
47
46
  * The CLI is the ONLY producer of this value. api-server stores it and compares it to other
48
47
  * values from this same function; it never recomputes one from text, so the two sides cannot
@@ -57,18 +56,3 @@ export declare function withParent(body: Record<string, unknown>): Record<string
57
56
  * `--original-prompt` produces — the count is a floor, never an overcount.
58
57
  */
59
58
  export declare function creatorAskDigest(override?: unknown): string | undefined;
60
- /**
61
- * The creator's ask as TEXT, bounded for a wire that has a body limit.
62
- *
63
- * The beacon carries this so the live-prompts Slack channel can show what an
64
- * agent is being asked for on the commands that send no prompt anywhere else —
65
- * `build`, `verify`, `dev`, `reload`, `publish` — which are most of what
66
- * building a GDK project consists of. api-server posts it and never stores it:
67
- * the count still runs on {@link creatorAskDigest}, and no prompt text reaches
68
- * Postgres.
69
- *
70
- * Capped by the same rule the digest hashes under, so the two always describe
71
- * the same words. `DO_NOT_TRACK` drops it upstream in `beginCommand`, like
72
- * every other field here.
73
- */
74
- export declare function creatorAskText(override?: unknown): string | undefined;
@@ -52,9 +52,8 @@ export function withParent(body) {
52
52
  return 'creatorPrompt' in field ? { ...body, ...field } : body;
53
53
  }
54
54
  /**
55
- * The creator's ask as an opaque, stable dedupe key — what a game's "Built with N prompts" is
56
- * counted on, so the COUNT never depends on storing anybody's words. (The beacon also carries the
57
- * words themselves in {@link creatorAskText}, for a channel that shows them and stores nothing.)
55
+ * The creator's ask as an opaque, stable dedupe key — what the command beacon sends so
56
+ * api-server can count "prompts this game was built with" without ever being told the text.
58
57
  *
59
58
  * The CLI is the ONLY producer of this value. api-server stores it and compares it to other
60
59
  * values from this same function; it never recomputes one from text, so the two sides cannot
@@ -69,29 +68,9 @@ export function withParent(body) {
69
68
  * `--original-prompt` produces — the count is a floor, never an overcount.
70
69
  */
71
70
  export function creatorAskDigest(override) {
72
- const text = creatorAskText(override);
73
- if (text === undefined)
74
- return undefined;
75
- return createHash('sha256').update(text).digest('hex').slice(0, 16);
76
- }
77
- /**
78
- * The creator's ask as TEXT, bounded for a wire that has a body limit.
79
- *
80
- * The beacon carries this so the live-prompts Slack channel can show what an
81
- * agent is being asked for on the commands that send no prompt anywhere else —
82
- * `build`, `verify`, `dev`, `reload`, `publish` — which are most of what
83
- * building a GDK project consists of. api-server posts it and never stores it:
84
- * the count still runs on {@link creatorAskDigest}, and no prompt text reaches
85
- * Postgres.
86
- *
87
- * Capped by the same rule the digest hashes under, so the two always describe
88
- * the same words. `DO_NOT_TRACK` drops it upstream in `beginCommand`, like
89
- * every other field here.
90
- */
91
- export function creatorAskText(override) {
92
71
  const field = creatorPromptField(override);
93
72
  if (!('creatorPrompt' in field))
94
73
  return undefined;
95
- return field.creatorPrompt.slice(0, MAX_ASK_CHARS);
74
+ return createHash('sha256').update(field.creatorPrompt.slice(0, MAX_ASK_CHARS)).digest('hex').slice(0, 16);
96
75
  }
97
76
  //# sourceMappingURL=creator-prompt.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"creator-prompt.js","sourceRoot":"","sources":["../../src/telemetry/creator-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,sGAAsG;AACtG,MAAM,aAAa,GAAG,IAAI,CAAC;AAE3B,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,oFAAoF;UAC7F,iEAAiE;CAC7D,CAAC;AAEX;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAkB;IACnD,MAAM,KAAK,GAAG,QAAQ,IAAI,cAAc,EAAE,EAAE,aAAa,CAAC;IAC1D,oFAAoF;IACpF,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACrG,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,UAAU,CAAC,IAA6B;IACtD,MAAM,KAAK,GAAG,kBAAkB,EAAE,CAAC;IACnC,gGAAgG;IAChG,8FAA8F;IAC9F,OAAO,eAAe,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACjE,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAkB;IACjD,MAAM,IAAI,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IACtC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACzC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACtE,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,QAAkB;IAC/C,MAAM,KAAK,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,CAAC,CAAC,eAAe,IAAI,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAClD,OAAO,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;AACrD,CAAC"}
1
+ {"version":3,"file":"creator-prompt.js","sourceRoot":"","sources":["../../src/telemetry/creator-prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,sGAAsG;AACtG,MAAM,aAAa,GAAG,IAAI,CAAC;AAE3B,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,oFAAoF;UAC7F,iEAAiE;CAC7D,CAAC;AAEX;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAkB;IACnD,MAAM,KAAK,GAAG,QAAQ,IAAI,cAAc,EAAE,EAAE,aAAa,CAAC;IAC1D,oFAAoF;IACpF,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACrG,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,UAAU,CAAC,IAA6B;IACtD,MAAM,KAAK,GAAG,kBAAkB,EAAE,CAAC;IACnC,gGAAgG;IAChG,8FAA8F;IAC9F,OAAO,eAAe,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACjE,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAkB;IACjD,MAAM,KAAK,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,CAAC,CAAC,eAAe,IAAI,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAClD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC7G,CAAC"}
@@ -16,19 +16,11 @@
16
16
  * bounded to {@link REPORT_TIMEOUT_MS} per request so a finished command is
17
17
  * never held open by a sulking network (the same reasoning as
18
18
  * update/check.ts). It never prints.
19
- * 2. Its ANALYTICS are categories, never messages: the command name, ok/failed,
20
- * the exit code, a `CliError.code`, and a duration. A message can name a
21
- * path; that does not belong in an analytics event. The game id keeps the
22
- * rule (it is an id we minted) and so does the ask DIGEST (opaque by
23
- * construction), and neither reaches GA4.
24
- *
25
- * `creatorPrompt` is the one field that carries words, and it is not
26
- * analytics: api-server posts it to an internal Slack channel and stores it
27
- * nowhere — not GA4, not Postgres, not BigQuery. It is here because the
28
- * commands that send prompt text to a route are the generators, and an
29
- * agent building a GDK project spends most of its commands on the offline
30
- * ones. `DO_NOT_TRACK` drops it with everything else. See
31
- * {@link CommandProvenance}.
19
+ * 2. It sends categories, never messages: the command name, ok/failed, the
20
+ * exit code, a `CliError.code`, and a duration. A message can name a path;
21
+ * that does not belong in an analytics event. The two later additions keep
22
+ * the rule: the project's game id is an id we minted, and the creator's ask
23
+ * travels as an opaque DIGEST, never its words. See {@link CommandProvenance}.
32
24
  * 3. It is authenticated with the creator's own token, so the server can key
33
25
  * the event to the account and look up their real Pro state. No token, no
34
26
  * report — an anonymous beacon would be a spammable endpoint for nothing.
@@ -40,7 +32,7 @@ import { resolveAuth0ClientId } from '../config/environments.js';
40
32
  import { getAccessToken } from '../auth/session.js';
41
33
  import { readProjectGameIdOrNull } from '../project/context.js';
42
34
  import { apiServerHeaders } from './request-headers.js';
43
- import { creatorAskDigest, creatorAskText } from './creator-prompt.js';
35
+ import { creatorAskDigest } from './creator-prompt.js';
44
36
  import { currentCommand, isTelemetryDisabled } from './command-context.js';
45
37
  // Re-exported because this is where the opt-out is enforced for a report that is already
46
38
  // under way; `beginCommand` consults the same predicate to skip collecting anything at all.
@@ -93,28 +85,21 @@ function defaultDeps() {
93
85
  return { fetch: globalThis.fetch, env: process.env };
94
86
  }
95
87
  /**
96
- * The game and the ask, when this command has either. Keys are omitted rather than sent as null:
97
- * api-server validates the body strictly, and an absent key is how "nothing to say" is spelled
98
- * everywhere else on this wire.
99
- *
100
- * Nothing is present unless the command declared `--original-prompt` AND the agent passed it —
101
- * `creatorAskDigest` reads the value `beginCommand` captured, which is also where `DO_NOT_TRACK`
102
- * already dropped it.
88
+ * The game and the ask, when this command has either. Both keys are omitted rather than sent as
89
+ * null: api-server validates the body strictly, and an absent key is how "nothing to say" is
90
+ * spelled everywhere else on this wire.
103
91
  *
104
- * `gameId` and `askDigest` are only sent TOGETHER: a digest with no game cannot be counted, and a
105
- * game with no digest is not an ask. `creatorPrompt` is independent of that pair, because the
106
- * channel it feeds wants the ask from a command run before a game exists just as much — the pair
107
- * is about counting, and counting needs a game to count against.
92
+ * The digest is only ever present when the command declared `--original-prompt` AND the agent
93
+ * passed it — `creatorAskDigest` reads the value `beginCommand` captured, which is also where
94
+ * `DO_NOT_TRACK` already dropped it. The pair is only sent together: a digest with no game
95
+ * cannot be counted, and a game with no digest is not an ask.
108
96
  */
109
97
  function provenance(deps) {
110
- const creatorPrompt = creatorAskText();
111
- if (creatorPrompt === undefined)
98
+ const askDigest = creatorAskDigest();
99
+ if (askDigest === undefined)
112
100
  return {};
113
101
  const gameId = readProjectGameIdOrNull(deps.cwd);
114
- const askDigest = creatorAskDigest();
115
- if (gameId === undefined || askDigest === undefined)
116
- return { creatorPrompt };
117
- return { creatorPrompt, gameId, askDigest };
102
+ return gameId === undefined ? {} : { gameId, askDigest };
118
103
  }
119
104
  /**
120
105
  * Report the running command's `report` to api-server. Resolves when the report
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/telemetry/report.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/telemetry/report.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitmagic/cli",
3
- "version": "0.1.65-dev.24",
3
+ "version": "0.1.65-dev.4",
4
4
  "description": "Build Bitmagic games from your own agent tool",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "Bitmagic Oy",
@@ -25,9 +25,9 @@
25
25
  "playwright-core": "^1.59.1",
26
26
  "tar": "^7.4.3",
27
27
  "ws": "^8.21.3",
28
- "@bitmagic/animation-forger": "0.1.20-dev.24",
29
- "@bitmagic/asset-core": "0.2.20-dev.24",
30
- "@bitmagic/world-forger": "0.1.25-dev.24"
28
+ "@bitmagic/animation-forger": "0.1.20-dev.4",
29
+ "@bitmagic/world-forger": "0.1.25-dev.4",
30
+ "@bitmagic/asset-core": "0.2.20-dev.4"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@eslint/js": "^9.38.0",
@@ -1,180 +0,0 @@
1
- # Trailer craft — structure, pacing, and on-screen text
2
-
3
- Read this before composing a cut or putting any text on screen. Compressed
4
- from Derek Lieu's trailer-editing essays (trailer editor for Half-Life: Alyx,
5
- Dead Cells, Spelunky 2) plus general trailer-typography guidance; sources at
6
- the bottom.
7
-
8
- ## Ordering: Genre → Hook → Anchors → Content
9
-
10
- - **Genre** in 1–2 shots: the viewer must know what kind of game this is
11
- within the first seconds. For our games one gameplay shot usually does it.
12
- - **Hook** — the thing only this game has — as soon as genre is established:
13
- ideally inside the first 10–15 s, never later than the first third.
14
- Showing generic-but-good content before the hook makes the game read as
15
- "a lesser version of an old game".
16
- - **Anchors** — the features people expect from the genre (for a racer:
17
- overtakes, drifts, crashes, varied tracks) fill the middle.
18
- - **Content** — breadth (levels, modes, vehicles) comes last, once the viewer
19
- already cares.
20
-
21
- ## Timeline layout: constraints first, footage last
22
-
23
- Lay the timeline out as a skeleton and only then hunt for footage — not the
24
- other way round:
25
-
26
- 1. Write the section skeleton: **Cold open → Introduction → Escalation →
27
- Climax → Breath → Button/End card**. Sections have different lengths and
28
- energy; they are not equal slices.
29
- 2. Reserve the **end card** first: 2–3 s, ONE card (logo + tagline + CTA),
30
- never a sequence of closing screens.
31
- 3. Place any **body title cards** next, as placeholders with their copy
32
- written — each one names what the following footage must prove.
33
- 4. Only now fill footage, chosen to demonstrate whatever the neighbouring
34
- card or section claims.
35
-
36
- This turns "pick 15 great clips" (squishy, drifts toward sameness) into
37
- "find the one clip that proves this beat" (constrained, self-diversifying).
38
-
39
- ## Pacing
40
-
41
- - Sections need **ebb and flow**: build to a peak, then give a deliberate
42
- breathing shot (~5 s, calmer, wider) before the next build or the finale.
43
- The stops emphasize the fast; the fast emphasizes the slow.
44
- - **Rule of three**: never more than three similar things in a row — three
45
- crashes, three drift shots, three of anything. Viewers extrapolate after
46
- two; the fourth is dead time.
47
- - **Do not cut on every beat.** Snap cuts to the grid, but vary clip lengths
48
- (2, 3, 4, 6 beats) and sometimes let a musical moment land on an in-clip
49
- action (a landing, an impact) instead of a cut. Constant per-beat cutting
50
- reads as a sizzle reel, and gets nauseating.
51
- - Average shot length is a genre statement: ~1.3 s reads as AAA shooter,
52
- ~4 s reads as contemplative indie. An arcade racer sits around 1.5–3 s
53
- with a few longer holds where one continuous action is the payoff.
54
- - **More editing is not better editing.** A cut must clarify or escalate;
55
- cutting fast to look "like a real trailer" hides the game. If a single
56
- take shows the whole stunt, keep the take.
57
- - Total length: under 90 s unless there's a reason; 30–45 s is a sweet spot
58
- for social/store use.
59
-
60
- ## Variety — the five axes
61
-
62
- Audit the cut on each axis; the labels list in the shots file is the tool
63
- (read the labels top to bottom — repetition is visible in text before you
64
- ever re-watch):
65
-
66
- 1. **Content** — different actions, not the same action in new places.
67
- Escalate variants (jump → bigger jump) rather than repeating.
68
- 2. **Composition** — vary camera distance and framing; chase cam all the way
69
- through is monotone. Watch eye-trace: the viewer's focus point should not
70
- teleport across the frame on a cut.
71
- 3. **Energy** — intense vs. quiet moments; contrast matters more than speed.
72
- 4. **Pacing** — vary section tempo, not just shot tempo.
73
- 5. **Shot length** — vary beats-per-clip even inside a fast section.
74
-
75
- ## Where the shots come from
76
-
77
- Played footage is the default and the bulk of any trailer: it is the only
78
- thing that shows what the game DOES, and a trailer of pure scenery reads as a
79
- tech demo however pretty it is. But two of the beats above are ones a chase
80
- camera almost never hands you:
81
-
82
- - the **cold open**, which wants the level to look composed and deliberate;
83
- - the **breath**, which wants one calm wide shot with nothing happening.
84
-
85
- Both are what an authored **camera fly-through** is for — a path through the
86
- level with the game running underneath, so traffic still drives and animations
87
- still play while the camera moves on rails. Recording one is cheap and nobody
88
- has to play it, so a fly-through is worth having even when there is plenty of
89
- gameplay: cut one or two of its shots into a gameplay trailer rather than
90
- building a trailer out of it.
91
-
92
- A fly-through alone is the right whole trailer in a narrow set of cases — a
93
- world reveal, an architectural or exploration piece, a level that is the
94
- feature — and whenever there is no one available to play. Otherwise it is a
95
- source of shots, not a substitute for showing the game.
96
-
97
- ## On-screen text
98
-
99
- When to use text at all: only when footage cannot say it. A card that
100
- narrates what the next shot visibly shows is noise. Default for our
101
- gameplay trailers: **end card only**; add body cards only when they carry
102
- information the footage can't (game name early, a hook that isn't visual,
103
- release date).
104
-
105
- Writing the cards:
106
- - Copy must sound like this game and no other. Exercise: describe the game
107
- in three words; build cards from what's left after cutting everything
108
- generic.
109
- - ≤ 6 words per card. Evocative verbs beat feature lists ("Forge your own
110
- path", not "Over 40 unique tracks").
111
- - Banned: content quantities ("5 unique levels"), genre-descriptor stacks
112
- ("a 2D rogue-lite action adventure"), player-verb lists ("Race! Drift!
113
- Win!"), and stock phrases ("In a world…", "Get ready…", "Experience…",
114
- "…like never before").
115
-
116
- Showing the cards:
117
- - **Intercut, don't overlay**: a card gets its own beat between gameplay
118
- shots (dimmed still or plain background). Never ask the viewer to read
119
- while action plays — they do neither. Small persistent text (logo bug,
120
- date) is the exception.
121
- - Reading time: ~0.5–0.7 s per word, minimum 2.5 s on screen; end card
122
- 2–3 s (ours may run longer over a music outro).
123
- - Cards ride the same beat grid as the cuts — a card is a clip.
124
- - Typography must match the game's art quality and universe: one typeface
125
- family for the whole trailer, generous letter-spacing for all-caps,
126
- strong contrast against footage (our title raster already adds shadow),
127
- subtle animation only (fade/scale-in) — a static default-font card reads
128
- as a last-minute add-on.
129
-
130
- ## Structure template (30–45 s, gameplay-only, end card close)
131
-
132
- | Section | ~share | What goes here |
133
- |---|---|---|
134
- | Cold open | 5–15% | The single most striking moment; genre obvious at a glance |
135
- | Introduction | 15–20% | Clean, readable driving; establish look + one anchor |
136
- | Escalation | 35–45% | Varied action, rising energy, hook prominent early in it |
137
- | Climax | 15–20% | Densest, loudest stretch; biggest moments back to back |
138
- | Breath | ~5% | One calmer, wider shot; lets the climax land |
139
- | End card | 2–3 s+ | Logo, tagline, CTA — over the music's outro |
140
-
141
- ## Selection rules already paid for
142
-
143
- These came out of review rounds on real cuts. They cost time to learn and
144
- nothing to apply, so apply them before the first render, not after.
145
-
146
- - **Never use slow motion.** On gameplay footage it reads as the game running
147
- at a low framerate, not as drama. `speed` stays 1.0.
148
- - **Numbers are not interest.** Event `severity` / `impactSpeed` ranks
149
- car-stops-dead-against-a-wall highest — the worst possible clip. A crash
150
- earns its slot only if things visibly break (`destruction` events, debris)
151
- and motion continues through the hit.
152
- - **Low speed can BE the drama.** Wheelspin recoveries throwing dirt or snow,
153
- plowing back onto the track, being overtaken while struggling
154
- (`position-change` with `gained: false`), `off-track` +
155
- `hard-acceleration` clusters — these are among the best clips and score
156
- near zero on any speed metric.
157
- - **"Some shots of X" means a few.** The failure mode is 0-or-100: one
158
- standing start is an opener, five is a broken trailer.
159
- - **Quota check before rendering.** Read the shots list labels top to bottom.
160
- Max one standing start; no more than three of any shot type in the whole
161
- cut and never three similar in a row; vary track or biome, camera distance
162
- and action type (the five axes above).
163
- - **Menu and selection clips need `"ui": false`** — the HUD replay only knows
164
- the gameplay HUD and will paint it over menus.
165
- - **Verify on pixels.** Contact sheets and stills for every candidate, and
166
- stills from the RENDERED file for anything you changed. The timeline knows
167
- about events; it cannot see framing, occlusion or beauty.
168
- - **Iterate cheaply, keep history.** Editing the shots and re-rendering is
169
- minutes, and revisions auto-version — so render rather than debate, and
170
- compare against the previous `-rN` before delivering.
171
-
172
- ## Sources
173
-
174
- - [How to Hook the Audience and How Quickly to Do it](https://www.derek-lieu.com/blog/2022/10/24/how-to-hook-the-audience-and-how-quickly-to-do-it)
175
- - [Step Two of Starting a Game Trailer Timeline](https://www.derek-lieu.com/blog/2023/2/19/step-two-of-starting-a-game-trailer-timeline)
176
- - [How to Think About Pacing in a Trailer](https://www.derek-lieu.com/blog/2020/11/16/how-to-think-about-pacing-in-a-trailer)
177
- - [Variety is the Spice of Trailers](https://www.derek-lieu.com/blog/2019/3/27/variety-is-the-spice-of-trailers)
178
- - [More Trailer Editing is not Better Trailer Editing](https://www.derek-lieu.com/blog/2023/4/23/more-trailer-editing-is-not-better-trailer-editing)
179
- - [How to Write Trailer Title Cards With Strong Messaging](https://www.derek-lieu.com/blog/2020/4/19/how-to-write-trailer-title-cards-with-strong-messaging)
180
- - [10 Common Indie Game Trailer Mistakes & How to Fix Them](https://www.derek-lieu.com/blog/2020/9/14/10-common-indie-game-trailer-mistakes-and-how-to-fix-them)
@@ -1,18 +0,0 @@
1
- import { type CharacterSearchRecord } from '../project/character-search.js';
2
- import { type CharacterArgs } from '../generate/character-body.js';
3
- /**
4
- * What `bitmagic character add` will ask for, from its flags and the cached search.
5
- *
6
- * Pure, and separated from the command so the branch that matters — which of the
7
- * two forms was asked for, and whether the cache can answer it — is testable
8
- * without a project, a token or a network. It returns the character args rather
9
- * than a body so the shared `buildCharacterBody` still owns the wire shape.
10
- */
11
- export declare function resolveAddRequest(args: {
12
- name: string;
13
- id?: string;
14
- prompt?: string;
15
- applyToPlayer?: boolean;
16
- record: CharacterSearchRecord | null;
17
- }): CharacterArgs;
18
- export declare const characterCommand: import("citty").CommandDef<import("citty").ArgsDef>;