@ninkch/dsh-infinite-canvas 0.17.11 → 0.17.13
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 +56 -18
- package/README.zh-CN.md +83 -40
- package/assets/canvas-studio/SKILL.md +31 -7
- package/client.js +710 -70
- package/docs/guide.en.md +225 -0
- package/docs/guide.zh-CN.md +229 -0
- package/index.js +34 -3
- package/package.json +1 -1
package/docs/guide.en.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Infinite Canvas User Guide — Case Study: "Time-Postman" (时空邮递员)
|
|
2
|
+
|
|
3
|
+
> **中文版:[guide.zh-CN.md](./guide.zh-CN.md)**
|
|
4
|
+
> This guide walks through a complete episode produced with the current UI. All screenshots are from the real production run.
|
|
5
|
+
> Core idea in one line: **let the Harness chat handle the batch work; fine-tune the details on the canvas yourself.**
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. What it is
|
|
10
|
+
|
|
11
|
+
Infinite Canvas is a DeepSeek Harness plugin that turns the sidebar into a node-based short-drama studio. Scripts, the series bible, storyboards, reference images, videos and final cuts all live as **nodes** on an infinite canvas, wired into a pipeline.
|
|
12
|
+
|
|
13
|
+
Two ways to drive it, best combined:
|
|
14
|
+
|
|
15
|
+
| Mode | Best for |
|
|
16
|
+
|---|---|
|
|
17
|
+
| **Harness chat (recommended primary)** | Batch & pipeline work: world view, full episode scripts, storyboard breakdowns, batches of reference images, per-scene videos — one sentence, the agent drives the canvas tools |
|
|
18
|
+
| **Manual canvas editing** (fine-tuning) | When a specific result isn't right: edit the prompt on the node and regenerate, tweak duration/ratio, reorder references, roll back history |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 2. Setup
|
|
23
|
+
|
|
24
|
+
1. Install the plugin (bundle folder) and **restart Harness once**. Open a workspace session — the **Infinite Canvas** entry appears; open the canvas panel.
|
|
25
|
+
2. The right panel has four tabs: **Projects / Assets / Bible / Settings**.
|
|
26
|
+
|
|
27
|
+

|
|
28
|
+
|
|
29
|
+
3. First time: finish the basics in the **Settings** tab (see section 5), then start from the chat.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 3. The core: driving the canvas from chat (a full episode)
|
|
34
|
+
|
|
35
|
+
### 3.1 World view & series bible
|
|
36
|
+
|
|
37
|
+
**You say:**
|
|
38
|
+
|
|
39
|
+
> "Use 'Time-Postman' as the sample project — write the world view and series bible first."
|
|
40
|
+
|
|
41
|
+
**The agent**: creates the project → writes the world view, style baseline, characters (Chen Shi / Granny Lin), scenes (Night Post Office / Wrinkled Alley / City Street), props (Fire-Seal Letter / Brass Pocket Watch / Canvas Mailbag…) into the **bible**.
|
|
42
|
+
|
|
43
|
+

|
|
44
|
+
|
|
45
|
+
**Why the bible matters**: it is the single source of truth for cross-shot, cross-episode consistency — every script, storyboard and video call automatically carries it; an `@Chen Shi` mention in a prompt automatically attaches that entity's description and reference assets, so **you never re-describe a character's looks**.
|
|
46
|
+
|
|
47
|
+
> 💡 Batch tip: "Fill in every character/scene/prop description until it's production-ready" — pure batch form-filling, far faster via chat.
|
|
48
|
+
|
|
49
|
+
### 3.2 Write the script (one episode = 60–120s of screen time)
|
|
50
|
+
|
|
51
|
+
**You say:**
|
|
52
|
+
|
|
53
|
+
> "Write episode 1, 'The Green Light of the Night Post Office', based on the bible."
|
|
54
|
+
|
|
55
|
+
**The agent**: creates the Episode-1 script node and runs it. The script automatically satisfies: one episode of 1–2 minutes in 4–10 scenes; **every scene starts with its own `【场N】name (location · time)` header** (the parse hook for the next step); each scene holds 10–15 seconds; dialogue on its own lines as `Character: line`.
|
|
56
|
+
|
|
57
|
+
### 3.3 Expand into scenes
|
|
58
|
+
|
|
59
|
+
Click **"Expand to scenes"** on the script node, or tell the agent: "Expand episode 1 into scenes." The canvas fills in one group per scene:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
Ep1-Scene1 text ──→ Ep1-Scene1 storyboard
|
|
63
|
+
Ep1-Scene2 text ──→ Ep1-Scene2 storyboard
|
|
64
|
+
… (one wire per scene; one generation per 10–15s scene video)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Each storyboard is broken into a shot list by AI: per shot — visual, motion & camera, characters/scene/props (`@name` references), duration, and **dialogue annotations** (which line belongs to which character — the voice-reference extractor relies on this). Shot count follows the actual action beats; the total stays ≤ 15 seconds.
|
|
68
|
+
|
|
69
|
+
The canvas after the episode is expanded (left: script → per-scene texts → per-scene storyboards):
|
|
70
|
+
|
|
71
|
+

