@wji.ai/cli 0.9.1 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/dist/index.js +4 -5
- package/package.json +1 -1
- package/skill/backreel/SKILL.md +1 -1
- package/skill/backreel/reference/episodes.md +7 -7
- package/skill/short-drama/SKILL.md +27 -4
- package/skill/short-drama/examples/night-shift/episodes/E01.json +173 -1
- package/skill/short-drama/examples/night-shift/project.json +6 -0
- package/skill/short-drama/reference/dialogue-craft.md +16 -11
- package/skill/short-drama/reference/prompt-audit.mjs +308 -0
- package/skill/short-drama/reference/reference-binding.md +84 -0
- package/skill/short-drama/reference/schema.md +14 -5
- package/skill/short-drama/reference/stage-characters.md +1 -1
- package/skill/short-drama/reference/stage-script.md +54 -7
- package/skill/short-drama/reference/stage-storyboard.md +29 -24
- package/skill/short-drama/scripts/selftest.mjs +154 -9
- package/skill/short-drama/scripts/short-drama.mjs +467 -23
- package/skill/w-film-dialogue-editor/CHANGELOG.md +44 -0
- package/skill/w-film-dialogue-editor/SKILL.md +124 -0
- package/skill/w-film-dialogue-editor/references/data/README.md +222 -0
- package/skill/w-film-dialogue-editor/references/data/en/core.json +1666 -0
- package/skill/w-film-dialogue-editor/references/data/en/slang.json +1602 -0
- package/skill/w-film-dialogue-editor/references/data/en/work.json +1722 -0
- package/skill/w-film-dialogue-editor/references/data/en-sentences.csv +134 -0
- package/skill/w-film-dialogue-editor/references/data/en-sentences.md +146 -0
- package/skill/w-film-dialogue-editor/references/data/ja/core.json +1978 -0
- package/skill/w-film-dialogue-editor/references/data/ja/slang.json +1927 -0
- package/skill/w-film-dialogue-editor/references/data/ja/work.json +1972 -0
- package/skill/w-film-dialogue-editor/references/data/ja-sentences.csv +134 -0
- package/skill/w-film-dialogue-editor/references/data/ja-sentences.md +146 -0
- package/skill/w-film-dialogue-editor/references/data/ko/core.json +1839 -0
- package/skill/w-film-dialogue-editor/references/data/ko/slang.json +1897 -0
- package/skill/w-film-dialogue-editor/references/data/ko/work.json +1829 -0
- package/skill/w-film-dialogue-editor/references/data/ko-sentences.csv +134 -0
- package/skill/w-film-dialogue-editor/references/data/ko-sentences.md +146 -0
- package/skill/w-film-dialogue-editor/references/data/zh-cn/core.json +1794 -0
- package/skill/w-film-dialogue-editor/references/data/zh-cn/slang.json +1609 -0
- package/skill/w-film-dialogue-editor/references/data/zh-cn/work.json +1648 -0
- package/skill/w-film-dialogue-editor/references/data/zh-cn-sentences.csv +134 -0
- package/skill/w-film-dialogue-editor/references/data/zh-cn-sentences.md +146 -0
- package/skill/w-film-dialogue-editor/references/data/zh-hk/core.json +2476 -0
- package/skill/w-film-dialogue-editor/references/data/zh-hk/gen-z.json +3263 -0
- package/skill/w-film-dialogue-editor/references/data/zh-hk/older.json +3632 -0
- package/skill/w-film-dialogue-editor/references/data/zh-hk/rough.json +1668 -0
- package/skill/w-film-dialogue-editor/references/data/zh-hk/workplace.json +3697 -0
- package/skill/w-film-dialogue-editor/references/data/zh-hk-sentences.csv +373 -0
- package/skill/w-film-dialogue-editor/references/data/zh-hk-sentences.md +391 -0
- package/skill/w-film-dialogue-editor/references/data/zh-tw/core.json +1640 -0
- package/skill/w-film-dialogue-editor/references/data/zh-tw/slang.json +1537 -0
- package/skill/w-film-dialogue-editor/references/data/zh-tw/work.json +1699 -0
- package/skill/w-film-dialogue-editor/references/data/zh-tw-sentences.csv +132 -0
- package/skill/w-film-dialogue-editor/references/data/zh-tw-sentences.md +144 -0
- package/skill/w-film-dialogue-editor/references/dialogue_revision_framework.md +84 -0
- package/skill/w-film-dialogue-editor/references/en-index.md +265 -0
- package/skill/w-film-dialogue-editor/references/ja-index.md +633 -0
- package/skill/w-film-dialogue-editor/references/ko-index.md +498 -0
- package/skill/w-film-dialogue-editor/references/lang-en.md +242 -0
- package/skill/w-film-dialogue-editor/references/lang-ja.md +312 -0
- package/skill/w-film-dialogue-editor/references/lang-ko.md +290 -0
- package/skill/w-film-dialogue-editor/references/lang-zh-cn.md +60 -0
- package/skill/w-film-dialogue-editor/references/lang-zh-hk-mandarin.md +34 -0
- package/skill/w-film-dialogue-editor/references/lang-zh-hk.md +306 -0
- package/skill/w-film-dialogue-editor/references/lang-zh-period.md +38 -0
- package/skill/w-film-dialogue-editor/references/lang-zh-tw.md +57 -0
- package/skill/w-film-dialogue-editor/references/zh-cn-index.md +636 -0
- package/skill/w-film-dialogue-editor/references/zh-hk-index.md +1450 -0
- package/skill/w-film-dialogue-editor/references/zh-tw-index.md +457 -0
- package/skill/w-film-dialogue-editor/scripts/rebuild.sh +13 -0
- package/skill/w-film-dialogue-editor/scripts/ref.mjs +539 -0
- package/skill/w-film-dialogue-editor/templates/dialogue_revision_report.md +43 -0
package/README.md
CHANGED
|
@@ -311,10 +311,15 @@ generations, banner sizes, AI-disclosure compliance); `social-media` holds
|
|
|
311
311
|
every platform's image / video specs (Instagram, TikTok, YouTube, Facebook, X,
|
|
312
312
|
LinkedIn, Pinterest, Threads, Snapchat, 小红书, 抖音, 快手, 视频号, B站, 微博,
|
|
313
313
|
公众号) and the repurposing recipes — an episode into 9:16 teasers and posters,
|
|
314
|
-
an ad master into every placement.
|
|
314
|
+
an ad master into every placement. `skill/w-film-dialogue-editor/` is the
|
|
315
|
+
dialogue skill short-drama reviews every script with: a guide per 语体 (粤语,
|
|
316
|
+
大陆普通话, 台湾国语, 港式普通话, 古装/年代, English, 韩文, 日文) and a corpus of
|
|
317
|
+
real usage queried with its `scripts/ref.mjs`; short-drama finds it when it is
|
|
318
|
+
installed beside it. Install them the same way:
|
|
315
319
|
|
|
316
320
|
```bash
|
|
317
321
|
cp -r "$(npm root -g)/@wji.ai/cli/skill/short-drama" ~/.claude/skills/short-drama
|
|
322
|
+
cp -r "$(npm root -g)/@wji.ai/cli/skill/w-film-dialogue-editor" ~/.claude/skills/w-film-dialogue-editor
|
|
318
323
|
cp -r "$(npm root -g)/@wji.ai/cli/skill/ads" ~/.claude/skills/ads
|
|
319
324
|
cp -r "$(npm root -g)/@wji.ai/cli/skill/social-media" ~/.claude/skills/social-media
|
|
320
325
|
```
|
package/dist/index.js
CHANGED
|
@@ -6349,7 +6349,7 @@ async function uploadToVod(token, file, onProgress) {
|
|
|
6349
6349
|
// src/commands/backreel-episode.ts
|
|
6350
6350
|
var MAX_EPISODES = 30;
|
|
6351
6351
|
var VIDEO_EXTS = [".mp4", ".mov", ".m4v", ".webm"];
|
|
6352
|
-
var
|
|
6352
|
+
var VIDEO_MAX_BYTES = 500 * 1024 * 1024;
|
|
6353
6353
|
var subtitlesOf = (e) => (e.subtitles || []).map((s) => ({ id: s.id, lang: s.lang, ...s.label ? { label: s.label } : {} }));
|
|
6354
6354
|
function toDto(e, order) {
|
|
6355
6355
|
const base = { title: e.title, order, tier: e.tier || "public", subtitles: subtitlesOf(e) };
|
|
@@ -6376,8 +6376,8 @@ async function resolveSource(client, opts, postId, file) {
|
|
|
6376
6376
|
const ext = extname2(file).toLowerCase();
|
|
6377
6377
|
if (!VIDEO_EXTS.includes(ext)) throw new Error(`${basename6(file)}: episodes must be ${VIDEO_EXTS.join(" / ")}`);
|
|
6378
6378
|
const size = (await stat5(file)).size;
|
|
6379
|
+
if (size > VIDEO_MAX_BYTES) throw new Error(`${basename6(file)} is over 500 MB`);
|
|
6379
6380
|
if (opts.legacy) {
|
|
6380
|
-
if (size > ASSET_VIDEO_MAX_BYTES) throw new Error(`${basename6(file)} is over 200 MB \u2014 drop --legacy to upload it to VOD`);
|
|
6381
6381
|
info(color.dim(`Uploading ${basename6(file)} as a WJI asset\u2026`));
|
|
6382
6382
|
const asset = await client.upload("/assets/v2/upload", file, {});
|
|
6383
6383
|
return { video: asset.id };
|
|
@@ -6452,7 +6452,7 @@ function pickRendition(renditions, want) {
|
|
|
6452
6452
|
}
|
|
6453
6453
|
return hit;
|
|
6454
6454
|
}
|
|
6455
|
-
var sourceOptions = (cmd) => cmd.option("--vid <vid>", "a Vid already in the Backreel VOD space").option("--asset <assetId>", "an uploaded WJI video asset (legacy path, public URL)").option("--legacy", "upload the file as a WJI asset (\
|
|
6455
|
+
var sourceOptions = (cmd) => cmd.option("--vid <vid>", "a Vid already in the Backreel VOD space").option("--asset <assetId>", "an uploaded WJI video asset (legacy path, public URL)").option("--legacy", "upload the file as a WJI asset (\u2264500 MB) instead of VOD");
|
|
6456
6456
|
function episodeCommand(globals2) {
|
|
6457
6457
|
const ep = new Command19("episode").aliases(["episodes", "ep"]).description("Episodes of a showcase post: upload, reorder, gate by tier, check transcoding");
|
|
6458
6458
|
ep.command("list <postId>", { isDefault: true }).description("List the episodes with their tier, source and VOD status").action(async (postId) => {
|
|
@@ -7992,7 +7992,6 @@ function backreelCommand(globals2) {
|
|
|
7992
7992
|
if (!(p.credits || []).length) advice.push("no credits");
|
|
7993
7993
|
const pending = episodes.filter((e) => e.vodVid && e.vodStatus !== "ready");
|
|
7994
7994
|
if (pending.length) advice.push(`${pending.length} episode(s) not ready on VOD (${pending.map((e) => `#${(e.order ?? 0) + 1} ${e.vodStatus || "?"}`).join(", ")}) \u2014 \`backreel episode status\``);
|
|
7995
|
-
if (p.trailerDurationSec && p.trailerDurationSec > 31) advice.push(`trailer is ${p.trailerDurationSec}s; the limit is 30s`);
|
|
7996
7995
|
if (p.donation?.enabled && p.kind === "crowdfunding" && p.campaign?.deadline && new Date(p.campaign.deadline) < /* @__PURE__ */ new Date()) {
|
|
7997
7996
|
advice.push("the campaign deadline has passed \u2014 donations are closed");
|
|
7998
7997
|
}
|
|
@@ -8070,7 +8069,7 @@ function backreelCommand(globals2) {
|
|
|
8070
8069
|
return br;
|
|
8071
8070
|
}
|
|
8072
8071
|
function postOptions(cmd) {
|
|
8073
|
-
return cmd.option("--kind <kind>", KINDS.join(" | ")).option("--logline <text>", `one-line hook, max ${LOGLINE_MAX} chars; public even when the description is locked ("" clears it)`).option("--category <category>", "category").option("--project-status <status>", PROJECT_STATUSES.join(" | ")).option("--tags <tags>", "comma-separated tags (replaces the list)").option("-d, --description <text>", "description, plain text or HTML (@file / - supported)").option("--cover <assetId>", "landscape cover asset").option("--cover-portrait <assetId>", "portrait cover asset").option("--trailer <assetId>", "trailer video asset (\
|
|
8072
|
+
return cmd.option("--kind <kind>", KINDS.join(" | ")).option("--logline <text>", `one-line hook, max ${LOGLINE_MAX} chars; public even when the description is locked ("" clears it)`).option("--category <category>", "category").option("--project-status <status>", PROJECT_STATUSES.join(" | ")).option("--tags <tags>", "comma-separated tags (replaces the list)").option("-d, --description <text>", "description, plain text or HTML (@file / - supported)").option("--cover <assetId>", "landscape cover asset").option("--cover-portrait <assetId>", "portrait cover asset").option("--trailer <assetId>", "trailer video asset (\u2264500 MB, any length)").option("--media <assetId...>", `LookBook gallery, images or videos in order (replaces it; \u2264${MEDIA_MAX}; "none" clears)`).option("--org <orgId|none>", "publish as one of your organizations; none = yourself (only the author can change it later)").option("--body <json>", "any other post fields as JSON (@file / - supported); flags win");
|
|
8074
8073
|
}
|
|
8075
8074
|
async function postBody(opts) {
|
|
8076
8075
|
const body = { ...await readJson(opts.body) || {} };
|
package/package.json
CHANGED
package/skill/backreel/SKILL.md
CHANGED
|
@@ -26,7 +26,7 @@ wji br list # your posts, drafts included
|
|
|
26
26
|
| kind | `showcase` (episodes, trailer) or `crowdfunding` (goal, supporters) — switching wipes the other side's data | `br create --kind`, `br set --kind` |
|
|
27
27
|
| title / logline / description | logline = one public line ≤200 chars; description = HTML or plain text | `br set --logline`, `-d @file.md` |
|
|
28
28
|
| images | 16:9 cover, 9:16 portrait, LookBook gallery (≤9), credit photos | `br image <file> --slot … --post` |
|
|
29
|
-
| trailer | a video asset ≤
|
|
29
|
+
| trailer | a video asset, ≤500 MB, any length | `wji asset upload` → `br set --trailer` |
|
|
30
30
|
| episodes | ≤30, each with its own viewer tier, hosted on VOD | `br episode …` |
|
|
31
31
|
| credits | cast / crew / creative, ≤30, may link a WJI user or an NPC | `br credit …` |
|
|
32
32
|
| campaign + donations | goal, offline total, deadline, donation tiers, offline supporters | `br fund …` |
|
|
@@ -6,19 +6,20 @@
|
|
|
6
6
|
| --- | --- | --- |
|
|
7
7
|
| posts | any | **showcase only** (switching to crowdfunding drops them) |
|
|
8
8
|
| count | one | ≤30 |
|
|
9
|
-
| length |
|
|
9
|
+
| length | no limit | no limit |
|
|
10
|
+
| size | ≤500 MB | ≤500 MB |
|
|
10
11
|
| storage | WJI asset (public URL) | BytePlus VOD (signed URL per play, ~5 min) |
|
|
11
12
|
| gated | no — always public | per episode: public / member / supporter / partner |
|
|
12
13
|
|
|
13
14
|
### Trailer
|
|
14
15
|
|
|
15
16
|
```bash
|
|
16
|
-
wji asset upload trailer.mp4 --json # ≤
|
|
17
|
+
wji asset upload trailer.mp4 --json # ≤500 MB, any length
|
|
17
18
|
wji br set <postId> --trailer <assetId>
|
|
18
19
|
```
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
There is no duration cap. The upload is rejected only when the file is over
|
|
22
|
+
500 MB.
|
|
22
23
|
|
|
23
24
|
## Uploading episodes
|
|
24
25
|
|
|
@@ -33,8 +34,7 @@ transcoding), then saves the episode list with the new `vodVid`.
|
|
|
33
34
|
|
|
34
35
|
- Formats: `.mp4`, `.mov`, `.m4v`, `.webm`. Upload the finished master;
|
|
35
36
|
VOD transcodes to MP4 for playback.
|
|
36
|
-
- The whole file goes up in one request
|
|
37
|
-
Multi-GB masters are better uploaded from the web, which chunks them.
|
|
37
|
+
- The whole file goes up in one request. The cap is 500 MB, with no duration limit.
|
|
38
38
|
- A credential lasts 15 minutes and the server allows 30 per 10 minutes —
|
|
39
39
|
upload a season one episode at a time, not in parallel.
|
|
40
40
|
- `--vid <vid>` attaches a video already in the space (e.g. uploaded on the
|
|
@@ -43,7 +43,7 @@ transcoding), then saves the episode list with the new `vodVid`.
|
|
|
43
43
|
### Legacy path
|
|
44
44
|
|
|
45
45
|
`--legacy` (or `--asset <assetId>`) stores the episode as a plain WJI asset
|
|
46
|
-
(≤
|
|
46
|
+
(≤500 MB) with a permanent public URL. It plays immediately with no
|
|
47
47
|
transcoding, but anyone who sees the URL can share it, and tier locks only hide
|
|
48
48
|
it on the page. Use VOD for anything gated; legacy only for short public
|
|
49
49
|
extras.
|
|
@@ -36,8 +36,11 @@ Either way, this skill only says **what to build**; the operations doc says how
|
|
|
36
36
|
|
|
37
37
|
**How the drama is written** comes from `{baseDir}/reference/craft-story.md` (the 短剧 method:
|
|
38
38
|
brief, three phases, 分集目录, 爽点 / 钩子 libraries, the episode formula, the character bible) and
|
|
39
|
-
`{baseDir}/reference/dialogue-craft.md` (lines as action, 语体 rules, the
|
|
39
|
+
`{baseDir}/reference/dialogue-craft.md` (lines as action, 语体 rules, the dialogue review). Read the
|
|
40
40
|
first before stage 1 and the second before stage 4. The gates encode what those two can check.
|
|
41
|
+
The full dialogue method is the user's **`w-film-dialogue-editor`** skill, installed beside this
|
|
42
|
+
one: its language guides and corpus are read while the lines are written and again in the required
|
|
43
|
+
dialogue review after the script.
|
|
41
44
|
|
|
42
45
|
**Re-read the guideline.** The 创作指引 (`render guideline`) is the drama's top rule document.
|
|
43
46
|
Print it before writing any character, any episode and any storyboard, and print the speakers'
|
|
@@ -277,6 +280,7 @@ Read `{baseDir}/reference/stage-script.md`.
|
|
|
277
280
|
writes `episodes/E0N.json` with target seconds, hook/cliff, claimed beats, the episode design
|
|
278
281
|
(`function` / `task` / `change` / `hookType`, `satisfactionBeat` to set) and a `seedNote`
|
|
279
282
|
(synopsis, the 爽点 to realise, register, guideline priorities, every speaker's `bible.speech`,
|
|
283
|
+
the dialogue skill's guides and per-speaker corpus queries in `dialogue`,
|
|
280
284
|
ids, previous cliff, budget). Fill `scenes[].flow` — action beats and line beats alternating,
|
|
281
285
|
**common actions only**, hook image inside the first 3 beats and by 15 s, a `turn: true` beat
|
|
282
286
|
at least every 30 s, the 爽点 on an action (`satisfactionBeat`), cliff as the last beat; lines
|
|
@@ -286,9 +290,13 @@ Read `{baseDir}/reference/stage-script.md`.
|
|
|
286
290
|
Delete `seedNote` when done.
|
|
287
291
|
2. `validate --stage script --ep N` — duration math, line length, speakers, hook window, the
|
|
288
292
|
rhythm, the design, filmability, upstream ids; the register gate only advises. Over budget: cut
|
|
289
|
-
actions first; under: add conflict, not small talk.
|
|
290
|
-
|
|
291
|
-
|
|
293
|
+
actions first; under: add conflict, not small talk.
|
|
294
|
+
3. **Dialogue review** (required, gate `dialogue-review`): `seed dialogue --ep N` → read the
|
|
295
|
+
`w-film-dialogue-editor` framework and the guide of each 语体 it prints, query the corpus per
|
|
296
|
+
speaker → fill the diagnosis, level, one row per line (issue / revised / reason / playable
|
|
297
|
+
note) and the guide's 自检 → `apply dialogue --ep N` → re-validate. A line edited later is
|
|
298
|
+
reviewed again. Details in `stage-script.md`.
|
|
299
|
+
4. Sync: `render script --ep N` (the 短剧 episode format with the 创作自检 table) → `story/` dataset
|
|
292
300
|
`E0N 剧本` (type `screenplay`, `viewMode=content`); bind `wji.screenplayDatasetId` with `--ep N`.
|
|
293
301
|
|
|
294
302
|
## Stage 5 — Storyboard (per episode)
|
|
@@ -307,6 +315,21 @@ prompt, alongside the camera package and each speaker's delivery.
|
|
|
307
315
|
|
|
308
316
|
**Two people talking** (gate `two-person-framing`, sheets mode): a two-shot once, then over-the-shoulder (`ots`) for the exchange, a clean single for the punchline. A single names only its person; every look states a screen direction (`eyeline`); the sides stay locked. See `reference/craft-shots.md`.
|
|
309
317
|
|
|
318
|
+
**Every picture says what it is, and what NOT to copy from it** (gate `ref-binding`, sheets mode).
|
|
319
|
+
The model reads one string: a legend line that only says "a character sheet" for two different
|
|
320
|
+
people is how faces get swapped, and a shot that never names its `@imageK` is a shot where the
|
|
321
|
+
model invents the face or the prop. So — one legend line per picture, naming a person by age /
|
|
322
|
+
hair / clothes from the character bible, the room by its name, a prop by its name; every picture
|
|
323
|
+
that is **not** a person also says what may not be copied from it (*take only its light ratios,
|
|
324
|
+
contrast and colour temperature — never its composition or its people*); the room is named once
|
|
325
|
+
for the whole segment (`Every shot stays inside @image1 …`); every person and every prop is bound
|
|
326
|
+
by its label again **inside its own shot**; no connected picture may go unused; and a segment may
|
|
327
|
+
not carry more pictures than the model takes (`refs` cap). Wording patterns and the six roles:
|
|
328
|
+
`reference/reference-binding.md`. A prompt that was written or edited by hand (or copied from a
|
|
329
|
+
production run) can be proofread before any image is spent:
|
|
330
|
+
`node {baseDir}/reference/prompt-audit.mjs --project <project> --ep 1 --segment E0N-k --prompt <file>`
|
|
331
|
+
— it reports per-shot unbound people and props, indistinguishable legend lines and unused pictures.
|
|
332
|
+
|
|
310
333
|
**Every cut is lit and composed in the preset's look.** Read the preset's guide
|
|
311
334
|
(`{baseDir}/reference/cinematography-<preset>.md`) before the first storyboard. Name the source
|
|
312
335
|
in `light.source`, stage the person against it, and choose the camera side that gives the
|
|
@@ -1879,5 +1879,177 @@
|
|
|
1879
1879
|
"canvasId": "",
|
|
1880
1880
|
"shotFolderId": "",
|
|
1881
1881
|
"displayNodes": {}
|
|
1882
|
+
},
|
|
1883
|
+
"dialogueReview": {
|
|
1884
|
+
"level": "轻修",
|
|
1885
|
+
"guides": [
|
|
1886
|
+
"lang-zh-cn.md"
|
|
1887
|
+
],
|
|
1888
|
+
"diagnosis": {
|
|
1889
|
+
"goal": "小夏想守住别人托付的袋子;老陈想弄清袋子从哪来",
|
|
1890
|
+
"conflict": "老陈步步试探,小夏用「别人的东西」挡住",
|
|
1891
|
+
"subtext": "老陈认得穿雨衣的人,却不说破;小夏开始怀疑他",
|
|
1892
|
+
"voice": "小夏短句、收得急;老陈慢、一字一顿,遮住名字也分得出",
|
|
1893
|
+
"rhythm": "问答都短,每两三句就被动作打断,节奏成立"
|
|
1894
|
+
},
|
|
1895
|
+
"rows": [
|
|
1896
|
+
{
|
|
1897
|
+
"scene": 1,
|
|
1898
|
+
"beat": 2,
|
|
1899
|
+
"speaker": "C03",
|
|
1900
|
+
"original": "帮我收着。明天有人来拿。",
|
|
1901
|
+
"issue": "无:两个短句,交代托付又不解释",
|
|
1902
|
+
"revised": "帮我收着。明天有人来拿。",
|
|
1903
|
+
"reason": "",
|
|
1904
|
+
"note": "压着嗓子,你不是请求,是把麻烦塞给她"
|
|
1905
|
+
},
|
|
1906
|
+
{
|
|
1907
|
+
"scene": 1,
|
|
1908
|
+
"beat": 3,
|
|
1909
|
+
"speaker": "C01",
|
|
1910
|
+
"original": "你是谁?我们不代收——",
|
|
1911
|
+
"issue": "无:被打断的半句,正好是人已走远",
|
|
1912
|
+
"revised": "你是谁?我们不代收——",
|
|
1913
|
+
"reason": "",
|
|
1914
|
+
"note": "追问,话到一半发现对方根本不听"
|
|
1915
|
+
},
|
|
1916
|
+
{
|
|
1917
|
+
"scene": 2,
|
|
1918
|
+
"beat": 3,
|
|
1919
|
+
"speaker": "C02",
|
|
1920
|
+
"original": "又是你值夜班。",
|
|
1921
|
+
"issue": "无:熟人寒暄,带着她天天值夜的信息",
|
|
1922
|
+
"revised": "又是你值夜班。",
|
|
1923
|
+
"reason": "",
|
|
1924
|
+
"note": "先吃一口再说,你在装作若无其事"
|
|
1925
|
+
},
|
|
1926
|
+
{
|
|
1927
|
+
"scene": 2,
|
|
1928
|
+
"beat": 4,
|
|
1929
|
+
"speaker": "C01",
|
|
1930
|
+
"original": "陈叔,你怎么天天半夜来。",
|
|
1931
|
+
"issue": "无:顺口一问,眼睛在袋子上,潜台词在动作里",
|
|
1932
|
+
"revised": "陈叔,你怎么天天半夜来。",
|
|
1933
|
+
"reason": "",
|
|
1934
|
+
"note": "嘴上问他,心思全在袋子上,别看他"
|
|
1935
|
+
},
|
|
1936
|
+
{
|
|
1937
|
+
"scene": 2,
|
|
1938
|
+
"beat": 5,
|
|
1939
|
+
"speaker": "C02",
|
|
1940
|
+
"original": "老了,睡不着。",
|
|
1941
|
+
"issue": "无:一句带过,把真正的原因藏住",
|
|
1942
|
+
"revised": "老了,睡不着。",
|
|
1943
|
+
"reason": "",
|
|
1944
|
+
"note": "笑着挡回去,不让她再问"
|
|
1945
|
+
},
|
|
1946
|
+
{
|
|
1947
|
+
"scene": 2,
|
|
1948
|
+
"beat": 7,
|
|
1949
|
+
"speaker": "C02",
|
|
1950
|
+
"original": "这是什么?",
|
|
1951
|
+
"issue": "无:最短的问题,压力在筷子停住",
|
|
1952
|
+
"revised": "这是什么?",
|
|
1953
|
+
"reason": "",
|
|
1954
|
+
"note": "声音不变,你在试探,不是好奇"
|
|
1955
|
+
},
|
|
1956
|
+
{
|
|
1957
|
+
"scene": 2,
|
|
1958
|
+
"beat": 8,
|
|
1959
|
+
"speaker": "C01",
|
|
1960
|
+
"original": "刚才一个人放这儿的,说明天有人来拿。",
|
|
1961
|
+
"issue": "无:耸肩一句,转述托付人的话,不加解释",
|
|
1962
|
+
"revised": "刚才一个人放这儿的,说明天有人来拿。",
|
|
1963
|
+
"reason": "",
|
|
1964
|
+
"note": "耸肩,你在敷衍,想把话题带过"
|
|
1965
|
+
},
|
|
1966
|
+
{
|
|
1967
|
+
"scene": 2,
|
|
1968
|
+
"beat": 10,
|
|
1969
|
+
"speaker": "C01",
|
|
1970
|
+
"original": "别人的东西。",
|
|
1971
|
+
"issue": "无:三个字划界线",
|
|
1972
|
+
"revised": "别人的东西。",
|
|
1973
|
+
"reason": "",
|
|
1974
|
+
"note": "手按住抽屉,你在拒绝,不用抬高声音"
|
|
1975
|
+
},
|
|
1976
|
+
{
|
|
1977
|
+
"scene": 2,
|
|
1978
|
+
"beat": 11,
|
|
1979
|
+
"speaker": "C02",
|
|
1980
|
+
"original": "小夏,那个人穿雨衣?",
|
|
1981
|
+
"issue": "无:叫名字一次,用在试探的关键处",
|
|
1982
|
+
"revised": "小夏,那个人穿雨衣?",
|
|
1983
|
+
"reason": "",
|
|
1984
|
+
"note": "很轻,你在确认一件你早就知道的事"
|
|
1985
|
+
},
|
|
1986
|
+
{
|
|
1987
|
+
"scene": 2,
|
|
1988
|
+
"beat": 13,
|
|
1989
|
+
"speaker": "C02",
|
|
1990
|
+
"original": "三年前,这店里丢过一样东西。",
|
|
1991
|
+
"issue": "无:只给半句往事,留钩子",
|
|
1992
|
+
"revised": "三年前,这店里丢过一样东西。",
|
|
1993
|
+
"reason": "",
|
|
1994
|
+
"note": "背对她说,你在决定要说多少"
|
|
1995
|
+
},
|
|
1996
|
+
{
|
|
1997
|
+
"scene": 2,
|
|
1998
|
+
"beat": 15,
|
|
1999
|
+
"speaker": "C02",
|
|
2000
|
+
"original": "别把它交给任何人。",
|
|
2001
|
+
"issue": "无:命令句,第一次正眼看她",
|
|
2002
|
+
"revised": "别把它交给任何人。",
|
|
2003
|
+
"reason": "",
|
|
2004
|
+
"note": "一字一顿,你在把责任压到她身上"
|
|
2005
|
+
},
|
|
2006
|
+
{
|
|
2007
|
+
"scene": 2,
|
|
2008
|
+
"beat": 17,
|
|
2009
|
+
"speaker": "VO",
|
|
2010
|
+
"original": "他怎么知道那人穿雨衣。",
|
|
2011
|
+
"issue": "无:心声一句,把怀疑交给观众",
|
|
2012
|
+
"revised": "他怎么知道那人穿雨衣。",
|
|
2013
|
+
"reason": "",
|
|
2014
|
+
"note": "压得很低,像自己不敢承认这个念头"
|
|
2015
|
+
},
|
|
2016
|
+
{
|
|
2017
|
+
"scene": 2,
|
|
2018
|
+
"beat": 19,
|
|
2019
|
+
"speaker": "C02",
|
|
2020
|
+
"original": "锁上门。",
|
|
2021
|
+
"issue": "无:三个字收尾,命令里有恐惧",
|
|
2022
|
+
"revised": "锁上门。",
|
|
2023
|
+
"reason": "",
|
|
2024
|
+
"note": "不回头,你在逼她立刻照做"
|
|
2025
|
+
}
|
|
2026
|
+
],
|
|
2027
|
+
"selfCheck": [
|
|
2028
|
+
{
|
|
2029
|
+
"item": "读出声:有没有播音腔的句子?",
|
|
2030
|
+
"ok": true,
|
|
2031
|
+
"note": "全部短句口语,无书面长句"
|
|
2032
|
+
},
|
|
2033
|
+
{
|
|
2034
|
+
"item": "语气词密度:一句最多一个,没有粤语残留(啦/喇/啫)",
|
|
2035
|
+
"ok": true,
|
|
2036
|
+
"note": "几乎不用语气词"
|
|
2037
|
+
},
|
|
2038
|
+
{
|
|
2039
|
+
"item": "网络用语符合年龄:长辈角色不用",
|
|
2040
|
+
"ok": true,
|
|
2041
|
+
"note": "老陈六十多岁,无网络用语"
|
|
2042
|
+
},
|
|
2043
|
+
{
|
|
2044
|
+
"item": "地域口音只给少数角色",
|
|
2045
|
+
"ok": true,
|
|
2046
|
+
"note": "全员标准普通话"
|
|
2047
|
+
},
|
|
2048
|
+
{
|
|
2049
|
+
"item": "英语夹杂符合行业身份",
|
|
2050
|
+
"ok": true,
|
|
2051
|
+
"note": "无英语夹杂,便利店夜班不需要"
|
|
2052
|
+
}
|
|
2053
|
+
]
|
|
1882
2054
|
}
|
|
1883
|
-
}
|
|
2055
|
+
}
|
|
@@ -588,6 +588,8 @@
|
|
|
588
588
|
"primary": true,
|
|
589
589
|
"reusePlan": "",
|
|
590
590
|
"summary": "凌晨两点的便利店:亮得刺眼、空得发冷,收银台是全店唯一有人气的地方,所有的戏都在那一米柜台前后发生。",
|
|
591
|
+
"condition": "lived-in",
|
|
592
|
+
"conditionReason": "这家便利店每晚都在营业:柜台和抽屉有日常使用的痕迹,不是残破,也不是刚搭好的布景。",
|
|
591
593
|
"anchors": [
|
|
592
594
|
{
|
|
593
595
|
"name": "关东煮灯箱",
|
|
@@ -647,6 +649,8 @@
|
|
|
647
649
|
"primary": true,
|
|
648
650
|
"reusePlan": "",
|
|
649
651
|
"summary": "店门外一米宽的雨棚:里面是灯,外面是雨,站在这里的人一半亮一半黑——所有来历不明的人都从这里进出。",
|
|
652
|
+
"condition": "lived-in",
|
|
653
|
+
"conditionReason": "雨棚在雨里站了很多年,红白条已经褪色,但店还在开,不是新搭的布景。",
|
|
650
654
|
"anchors": [
|
|
651
655
|
{
|
|
652
656
|
"name": "褪色的红白雨棚",
|
|
@@ -709,6 +713,8 @@
|
|
|
709
713
|
],
|
|
710
714
|
"scale": "handheld",
|
|
711
715
|
"summary": "一块旧的 3.5 寸机械硬盘,装在防静电袋里,标签被撕掉一半。",
|
|
716
|
+
"condition": "worn",
|
|
717
|
+
"conditionReason": "这是三年前的监控硬盘:标签撕掉一半,接口生锈,不是主办方刚发的新道具。",
|
|
712
718
|
"anchors": [
|
|
713
719
|
{
|
|
714
720
|
"name": "撕掉一半的标签",
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# Dialogue craft — lines as action, in the right 语体
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
A summary of the user's `w-film-dialogue-editor` skill, which is installed beside this one and is
|
|
4
|
+
the source of truth: its revision framework, one language guide per 语体 and a corpus of real
|
|
5
|
+
usage queried with `scripts/ref.mjs`. This page is the short version to keep in mind; the guide of
|
|
6
|
+
the drama's 语体 is read in full before writing lines and again in the dialogue review (§3). Two
|
|
7
|
+
gates: the **advisory** `dialogue-register` notes lines that break the register (a 穿越 character
|
|
8
|
+
speaking 古装 in a modern drama is right, not wrong), and the **required** `dialogue-review` holds
|
|
9
|
+
the storyboard until every line has been reviewed.
|
|
7
10
|
|
|
8
11
|
## 1. A line is an action under pressure
|
|
9
12
|
|
|
@@ -94,14 +97,16 @@ a 6–18-month half-life: two or three signature words per character, no more. P
|
|
|
94
97
|
vertical short drama allows damn / hell / ass / limited bitch, avoids the f-word; the first three
|
|
95
98
|
seconds are clean.
|
|
96
99
|
|
|
97
|
-
## 3. The
|
|
100
|
+
## 3. The dialogue review — `seed dialogue` → fill → `apply dialogue`
|
|
98
101
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
Required after every script (`stage-script.md` § Dialogue review). `seed dialogue --ep N` writes
|
|
103
|
+
`episode.dialogueReview` — one row per line with 原句 filled — and prints the guide and the corpus
|
|
104
|
+
query for each speaker. Fill it the way the dialogue skill reviews a scene: the diagnosis first,
|
|
105
|
+
then per line 问题 / 修改句 / 修改理由 / 导演/演员提示, then the guide's 自检清单. Levels: 轻修 (keep
|
|
106
|
+
the sentence, fix tone, rhythm, filler), 中修 (restructure, cut explanation, sharpen the attack and
|
|
107
|
+
defence), 重修 (re-design the beats and strategies, keep the story intent). `apply dialogue` writes
|
|
108
|
+
the revised lines into the script; `render dialogue` prints the filled table, which is appended to
|
|
109
|
+
the screenplay dataset under `## 对白校对`.
|
|
105
110
|
|
|
106
111
|
| 原句 | 问题 | 修改句 | 修改理由 |
|
|
107
112
|
| --- | --- | --- | --- |
|