@waterwx/dsh-novel-forge 1.10.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/README.md +287 -281
  2. package/lib/client.js +19572 -18127
  3. package/lib/index.js +12171 -6932
  4. package/lib/types/action-guard.d.ts +61 -0
  5. package/lib/types/ai-scan.d.ts +30 -0
  6. package/lib/types/assets.d.ts +20 -9
  7. package/lib/types/assistant.d.ts +29 -0
  8. package/lib/types/author-assets.d.ts +1 -3
  9. package/lib/types/bookshelf.d.ts +13 -3
  10. package/lib/types/client/api.d.ts +137 -21
  11. package/lib/types/client/chip-prefs.d.ts +36 -0
  12. package/lib/types/client/docx.d.ts +2 -2
  13. package/lib/types/client/index.d.ts +1 -1
  14. package/lib/types/client/llmLive.d.ts +31 -0
  15. package/lib/types/client/locales.d.ts +15 -70
  16. package/lib/types/client/mount.d.ts +0 -2
  17. package/lib/types/client/panel/AiTag.d.ts +1 -0
  18. package/lib/types/client/panel/AssistantTab.d.ts +4 -1
  19. package/lib/types/client/panel/AuthorHome.d.ts +13 -9
  20. package/lib/types/client/panel/BookAnalysisView.d.ts +4 -0
  21. package/lib/types/client/panel/CmdPalette.d.ts +12 -0
  22. package/lib/types/client/panel/CreateBookView.d.ts +5 -1
  23. package/lib/types/client/panel/DirectorView.d.ts +7 -0
  24. package/lib/types/client/panel/IdeaInspirationView.d.ts +6 -0
  25. package/lib/types/client/panel/KnowledgeBaseView.d.ts +4 -0
  26. package/lib/types/client/panel/LiveFeedLog.d.ts +13 -0
  27. package/lib/types/client/panel/MarketRadarView.d.ts +5 -0
  28. package/lib/types/client/panel/ModelManager.d.ts +2 -2
  29. package/lib/types/client/panel/NovelPanel.d.ts +6 -1
  30. package/lib/types/client/panel/PageHeader.d.ts +18 -0
  31. package/lib/types/client/panel/PromptSlotsView.d.ts +11 -0
  32. package/lib/types/client/panel/SettingsView.d.ts +12 -7
  33. package/lib/types/client/panel/ShelfView.d.ts +10 -1
  34. package/lib/types/client/panel/SubPage.d.ts +27 -0
  35. package/lib/types/client/panel/TensionView.d.ts +18 -0
  36. package/lib/types/client/panel/TimelineView.d.ts +18 -0
  37. package/lib/types/client/panel/helpers.d.ts +5 -3
  38. package/lib/types/client/panel/market-radar-state.d.ts +56 -0
  39. package/lib/types/client/panel/toast.d.ts +2 -0
  40. package/lib/types/client/panel/views.d.ts +21 -35
  41. package/lib/types/client/run-status.d.ts +21 -0
  42. package/lib/types/client/sidebar-entry.d.ts +0 -2
  43. package/lib/types/docx-core.d.ts +16 -0
  44. package/lib/types/docx.d.ts +2 -3
  45. package/lib/types/engine.d.ts +83 -79
  46. package/lib/types/global-assets.d.ts +6 -0
  47. package/lib/types/home.d.ts +11 -0
  48. package/lib/types/index.d.ts +27 -13
  49. package/lib/types/llm-live.d.ts +70 -0
  50. package/lib/types/llm-retry.d.ts +38 -0
  51. package/lib/types/market-radar-scan.d.ts +18 -0
  52. package/lib/types/market-radar-sources.d.ts +31 -0
  53. package/lib/types/migrate-output.d.ts +25 -0
  54. package/lib/types/model-capability.d.ts +93 -0
  55. package/lib/types/novel-context.d.ts +80 -0
  56. package/lib/types/output-budget.d.ts +86 -0
  57. package/lib/types/prompt-slots.d.ts +57 -0
  58. package/lib/types/prompting.d.ts +10 -0
  59. package/lib/types/protocol.d.ts +829 -522
  60. package/lib/types/revision.d.ts +76 -0
  61. package/lib/types/routes.d.ts +9 -3
  62. package/lib/types/run.d.ts +23 -1
  63. package/lib/types/settings-persist.d.ts +59 -0
  64. package/lib/types/snapshots.d.ts +46 -0
  65. package/lib/types/stage-contract.d.ts +58 -0
  66. package/lib/types/tension.d.ts +53 -0
  67. package/lib/types/timeline.d.ts +37 -0
  68. package/package.json +50 -28
  69. package/src/action-guard.ts +127 -0
  70. package/src/ai-scan.ts +155 -0
  71. package/src/assets.ts +1801 -535
  72. package/src/assistant.ts +1098 -770
  73. package/src/author-assets.ts +131 -147
  74. package/src/bookshelf.ts +193 -167
  75. package/src/client/api.ts +767 -607
  76. package/src/client/chip-prefs.ts +121 -0
  77. package/src/client/docx.ts +32 -69
  78. package/src/client/index.ts +3 -1
  79. package/src/client/llmLive.ts +111 -0
  80. package/src/client/locales.ts +15 -274
  81. package/src/client/mount.tsx +4 -3
  82. package/src/client/panel/AdaptModeView.tsx +535 -520
  83. package/src/client/panel/AiTag.tsx +7 -0
  84. package/src/client/panel/AssetsTab.tsx +448 -458
  85. package/src/client/panel/AssistantTab.tsx +355 -301
  86. package/src/client/panel/AuthorAssetsView.tsx +205 -207
  87. package/src/client/panel/AuthorHome.tsx +309 -202
  88. package/src/client/panel/BookAnalysisView.tsx +63 -0
  89. package/src/client/panel/CmdPalette.tsx +102 -0
  90. package/src/client/panel/CreateBookView.tsx +366 -352
  91. package/src/client/panel/DirectorView.tsx +200 -0
  92. package/src/client/panel/GlobalAssetLibraryView.tsx +168 -172
  93. package/src/client/panel/IdeaInspirationView.tsx +76 -0
  94. package/src/client/panel/ImportModal.tsx +302 -302
  95. package/src/client/panel/KnowledgeBaseView.tsx +125 -0
  96. package/src/client/panel/LiveFeedLog.tsx +204 -0
  97. package/src/client/panel/MarketRadarView.tsx +415 -0
  98. package/src/client/panel/ModelManager.tsx +205 -205
  99. package/src/client/panel/NovelPanel.tsx +5559 -4655
  100. package/src/client/panel/PageHeader.tsx +37 -0
  101. package/src/client/panel/ProgressConsole.tsx +63 -64
  102. package/src/client/panel/PromptSlotsView.tsx +97 -0
  103. package/src/client/panel/ReaderView.tsx +306 -306
  104. package/src/client/panel/RunPanel.tsx +56 -24
  105. package/src/client/panel/SettingsView.tsx +175 -112
  106. package/src/client/panel/ShelfView.tsx +63 -39
  107. package/src/client/panel/SubPage.tsx +42 -0
  108. package/src/client/panel/TensionView.tsx +212 -0
  109. package/src/client/panel/TimelineView.tsx +208 -0
  110. package/src/client/panel/WorldTab.tsx +202 -202
  111. package/src/client/panel/helpers.ts +7 -5
  112. package/src/client/panel/market-radar-state.ts +79 -0
  113. package/src/client/panel/panel.module.css +5767 -4199
  114. package/src/client/panel/toast.ts +51 -0
  115. package/src/client/panel/views.tsx +316 -314
  116. package/src/client/run-status.ts +171 -0
  117. package/src/client/sidebar-entry.ts +3 -3
  118. package/src/docx-core.ts +53 -0
  119. package/src/docx.ts +44 -83
  120. package/src/engine.ts +1610 -1541
  121. package/src/global-assets.ts +58 -0
  122. package/src/home.ts +33 -0
  123. package/src/index.ts +184 -103
  124. package/src/llm-live.ts +245 -0
  125. package/src/llm-retry.ts +77 -0
  126. package/src/market-radar-scan.ts +35 -0
  127. package/src/market-radar-sources.ts +173 -0
  128. package/src/migrate-output.ts +76 -0
  129. package/src/model-capability.ts +215 -0
  130. package/src/novel-context.ts +286 -0
  131. package/src/output-budget.ts +147 -0
  132. package/src/prompt-slots.ts +125 -0
  133. package/src/prompting.ts +26 -0
  134. package/src/protocol.ts +2454 -2148
  135. package/src/revision.ts +283 -0
  136. package/src/routes.ts +3795 -3359
  137. package/src/run.ts +113 -17
  138. package/src/settings-persist.ts +114 -0
  139. package/src/snapshots.ts +174 -0
  140. package/src/stage-contract.ts +186 -0
  141. package/src/tension.ts +251 -0
  142. package/src/timeline.ts +159 -0
  143. package/assets/styles/arcane-thick-3d.webp +0 -0
  144. package/assets/styles/chinese-ink.webp +0 -0
  145. package/assets/styles/clay-stopmotion-3d.webp +0 -0
  146. package/assets/styles/dark-ghibli.webp +0 -0
  147. package/assets/styles/dark-gothic-3d.webp +0 -0
  148. package/assets/styles/film-photo.webp +0 -0
  149. package/assets/styles/guofeng-heavy.webp +0 -0
  150. package/assets/styles/horror-game-3d.webp +0 -0
  151. package/assets/styles/japan-cel-dark.webp +0 -0
  152. package/assets/styles/korean-webtoon.webp +0 -0
  153. package/assets/styles/low-cyberpunk-3d.webp +0 -0
  154. package/assets/styles/nextgen-cg.webp +0 -0
  155. package/assets/styles/noir-film.webp +0 -0
  156. package/assets/styles/openworld-survival.webp +0 -0
  157. package/assets/styles/paper-cut-3d.webp +0 -0
  158. package/assets/styles/pixar-adult-3d.webp +0 -0
  159. package/assets/styles/pop-marvel-2d.webp +0 -0
  160. package/assets/styles/shinkai-anime.webp +0 -0
  161. package/assets/styles/tactical-stealth.webp +0 -0
  162. package/assets/styles/vaporwave-3d.webp +0 -0
  163. package/assets/styles/vhs90.webp +0 -0
  164. package/lib/types/client/panel/BookshelfBar.d.ts +0 -11
  165. package/lib/types/client/panel/FlowGuide.d.ts +0 -21
  166. package/lib/types/client/panel/MangaRoleLibrary.d.ts +0 -18
  167. package/lib/types/client/panel/MangaWorkspace.d.ts +0 -15
  168. package/lib/types/client/panel/ModelPicker.d.ts +0 -11
  169. package/lib/types/client/panel/ProgressHomeView.d.ts +0 -5
  170. package/lib/types/client/panel/SceneLibrary.d.ts +0 -14
  171. package/lib/types/client/panel/StoryboardTab.d.ts +0 -19
  172. package/lib/types/client/panel/StyleCard.d.ts +0 -8
  173. package/lib/types/client/panel/StyleGallery.d.ts +0 -1
  174. package/lib/types/comic-presets.d.ts +0 -12
  175. package/lib/types/shot-language.d.ts +0 -46
  176. package/lib/types/story-beat-language.d.ts +0 -35
  177. package/lib/types/style-library.d.ts +0 -33
  178. package/skills/chapter-batch/SKILL.md +0 -81
  179. package/src/client/mount.tsx._new +0 -97
  180. package/src/client/mount.tsx._nf +0 -97
  181. package/src/client/mount.tsx._tmp +0 -97
  182. package/src/client/panel/BookshelfBar.tsx +0 -170
  183. package/src/client/panel/FlowGuide.tsx +0 -83
  184. package/src/client/panel/MangaRoleLibrary.tsx +0 -810
  185. package/src/client/panel/MangaWorkspace.tsx +0 -359
  186. package/src/client/panel/ProgressHomeView.tsx +0 -87
  187. package/src/client/panel/SceneLibrary.tsx +0 -396
  188. package/src/client/panel/StoryboardTab.tsx +0 -466
  189. package/src/client/panel/StyleCard.tsx +0 -90
  190. package/src/client/panel/StyleGallery.tsx +0 -58
  191. package/src/comic-presets.ts +0 -67
  192. package/src/shot-language.ts +0 -181
  193. package/src/story-beat-language.ts +0 -130
  194. package/src/style-library.ts +0 -78
