@bitmagic/cli 0.1.65-dev.23 → 0.1.65-dev.3
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 +14 -137
- package/dist/assets/materials.d.ts +0 -9
- package/dist/assets/materials.js +2 -10
- package/dist/assets/materials.js.map +1 -1
- package/dist/cli.d.ts +0 -9
- package/dist/cli.js +0 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/forge.d.ts +0 -15
- package/dist/commands/forge.js +38 -143
- package/dist/commands/forge.js.map +1 -1
- package/dist/commands/generate.d.ts +13 -31
- package/dist/commands/generate.js +56 -48
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/trailer.js +1 -1
- package/dist/commands/trailer.js.map +1 -1
- package/dist/editor/animation-preview-page.js +1 -88
- package/dist/editor/animation-preview-page.js.map +1 -1
- package/dist/editor/asset-detail-panel.d.ts +2 -2
- package/dist/editor/asset-detail-panel.js +0 -21
- package/dist/editor/asset-detail-panel.js.map +1 -1
- package/dist/editor/asset-viewer.js +8 -31
- package/dist/editor/asset-viewer.js.map +1 -1
- package/dist/editor/shell-page.js +1 -63
- package/dist/editor/shell-page.js.map +1 -1
- package/dist/forge/run-pipeline.js +1 -5
- package/dist/forge/run-pipeline.js.map +1 -1
- package/dist/forge/stream.d.ts +1 -5
- package/dist/forge/stream.js +0 -4
- package/dist/forge/stream.js.map +1 -1
- package/dist/mobile/asset-hosts.d.ts +9 -7
- package/dist/mobile/asset-hosts.js +16 -7
- package/dist/mobile/asset-hosts.js.map +1 -1
- package/dist/scaffold/blender-level-skill-files.js +2 -3
- package/dist/scaffold/blender-level-skill-files.js.map +1 -1
- package/dist/scaffold/claude-settings.js +0 -4
- package/dist/scaffold/claude-settings.js.map +1 -1
- package/dist/scaffold/project-files.js +12 -18
- package/dist/scaffold/project-files.js.map +1 -1
- package/dist/scaffold/project.js +1 -4
- package/dist/scaffold/project.js.map +1 -1
- package/dist/scaffold/skill-files.d.ts +5 -32
- package/dist/scaffold/skill-files.js +63 -102
- package/dist/scaffold/skill-files.js.map +1 -1
- package/dist/telemetry/creator-prompt.d.ts +2 -18
- package/dist/telemetry/creator-prompt.js +3 -24
- package/dist/telemetry/creator-prompt.js.map +1 -1
- package/dist/telemetry/report.js +16 -31
- package/dist/telemetry/report.js.map +1 -1
- package/package.json +4 -4
- package/assets/skills/trailer-craft.md +0 -180
- package/dist/commands/character.d.ts +0 -18
- package/dist/commands/character.js +0 -268
- package/dist/commands/character.js.map +0 -1
- package/dist/forge/edit-target.d.ts +0 -30
- package/dist/forge/edit-target.js +0 -88
- package/dist/forge/edit-target.js.map +0 -1
- package/dist/forge/prune-store.d.ts +0 -46
- package/dist/forge/prune-store.js +0 -86
- package/dist/forge/prune-store.js.map +0 -1
- package/dist/forge/remote-store.d.ts +0 -36
- package/dist/forge/remote-store.js +0 -113
- package/dist/forge/remote-store.js.map +0 -1
- package/dist/generate/character-body.d.ts +0 -79
- package/dist/generate/character-body.js +0 -100
- package/dist/generate/character-body.js.map +0 -1
- package/dist/project/character-search.d.ts +0 -30
- package/dist/project/character-search.js +0 -82
- package/dist/project/character-search.js.map +0 -1
- package/dist/scaffold/asset-pipeline-skill-files.d.ts +0 -42
- package/dist/scaffold/asset-pipeline-skill-files.js +0 -207
- package/dist/scaffold/asset-pipeline-skill-files.js.map +0 -1
|
@@ -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
|
|
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"}
|
package/dist/telemetry/report.js
CHANGED
|
@@ -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.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* rule
|
|
23
|
-
*
|
|
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
|
|
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.
|
|
97
|
-
* api-server validates the body strictly, and an absent key is how "nothing to say" is
|
|
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
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
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
|
|
111
|
-
if (
|
|
98
|
+
const askDigest = creatorAskDigest();
|
|
99
|
+
if (askDigest === undefined)
|
|
112
100
|
return {};
|
|
113
101
|
const gameId = readProjectGameIdOrNull(deps.cwd);
|
|
114
|
-
|
|
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":"AAAA
|
|
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.
|
|
3
|
+
"version": "0.1.65-dev.3",
|
|
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/
|
|
29
|
-
"@bitmagic/
|
|
30
|
-
"@bitmagic/
|
|
28
|
+
"@bitmagic/animation-forger": "0.1.20-dev.3",
|
|
29
|
+
"@bitmagic/asset-core": "0.2.20-dev.3",
|
|
30
|
+
"@bitmagic/world-forger": "0.1.25-dev.3"
|
|
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>;
|
|
@@ -1,268 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `bitmagic character` — make one, look through the ready-made ones, or add one.
|
|
3
|
-
*
|
|
4
|
-
* Its own noun group rather than three flags on `bitmagic generate character`,
|
|
5
|
-
* because the shelf and the forge are two different requests that happened to
|
|
6
|
-
* share a command:
|
|
7
|
-
*
|
|
8
|
-
* generate costs sparks, makes a new body, may substitute a close stored one
|
|
9
|
-
* search free, read-only, shows what the shelf has and how close it is
|
|
10
|
-
* add free, puts a stored body in the game, never forges
|
|
11
|
-
*
|
|
12
|
-
* The old surface expressed "add" as `generate character --library-only`, a
|
|
13
|
-
* command that generates nothing, and it carried two flags that existed only to
|
|
14
|
-
* be refused on that path (`--head-scale` was accepted, reported and dropped;
|
|
15
|
-
* `--mesh-model` was rejected outright). Both refusals disappear here, because a
|
|
16
|
-
* command that never forges simply does not offer the flags that pick how a
|
|
17
|
-
* forge runs.
|
|
18
|
-
*
|
|
19
|
-
* `search` exists because no similarity floor can do this job. Measured against
|
|
20
|
-
* the live index, genuine matches score 0.624-0.831 while humanoid prompts the
|
|
21
|
-
* shelf cannot answer score 0.552-0.698 — overlapping, so a threshold that keeps
|
|
22
|
-
* the good ones keeps "a humanoid bee" for "a beekeeper" too. A person reading
|
|
23
|
-
* three captions settles in a second what a number cannot settle at all.
|
|
24
|
-
*/
|
|
25
|
-
import { defineCommand } from 'citty';
|
|
26
|
-
import { CliError } from '../errors.js';
|
|
27
|
-
import { createOutput } from '../output.js';
|
|
28
|
-
import { apiGet } from '../http/client.js';
|
|
29
|
-
import { resolveArtStyle } from '../project/art-style.js';
|
|
30
|
-
import { findCachedCandidate, readCharacterSearch, writeCharacterSearch, } from '../project/character-search.js';
|
|
31
|
-
import { ORIGINAL_PROMPT_FLAG, withParent } from '../telemetry/creator-prompt.js';
|
|
32
|
-
import { JSON_FLAG, resolveRun, runAssetGeneration } from './generate.js';
|
|
33
|
-
import { APPLY_TO_PLAYER_ARG, buildCharacterBody, defaultVoxelizeForProject, FRESH_ARG, HEAD_SCALE_ARG, LIBRARY_ARG, MESH_MODEL_ARG, NAME_ARG, PROMPT_ARG, VOXELIZE_ARG, } from '../generate/character-body.js';
|
|
34
|
-
const generateCommand = defineCommand({
|
|
35
|
-
meta: {
|
|
36
|
-
name: 'generate',
|
|
37
|
-
description: 'Forge a new rigged character and add it to world.json assets. Costs sparks.',
|
|
38
|
-
},
|
|
39
|
-
args: {
|
|
40
|
-
name: NAME_ARG,
|
|
41
|
-
prompt: PROMPT_ARG,
|
|
42
|
-
'apply-to-player': APPLY_TO_PLAYER_ARG,
|
|
43
|
-
'head-scale': HEAD_SCALE_ARG,
|
|
44
|
-
fresh: FRESH_ARG,
|
|
45
|
-
library: LIBRARY_ARG,
|
|
46
|
-
voxelize: VOXELIZE_ARG,
|
|
47
|
-
'mesh-model': MESH_MODEL_ARG,
|
|
48
|
-
'original-prompt': ORIGINAL_PROMPT_FLAG,
|
|
49
|
-
json: JSON_FLAG,
|
|
50
|
-
},
|
|
51
|
-
async run({ args }) {
|
|
52
|
-
const body = buildCharacterBody({
|
|
53
|
-
name: args.name,
|
|
54
|
-
prompt: args.prompt,
|
|
55
|
-
applyToPlayer: args['apply-to-player'],
|
|
56
|
-
headScale: args['head-scale'],
|
|
57
|
-
fresh: args.fresh,
|
|
58
|
-
library: args.library,
|
|
59
|
-
voxelize: args.voxelize ?? defaultVoxelizeForProject(),
|
|
60
|
-
meshModel: args['mesh-model'],
|
|
61
|
-
});
|
|
62
|
-
await runAssetGeneration('character', 'character', withParent(body), args.json === true);
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
/** `62%` — the only form a similarity is ever shown in, so the table lines up. */
|
|
66
|
-
function percent(value) {
|
|
67
|
-
return `${Math.round(value * 100)}%`;
|
|
68
|
-
}
|
|
69
|
-
function renderCandidates(candidates, threshold, log) {
|
|
70
|
-
const width = Math.max(2, ...candidates.map((row) => row.sid.length));
|
|
71
|
-
log('');
|
|
72
|
-
log(` # ${'id'.padEnd(width)} match auto description`);
|
|
73
|
-
candidates.forEach((row, index) => {
|
|
74
|
-
// The "auto" column is why the floor is reported rather than applied: it
|
|
75
|
-
// says which of these automatic substitution would have taken, so a creator
|
|
76
|
-
// can see both that a body cleared the bar and that a weaker one exists.
|
|
77
|
-
const auto = row.similarity >= threshold ? ' yes' : ' -';
|
|
78
|
-
const label = row.subject ?? row.description ?? '';
|
|
79
|
-
log(` ${String(index + 1).padStart(1)} ${row.sid.padEnd(width)} ${percent(row.similarity).padStart(5)} ${auto} ${label.slice(0, 60)}`);
|
|
80
|
-
});
|
|
81
|
-
log('');
|
|
82
|
-
}
|
|
83
|
-
const searchCommand = defineCommand({
|
|
84
|
-
meta: {
|
|
85
|
-
name: 'search',
|
|
86
|
-
description: 'List the ready-made characters closest to a description. Free; changes nothing.',
|
|
87
|
-
},
|
|
88
|
-
args: {
|
|
89
|
-
prompt: {
|
|
90
|
-
type: 'string',
|
|
91
|
-
required: true,
|
|
92
|
-
description: 'What the character should look like.',
|
|
93
|
-
},
|
|
94
|
-
limit: {
|
|
95
|
-
type: 'string',
|
|
96
|
-
description: 'How many candidates to list, 1-16. Default 5.',
|
|
97
|
-
},
|
|
98
|
-
representation: {
|
|
99
|
-
type: 'string',
|
|
100
|
-
description: "Which shelf to search: 'voxel' or 'lowpoly'. Omit to follow the project's art style.",
|
|
101
|
-
},
|
|
102
|
-
json: JSON_FLAG,
|
|
103
|
-
},
|
|
104
|
-
async run({ args }) {
|
|
105
|
-
const json = args.json === true;
|
|
106
|
-
const { output, runDeps, context, environment, token } = await resolveRun(json);
|
|
107
|
-
const representation = (() => {
|
|
108
|
-
const asked = args.representation;
|
|
109
|
-
// `resolveArtStyle` also reports a game.json value that is neither word,
|
|
110
|
-
// which is the same note every other art-style-aware command prints.
|
|
111
|
-
if (asked === undefined)
|
|
112
|
-
return resolveArtStyle(context.root, output.info) === 'low-poly' ? 'lowpoly' : 'voxel';
|
|
113
|
-
if (asked !== 'voxel' && asked !== 'lowpoly') {
|
|
114
|
-
throw new CliError("--representation must be 'voxel' or 'lowpoly'.", 1, 'invalid_flag');
|
|
115
|
-
}
|
|
116
|
-
return asked;
|
|
117
|
-
})();
|
|
118
|
-
const query = new URLSearchParams({
|
|
119
|
-
gameId: context.metadata.gameId,
|
|
120
|
-
prompt: args.prompt,
|
|
121
|
-
representation,
|
|
122
|
-
});
|
|
123
|
-
if (args.limit !== undefined)
|
|
124
|
-
query.set('limit', args.limit);
|
|
125
|
-
const response = await apiGet(environment, `/api/cli/v1/characters/search?${query.toString()}`, token, runDeps);
|
|
126
|
-
// Written even when empty: "the shelf has nothing like this" is a result a
|
|
127
|
-
// re-run should not have to rediscover, and an empty cache makes `add --id`
|
|
128
|
-
// say "search first" rather than "no such id".
|
|
129
|
-
writeCharacterSearch(context.root, {
|
|
130
|
-
prompt: response.prompt,
|
|
131
|
-
representation,
|
|
132
|
-
threshold: response.threshold,
|
|
133
|
-
searchedAt: new Date().toISOString(),
|
|
134
|
-
candidates: response.candidates,
|
|
135
|
-
});
|
|
136
|
-
if (response.candidates.length === 0) {
|
|
137
|
-
const nearest = response.topSimilarity !== undefined
|
|
138
|
-
? ` The closest was ${percent(response.topSimilarity)}, which had no usable file.`
|
|
139
|
-
: '';
|
|
140
|
-
output.info(`No ready-made ${representation} character matches "${response.prompt}".${nearest}`);
|
|
141
|
-
output.info(`Forge one instead: bitmagic character generate --name <name> --prompt "${response.prompt}"`);
|
|
142
|
-
output.result({ ok: true, kind: 'character search', representation, threshold: response.threshold, candidates: [], ...(response.reason ? { reason: response.reason } : {}) });
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
output.info(`${response.candidates.length} ready-made ${representation} character(s) for "${response.prompt}":`);
|
|
146
|
-
renderCandidates(response.candidates, response.threshold, output.info);
|
|
147
|
-
const best = response.candidates[0];
|
|
148
|
-
if (best.similarity < response.threshold) {
|
|
149
|
-
// Said plainly rather than hidden: on this corpus a confident-looking
|
|
150
|
-
// caption can still be the wrong character, and the creator is the only
|
|
151
|
-
// one who can tell.
|
|
152
|
-
output.info(`None clears the ${percent(response.threshold)} bar automatic substitution requires — read the captions before adding one.`);
|
|
153
|
-
}
|
|
154
|
-
output.info(`Add one: bitmagic character add --id ${best.sid} --name <name>`);
|
|
155
|
-
output.result({
|
|
156
|
-
ok: true,
|
|
157
|
-
kind: 'character search',
|
|
158
|
-
representation,
|
|
159
|
-
threshold: response.threshold,
|
|
160
|
-
candidates: response.candidates,
|
|
161
|
-
});
|
|
162
|
-
},
|
|
163
|
-
});
|
|
164
|
-
/**
|
|
165
|
-
* What `bitmagic character add` will ask for, from its flags and the cached search.
|
|
166
|
-
*
|
|
167
|
-
* Pure, and separated from the command so the branch that matters — which of the
|
|
168
|
-
* two forms was asked for, and whether the cache can answer it — is testable
|
|
169
|
-
* without a project, a token or a network. It returns the character args rather
|
|
170
|
-
* than a body so the shared `buildCharacterBody` still owns the wire shape.
|
|
171
|
-
*/
|
|
172
|
-
export function resolveAddRequest(args) {
|
|
173
|
-
if (args.id === undefined) {
|
|
174
|
-
if (args.prompt === undefined) {
|
|
175
|
-
throw new CliError('Pass --id (from `bitmagic character search`) or --prompt to take the closest match.', 1, 'invalid_flag');
|
|
176
|
-
}
|
|
177
|
-
// The no-id form: the server searches with no floor and adds the best usable
|
|
178
|
-
// body, or fails without charging. Deliberately still available — "any of
|
|
179
|
-
// these will do" is a real request, and it is one call rather than two.
|
|
180
|
-
return {
|
|
181
|
-
name: args.name,
|
|
182
|
-
prompt: args.prompt,
|
|
183
|
-
applyToPlayer: args.applyToPlayer,
|
|
184
|
-
libraryOnly: true,
|
|
185
|
-
voxelize: defaultVoxelizeForProject(),
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
if (args.record === null) {
|
|
189
|
-
throw new CliError('No character search to pick from. Run `bitmagic character search --prompt "..."` first.', 1, 'no_search');
|
|
190
|
-
}
|
|
191
|
-
const candidate = findCachedCandidate(args.record, args.id);
|
|
192
|
-
if (candidate === null) {
|
|
193
|
-
const known = args.record.candidates.map((row) => row.sid).join(', ');
|
|
194
|
-
throw new CliError(`"${args.id}" was not in the last character search`
|
|
195
|
-
+ (known === '' ? ' (it found nothing).' : `. It offered: ${known}.`)
|
|
196
|
-
+ ' Run `bitmagic character search` again to pick from a fresh list.', 1, 'unknown_candidate');
|
|
197
|
-
}
|
|
198
|
-
return {
|
|
199
|
-
name: args.name,
|
|
200
|
-
// The CREATOR's brief, not the library row's own caption: this is what a
|
|
201
|
-
// regeneration re-drives, so it must describe what they asked for.
|
|
202
|
-
prompt: args.prompt ?? args.record.prompt,
|
|
203
|
-
applyToPlayer: args.applyToPlayer,
|
|
204
|
-
libraryPick: {
|
|
205
|
-
sid: candidate.sid,
|
|
206
|
-
assetUrl: candidate.assetUrl,
|
|
207
|
-
similarity: candidate.similarity,
|
|
208
|
-
...(candidate.description ? { description: candidate.description } : {}),
|
|
209
|
-
},
|
|
210
|
-
// The shelf that produced the row decides the medium, not the project's art
|
|
211
|
-
// style at the moment of adding: mixing them would hand a low-poly game a
|
|
212
|
-
// pile of cubes.
|
|
213
|
-
voxelize: args.record.representation === 'voxel',
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
const addCommand = defineCommand({
|
|
217
|
-
meta: {
|
|
218
|
-
name: 'add',
|
|
219
|
-
description: 'Add a ready-made character from the library to world.json assets. Free; never forges.',
|
|
220
|
-
},
|
|
221
|
-
args: {
|
|
222
|
-
name: NAME_ARG,
|
|
223
|
-
id: {
|
|
224
|
-
type: 'string',
|
|
225
|
-
description: 'The id of a candidate from `bitmagic character search`. Omit to take the closest match to --prompt.',
|
|
226
|
-
},
|
|
227
|
-
prompt: {
|
|
228
|
-
type: 'string',
|
|
229
|
-
description: 'What the character should look like. Required without --id; with --id it defaults to the search that found it.',
|
|
230
|
-
},
|
|
231
|
-
'apply-to-player': APPLY_TO_PLAYER_ARG,
|
|
232
|
-
'original-prompt': ORIGINAL_PROMPT_FLAG,
|
|
233
|
-
json: JSON_FLAG,
|
|
234
|
-
},
|
|
235
|
-
async run({ args }) {
|
|
236
|
-
const json = args.json === true;
|
|
237
|
-
const { context } = await resolveRun(json);
|
|
238
|
-
const output = createOutput(json);
|
|
239
|
-
// Only the --id form consults the cache; the --prompt form is a fresh ask.
|
|
240
|
-
const record = args.id === undefined ? null : readCharacterSearch(context.root);
|
|
241
|
-
const request = resolveAddRequest({
|
|
242
|
-
name: args.name,
|
|
243
|
-
id: args.id,
|
|
244
|
-
prompt: args.prompt,
|
|
245
|
-
applyToPlayer: args['apply-to-player'],
|
|
246
|
-
record,
|
|
247
|
-
});
|
|
248
|
-
if (request.libraryPick) {
|
|
249
|
-
// The search's own date, not an expiry: age is worth seeing, and the
|
|
250
|
-
// catalogue only changes when somebody promotes to it.
|
|
251
|
-
output.info(`Adding ${request.libraryPick.sid} (${percent(request.libraryPick.similarity)} match`
|
|
252
|
-
+ `${record?.searchedAt ? `, from the search on ${record.searchedAt.slice(0, 10)}` : ''}).`);
|
|
253
|
-
}
|
|
254
|
-
await runAssetGeneration('character', 'character', withParent(buildCharacterBody(request)), json);
|
|
255
|
-
},
|
|
256
|
-
});
|
|
257
|
-
export const characterCommand = defineCommand({
|
|
258
|
-
meta: {
|
|
259
|
-
name: 'character',
|
|
260
|
-
description: 'Forge a character, search the ready-made ones, or add one to your game.',
|
|
261
|
-
},
|
|
262
|
-
subCommands: {
|
|
263
|
-
generate: generateCommand,
|
|
264
|
-
search: searchCommand,
|
|
265
|
-
add: addCommand,
|
|
266
|
-
},
|
|
267
|
-
});
|
|
268
|
-
//# sourceMappingURL=character.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"character.js","sourceRoot":"","sources":["../../src/commands/character.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `bitmagic forge --edit` — which level is being edited, and the request an
|
|
3
|
-
* edit job is frozen with.
|
|
4
|
-
*
|
|
5
|
-
* Pure over the project's world.json so the resolution rules are testable
|
|
6
|
-
* without a project on disk: `--level` names a level by id, by exact name, or
|
|
7
|
-
* by a unique case-insensitive name; omitted, it means the ONE level this
|
|
8
|
-
* project could edit, and anything else is refused with the candidates named.
|
|
9
|
-
* A level can be edited when its `.vwld` asset records the forge job that
|
|
10
|
-
* built it (or, for older levels, carries the job id in its source GLB key —
|
|
11
|
-
* see `parentForgeJobId`).
|
|
12
|
-
*/
|
|
13
|
-
import { type ForgeJobInput, type ForgeReusePlan, type ForgeArtifact } from '@bitmagic/world-forger/pipeline/index.js';
|
|
14
|
-
import { type JsonObject } from '../project/world-json.js';
|
|
15
|
-
export interface EditTarget {
|
|
16
|
-
levelId: string;
|
|
17
|
-
name: string;
|
|
18
|
-
vwldAssetId: string;
|
|
19
|
-
parentJobId: string;
|
|
20
|
-
}
|
|
21
|
-
export declare function resolveEditTarget(world: JsonObject, levelArg: string | undefined): EditTarget;
|
|
22
|
-
/** The frozen request of an edit job: the level's own name, the parent it edits, the level it replaces. */
|
|
23
|
-
export declare function buildEditJobInput(options: {
|
|
24
|
-
target: EditTarget;
|
|
25
|
-
editPrompt: string;
|
|
26
|
-
gameId: string;
|
|
27
|
-
groundPlane?: boolean;
|
|
28
|
-
}): ForgeJobInput;
|
|
29
|
-
/** A plan that reuses nothing — what a terminal frame without one means. */
|
|
30
|
-
export declare function bakeEverythingPlan(artifact: ForgeArtifact, reason: string): ForgeReusePlan;
|