|
|
72
|
+
|
|
73
|
+
### 3.4 Generate reference images (characters / scenes / props)
|
|
74
|
+
|
|
75
|
+
**You say:**
|
|
76
|
+
|
|
77
|
+
> "Generate reference images for every character, scene and prop, following the naming convention."
|
|
78
|
+
|
|
79
|
+
**The agent**: batch-creates image nodes (`Character-ChenShi multi-view`, `Scene-NightPostOffice multi-view`, `Prop-FireSealLetter multi-view`…) and runs them. Before generating it runs a **consistency check**: entities that appear in shots but aren't registered (or have empty descriptions) raise warnings, and the agent fills the bible first.
|
|
80
|
+
|
|
81
|
+
Generated assets land in the **Assets** tab, organized by category (Character / Scene / Prop / Script / Storyboard / Voice / Final cut):
|
|
82
|
+
|
|
83
|
+

|
|
84
|
+
|
|
85
|
+
> 💡 Batch tip: ten reference images and six storyboards are exactly the kind of repetitive work the chat side is fastest at — one sentence does it all; you just review the images.
|
|
86
|
+
|
|
87
|
+
### 3.5 Storyboard + references → scene video
|
|
88
|
+
|
|
89
|
+
**You say:**
|
|
90
|
+
|
|
91
|
+
> "Generate scene 1's video."
|
|
92
|
+
|
|
93
|
+
**The agent**:
|
|
94
|
+
|
|
95
|
+
1. Reads scene 1's shot list from the storyboard (the shot sequence comes from there, never invented);
|
|
96
|
+
2. Creates a video node wired to the storyboard — all shots (order + durations) compose ONE prompt and the video model renders the whole clip in one call (hard cuts by the model);
|
|
97
|
+
3. Wires the scene's reference assets to the video node's reference port (`[图1] Character-ChenShi, [图2] Scene-CityStreet…`); `@mentions` in the prompt attach their assets automatically;
|
|
98
|
+
4. Runs and polls; when done it **extracts the tail frame** onto the `last` port — scene 2 chains via tail-frame → first-frame for visual continuity.
|
|
99
|
+
|
|
100
|
+
Scene 1's result: the video node with preview, bound references, and the tail-frame asset (the Assets panel gains "Ep1-Scene1 video" and "tail frame" cards):
|
|
101
|
+
|
|
102
|
+

|
|
103
|
+
|
|
104
|
+
### 3.6 Post-production with the Craft family
|
|
105
|
+
|
|
106
|
+
With the companion [ArtCraft](../dsh-artcraft/README.md) plugin installed, the canvas works with the local Craft suite (12 apps: PhotoCraft imaging / FilmCraft editing+render / SoundCraft audio…):
|
|
107
|
+
|
|
108
|
+
- **You say:** "Export scenes 1–6 to FilmCraft as an MP4 in order, subtitles from the shot dialogue."
|
|
109
|
+
- The final-cut node writes a **FCP7 XML timeline + SRT subtitles** into the data root's `craft/` folder — FilmCraft opens and renders;
|
|
110
|
+
- Single assets go to PhotoCraft for grading in one click; the Settings Craft card shows 12 status lights (12/12 ready in the screenshots).
|
|
111
|
+
|
|
112
|
+
### 3.7 The whole flow
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
chat: world view/bible → episode script → expand to scenes → batch refs → per-scene videos → craft post
|
|
116
|
+
canvas: project card script node text+storyboard ×N ref image nodes ×N video nodes ×N craft/ output
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 4. Manual fine-tuning: nodes are the workbench
|
|
122
|
+
|
|
123
|
+
After the chat batch is done, the canvas is where you polish:
|
|
124
|
+
|
|
125
|
+
- **Regenerate**: edit the prompt/idea on a node and hit generate again;
|
|
126
|
+
- **Swap references**: the video node's reference list supports reorder (↑↓), remove, and re-attach from the asset page;
|
|
127
|
+
- **Parameters**: per-scene duration (≤15s), ratio (16:9/9:16…), resolution (720P/1080P) switch right on the node;
|
|
128
|
+
- **Mask inpainting**: image nodes support brush-mask partial redraw;
|
|
129
|
+
- **History**: each media node keeps the last 8 results — click a thumbnail to roll back;
|
|
130
|
+
- **Re-wire**: unhappy with a scene's storyboard? Wire its text node to another storyboard and re-break.
|
|
131
|
+
|
|
132
|
+
**Recommended rhythm**: let chat finish the 80% batch → polish the 20% you care about on the canvas → have chat re-run the changed parts.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 5. Model configuration: providers + models
|
|
137
|
+
|
|
138
|
+
Settings tab → Image models / Video models / TTS voices, organized in **two levels**:
|
|
139
|
+
|
|
140
|
+
1. **Provider** (collapsed row): configure the endpoint + API key **once** (+ optional extra params);
|
|
141
|
+
2. **Models**: list several model IDs under it (same vendor, different tiers); **star ★ one as the default** — nodes without an explicit pick route there automatically.
|
|
142
|
+
|
|
143
|
+

|
|
144
|
+
|
|
145
|
+
Expand a provider to edit its details (endpoint, key, output format, extra params, model list):
|
|
146
|
+
|
|
147
|
+