@@ -1,67 +0,0 @@
1
- /** 漫画风格预设:每个预设对应一组出图提示词与排版偏好。 */
2
-
3
- export interface ComicStylePreset {
4
- id: string
5
- label: string
6
- /** 注入 imagePrompt 的风格描述词。 */
7
- prompt: string
8
- /** 可选:排版偏好说明。 */
9
- layoutHint?: string
10
- }
11
-
12
- export const COMIC_STYLE_PRESETS: ComicStylePreset[] = [
13
- {
14
- id: 'japan',
15
- label: '日漫 / 黑白',
16
- prompt: 'manga style, screentone, bold ink lines, high contrast, black and white, cel shading',
17
- layoutHint: '页漫优先',
18
- },
19
- {
20
- id: 'korea',
21
- label: '韩漫 / 条漫',
22
- prompt: 'manhwa style, soft cel shading, vibrant colors, clean lineart, webtoon vertical composition, glossy highlights',
23
- layoutHint: '条漫优先',
24
- },
25
- {
26
- id: 'china',
27
- label: '国漫 / 古风',
28
- prompt: 'chinese ink painting style, flowing brush strokes, traditional palette, ethereal atmosphere, xianxia aesthetic',
29
- layoutHint: '页漫/条漫均可',
30
- },
31
- {
32
- id: 'america',
33
- label: '美漫 / 超级英雄',
34
- prompt: 'american comic style, bold outlines, dramatic lighting, dynamic poses, vibrant colors, halftone shading',
35
- layoutHint: '页漫优先',
36
- },
37
- {
38
- id: 'chibi',
39
- label: 'Q版 / 搞笑',
40
- prompt: 'chibi style, cute proportions, big head, exaggerated expressions, simple background, bright colors',
41
- layoutHint: '条漫/四格优先',
42
- },
43
- {
44
- id: 'realistic',
45
- label: '写实 / 电影感',
46
- prompt: 'realistic cinematic style, detailed textures, natural lighting, film grain, high detail',
47
- layoutHint: '页漫/全彩',
48
- },
49
- {
50
- id: 'cyber',
51
- label: '赛博 / 暗黑',
52
- prompt: 'cyberpunk style, neon lights, dark atmosphere, high contrast, futuristic city, cool tones',
53
- layoutHint: '页漫/全彩',
54
- },
55
- ]
56
-
57
- export function getComicStylePrompt(styleId?: string): string {
58
- if (!styleId) return ''
59
- const preset = COMIC_STYLE_PRESETS.find(s => s.id === styleId)
60
- return preset?.prompt ?? ''
61
- }
62
-
63
- export function getComicStyleLabel(styleId?: string): string {
64
- if (!styleId) return ''
65
- const preset = COMIC_STYLE_PRESETS.find(s => s.id === styleId)
66
- return preset?.label ?? styleId
67
- }
@@ -1,181 +0,0 @@
1
- /**
2
- * 镜头语言词库(分镜规范化基准)。
3
- * 分镜表的 shot/camera/composition/light 字段统一从这里取值(英文 id),
4
- * 生成提示词时用 zh 中文词块;适配英文平台时用 en。
5
- * 目的:让"景别/运镜/构图/光效"有标准词表,避免 LLM 自由发挥导致漂移。
6
- */
7
-
8
- /** 景别。 */
9
- export type ShotSizeId =
10
- | 'extreme_wide' | 'wide' | 'full' | 'medium'
11
- | 'medium_close' | 'close' | 'extreme_close' | 'big_extreme_close'
12
-
13
- /** 运镜/机位。 */
14
- export type CameraMoveId =
15
- | 'static' | 'dolly_in' | 'dolly_out' | 'pan_left' | 'pan_right'
16
- | 'track_left' | 'track_right' | 'follow' | 'pedestal_up' | 'pedestal_down'
17
- | 'orbit' | 'handheld' | 'low_angle' | 'high_angle' | 'over_shoulder'
18
-
19
- /** 构图。 */
20
- export type CompositionId =
21
- | 'rule_of_thirds' | 'center' | 'leading_line' | 'foreground'
22
- | 'low' | 'overhead' | 'symmetry'
23
-
24
- /** 光效。 */
25
- export type LightingId =
26
- | 'front' | 'side' | 'back' | 'top' | 'rembrandt'
27
- | 'neon' | 'hard' | 'soft' | 'mood' | 'contrast'
28
-
29
- export interface ShotLangEntry<T extends string> {
30
- id: T
31
- /** 中文(提示词/展示用)。 */
32
- zh: string
33
- /** 英文(英文平台适配用)。 */
34
- en: string
35
- /** 一句话说明(下拉/卡片)。 */
36
- hint: string
37
- }
38
-
39
- export const SHOT_SIZES: readonly ShotLangEntry<ShotSizeId>[] = [
40
- { id: 'extreme_wide', zh: '大远景', en: 'extreme wide shot', hint: '环境为主,人物很小' },
41
- { id: 'wide', zh: '远景', en: 'wide shot', hint: '人在景中,交代环境' },
42
- { id: 'full', zh: '全景', en: 'full shot', hint: '全身』人物整体' },
43
- { id: 'medium', zh: '中景', en: 'medium shot', hint: '膝部以上,叙事主力' },
44
- { id: 'medium_close', zh: '中近景', en: 'medium close-up', hint: '胸以上,表情+动作' },
45
- { id: 'close', zh: '近景', en: 'close-up', hint: '肩以上,突出表情' },
46
- { id: 'extreme_close', zh: '特写', en: 'extreme close-up', hint: '脸/物细节' },
47
- { id: 'big_extreme_close', zh: '大特写', en: 'big close-up', hint: '局部(眼/手/标志物)' },
48
- ]
49
-
50
- export const CAMERA_MOVES: readonly ShotLangEntry<CameraMoveId>[] = [
51
- { id: 'static', zh: '固定机位', en: 'static camera', hint: '机位不动' },
52
- { id: 'dolly_in', zh: '推近', en: 'dolly in', hint: '镜头向主体逼近' },
53
- { id: 'dolly_out', zh: '拉远', en: 'dolly out', hint: '镜头远离主体' },
54
- { id: 'pan_left', zh: '左摇', en: 'pan left', hint: '机位不动,镜头左转' },
55
- { id: 'pan_right', zh: '右摇', en: 'pan right', hint: '机位不动,镜头右转' },
56
- { id: 'track_left', zh: '左横移', en: 'track left', hint: '机位随主体左移' },
57
- { id: 'track_right', zh: '右横移', en: 'track right', hint: '机位随主体右移' },
58
- { id: 'follow', zh: '跟随', en: 'follow shot', hint: '镜头跟着主体运动' },
59
- { id: 'pedestal_up', zh: '升镜', en: 'pedestal up', hint: '机位抬高' },
60
- { id: 'pedestal_down', zh: '降镜', en: 'pedestal down', hint: '机位降低' },
61
- { id: 'orbit', zh: '环绕', en: 'orbit shot', hint: '镜头绕主体转' },
62
- { id: 'handheld', zh: '手持晃动', en: 'handheld', hint: '真实感/紧张感' },
63
- { id: 'low_angle', zh: '低机位仰拍', en: 'low angle', hint: '突出威严/压迫' },
64
- { id: 'high_angle', zh: '高机位俯拍', en: 'high angle', hint: '突出渺小/全知' },
65
- { id: 'over_shoulder', zh: '过肩镜头', en: 'over-the-shoulder', hint: '对话常用' },
66
- ]
67
-
68
- export const COMPOSITIONS: readonly ShotLangEntry<CompositionId>[] = [
69
- { id: 'rule_of_thirds', zh: '三分法', en: 'rule of thirds', hint: '主体偏三分之一处' },
70
- { id: 'center', zh: '中心对称', en: 'centered', hint: '主体居中' },
71
- { id: 'leading_line', zh: '引导线', en: 'leading lines', hint: '视线沿线条引向主体' },
72
- { id: 'foreground', zh: '前景遮挡', en: 'foreground framing', hint: '前景物框住主体' },
73
- { id: 'low', zh: '低机位', en: 'low camera', hint: '低于视线' },
74
- { id: 'overhead', zh: '俯拍', en: 'overhead', hint: '从上方俯视' },
75
- { id: 'symmetry', zh: '对称构图', en: 'symmetrical', hint: '左右镜像' },
76
- ]
77
-
78
- export const LIGHTINGS: readonly ShotLangEntry<LightingId>[] = [
79
- { id: 'front', zh: '顺光', en: 'front light', hint: '正面均匀照明' },
80
- { id: 'side', zh: '侧光', en: 'side light', hint: '明暗对比强' },
81
- { id: 'back', zh: '逆光', en: 'back light', hint: '轮廓光/剪影' },
82
- { id: 'top', zh: '顶光', en: 'top light', hint: '俯照硬朗' },
83
- { id: 'rembrandt', zh: '伦勃朗光', en: 'rembrandt lighting', hint: '侧逆光,经典人像' },
84
- { id: 'neon', zh: '霓虹光', en: 'neon lighting', hint: '赛博/夜景' },
85
- { id: 'hard', zh: '硬光', en: 'hard light', hint: '犀利阴影' },
86
- { id: 'soft', zh: '柔光', en: 'soft light', hint: '柔和过渡' },
87
- { id: 'mood', zh: '氛围光', en: 'mood lighting', hint: '情绪化色温' },
88
- { id: 'contrast', zh: '高反差', en: 'high contrast', hint: '黑白/强明暗' },
89
- ]
90
-
91
- export interface ShotLanguage {
92
- shot?: ShotSizeId
93
- camera: CameraMoveId[]
94
- composition?: CompositionId
95
- light: LightingId[]
96
- }
97
-
98
- /** 从中文文本归一化到景别(处理旧数据/LLM 口语)。未知回退 medium。 */
99
- export function normalizeShotSize(text: string | undefined): ShotSizeId {
100
- if (text === undefined || text === '') return 'medium'
101
- const t = text.trim()
102
- if (t.includes('大远景')) return 'extreme_wide'
103
- if (t.includes('远景')) return 'wide'
104
- if (t.includes('全景')) return 'full'
105
- if (t.includes('中近景') || t.includes('中景')) return 'medium'
106
- if (t.includes('近景') || t.includes('胸')) return 'close'
107
- if (t.includes('大特写')) return 'big_extreme_close'
108
- if (t.includes('特写')) return 'extreme_close'
109
- return 'medium'
110
- }
111
-
112
- /** 从中文文本归一化到运镜列表。 */
113
- export function normalizeCameras(text: string | undefined): CameraMoveId[] {
114
- if (text === undefined || text === '') return ['static']
115
- const t = text.trim()
116
- const out: CameraMoveId[] = []
117
- const push = (id: CameraMoveId) => { if (!out.includes(id)) out.push(id) }
118
- if (t.includes('推近') || t.includes('推进')) push('dolly_in')
119
- if (t.includes('拉远') || t.includes('拉出')) push('dolly_out')
120
- if (t.includes('左摇')) push('pan_left')
121
- if (t.includes('右摇')) push('pan_right')
122
- if (t.includes('横移')) push(t.includes('左') ? 'track_left' : 'track_right')
123
- if (t.includes('跟随') || t.includes('跟拍')) push('follow')
124
- if (t.includes('升降') || t.includes('升') || t.includes('降')) push('pedestal_up')
125
- if (t.includes('环绕')) push('orbit')
126
- if (t.includes('手持') || t.includes('晃动')) push('handheld')
127
- if (t.includes('低机位') || t.includes('仰拍') || t.includes('仰')) push('low_angle')
128
- if (t.includes('高机位') || t.includes('俯拍') || t.includes('俯')) push('high_angle')
129
- if (t.includes('过肩')) push('over_shoulder')
130
- if (out.length === 0) push('static')
131
- return out
132
- }
133
-
134
- /** 从中文文本归一化到构图(可选)。 */
135
- export function normalizeComposition(text: string | undefined): CompositionId | undefined {
136
- if (text === undefined || text === '') return undefined
137
- const t = text.trim()
138
- if (t.includes('三分')) return 'rule_of_thirds'
139
- if (t.includes('中心') || t.includes('居中')) return 'center'
140
- if (t.includes('引导')) return 'leading_line'
141
- if (t.includes('前景')) return 'foreground'
142
- if (t.includes('低机位')) return 'low'
143
- if (t.includes('俯拍') || t.includes('俯视')) return 'overhead'
144
- if (t.includes('对称')) return 'symmetry'
145
- return undefined
146
- }
147
-
148
- /** 从中文文本归一化到光效列表。 */
149
- export function normalizeLightings(text: string | undefined): LightingId[] {
150
- if (text === undefined || text === '') return ['soft']
151
- const t = text.trim()
152
- const out: LightingId[] = []
153
- const push = (id: LightingId) => { if (!out.includes(id)) out.push(id) }
154
- if (t.includes('顺光')) push('front')
155
- if (t.includes('侧光') || t.includes('伦勃朗')) push(t.includes('伦勃朗') ? 'rembrandt' : 'side')
156
- if (t.includes('逆光')) push('back')
157
- if (t.includes('顶光')) push('top')
158
- if (t.includes('霓虹')) push('neon')
159
- if (t.includes('硬光')) push('hard')
160
- if (t.includes('柔光')) push('soft')
161
- if (t.includes('氛围') || t.includes('情绪')) push('mood')
162
- if (t.includes('高反差')) push('contrast')
163
- if (out.length === 0) push('soft')
164
- return out
165
- }
166
-
167
- /** 取词条中文(ZHs 合并句子)。 */
168
- export function sizeZh(id: ShotSizeId | undefined): string {
169
- return SHOT_SIZES.find(e => e.id === id)?.zh ?? '中景'
170
- }
171
- export function cameraZh(ids: CameraMoveId[] | undefined): string {
172
- if (ids === undefined || ids.length === 0) return '固定机位'
173
- return CAMERA_MOVES.filter(e => ids.includes(e.id)).map(e => e.zh).join(' + ')
174
- }
175
- export function compoZh(id: CompositionId | undefined): string {
176
- return COMPOSITIONS.find(e => e.id === id)?.zh ?? ''
177
- }
178
- export function lightZh(ids: LightingId[] | undefined): string {
179
- if (ids === undefined || ids.length === 0) return '柔光'
180
- return LIGHTINGS.filter(e => ids.includes(e.id)).map(e => e.zh).join(' + ')
181
- }
@@ -1,130 +0,0 @@
1
- /**
2
- * 编剧词库(剧情骨架规范化基准)。
3
- * 骨架的 function(叙事功能)与 emotion(情绪走向)统一从这里取值(英文 id),
4
- * 生成提示词/展示时用 zh 中文。
5
- * 目的:让"叙事功能/情绪"有标准词表,避免 LLM 自由发挥导致情绪链漂移。
6
- */
7
-
8
- /** 叙事功能(对应节拍在剧情中的作用)。 */
9
- export type StoryFunctionId =
10
- | 'exposition' | 'conflict' | 'turn' | 'climax'
11
- | 'resolve' | 'foreshadow' | 'character'
12
-
13
- /** 情绪词(低→高能量的情绪阶,角色在节拍中的主要情绪点)。 */
14
- export type EmotionId =
15
- // 起:低能量
16
- | 'calm' | 'indifferent' | 'expectant' | 'curious' | 'alert'
17
- // 承:蓄势
18
- | 'suppressed' | 'enduring' | 'worried' | 'irritable' | 'uneasy'
19
- // 转:激化
20
- | 'terrified' | 'angry' | 'collapsing' | 'resolute' | 'grieved'
21
- // 合:落点
22
- | 'relieved' | 'bittersweet' | 'triumphant' | 'reborn' | 'numb'
23
-
24
- export interface BeatLangEntry<T extends string> {
25
- id: T
26
- /** 中文(展示用)。 */
27
- zh: string
28
- /** 英文(英文平台适配用)。 */
29
- en: string
30
- /** 一句话说明。 */
31
- hint: string
32
- }
33
-
34
- /** 叙事功能词表。 */
35
- export const STORY_FUNCTIONS: readonly BeatLangEntry<StoryFunctionId>[] = [
36
- { id: 'exposition', zh: '铺垫', en: 'exposition', hint: '介绍背景/人物/悬念' },
37
- { id: 'conflict', zh: '冲突', en: 'conflict', hint: '矛盾显现/加剧' },
38
- { id: 'turn', zh: '转折', en: 'turning point', hint: '剧情反转/方向改变' },
39
- { id: 'climax', zh: '高潮', en: 'climax', hint: '冲突顶峰/揭示' },
40
- { id: 'resolve', zh: '收束', en: 'resolution', hint: '矛盾化解/结果' },
41
- { id: 'foreshadow', zh: '伏笔', en: 'foreshadowing', hint: '埋下后续线索' },
42
- { id: 'character', zh: '人物塑造', en: 'characterization', hint: '展现人物特质/转变' },
43
- ]
44
-
45
- /** 情绪词表(按能量/阶段排序)。 */
46
- export const EMOTIONS: readonly BeatLangEntry<EmotionId>[] = [
47
- // 起:低能量
48
- { id: 'calm', zh: '平静', en: 'calm', hint: '无波澜' },
49
- { id: 'indifferent', zh: '淡然', en: 'indifferent', hint: '不在乎' },
50
- { id: 'expectant', zh: '期待', en: 'expectant', hint: '有所期盼' },
51
- { id: 'curious', zh: '好奇', en: 'curious', hint: '想要探究' },
52
- { id: 'alert', zh: '警觉', en: 'alert', hint: '察觉到异样' },
53
- // 承:蓄势
54
- { id: 'suppressed', zh: '压抑', en: 'suppressed', hint: '情绪被压制' },
55
- { id: 'enduring', zh: '隐忍', en: 'enduring', hint: '强忍着' },
56
- { id: 'worried', zh: '担忧', en: 'worried', hint: '担心后果' },
57
- { id: 'irritable', zh: '焦躁', en: 'irritable', hint: '烦躁不耐' },
58
- { id: 'uneasy', zh: '不安', en: 'uneasy', hint: '心里没底' },
59
- // 转:激化
60
- { id: 'terrified', zh: '惊惧', en: 'terrified', hint: '极度恐惧' },
61
- { id: 'angry', zh: '愤怒', en: 'angry', hint: '强烈不满' },
62
- { id: 'collapsing', zh: '崩溃', en: 'collapsing', hint: '情绪失控' },
63
- { id: 'resolute', zh: '决绝', en: 'resolute', hint: '下定狠心' },
64
- { id: 'grieved', zh: '痛心', en: 'grieved', hint: '悲伤心痛' },
65
- // 合:落点
66
- { id: 'relieved', zh: '释然', en: 'relieved', hint: '放下包袱' },
67
- { id: 'bittersweet', zh: '悲凉', en: 'bittersweet', hint: '苦涩无奈' },
68
- { id: 'triumphant', zh: '得意', en: 'triumphant', hint: '占据上风' },
69
- { id: 'reborn', zh: '重生', en: 'reborn', hint: '脱胎换骨' },
70
- { id: 'numb', zh: '麻木', en: 'numb', hint: '失去感知' },
71
- ]
72
-
73
- export interface StoryBeatLanguage {
74
- function: StoryFunctionId
75
- emotion: EmotionId[]
76
- }
77
-
78
- /** 从中文归一化叙事功能(未知回退 exposition)。 */
79
- export function normalizeStoryFunction(text: string | undefined): StoryFunctionId {
80
- if (text === undefined || text === '') return 'exposition'
81
- const t = text.trim()
82
- if (t.includes('铺垫')) return 'exposition'
83
- if (t.includes('冲突')) return 'conflict'
84
- if (t.includes('转折')) return 'turn'
85
- if (t.includes('高潮')) return 'climax'
86
- if (t.includes('收束')) return 'resolve'
87
- if (t.includes('伏笔')) return 'foreshadow'
88
- if (t.includes('人物塑造')) return 'character'
89
- return 'exposition'
90
- }
91
-
92
- /** 从中文文本归一化情绪词列表(可含→箭头链)。 */
93
- export function normalizeEmotions(text: string | undefined): EmotionId[] {
94
- if (text === undefined || text === '') return ['calm']
95
- const t = text.trim()
96
- const out: EmotionId[] = []
97
- const push = (id: EmotionId) => { if (!out.includes(id)) out.push(id) }
98
- if (t.includes('平静')) push('calm')
99
- if (t.includes('淡然')) push('indifferent')
100
- if (t.includes('期待')) push('expectant')
101
- if (t.includes('好奇')) push('curious')
102
- if (t.includes('警觉')) push('alert')
103
- if (t.includes('压抑')) push('suppressed')
104
- if (t.includes('隐忍')) push('enduring')
105
- if (t.includes('担忧')) push('worried')
106
- if (t.includes('焦躁')) push('irritable')
107
- if (t.includes('不安')) push('uneasy')
108
- if (t.includes('惊惧')) push('terrified')
109
- if (t.includes('愤怒')) push('angry')
110
- if (t.includes('崩溃')) push('collapsing')
111
- if (t.includes('决绝')) push('resolute')
112
- if (t.includes('痛心')) push('grieved')
113
- if (t.includes('释然')) push('relieved')
114
- if (t.includes('悲凉')) push('bittersweet')
115
- if (t.includes('得意')) push('triumphant')
116
- if (t.includes('重生')) push('reborn')
117
- if (t.includes('麻木')) push('numb')
118
- if (out.length === 0) push('calm')
119
- return out
120
- }
121
-
122
- /** 叙事功能中文。 */
123
- export function functionZh(id: StoryFunctionId | undefined): string {
124
- return STORY_FUNCTIONS.find(e => e.id === id)?.zh ?? '铺垫'
125
- }
126
- /** 情绪中文(箭头连接)。 */
127
- export function emotionZh(ids: EmotionId[] | undefined): string {
128
- if (ids === undefined || ids.length === 0) return '平静'
129
- return EMOTIONS.filter(e => ids.includes(e.id)).map(e => e.zh).join('→')
130
- }
@@ -1,78 +0,0 @@
1
- /**
2
- * 风格库(内置模板):漫剧方案的视觉基底 + 可叠加滤镜。
3
- * 字段来自通用风格模板(豆包整理),keywords 即风格前缀词块,生成时直接套用。
4
- */
5
-
6
- export type StyleCategory = '3d' | 'game' | '2d' | 'film' | 'craft'
7
-
8
- export interface ArtStyle {
9
- id: string
10
- /** 风格名(用户可见)。 */
11
- name: string
12
- category: StyleCategory
13
- /** 特点一句话(卡片展示)。 */
14
- traits: string
15
- /** 风格关键词/前缀(生成角色图/视频提示词时套用)。 */
16
- keywords: string
17
- /** 是否可作为滤镜叠加在基底风格之上(影视实验类;缺省 false)。 */
18
- stackable?: boolean
19
- /** 默认推荐排序权重(0-1,推荐池排序参考)。 */
20
- weight?: number
21
- }
22
-
23
- export const STYLE_CATEGORIES: ReadonlyArray<{ id: StyleCategory; label: string; icon: string; desc: string }> = [
24
- { id: '3d', label: '3D 类', icon: '🧊', desc: '人物稳定性最好,视频不易崩脸' },
25
- { id: 'game', label: '游戏 3D', icon: '🎮', desc: '游戏渲染质感与镜头语言(生存/恐怖/潜行)' },
26
- { id: '2d', label: '2D 二次元绘画', icon: '✏️', desc: '手绘感,人物一致性略弱' },
27
- { id: 'film', label: '影视实验质感', icon: '🎞️', desc: '滤镜/影像体系,可叠加在 3D/2D 之上' },
28
- { id: 'craft', label: '国风/特殊工艺', icon: '🏮', desc: '国风与传统工艺质感' },
29
- ]
30
-
31
- /** 内置风格模板(18 个)。 */
32
- export const STYLE_LIBRARY: ArtStyle[] = [
33
- // ---------------- 3D 类 ----------------
34
- { id: 'pixar-adult-3d', name: '成人向皮克斯 3D', category: '3d', traits: 'CG 三维渲染,材质细腻,微表情表现力强;需压制 Q 版可爱感', keywords: '3D皮克斯动画,成人写实CGI,电影光影,拒绝Q版', weight: 1.0 },
35
- { id: 'arcane-thick-3d', name: '双城之战美漫厚涂 3D', category: '3d', traits: '粗重轮廓线,高对比硬阴影,材质粗粝,悲剧、压抑、科幻题材适配高', keywords: '双城之战美术,3D美漫厚涂,强轮廓光影,暗调粗粝渲染', weight: 0.95 },
36
- { id: 'nextgen-cg', name: '次世代游戏 CG', category: '3d', traits: '接近真人的三维渲染,照片级布料、皮肤材质,冷峻写实', keywords: '次世代游戏CG渲染,超写实3D,真实物理材质,电影布光', weight: 0.9 },
37
- { id: 'low-cyberpunk-3d', name: '底层赛博朋克 3D', category: '3d', traits: '锈蚀工业、破碎霓虹、屏幕噪点;避开华丽高楼,偏向破败底层', keywords: '底层赛博朋克3D,废土工业,破碎霓虹,画面噪点色散', weight: 0.85 },
38
- { id: 'vaporwave-3d', name: '复古蒸汽波 3D', category: '3d', traits: '粉-蓝-紫霓虹轮廓、90 年代复古网格、胶片色散颗粒,颓废疏离', keywords: '3D复古蒸汽波,90年代三维渲染,霓虹轮廓光,胶片颗粒', weight: 0.8 },
39
- { id: 'dark-gothic-3d', name: '暗黑哥特 3D', category: '3d', traits: '大面积阴影、冷青色调、衰败破败质感,适合幽暗密闭空间', keywords: '3D暗黑哥特,冷青暗光,衰败质感,大面积阴影', weight: 0.8 },
40
- { id: 'clay-stopmotion-3d', name: '黏土 / 定格 3D', category: '3d', traits: '捏塑颗粒肌理,手工定格质感;可做压抑向,不局限可爱风', keywords: '3D黏土定格渲染,泥塑肌理,电影打光', weight: 0.7 },
41
- { id: 'openworld-survival', name: '开放世界生存游戏风', category: 'game', traits: '场景破败感强,货架、仓库、管线、灰尘、锈蚀明显;人物带一点“生存者”气质;适合探索感、逃亡感、世界观展示', keywords: '开放世界生存游戏风格,废土场景,破败仓库,锈蚀金属货架,灰尘粒子,冷色写实光影', weight: 0.8 },
42
- { id: 'horror-game-3d', name: '恐怖游戏 3D', category: 'game', traits: '大面积阴影,荧光灯频闪,空间压抑;适合悬疑、压迫、精神异常段落', keywords: '恐怖游戏 3D 风格,昏暗仓库,老旧荧光灯,硬阴影,压迫空间,冷灰蓝调,低饱和', weight: 0.75 },
43
- { id: 'tactical-stealth', name: '战术潜行游戏风', category: 'game', traits: '低视角、第三人称镜头感;人物在货架之间移动,光影克制;适合紧张剧情', keywords: '战术潜行游戏视角,第三人称镜头,货架通道,冷色暗光,真实3D渲染,紧张压迫氛围', weight: 0.7 },
44
- // ---------------- 2D 类 ----------------
45
- { id: 'korean-webtoon', name: '韩漫条漫风', category: '2d', traits: '修长人物,低饱和高级灰,氛围感强,都市向漫剧爆款画风', keywords: '韩漫2D绘画,精致人物,低饱和灰调,氛围感插画', weight: 1.0 },
46
- { id: 'japan-cel-dark', name: '日系赛璐璐动画', category: '2d', traits: '干净勾线,硬阴影;分明亮版、暗调悲剧版(边缘行者质感)', keywords: '日系赛璐璐动画,清晰轮廓线,硬阴影,暗调都市动画', weight: 0.9 },
47
- { id: 'shinkai-anime', name: '新海诚动画风', category: '2d', traits: '极致环境光影、丁达尔、空气中尘埃粒子,擅长雨夜、夜景外景', keywords: '新海诚动画渲染,细腻环境光,漂浮尘埃粒子', weight: 0.85 },
48
- { id: 'pop-marvel-2d', name: '波普美漫', category: '2d', traits: '网点半调、强撞色,线条张扬,节奏冲击力强', keywords: '平行宇宙波普美漫,网点半调,漫画粗线条', weight: 0.8 },
49
- { id: 'dark-ghibli', name: '暗黑吉卜力手绘', category: '2d', traits: '手绘水彩肌理;强制关闭温暖治愈,做残酷冷调版本', keywords: '吉卜力手绘动画,暗黑写实,水彩肌理,拒绝暖光治愈', weight: 0.75 },
50
- // ---------------- 影视实验质感(可叠加滤镜) ----------------
51
- { id: 'noir-film', name: '黑色电影 Noir', category: 'film', traits: '高反差黑白,只保留少量色彩作为视觉锚点,张力极强', keywords: '黑色电影,大部分黑白,局部保留色彩,硬侧光,胶片颗粒', stackable: true, weight: 1.0 },
52
- { id: 'vhs90', name: 'VHS 90 录像带复古', category: 'film', traits: '扫描线、色彩偏移、磁带噪点,模拟老旧档案录像', keywords: 'VHS录像带质感,扫描线,色彩偏移,磁带噪点', stackable: true, weight: 0.9 },
53
- { id: 'film-photo', name: '胶片电影写真', category: 'film', traits: '电影机拍摄质感,轻微颗粒,景深虚化,无夸张特效', keywords: '电影写真质感,35mm胶片,胶片颗粒,浅景深', stackable: true, weight: 0.85 },
54
- // ---------------- 国风 / 特殊工艺 ----------------
55
- { id: 'chinese-ink', name: '新中式水墨动画', category: 'craft', traits: '水墨晕染,留白写意', keywords: '水墨动画渲染,写意晕染,国风2D', weight: 1.0 },
56
- { id: 'paper-cut-3d', name: '纸雕定格', category: 'craft', traits: '多层纸张镂空叠层,光影穿透纸面', keywords: '立体纸雕定格,纸张肌理,层叠镂空光影', weight: 0.9 },
57
- { id: 'guofeng-heavy', name: '工笔重彩国风', category: 'craft', traits: '精细线条,矿物颜料质感,古典华美', keywords: '工笔重彩,国风2D绘画,矿物颜料质感,精细勾线', weight: 0.8 },
58
- ]
59
-
60
- /** 按分类取风格。 */
61
- export function stylesByCategory(category: StyleCategory): ArtStyle[] {
62
- return STYLE_LIBRARY.filter(s => s.category === category)
63
- }
64
-
65
- /** 取单个风格(未找到返回 undefined)。 */
66
- export function findStyle(id: string): ArtStyle | undefined {
67
- return STYLE_LIBRARY.find(s => s.id === id)
68
- }
69
-
70
- /** 按基底 + 滤镜拼接风格关键词(角色图/分镜/视频提示词共用;缺省回退 3D 动漫)。 */
71
- export function styleKeywords(styleId?: string, filterId?: string): string {
72
- const parts: string[] = []
73
- const base = styleId !== undefined ? findStyle(styleId) : undefined
74
- if (base !== undefined) parts.push(base.keywords)
75
- const filter = filterId !== undefined ? findStyle(filterId) : undefined
76
- if (filter !== undefined) parts.push(filter.keywords)
77
- return parts.join(',') || '3D动漫,超精细建模,电影光影'
78
- }