@ninkch/dsh-infinite-canvas 0.19.4 → 0.19.6
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 +4 -4
- package/README.zh-CN.md +6 -6
- package/assets/canvas-director/SKILL.md +14 -14
- package/assets/canvas-director/forms/interview.md +1 -1
- package/assets/canvas-director/manifest.json +8 -8
- package/assets/canvas-director/pack.js +8 -12
- package/assets/canvas-studio/SKILL.md +2 -2
- package/assets/director/clips/dodge_back.json +1 -0
- package/assets/director/clips/idle_02.json +1 -0
- package/assets/director/clips/idle_03.json +1 -0
- package/assets/director/clips/jump.json +1 -0
- package/assets/director/clips/manifest.json +156 -0
- package/assets/director/clips/run.json +1 -0
- package/assets/director/clips/run_back.json +1 -0
- package/assets/director/clips/run_forward.json +1 -0
- package/assets/director/clips/run_left.json +1 -0
- package/assets/director/clips/run_right.json +1 -0
- package/assets/director/clips/run_stop.json +1 -0
- package/assets/director/clips/running_jump.json +1 -0
- package/assets/director/clips/sit_laugh.json +1 -0
- package/assets/director/clips/turn_left.json +1 -0
- package/assets/director/clips/turn_right.json +1 -0
- package/assets/director/clips/walk.json +1 -0
- package/assets/director/clips/walk_back.json +1 -0
- package/assets/director/clips/walk_forward.json +1 -0
- package/assets/director/clips/walk_left.json +1 -0
- package/assets/director/clips/walk_right.json +1 -0
- package/assets/director/engine.js +291 -65
- package/assets/director/models/explorer.json +1 -0
- package/assets/director/models/index.json +10 -0
- package/assets/director/models/soldier.json +1 -1
- package/assets/director/models/xbot.json +1 -1
- package/client.js +19727 -19577
- package/docs/guide.en.md +5 -5
- package/docs/guide.zh-CN.md +9 -9
- package/index-core-skill-profile.js +2 -6
- package/index.js +10 -25
- package/package.json +5 -1
- package/skill-pack.js +19 -14
package/docs/guide.en.md
CHANGED
|
@@ -309,22 +309,22 @@ There are **no dropdowns** on the page. Every option is an icon tile: click to s
|
|
|
309
309
|
|---|---|---|---|
|
|
310
310
|
| **Director** | 24 | Camera language, lighting, cutting rhythm, style parameters | It constrains the shot's camera fields, the keyframe and the video's camera move at once — the least replaceable decision in the whole piece |
|
|
311
311
|
| **Genre** | 21 narrative / 10 sector | Pressure mechanics, audience payoff, scene granules, episode hooks | The same "revenge" premise is fragmented neon under Wong Kar-wai and hard-lit slow motion under Tsui Hark; folding them together poisons both |
|
|
312
|
-
| **
|
|
312
|
+
| **Spec** | 8 | Structure blocks, ASL floor, rhythm, quality bar | It decides "short drama vs cinematic texture vs commercial", which is orthogonal to genre |
|
|
313
313
|
| **Look** | 9 | Imaging base, material, render texture | 2D thick paint / guoman 3D / game CG are imaging domains, not directors |
|
|
314
314
|
|
|
315
|
-
**Eight
|
|
315
|
+
**Eight specs**: Short drama · Cinematic texture · Commercial · Documentary · Music video · Trailer · Explainer · Interview.
|
|
316
316
|
|
|
317
317
|
- A **short drama** is a self-contained 60–180 s unit and **covers both single episodes and multi-episode series** — a series is just episode after episode, so there is no separate "series" form. Its quality bar is "shoot it like film", not "shoot it like a short video".
|
|
318
318
|
- **Cinematic texture** is a *texture* spec, not a feature-length one. It constrains how each shot must be made to read as cinema (ASL floor 1.5 s, 24 fps, motivated light, real materials, readable depth), and its duration tiers stop at 30–300 s. The reason is practical: **a video model emits only 3–8 s per clip** (5 s by default here), so "a 120-minute film" can only be hundreds of clips stitched together — a 120-minute tier in the spec would be fiction. For a feature, advance episode by episode; this spec makes each segment pass the cinema line.
|
|
319
319
|
- **Commercial** merges 宣传片 (brand film) / 广告片 (ad) / 产品片 (product film) into one card — near-identical needs, split internally by block ratios instead of three cards.
|
|
320
320
|
|
|
321
|
-
The genre layer **switches automatically with the
|
|
321
|
+
The genre layer **switches automatically with the spec**: pick Commercial and it shows sector cards (tech, finance, medical, beauty, auto, education, FMCG, travel, real estate, food); every other form shows narrative genres.
|
|
322
322
|
|
|
323
|
-
**Priority**: explicit user instruction > director >
|
|
323
|
+
**Priority**: explicit user instruction > director > spec (only on ASL and structure) > genre > look.
|
|
324
324
|
|
|
325
325
|
### 9.2 Aspect ratio is not decided here
|
|
326
326
|
|
|
327
|
-
Vertical, horizontal, square or widescreen all work with any
|
|
327
|
+
Vertical, horizontal, square or widescreen all work with any spec — **aspect and resolution are chosen on the video node at generation time**. Vertical delivery is common for short drama, but that is a distribution choice, not a craft spec; **a short drama can equally be shot horizontal and to a cinematic standard**. The spec constrains **structure, rhythm and quality bar**, not proportion.
|
|
328
328
|
|
|
329
329
|
### 9.3 Three buttons
|
|
330
330
|
|
package/docs/guide.zh-CN.md
CHANGED
|
@@ -313,26 +313,26 @@
|
|
|
313
313
|
|---|---|---|---|
|
|
314
314
|
| **导演** | 24 | 镜头语言、灯光色彩、剪辑节奏、风格参数 | 它同时约束分镜的机位字段、图片关键帧、视频运镜——整部片最不可替换的决策 |
|
|
315
315
|
| **题材** | 叙事 21 / 行业 10 | 压力机制、观众回报、场面颗粒、集尾钩子 | 同一个「复仇打脸」,王家卫拍是抽帧暧昧,徐克拍是凌厉升格;混进导演层会互相污染 |
|
|
316
|
-
|
|
|
316
|
+
| **规格** | 8 | 结构块、平均镜长下限、节奏、质量档 | 它决定「这是短剧、电影还是商业片」,与题材正交 |
|
|
317
317
|
| **影调** | 9 | 成像底层、材质、渲染质感 | 2D 厚涂 / 国漫 3D / 游戏 CG 是成像域,不是导演;塞进导演会让「怎么剪」和「长什么样」打架 |
|
|
318
318
|
|
|
319
|
-
|
|
319
|
+
**八种规格**:短剧 · 电影质感 · 商业片 · 纪实 · 音乐视频 · 预告 · 解说 · 访谈。
|
|
320
320
|
|
|
321
321
|
其中:
|
|
322
322
|
- **短剧**是单集 60–180 秒的自足单元,**同时覆盖单集与连续多集**——一部剧就是一集一集往下做,不需要单独的「连续剧」规格。它对质量的要求是「按电影标准拍」,不是「短视频标准」:真实光源与光比、有依据的焦段、可读的景深。
|
|
323
|
-
- **电影质感**是**质感规格,不是长片规格**。它约束每一镜怎么做才像电影(ASL 1.5 秒以上、24 帧、动机光、真材质、成立构图),成片长度档只到 30–300 秒。原因很实际:**AI 视频模型单次只出 3–8 秒**(本插件默认 5 秒),所谓「一部 120
|
|
323
|
+
- **电影质感**是**质感规格,不是长片规格**。它约束每一镜怎么做才像电影(ASL 1.5 秒以上、24 帧、动机光、真材质、成立构图),成片长度档只到 30–300 秒。原因很实际:**AI 视频模型单次只出 3–8 秒**(本插件默认 5 秒),所谓「一部 120 分钟的电影」只能是几百上千个片段接起来,把它写成规格里的一个时长档没有意义。要拍长片,按集/按段推进,本规格负责每一段都过电影线。
|
|
324
324
|
- **商业片**把「宣传片 / 广告片 / 产品片」合成一张卡——它们是相近需求,靠段位配比内部分流,不再拆成三张。
|
|
325
325
|
|
|
326
|
-
**画幅不在这里决定。**
|
|
326
|
+
**画幅不在这里决定。** 横屏、竖屏、方屏、宽银幕都能用任何规格——**画幅与分辨率是视频节点生成时的选项**。短剧竖屏投放很常见,但那是发行选择,不是创作规格;短剧同样可以横屏、可以按电影标准拍。规格约束的是**结构、节奏、质量档**,不是比例。
|
|
327
327
|
|
|
328
|
-
|
|
328
|
+
题材层会**随规格自动切换**:选「商业片」时换成行业题材(科技、金融、医疗、美妆、汽车、教育、快消、文旅、地产、餐饮);其余类型显示叙事题材。
|
|
329
329
|
|
|
330
|
-
优先级:**用户显式指令 > 导演 >
|
|
330
|
+
优先级:**用户显式指令 > 导演 > 规格(仅单镜时长与结构上压过导演)> 题材 > 影调**。
|
|
331
331
|
|
|
332
332
|
### 9.2 三个按钮
|
|
333
333
|
|
|
334
334
|
- **预览**:显示当前配置注入到剧本的切片全文与字节数。用来确认「到底塞了什么进去」。
|
|
335
|
-
- **写设定集**:把风格摘要(导演名 + 题材 +
|
|
335
|
+
- **写设定集**:把风格摘要(导演名 + 题材 + 规格 + 影调)写进设定集的「风格基调」,这样对话侧也能读到。
|
|
336
336
|
- **清空**:四层全归零,生成行为回到默认。
|
|
337
337
|
|
|
338
338
|
### 9.3 配置按项目保存
|
|
@@ -353,8 +353,8 @@
|
|
|
353
353
|
|
|
354
354
|
| 节点 / 能力 | 拿到的切片 |
|
|
355
355
|
|---|---|
|
|
356
|
-
| 剧本节点 | 题材卡 + 导演的叙事/节奏/表演节 +
|
|
357
|
-
| 分镜表节点 | 导演的镜头语言/灯光/风格参数/拍摄清单 +
|
|
356
|
+
| 剧本节点 | 题材卡 + 导演的叙事/节奏/表演节 + 规格的结构块 |
|
|
357
|
+
| 分镜表节点 | 导演的镜头语言/灯光/风格参数/拍摄清单 + 规格 + 运镜词典 |
|
|
358
358
|
| 图片节点 | 只追加「镜头语言锁」:风格参数 + 影调负向词 |
|
|
359
359
|
| 视频节点 | 同上(有上游分镜表时也追加,不打断结构化字段) |
|
|
360
360
|
| 角色/场景/道具设定图 | 导演的灯光色彩 + 影调卡 |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 技能配置(四层:导演透镜 / 题材 /
|
|
2
|
+
* 技能配置(四层:导演透镜 / 题材 / 规格 / 影调)的字段规范化。
|
|
3
3
|
*
|
|
4
4
|
* 单独成文件是为了让 index.js 与 skill-pack.js 都能引用而不产生循环依赖。
|
|
5
5
|
* 与 normalizeBible 同风格:字符串裁剪、空值剔除、非法值静默回落(不抛错,老项目零迁移)。
|
|
@@ -19,15 +19,11 @@ export function normalizeSkillProfile(raw, allowed) {
|
|
|
19
19
|
.filter((x) => !Array.isArray(a.genres) || !a.genres.length || a.genres.includes(x))
|
|
20
20
|
.slice(0, 12)
|
|
21
21
|
: [];
|
|
22
|
-
const sec = Number(b.targetSec);
|
|
23
22
|
const mode = (b.genreMode === 'narrative' || b.genreMode === 'industry') ? b.genreMode : 'auto';
|
|
24
23
|
return {
|
|
25
24
|
lens: pick(b.lens, a.lenses),
|
|
26
25
|
genres,
|
|
27
26
|
form: pick(b.form, a.forms),
|
|
28
|
-
aspect: pick(b.aspect, a.aspects),
|
|
29
|
-
targetSec: Number.isFinite(sec) && sec > 0 ? Math.min(3600, Math.round(sec)) : 0,
|
|
30
|
-
platform: pick(b.platform, a.platforms),
|
|
31
27
|
look: pick(b.look, a.looks),
|
|
32
28
|
genreMode: mode,
|
|
33
29
|
};
|
|
@@ -35,5 +31,5 @@ export function normalizeSkillProfile(raw, allowed) {
|
|
|
35
31
|
|
|
36
32
|
/** 默认配置(老项目无该字段时就是它,保证行为与未引入技能包前完全一致)。 */
|
|
37
33
|
export const DEFAULT_SKILL_PROFILE = {
|
|
38
|
-
lens: '', genres: [], form: '',
|
|
34
|
+
lens: '', genres: [], form: '', look: '', genreMode: 'auto',
|
|
39
35
|
};
|
package/index.js
CHANGED
|
@@ -934,7 +934,7 @@ function normalizeBible(raw) {
|
|
|
934
934
|
};
|
|
935
935
|
}
|
|
936
936
|
/**
|
|
937
|
-
* 技能配置(四层:导演透镜 / 题材 /
|
|
937
|
+
* 技能配置(四层:导演透镜 / 题材 / 规格 / 影调)字段规范化。
|
|
938
938
|
* 实现搬进 index-core-skill-profile.js(skill-pack.js 也要引用,避免循环依赖)。
|
|
939
939
|
*/
|
|
940
940
|
/**
|
|
@@ -1299,7 +1299,7 @@ async function projectsPut(args) {
|
|
|
1299
1299
|
out.bible = prev.bible;
|
|
1300
1300
|
out.bibleUpdatedAt = prev.bibleUpdatedAt || 0;
|
|
1301
1301
|
}
|
|
1302
|
-
//
|
|
1302
|
+
// 技能配置(四层:导演/题材/规格/影调)同样是项目级,与设定集同一套同步语义
|
|
1303
1303
|
let canvasSkillProfile = null;
|
|
1304
1304
|
if (canvasId) {
|
|
1305
1305
|
const projectDoc = readDocOrNull(id) || {};
|
|
@@ -1618,7 +1618,7 @@ function nextNodePos(doc, type, connectFromId, size) {
|
|
|
1618
1618
|
}
|
|
1619
1619
|
// ---------- 内置技能(操作规程 + 创作方法论,约束并提升对话的画布创作)----------
|
|
1620
1620
|
// canvas-studio=操作硬约束;canvas-craft=剧本/分镜/提示词创作方法论;canvas-layout=节点布局纪律;
|
|
1621
|
-
// canvas-director
|
|
1621
|
+
// canvas-director=导演透镜/题材/规格/影调/运镜(创作控制层,按生成能力切片注入)
|
|
1622
1622
|
const SKILL_NAMES = ['canvas-studio', 'canvas-craft', 'canvas-layout', 'canvas-director'];
|
|
1623
1623
|
// = @deepseek-ai/dsh-skill 的 BUNDLED_SKILL_RANK(避免 import DSH 包;registry 要求 rank 必须是有限数字)
|
|
1624
1624
|
const SKILL_RANK = 600;
|
|
@@ -3264,25 +3264,7 @@ export function apply(ctx) {
|
|
|
3264
3264
|
text: String(text ?? ((def && typeof def === 'object') ? JSON.stringify(def) : '')).slice(0, 80000),
|
|
3265
3265
|
};
|
|
3266
3266
|
},
|
|
3267
|
-
|
|
3268
|
-
* 安全:白名单前缀 + 禁 `..` + 禁绝对路径/盘符 + 只许 .md/.js/.json + 落在包目录内 + ≤256KB。 */
|
|
3269
|
-
async readSkillPack(args) {
|
|
3270
|
-
const rel = String((args && args.rel) || '').replace(/\\/g, '/').replace(/^\/+/, '').trim();
|
|
3271
|
-
if (!rel) throw new Error('缺少 rel');
|
|
3272
|
-
if (rel.includes('..')) throw new Error('非法路径: ' + rel);
|
|
3273
|
-
if (/^[a-z]:/i.test(rel) || rel.startsWith('/')) throw new Error('非法路径: ' + rel);
|
|
3274
|
-
if (!/^canvas-director\/(?:[A-Za-z0-9_.\-\u4e00-\u9fa5]+\/)*[A-Za-z0-9_.\-\u4e00-\u9fa5]+\.(?:md|js|json)$/.test(rel)) {
|
|
3275
|
-
throw new Error('非法路径: ' + rel + '(只允许 canvas-director 下的 .md/.js/.json)');
|
|
3276
|
-
}
|
|
3277
|
-
const baseDir = path.join(HERE, 'assets', 'canvas-director');
|
|
3278
|
-
const abs = path.resolve(path.join(HERE, 'assets', rel));
|
|
3279
|
-
if (abs !== baseDir && !abs.startsWith(baseDir + path.sep)) throw new Error('路径越界: ' + rel);
|
|
3280
|
-
let st;
|
|
3281
|
-
try { st = statSync(abs); } catch { throw new Error('文件不存在: ' + rel); }
|
|
3282
|
-
if (!st.isFile()) throw new Error('不是文件: ' + rel);
|
|
3283
|
-
if (st.size > 256 * 1024) throw new Error('文件过大: ' + rel + '(>' + (256 * 1024) + 'B)');
|
|
3284
|
-
return { rel, text: readFileSync(abs, 'utf8'), bytes: st.size };
|
|
3285
|
-
},
|
|
3267
|
+
|
|
3286
3268
|
};
|
|
3287
3269
|
|
|
3288
3270
|
const toolDisposers = [];
|
|
@@ -3818,7 +3800,7 @@ export function apply(ctx) {
|
|
|
3818
3800
|
// ── 技能包:把「本插件有哪些技能、各管什么」和「当前该按什么口径写提示词」交给对话侧 ──
|
|
3819
3801
|
reg({
|
|
3820
3802
|
name: 'canvas_list_skills',
|
|
3821
|
-
description: '列出本插件(无限画布)提供的全部技能,以及技能包(导演透镜 / 题材 /
|
|
3803
|
+
description: '列出本插件(无限画布)提供的全部技能,以及技能包(导演透镜 / 题材 / 规格 / 影调 / 运镜)的完整清单和当前项目的已选配置。【开始任何画布创作前先调它】:它会告诉你写剧本、分镜、图片提示词、视频提示词各自该加载哪份技能、可用哪些透镜与题材,随后用 canvas_skill_pack 取切片。',
|
|
3822
3804
|
parameters: {
|
|
3823
3805
|
type: 'object',
|
|
3824
3806
|
properties: { projectId: { type: 'string', description: '可选:项目 id(给出时一并返回该项目的已选配置)' } },
|
|
@@ -3847,7 +3829,7 @@ export function apply(ctx) {
|
|
|
3847
3829
|
});
|
|
3848
3830
|
reg({
|
|
3849
3831
|
name: 'canvas_skill_pack',
|
|
3850
|
-
description: '按生成能力取「导演透镜 + 题材 +
|
|
3832
|
+
description: '按生成能力取「导演透镜 + 题材 + 规格 + 影调 + 运镜」的已拼装切片,用于写剧本(script)/ 分镜(storyboard)/ 图片与视频提示词(prompt)/ 角色场景道具设定图(assets)。返回切片全文、字节数与生效配置,可直接拼进你的系统提示或提示词。【这是让对话写出的内容与画布自生成保持同一口径的唯一入口】;也可以用 lens/genres/form/look 临时覆盖,或传 set:true 把配置写进项目(与画布 UI 选择同源)。',
|
|
3851
3833
|
parameters: {
|
|
3852
3834
|
type: 'object',
|
|
3853
3835
|
properties: {
|
|
@@ -3855,7 +3837,7 @@ export function apply(ctx) {
|
|
|
3855
3837
|
kind: { type: 'string', enum: ['script', 'storyboard', 'prompt', 'assets'], description: '生成能力:script=剧本,storyboard=分镜,prompt=图片/视频提示词,assets=资产设定图。缺省 script' },
|
|
3856
3838
|
lens: { type: 'string', description: '可选:临时覆盖导演透镜 id(见 canvas_list_skills)' },
|
|
3857
3839
|
genres: { type: 'array', items: { type: 'string' }, description: '可选:临时覆盖题材 id 数组(叙事题材与行业题材都可)' },
|
|
3858
|
-
form: { type: 'string', description: '
|
|
3840
|
+
form: { type: 'string', description: '可选:临时覆盖规格 id' },
|
|
3859
3841
|
look: { type: 'string', description: '可选:临时覆盖影调 id;传空串表示跟随导演' },
|
|
3860
3842
|
set: { type: 'boolean', description: '可选:true = 把本次生效的配置写进项目(之后画布自生成也用同一套)' },
|
|
3861
3843
|
},
|
|
@@ -3878,6 +3860,9 @@ export function apply(ctx) {
|
|
|
3878
3860
|
if (args.look !== undefined) override.look = args.look;
|
|
3879
3861
|
const merged = normalizeSkillProfile({ ...base, ...override }, allow);
|
|
3880
3862
|
const kind = String((args && args.kind) || 'script');
|
|
3863
|
+
if (!['script', 'storyboard', 'prompt', 'assets'].includes(kind)) {
|
|
3864
|
+
throw new Error('kind 必须是 script / storyboard / prompt / assets,收到:' + kind);
|
|
3865
|
+
}
|
|
3881
3866
|
const built = await buildSkillPack({ kind, profile: merged, hereDir: HERE, zh: true });
|
|
3882
3867
|
if (args.set) {
|
|
3883
3868
|
doc.skillProfile = merged;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ninkch/dsh-infinite-canvas",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.6",
|
|
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",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"assets/support/*",
|
|
46
46
|
"assets/director/*.js",
|
|
47
47
|
"assets/director/models/*.json",
|
|
48
|
+
"assets/director/clips/*.json",
|
|
48
49
|
"README.md",
|
|
49
50
|
"README.zh-CN.md",
|
|
50
51
|
"docs/*.md",
|
|
@@ -62,5 +63,8 @@
|
|
|
62
63
|
"platform": "web",
|
|
63
64
|
"immediately": true
|
|
64
65
|
}
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"fbx2gltf": "^0.9.7-p1"
|
|
65
69
|
}
|
|
66
70
|
}
|
package/skill-pack.js
CHANGED
|
@@ -12,7 +12,8 @@ import { normalizeSkillProfile } from './index-core-skill-profile.js';
|
|
|
12
12
|
/** moves 永远随 storyboard/prompt 走(运镜是这两类生成的必需品)。 */
|
|
13
13
|
const MOVES_FOR_KIND = {
|
|
14
14
|
script: [],
|
|
15
|
-
|
|
15
|
+
// 分镜要调度动作,运镜 + 打斗节奏两张卡都带;提示词只需运镜。
|
|
16
|
+
storyboard: ['camera-moves', 'fight-rhythm'],
|
|
16
17
|
prompt: ['camera-moves'],
|
|
17
18
|
assets: [],
|
|
18
19
|
};
|
|
@@ -65,11 +66,15 @@ export async function buildSkillPack(opts) {
|
|
|
65
66
|
const md = readCard(hereDir, 'looks', lookEntry.file);
|
|
66
67
|
if (md) items.push({ layer: 'look', md, meta: lookEntry });
|
|
67
68
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
69
|
+
// 运镜只在「已经有层卡命中」时才跟随注入。
|
|
70
|
+
// 否则四层全空的项目也会被塞进 5KB 运镜词典 —— 违反「未配置不注入」(老项目零变化)。
|
|
71
|
+
if (items.length) {
|
|
72
|
+
for (const mid of (MOVES_FOR_KIND[kind] || [])) {
|
|
73
|
+
const mv = (inv.moves || []).find((x) => x.id === mid);
|
|
74
|
+
if (!mv) continue;
|
|
75
|
+
const md = readMove(hereDir, mv.file);
|
|
76
|
+
if (md) items.push({ layer: 'moves', md, meta: mv });
|
|
77
|
+
}
|
|
73
78
|
}
|
|
74
79
|
|
|
75
80
|
const P = await getPackModule();
|
|
@@ -97,15 +102,15 @@ function headLine(kind, profile, inv, zh) {
|
|
|
97
102
|
return [
|
|
98
103
|
'【画布技能包 · ' + kindLabel(kind) + '】',
|
|
99
104
|
'导演透镜:' + nameOf('lenses', profile.lens) + ' 题材:' + (genreNames.join('、') || '—')
|
|
100
|
-
+ '
|
|
101
|
-
'优先级:用户显式指令 > 导演透镜 >
|
|
105
|
+
+ ' 规格:' + nameOf('forms', profile.form) + ' 影调:' + (profile.look ? nameOf('looks', profile.look) : '跟随导演'),
|
|
106
|
+
'优先级:用户显式指令 > 导演透镜 > 规格(仅单镜时长与结构上压过透镜;画幅由视频节点生成时决定,不在此列)> 题材 > 影调 > 技能默认。以下为对应切片,写提示词时必须遵守;与本块冲突的通则让位于本块。',
|
|
102
107
|
].join('\n');
|
|
103
108
|
}
|
|
104
109
|
return [
|
|
105
110
|
'[Canvas skill pack · ' + kindLabel(kind, false) + ']',
|
|
106
111
|
'Director lens: ' + nameOf('lenses', profile.lens) + ' Genre: ' + (genreNames.join(', ') || '-')
|
|
107
|
-
+ '
|
|
108
|
-
'Precedence: explicit user instruction > director lens >
|
|
112
|
+
+ ' Spec: ' + nameOf('forms', profile.form) + ' Look: ' + (profile.look ? nameOf('looks', profile.look) : 'follow the lens'),
|
|
113
|
+
'Precedence: explicit user instruction > director lens > spec (only clip length and structure; aspect is chosen on the video node at generation time) > genre > look > skill defaults. The slices below are binding; where a generic rule disagrees, this block wins.',
|
|
109
114
|
].join('\n');
|
|
110
115
|
}
|
|
111
116
|
|
|
@@ -121,14 +126,14 @@ export const SKILL_CATALOG = [
|
|
|
121
126
|
{ name: 'canvas-studio', when: '任何时候先读:建项目 / 写节点 / 触发生成 / 查状态' },
|
|
122
127
|
{ name: 'canvas-craft', when: '写剧本或拆分镜前:剧本四要素、分镜六要素、提示词规范' },
|
|
123
128
|
{ name: 'canvas-layout', when: '批量建节点前:一类型一列、绝不重叠' },
|
|
124
|
-
{ name: 'canvas-director', when: '写任何提示词前:导演透镜 / 题材 /
|
|
129
|
+
{ name: 'canvas-director', when: '写任何提示词前:导演透镜 / 题材 / 规格 / 影调 / 运镜,先用 canvas_skill_pack 取切片' },
|
|
125
130
|
];
|
|
126
131
|
|
|
127
132
|
/** 层清单的可读渲染(canvas_list_skills 的正文)。 */
|
|
128
133
|
export function renderInventory(inv, profile, zh) {
|
|
129
134
|
const lines = [];
|
|
130
|
-
const ZH_LABEL = { lenses: '导演透镜', genres: '叙事题材', industries: '行业题材', forms: '
|
|
131
|
-
const EN_LABEL = { lenses: 'Director lenses', genres: 'Genres', industries: 'Industries', forms: '
|
|
135
|
+
const ZH_LABEL = { lenses: '导演透镜', genres: '叙事题材', industries: '行业题材', forms: '规格', looks: '影调质感' };
|
|
136
|
+
const EN_LABEL = { lenses: 'Director lenses', genres: 'Genres', industries: 'Industries', forms: 'Specs', looks: 'Looks' };
|
|
132
137
|
const L = zh === false ? EN_LABEL : ZH_LABEL;
|
|
133
138
|
for (const layer of ['lenses', 'genres', 'industries', 'forms', 'looks']) {
|
|
134
139
|
const list = (inv && inv[layer]) || [];
|
|
@@ -172,7 +177,7 @@ export function renderProfile(profile, inv, zh) {
|
|
|
172
177
|
}
|
|
173
178
|
return '导演=' + (nameOf('lenses', profile.lens) || '(未选)')
|
|
174
179
|
+ ' 题材=' + (g.join('、') || '(未选)')
|
|
175
|
-
+ '
|
|
180
|
+
+ ' 规格=' + (nameOf('forms', profile.form) || '(未选)')
|
|
176
181
|
+ ' 影调=' + (profile.look ? nameOf('looks', profile.look) : '跟随导演');
|
|
177
182
|
}
|
|
178
183
|
|