|
|
148
|
+
|
|
149
|
+
Key points:
|
|
150
|
+
|
|
151
|
+
- **Fill the endpoint any way you like**: bare domain (`https://api.xxx.com`), up to `/v1`, or the full endpoint — the canvas normalizes it;
|
|
152
|
+
- **Extra params (JSON, optional)**: vendor-specific keys (`watermark`, `prompt_extend`, `output_format`, `seed`…) merge into the request body last — switching vendors needs zero code;
|
|
153
|
+
- **Node model dropdowns** list every configured model (starred ones carry ★); empty = the starred default; with nothing configured, a run fails with a clear error;
|
|
154
|
+
- **Compatibility**: OpenAI-style task APIs, Seedance-native `content[]` and Sora-style `/v1/videos` are auto-detected with a fallback chain; resolution/ratio/first-frame/references are mapped to each vendor's conventions;
|
|
155
|
+
- **Text models** use whatever Harness has configured — no extra keys;
|
|
156
|
+
- **TTS voices**: same provider structure, mixed into the final cut per shot.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 6. Data root: setup & cross-machine migration
|
|
161
|
+
|
|
162
|
+
### 6.1 Set the data root
|
|
163
|
+
|
|
164
|
+
Settings tab → **Data root**: enter a local folder (e.g. `D:\model\canvas-data`) → **Set directory**. Everything is persisted per **project name**:
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
<data root>/
|
|
168
|
+
├─ canvas.meta.json # project id → folder mapping
|
|
169
|
+
└─ projects/
|
|
170
|
+
└─ Time-Postman/
|
|
171
|
+
├─ project.json # canvas doc (nodes/edges/bible)
|
|
172
|
+
├─ assets.json # asset index
|
|
173
|
+
├─ image/ video/ audio/ text/ # media by type
|
|
174
|
+
└─ craft/ # Craft post-production output (XML/SRT/MP4)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Open folder** opens it in Explorer; **Import from data root** merges disk projects into the canvas in one click.
|
|
178
|
+
|
|
179
|
+
> Tip: put the data root inside a **cloud-sync folder** (OneDrive/Nutstore/…) and multiple machines stay in sync automatically.
|
|
180
|
+
|
|
181
|
+
### 6.2 Copying to another machine
|
|
182
|
+
|
|
183
|
+
1. **Old machine**: copy the whole data root to a USB drive / cloud folder;
|
|
184
|
+
2. **New machine**: install the plugin → point Settings → Data root at the copied folder → **auto-recognized**, existing projects appear in the project list;
|
|
185
|
+
3. For any browser-local leftovers, click **Import from data root** to merge.
|
|
186
|
+
|
|
187
|
+
Media lives on disk, organized by project — **copying the folder IS the full migration** (images, videos, audio, scripts and the bible included).
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 7. Assets & the bible
|
|
192
|
+
|
|
193
|
+
### Assets tab
|
|
194
|
+
|
|
195
|
+
- Everything generated or imported — images, videos, audio, text — in one place; filter by category: All / Character / Scene / Prop / Script / **Storyboard** / **Voice** / **Final cut** / General;
|
|
196
|
+
- Each asset card: project dropdown (editable), category dropdown (editable), rename (✎), creation time;
|
|
197
|
+
- **Sync all assets to disk**: flush every browser-held asset to the data root;
|
|
198
|
+
- **Import image/video**: bring local files in as assets (e.g. a character's line clipped in an NLE);
|
|
199
|
+
- Deleting an asset **also deletes the file on disk**.
|
|
200
|
+
|
|
201
|
+
### Series bible
|
|
202
|
+
|
|
203
|
+
- One per project: world view / style baseline / characters / scenes / props; "✦ Draft bible with AI" fills it in one click;
|
|
204
|
+
- **Injected into everything**: every script, storyboard, image and video call carries it — cross-shot, cross-episode consistency;
|
|
205
|
+
- **Bind assets to entities** (📷 button): give "Chen Shi" his multi-view sheet + voice reference, and `@Chen Shi` carries them automatically;
|
|
206
|
+
- **Consistency warnings**: unregistered entities appearing in storyboards raise warnings that the agent resolves (names verbatim).
|
|
207
|
+
|
|
208
|
+
### Voice references (character voice consistency)
|
|
209
|
+
|
|
210
|
+
1. Check "generate synced audio" on the video provider → generated clips carry their own audio track;
|
|
211
|
+
2. On a video/final-cut node click **"Extract voice reference"** → type the character name → every dialogue window is located automatically from the storyboard `dialogue` annotations and merged into one `Character-<name> voice` audio asset (auto-bound to the entity);
|
|
212
|
+
3. From then on, `@<name>` in that character's video prompts attaches the voice reference (`audios[]`) and the generated speech aligns to it.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 8. Troubleshooting
|
|
217
|
+
|
|
218
|
+
| Symptom | Cause & fix |
|
|
219
|
+
|---|---|
|
|
220
|
+
| Video fails with HTTP 413 | References too large — fixed since 0.17.11 (auto 1024px JPEG downscale); upgrade |
|
|
221
|
+
| Video 404 / "Unsupported model type" | The gateway endpoint doesn't serve that model's channel: verify the endpoint URL and model ID (copy from the platform's model list); some platforms also need the right **token group**; the canvas automatically falls back to Seedance-native `content[]` and `/v1/videos` |
|
|
222
|
+
| Video 503 supply unavailable | The platform's model supply is temporarily down — retry later |
|
|
223
|
+
| Deleted nodes come back | Old sync race — upgrade to 0.17.11+ |
|
|
224
|
+
| Storyboards always have exactly 6 shots | Old anchoring issue — since 0.17.11 shot counts follow the content beats |
|
|
225
|
+
| Demo-mode images | No model configured, or the node has no pick and no starred default — see section 5 |
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# 无限画布操作手册 —— 以《时空邮递员》为例
|
|
2
|
+
|
|
3
|
+
> **English guide: [guide.en.md](./guide.en.md)**(英文版为主)
|
|
4
|
+
> 本手册以示例项目《时空邮递员》贯穿全程,截图均来自真实制作过程(当前版本界面)。
|
|
5
|
+
> 核心理念一句话:**批量工作交给 Harness 对话,细节自己在画布上调。**
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. 这是什么
|
|
10
|
+
|
|
11
|
+
无限画布是 DeepSeek Harness 的插件:把侧边栏变成"节点式短剧工作室"。剧本、设定集、分镜、资产图、视频、成片全部以**节点**摆在无限画布上,连线组成流水线。
|
|
12
|
+
|
|
13
|
+
两种驱动方式,配合使用效率最高:
|
|
14
|
+
|
|
15
|
+
| 方式 | 适合做什么 |
|
|
16
|
+
|---|---|
|
|
17
|
+
| **Harness 对话驱动**(推荐主力) | 批量与流程性工作:出世界观、写整集剧本、铺开分镜、批量生成参考图、逐场生成视频——一句话,Agent 调用画布工具批量完成 |
|
|
18
|
+
| **画布手动操作**(精修) | 个别结果不满意时:节点上直接改提示词重新生成、调时长/比例、拖参考图顺序、回退历史版本 |
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 2. 准备工作
|
|
23
|
+
|
|
24
|
+
1. 安装插件(bundle 目录)后**重启一次 Harness**,进入工作区会话,侧边栏/工具栏出现**无限画布**入口。
|
|
25
|
+
2. 点开画布面板,右侧是四个页签:**项目 / 资产 / 设定集 / 设置**。
|
|
26
|
+
|
|
27
|
+

|
|
28
|
+
|
|
29
|
+
3. 首次使用先到**设置**页签完成基础配置(见第 5 节),回到对话即可开工。
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 3. 核心:用对话驱动画布(以第一集完整制作为例)
|
|
34
|
+
|
|
35
|
+
### 3.1 出世界观、写设定集
|
|
36
|
+
|
|
37
|
+
**你说:**
|
|
38
|
+
|
|
39
|
+
> 「用【时空邮递员】做示例项目,先出世界观和设定集。」
|
|
40
|
+
|
|
41
|
+
**Agent 做的事**:创建项目 → 把世界观、风格基调、角色(陈拾/林婆婆)、场景(深夜邮局/褶皱巷/城市街头)、道具(火漆信/黄铜怀表/帆布邮包…)逐条写入**设定集**。
|
|
42
|
+
|
|
43
|
+

|
|
44
|
+
|
|
45
|
+
**为什么设定集重要**:它是跨镜、跨集一致性的唯一事实源——之后每次剧本生成、分镜拆解、视频生成都自动注入设定集;提示词里 `@陈拾` 这样的引用会自动携带该实体的设定描述与参考图资产,**不需要在每个提示词里重复描述人物长相**。
|
|
46
|
+
|
|
47
|
+
> 💡 批量提示:「把所有角色/场景/道具的设定补全到可直接生成的程度」——纯批量填表工作,交给对话远快于手动。
|
|
48
|
+
|
|
49
|
+
### 3.2 写剧本(一集 = 60–120 秒成片)
|
|
50
|
+
|
|
51
|
+
**你说:**
|
|
52
|
+
|
|
53
|
+
> 「根据设定集写第一集剧本《深夜邮局的绿灯》。」
|
|
54
|
+
|
|
55
|
+
**Agent 做的事**:创建「第一节剧本」节点并触发生成。剧本自动满足:一集 1–2 分钟、4–10 场、**每场以「【场N】场景名(地点·时间)」单独一行开头**(下一步自动铺开的解析标记)、每场 10–15 秒容量、对白逐行「角色:台词」。
|
|
56
|
+
|
|
57
|
+
### 3.3 铺开到场景
|
|
58
|
+
|
|
59
|
+
点剧本节点的**「铺开到场景」按钮**,或对 Agent 说「把第一集铺开到场景」。画布上自动出现每场一组的节点组合:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
第一节-场1文本 ──→ 第一节-场1分镜表
|
|
63
|
+
第一节-场2文本 ──→ 第一节-场2分镜表
|
|
64
|
+
……(每场一条连线,一次生成一个 10–15s 的场景视频)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
分镜表由 AI 拆解为镜头清单:每镜含画面、动作与运镜、角色/场景/道具(`@名称` 引用)、时长、**台词标注**(哪句台词属于哪个角色——后面提取声音参考就靠它)。镜头数量按内容节拍自然决定,全部镜头时长之和 ≤ 15 秒。
|
|
68
|
+
|
|
69
|
+
整集铺开后的画布(左侧:剧本 → 各场文本 → 各场分镜表的连线组):
|
|
70
|
+
|
|
71
|
+

|
|
72
|
+
|
|
73
|
+
场1 的连线细节(场1文本 → 场1分镜表 → 场1视频):
|
|
74
|
+
|
|
75
|
+

|
|
76
|
+
|
|
77
|
+
### 3.4 生成资产图(角色/场景/道具参考图)
|
|
78
|
+
|
|
79
|
+
**你说:**
|
|
80
|
+
|
|
81
|
+
> 「把设定集里的所有角色、场景、道具都生成参考图,按命名规范。」
|
|
82
|
+
|
|
83
|
+
**Agent 做的事**:批量创建图片生成节点(`角色-陈拾 多视图`、`场景-深夜邮局 多视图`、`道具-火漆信 多视图`…),逐个触发生成。生成前自动做**一致性检查**:分镜里出现但设定集未登记(或描述为空)的实体会产生告警,Agent 先补全设定再生成。
|
|
84
|
+
|
|
85
|
+
生成完的资产进入右侧**资产页签**,按分类(角色/场景/道具/剧本/分镜表/配音/成片)归档:
|
|
86
|
+
|
|
87
|
+

|
|
88
|
+
|
|
89
|
+
> 💡 批量提示:10 张参考图、6 个分镜表这类重复性批量工作是对话驱动的最大收益点——一句话全做完,你只检查画面细节。
|
|
90
|
+
|
|
91
|
+
### 3.5 分镜 + 资产图 → 生成场景视频
|
|
92
|
+
|
|
93
|
+
**你说:**
|
|
94
|
+
|
|
95
|
+
> 「生成场1的视频。」
|
|
96
|
+
|
|
97
|
+
**Agent 做的事**:
|
|
98
|
+
|
|
99
|
+
1. 读取场1分镜表的镜头清单(镜头序列以此为准,不自行编造);
|
|
100
|
+
2. 创建视频生成节点并连线分镜表——全部镜头按顺序+时长合成一条提示词,**视频模型一次性生成整段**(镜头间硬切);
|
|
101
|
+
3. 把本场参考图连到视频节点参考端口(`[图1] 角色-陈拾、[图2] 场景-城市街头…`),提示词里的 `@引用` 也会自动挂载;
|
|
102
|
+
4. 触发生成并轮询;完成后自动**提取尾帧**挂到 `last` 端口——场2 用「尾帧 → 首帧」串联,保证段间画面连贯。
|
|
103
|
+
|
|
104
|
+
场1 的成品:视频节点带预览、参考图绑定、尾帧资产(右侧资产页同时出现「第一节-场1视频」与「尾帧」卡片):
|
|
105
|
+
|
|
106
|
+

|
|
107
|
+
|
|
108
|
+
### 3.6 调用 Craft 家族做后期
|
|
109
|
+
|
|
110
|
+
安装 [ArtCraft](../dsh-artcraft/README.md) 插件后,画布与本地 Craft 家族(12 个:PhotoCraft 修图 / FilmCraft 剪辑渲染 / SoundCraft 音频…)协作:
|
|
111
|
+
|
|
112
|
+
- **你说:**「把场1到场6按顺序导出给 FilmCraft 渲染 MP4,字幕用分镜台词。」
|
|
113
|
+
- 成片节点写出 **FCP7 XML 时间线 + SRT 字幕**到数据目录 `craft/` 文件夹,FilmCraft 打开即渲染;
|
|
114
|
+
- 单张资产图一键交 PhotoCraft 调色;设置页 Craft 卡片显示 12 盏状态灯(12/12 就绪)。
|
|
115
|
+
|
|
116
|
+
### 3.7 流程总览
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
对话:出世界观/设定集 → 写第一集剧本 → 铺开到场景 → 批量资产图 → 逐场视频 → craft 成片
|
|
120
|
+
画布: 项目卡片 剧本节点 文本+分镜表×N 资产图节点×N 视频节点×N craft/ 产物
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 4. 手动微调:节点就是工作台
|
|
126
|
+
|
|
127
|
+
对话批量跑完后,画布是你精修的地方:
|
|
128
|
+
|
|
129
|
+
- **重新生成**:改节点上的提示词/创意,再点一次生成;
|
|
130
|
+
- **换参考图**:视频节点的参考图列表可排序(↑↓)、删除、从资产页补挂;
|
|
131
|
+
- **调参数**:每场视频的时长(≤15s)、比例(16:9/9:16…)、分辨率(720P/1080P)节点上直接切;
|
|
132
|
+
- **蒙版重绘**:图片节点支持涂抹蒙版局部重绘;
|
|
133
|
+
- **历史版本**:每个媒体节点保留最近 8 次结果,点缩略图即回退;
|
|
134
|
+
- **拖拽重连**:不满意某场分镜?把文本节点连到另一个分镜表重新拆。
|
|
135
|
+
|
|
136
|
+
**推荐节奏**:对话干完 80% 批量活 → 画布上精修不满意的 20% → 再让对话批量重跑改过的部分。
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 5. 模型配置:供应商 + 模型
|
|
141
|
+
|
|
142
|
+
设置页签 → 图片模型 / 视频模型 / TTS 配音,采用**两级结构**:
|
|
143
|
+
|
|
144
|
+
1. **供应商**(折叠行):**一个供应商只配一次**接口地址 + API Key(+ 可选扩展参数);
|
|
145
|
+
2. **模型**:供应商下挂多个模型 ID(同厂不同等级),**点 ★ 星标 = 默认模型**——节点上没选模型时自动路由到这里。
|
|
146
|
+
|
|
147
|
+

|
|
148
|
+
|
|
149
|
+
展开某个供应商即可编辑详情(地址、Key、输出格式、扩展参数、模型列表):
|
|
150
|
+
|
|
151
|
+

|
|
152
|
+
|
|
153
|
+
要点:
|
|
154
|
+
|
|
155
|
+
- **接口地址怎么填都行**:裸域(`https://api.xxx.com`)、填到 `/v1`、或完整端点,画布自动归一化;
|
|
156
|
+
- **扩展参数(JSON,可选)**:厂商专属参数(`watermark`、`prompt_extend`、`output_format`、`seed`…)逐键合并进请求体,**换厂商零代码**;
|
|
157
|
+
- **节点上的模型下拉**直接列出所有已配置模型(星标带 ★);留空 = 用默认模型;一个模型都没配时运行明确报错;
|
|
158
|
+
- **兼容性**:OpenAI 风格任务接口、Seedance 原生 `content[]`、Sora 风格 `/v1/videos` 自动识别与降级;分辨率/比例/首帧/参考图按厂商惯例自动转换;
|
|
159
|
+
- **文本模型**直接使用 Harness 当前配置的模型,无需额外 Key;
|
|
160
|
+
- **TTS 配音**:同一供应商结构,按镜配音混入成片。
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 6. 数据目录:设置与跨电脑迁移
|
|
165
|
+
|
|
166
|
+
### 6.1 设置数据目录
|
|
167
|
+
|
|
168
|
+
设置页签 → **数据根目录**:填本地文件夹路径(如 `D:\model\canvas-data`)→「设置此目录」。设置后所有项目数据按**项目名**落盘:
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
<数据根目录>/
|
|
172
|
+
├─ canvas.meta.json # 项目 ID → 文件夹 映射
|
|
173
|
+
└─ projects/
|
|
174
|
+
└─ 时空邮递员/
|
|
175
|
+
├─ project.json # 画布文档(节点/连线/设定集)
|
|
176
|
+
├─ assets.json # 资产索引
|
|
177
|
+
├─ image/ video/ audio/ text/ # 媒体文件(按类型分目录)
|
|
178
|
+
└─ craft/ # Craft 家族后期产物(XML/SRT/MP4)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
「打开目录」可直接在资源管理器中打开;「从数据目录导入」一键把磁盘上的项目合并进画布。
|
|
182
|
+
|
|
183
|
+
> 建议把数据目录放进**网盘同步文件夹**(OneDrive/坚果云等),多台电脑自动同步。
|
|
184
|
+
|
|
185
|
+
### 6.2 跨电脑复制导入
|
|
186
|
+
|
|
187
|
+
1. **旧电脑**:整个数据根目录复制到 U 盘/网盘;
|
|
188
|
+
2. **新电脑**:安装插件 → 设置页签把数据根目录指向复制来的文件夹 → **自动识别**,已有项目直接出现在项目列表;
|
|
189
|
+
3. 浏览器本地若有零散未落盘数据,点 **「从数据目录导入」** 一键合并。
|
|
190
|
+
|
|
191
|
+
媒体文件全部在磁盘上、按项目名组织——**复制目录 = 完整迁移**(含所有图片、视频、音频、剧本文本与设定集)。
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 7. 资产管理与设定集
|
|
196
|
+
|
|
197
|
+
### 资产页
|
|
198
|
+
|
|
199
|
+
- 所有生成/导入的图片、视频、音频、文本集中管理;顶部分类筛选:全部 / 角色 / 场景 / 道具 / 剧本 / **分镜表** / **配音** / **成片** / 通用;
|
|
200
|
+
- 每张资产卡:项目归属下拉(可改)、分类下拉(可改)、编辑名(✎)、生成时间;
|
|
201
|
+
- **「同步全部资产到磁盘」**:把浏览器里的历史资产一次性落盘到数据目录;
|
|
202
|
+
- **「导入图片/视频」**:把本地文件导入为资产(如剪辑软件里剪出的角色台词片段);
|
|
203
|
+
- 删除资产会**同步删除磁盘文件**。
|
|
204
|
+
|
|
205
|
+
### 设定集(Series Bible)
|
|
206
|
+
|
|
207
|
+
- 每项目一份:世界观 / 风格基调 / 角色 / 场景 / 道具;「✦ AI 起草设定集」一键起草;
|
|
208
|
+
- **注入一切生成**:剧本、分镜、图片、视频的每次 AI 调用都携带设定集,保证跨镜跨集一致;
|
|
209
|
+
- **实体绑定资产**(📷 按钮):给「陈拾」绑定他的多视图图 + 声音参考,`@陈拾` 自动携带;
|
|
210
|
+
- **一致性告警**:分镜里出现未登记实体时产生告警,Agent 自动补全(名称逐字一致)。
|
|
211
|
+
|
|
212
|
+
### 声音参考(角色音色一致性)
|
|
213
|
+
|
|
214
|
+
1. 视频供应商勾选「生成同步音频」→ 生成自带音轨的视频;
|
|
215
|
+
2. 视频/成片节点点「**提取声音参考**」→ 输入角色名 → 自动按分镜台词标注定位该角色全部台词时间窗,拼接为一个 `角色-<名> 声音` 音频资产(自动绑定实体);
|
|
216
|
+
3. 之后该角色的视频提示词 `@<名>` 自动携带音色参考,模型生成的对白向参考音色对齐。
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 8. 常见问题
|
|
221
|
+
|
|
222
|
+
| 现象 | 原因与处理 |
|
|
223
|
+
|---|---|
|
|
224
|
+
| 视频报 HTTP 413 | 参考图过大——0.17.11 起已自动压缩(1024px JPEG),请升级 |
|
|
225
|
+
| 视频报 404 / "Unsupported model type" | 网关端点与模型渠道不匹配:核对接口地址与模型 ID(从平台模型列表复制);部分平台需检查**令牌分组**;画布会自动降级尝试 Seedance 原生 `content[]` 格式与 `/v1/videos` |
|
|
226
|
+
| 视频报 503 supply unavailable | 平台侧模型供货暂时不可用,稍后重试 |
|
|
227
|
+
| 删除的节点又出现 | 旧版本同步竞态,升级到 0.17.11+ |
|
|
228
|
+
| 分镜只有固定 6 镜 | 旧版锚定问题,0.17.11 起镜头数按内容节拍自动决定 |
|
|
229
|
+
| 演示模式出图 | 没配对应模型,或节点上没选且无星标默认——按第 5 节配置 |
|
package/index.js
CHANGED
|
@@ -253,6 +253,24 @@ function writeAssetIndex(pid, projectName, assets, opts) {
|
|
|
253
253
|
if (i >= 0) list[i] = a;
|
|
254
254
|
else list.push(a);
|
|
255
255
|
}
|
|
256
|
+
// replace 语义保留"文件仍存在"的孤儿记录:手工放进数据目录/导入中的资产不被启动对齐误清;
|
|
257
|
+
// 文件已不存在的记录才是真幽灵(删除后残留),照常清理。
|
|
258
|
+
if (opts && opts.replace) {
|
|
259
|
+
const keepIds = new Set(list.map((x) => x.id));
|
|
260
|
+
const orphans = [];
|
|
261
|
+
try {
|
|
262
|
+
const prev = JSON.parse(readFileSync(f, 'utf8'));
|
|
263
|
+
for (const a of (Array.isArray(prev) ? prev : [])) {
|
|
264
|
+
if (!a || !a.id || keepIds.has(a.id)) continue;
|
|
265
|
+
let alive = false;
|
|
266
|
+
if (a.rel) {
|
|
267
|
+
try { const pr = physicalRel(a.rel); if (pr) alive = existsSync(path.join(root, pr)); } catch { alive = false; }
|
|
268
|
+
}
|
|
269
|
+
if (alive) orphans.push(a);
|
|
270
|
+
}
|
|
271
|
+
} catch { /* 首次/损坏 → 无孤儿可保留 */ }
|
|
272
|
+
for (const a of orphans) list.push(a);
|
|
273
|
+
}
|
|
256
274
|
const tmp = f + '.' + process.pid + '.tmp';
|
|
257
275
|
writeFileSync(tmp, JSON.stringify(list, null, 1), 'utf8');
|
|
258
276
|
renameSync(tmp, f);
|
|
@@ -859,6 +877,7 @@ function canvasWriteNode(args) {
|
|
|
859
877
|
dialogue: Array.isArray(s && s.dialogue)
|
|
860
878
|
? s.dialogue.slice(0, 6).map((d) => ({ role: String(d && d.role || '').trim().slice(0, 24), line: String(d && d.line || '').trim().slice(0, 200) })).filter((d) => d.role && d.line)
|
|
861
879
|
: [],
|
|
880
|
+
sfx: String((s && s.sfx) || '').trim().slice(0, 120),
|
|
862
881
|
}));
|
|
863
882
|
node.data.aiStatus = 'idle';
|
|
864
883
|
node.data.aiError = null;
|
|
@@ -1219,6 +1238,8 @@ async function canvasNodeStatus(args) {
|
|
|
1219
1238
|
dialogue: Array.isArray(s && s.dialogue)
|
|
1220
1239
|
? s.dialogue.slice(0, 6).map((d) => ({ role: String(d && d.role || '').slice(0, 24), line: String(d && d.line || '').slice(0, 200) }))
|
|
1221
1240
|
: [],
|
|
1241
|
+
// 音效/环境音:声音设计提示,随镜头透出给对话侧与视频提示词
|
|
1242
|
+
sfx: String((s && s.sfx) || '').slice(0, 120),
|
|
1222
1243
|
}))
|
|
1223
1244
|
: undefined;
|
|
1224
1245
|
return {
|
|
@@ -1229,6 +1250,9 @@ async function canvasNodeStatus(args) {
|
|
|
1229
1250
|
output: String((n.data && n.data.output) || '').slice(0, 6000),
|
|
1230
1251
|
idea: String((n.data && n.data.idea) || '').slice(0, 2000),
|
|
1231
1252
|
assetId: (n.data && n.data.assetId) || null,
|
|
1253
|
+
// 视频任务凭据:中断/超时后对话侧可凭 id 回查结果(钱花了就必须能找回)
|
|
1254
|
+
taskId: (n.data && n.data.taskId) || null,
|
|
1255
|
+
taskQueryUrl: (n.data && n.data.taskQueryUrl) || null,
|
|
1232
1256
|
// 分镜表:一致性告警随状态返回——对话侧据此逐条补全设定集(缺失则要自动补充,绝不忽略)
|
|
1233
1257
|
warnings: Array.isArray(n.data && n.data.warnings) ? n.data.warnings : [],
|
|
1234
1258
|
shots,
|
|
@@ -1252,11 +1276,11 @@ const PORT_TABLE = {
|
|
|
1252
1276
|
'text': { inputs: [], outputs: [{ id: 'out', kind: 'text' }] },
|
|
1253
1277
|
'shot': { inputs: [{ id: 'char', kind: 'image' }, { id: 'scene', kind: 'image' }, { id: 'prop', kind: 'image' }], outputs: [{ id: 'visual', kind: 'text' }, { id: 'motion', kind: 'text' }] },
|
|
1254
1278
|
'script': { inputs: [], outputs: [{ id: 'out', kind: 'text' }] },
|
|
1255
|
-
'storyboard': { inputs: [{ id: 'script', kind: 'text' }], outputs: [{ id: 'out', kind: 'text' }] },
|
|
1279
|
+
'storyboard': { inputs: [{ id: 'prev', kind: 'text' }, { id: 'script', kind: 'text' }], outputs: [{ id: 'out', kind: 'text' }, { id: 'tail', kind: 'text' }] },
|
|
1256
1280
|
'image-gen': { inputs: [{ id: 'prompt', kind: 'text' }, { id: 'ref', kind: 'image' }], outputs: [{ id: 'out', kind: 'image' }] },
|
|
1257
1281
|
'video-gen': { inputs: [{ id: 'prompt', kind: 'text' }, { id: 'frame', kind: 'image' }, { id: 'ref', kind: 'image' }], outputs: [{ id: 'out', kind: 'video' }, { id: 'last', kind: 'image' }] },
|
|
1258
1282
|
'image-asset': { inputs: [{ id: 'in', kind: 'image' }], outputs: [{ id: 'out', kind: 'image' }] },
|
|
1259
|
-
'video-asset': { inputs: [{ id: 'in', kind: 'video' }], outputs: [{ id: 'out', kind: 'video' }] },
|
|
1283
|
+
'video-asset': { inputs: [{ id: 'in', kind: 'video' }], outputs: [{ id: 'out', kind: 'video' }, { id: 'last', kind: 'image' }] },
|
|
1260
1284
|
'finalcut': { inputs: [{ id: 'in', kind: 'video' }], outputs: [] },
|
|
1261
1285
|
'group': { inputs: [], outputs: [] },
|
|
1262
1286
|
};
|
|
@@ -1860,13 +1884,20 @@ export function apply(ctx) {
|
|
|
1860
1884
|
const lines = ['节点[' + s.type + ']「' + (s.label || s.nodeId) + '」', '状态: ' + s.status + (s.aiStatus && s.aiStatus !== 'idle' ? ' / ' + s.aiStatus : '')];
|
|
1861
1885
|
if (s.error) lines.push('错误: ' + s.error);
|
|
1862
1886
|
if (s.assetId) lines.push('产物资产: ' + s.assetId);
|
|
1887
|
+
if (s.taskId) lines.push('任务凭据: ' + s.taskId + (s.taskQueryUrl ? '(查询: ' + s.taskQueryUrl + ')' : ''));
|
|
1863
1888
|
if (s.idea) lines.push('提示词: ' + s.idea.slice(0, 400));
|
|
1864
1889
|
if (s.output) lines.push('成稿:\n' + s.output);
|
|
1865
1890
|
// 镜头清单:结构化返回 + 渲染进文本——对话侧据此组织多镜头视频提示词(绝不自行编造镜头表)
|
|
1866
1891
|
const shots = Array.isArray(s.shots) ? s.shots : [];
|
|
1867
1892
|
if (shots.length) {
|
|
1868
1893
|
lines.push('镜头清单(' + shots.length + ' 镜,总时长 ' + shots.reduce((a, x) => a + (Number(x.duration) || 0), 0) + 's)——视频提示词的镜头序列以此为准:');
|
|
1869
|
-
shots.forEach((sh) =>
|
|
1894
|
+
shots.forEach((sh) => {
|
|
1895
|
+
const dl = (sh.dialogue || []).map((d) => d.role + ':' + d.line).join(';');
|
|
1896
|
+
lines.push(sh.index + '. ' + sh.title + '(' + sh.duration + 's)角色:' + (sh.characters.join('/') || '-') + '|场景:' + (sh.scene || '-') + '|道具:' + (sh.props.join('/') || '-')
|
|
1897
|
+
+ '\n 画面: ' + sh.visual + '\n 动作: ' + sh.motion
|
|
1898
|
+
+ (dl ? '\n 台词: ' + dl : '')
|
|
1899
|
+
+ (sh.sfx ? '\n 音效: ' + sh.sfx : ''));
|
|
1900
|
+
});
|
|
1870
1901
|
}
|
|
1871
1902
|
// 一致性告警:结构化返回 + 渲染进文本——对话侧据此逐条补全设定集,绝不忽略
|
|
1872
1903
|
const warnings = Array.isArray(s.warnings) ? s.warnings : [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ninkch/dsh-infinite-canvas",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.13",
|
|
4
4
|
"description": "Node-based short-drama studio for DeepSeek Harness: script → storyboard → assets → shots → voiced, subtitled final cut on an infinite canvas.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|