@lingjingai/script-editor 0.0.1
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/INTEGRATION.md +132 -0
- package/dist/index.d.ts +596 -0
- package/dist/index.js +3568 -0
- package/dist/index.js.map +1 -0
- package/dist/paper-fibers.png +0 -0
- package/dist/style.css +784 -0
- package/package.json +51 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,596 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactElement, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
declare enum ScriptContentType {
|
|
5
|
+
Action = "action",
|
|
6
|
+
Dialogue = "dialogue",
|
|
7
|
+
Narration = "narration",
|
|
8
|
+
InnerThought = "inner_thought"
|
|
9
|
+
}
|
|
10
|
+
interface SceneEnvironment {
|
|
11
|
+
space?: "exterior" | "interior" | string;
|
|
12
|
+
time?: "day" | "night" | "dawn" | "dusk" | string;
|
|
13
|
+
}
|
|
14
|
+
interface ScriptItem {
|
|
15
|
+
type?: ScriptContentType | string;
|
|
16
|
+
content?: string;
|
|
17
|
+
actor_id?: string;
|
|
18
|
+
speaker_id?: string;
|
|
19
|
+
speakers?: Array<{
|
|
20
|
+
speaker_id?: string;
|
|
21
|
+
}>;
|
|
22
|
+
delivery?: "single" | "simultaneous" | "overlap" | "group" | string;
|
|
23
|
+
lines?: Array<{
|
|
24
|
+
speaker_id?: string;
|
|
25
|
+
content?: string;
|
|
26
|
+
}>;
|
|
27
|
+
emotion?: string;
|
|
28
|
+
state_changes?: StateChange[];
|
|
29
|
+
transition_prompt?: TransitionPrompt;
|
|
30
|
+
}
|
|
31
|
+
interface AssetState {
|
|
32
|
+
state_id?: string;
|
|
33
|
+
state_name?: string;
|
|
34
|
+
name?: string;
|
|
35
|
+
description?: string;
|
|
36
|
+
}
|
|
37
|
+
type ScriptTargetKind = "actor" | "location" | "prop";
|
|
38
|
+
interface StateChange {
|
|
39
|
+
target_kind?: ScriptTargetKind | string;
|
|
40
|
+
target_id?: string;
|
|
41
|
+
from_state_id?: string | null;
|
|
42
|
+
to_state_id?: string | null;
|
|
43
|
+
effective_from?: "before_action" | "after_action" | string;
|
|
44
|
+
}
|
|
45
|
+
interface TransitionPrompt {
|
|
46
|
+
target_kind?: ScriptTargetKind | string;
|
|
47
|
+
target_id?: string;
|
|
48
|
+
process?: string;
|
|
49
|
+
contrast?: string;
|
|
50
|
+
}
|
|
51
|
+
interface SceneContext {
|
|
52
|
+
actors?: Array<{
|
|
53
|
+
actor_id?: string;
|
|
54
|
+
state_id?: string | null;
|
|
55
|
+
}>;
|
|
56
|
+
locations?: Array<{
|
|
57
|
+
location_id?: string;
|
|
58
|
+
state_id?: string | null;
|
|
59
|
+
}>;
|
|
60
|
+
props?: Array<{
|
|
61
|
+
prop_id?: string;
|
|
62
|
+
state_id?: string | null;
|
|
63
|
+
}>;
|
|
64
|
+
}
|
|
65
|
+
interface Scene {
|
|
66
|
+
scene_id?: string;
|
|
67
|
+
environment?: SceneEnvironment;
|
|
68
|
+
location_ids?: string[];
|
|
69
|
+
context?: SceneContext;
|
|
70
|
+
actors?: Array<{
|
|
71
|
+
actor_id?: string;
|
|
72
|
+
state_id?: string | null;
|
|
73
|
+
}>;
|
|
74
|
+
locations?: Array<{
|
|
75
|
+
location_id?: string;
|
|
76
|
+
state_id?: string | null;
|
|
77
|
+
}>;
|
|
78
|
+
props?: Array<{
|
|
79
|
+
prop_id?: string;
|
|
80
|
+
state_id?: string | null;
|
|
81
|
+
}>;
|
|
82
|
+
actions?: ScriptItem[];
|
|
83
|
+
}
|
|
84
|
+
interface ScriptActor {
|
|
85
|
+
actor_id?: string;
|
|
86
|
+
actor_name?: string;
|
|
87
|
+
name?: string;
|
|
88
|
+
description?: string;
|
|
89
|
+
states?: AssetState[];
|
|
90
|
+
}
|
|
91
|
+
interface ScriptLocation {
|
|
92
|
+
location_id?: string;
|
|
93
|
+
location_name?: string;
|
|
94
|
+
name?: string;
|
|
95
|
+
description?: string;
|
|
96
|
+
states?: AssetState[];
|
|
97
|
+
}
|
|
98
|
+
interface ScriptProp {
|
|
99
|
+
prop_id?: string;
|
|
100
|
+
prop_name?: string;
|
|
101
|
+
name?: string;
|
|
102
|
+
description?: string;
|
|
103
|
+
states?: AssetState[];
|
|
104
|
+
}
|
|
105
|
+
interface ScriptEpisode {
|
|
106
|
+
episode_id?: string;
|
|
107
|
+
title?: string | null;
|
|
108
|
+
scenes?: Scene[];
|
|
109
|
+
}
|
|
110
|
+
interface ScriptSpeaker {
|
|
111
|
+
speaker_id?: string;
|
|
112
|
+
display_name?: string;
|
|
113
|
+
source_kind?: "actor" | "location" | "prop" | "system" | "broadcast" | "group" | "other" | string;
|
|
114
|
+
source_id?: string | null;
|
|
115
|
+
voice_desc?: string;
|
|
116
|
+
}
|
|
117
|
+
interface ScriptProject {
|
|
118
|
+
version?: number | string;
|
|
119
|
+
title?: string;
|
|
120
|
+
worldview?: string;
|
|
121
|
+
worldview_raw?: string;
|
|
122
|
+
style?: string;
|
|
123
|
+
actors?: ScriptActor[];
|
|
124
|
+
locations?: ScriptLocation[];
|
|
125
|
+
props?: ScriptProp[];
|
|
126
|
+
speakers?: ScriptSpeaker[];
|
|
127
|
+
episodes?: ScriptEpisode[];
|
|
128
|
+
}
|
|
129
|
+
type ScriptData = ScriptProject;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Studio 页的选中状态。
|
|
133
|
+
* 剧集编辑是"一集一页":episode 选中打开集页、scene 选中打开同集并滚到对应场。
|
|
134
|
+
*/
|
|
135
|
+
/**
|
|
136
|
+
* Studio 主工作区视图:
|
|
137
|
+
* - script 剧本写作(默认)
|
|
138
|
+
* - review 审片:分镜 / Prompt / 视频对照表
|
|
139
|
+
* - files 项目文件浏览器(不依赖剧集,由 StudioHeader 上的"文件"按钮切换)
|
|
140
|
+
*
|
|
141
|
+
* 历史上还有 storyboard / assets / prompt / video 等独立 tab,已合入 review。
|
|
142
|
+
*/
|
|
143
|
+
type EpisodeWorkspaceView = "script" | "review" | "files";
|
|
144
|
+
/**
|
|
145
|
+
* 跨页跳转的来源标记。点击资产详情底部的"出现在 X 处"跳到 scene 时带上,
|
|
146
|
+
* 让目标页可以渲染"返回 XX"入口并把用户送回原资产。
|
|
147
|
+
*/
|
|
148
|
+
type StudioSelectionFrom = {
|
|
149
|
+
kind: "actor";
|
|
150
|
+
actorId: string;
|
|
151
|
+
} | {
|
|
152
|
+
kind: "location";
|
|
153
|
+
locationId: string;
|
|
154
|
+
} | {
|
|
155
|
+
kind: "prop";
|
|
156
|
+
propId: string;
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* selection 变化的驱动源。在 ScriptStream 中用于区分"该不该触发滚动":
|
|
160
|
+
* - 'scroll' 来自滚动 spy(视口里出现新 item 自动上抛),收到时 ScriptStream 不再调 scrollToIndex
|
|
161
|
+
* - 'sidebar' / 'diff' / 'reference' / 'chat' / 'init' / 'episode-toggle'
|
|
162
|
+
* 来自人为/外部驱动,需要 ScriptStream 主动滚到目标 item
|
|
163
|
+
*
|
|
164
|
+
* 不打 origin 时按 'sidebar' 等价处理(保守滚动)。
|
|
165
|
+
*/
|
|
166
|
+
type StudioSelectionOrigin = "sidebar" | "scroll" | "reference" | "diff" | "chat" | "init" | "episode-toggle";
|
|
167
|
+
declare function buildSelectionFrom(kind: StudioSelectionFrom["kind"], id: string): StudioSelectionFrom | undefined;
|
|
168
|
+
declare function fromToSelection(from: StudioSelectionFrom): StudioSelection;
|
|
169
|
+
/** 公共字段:所有 selection variant 都可携带(origin 防双向联动死循环;from 资产回链)。 */
|
|
170
|
+
type SelectionMeta = {
|
|
171
|
+
origin?: StudioSelectionOrigin;
|
|
172
|
+
};
|
|
173
|
+
type SelectionMetaWithFrom = SelectionMeta & {
|
|
174
|
+
from?: StudioSelectionFrom;
|
|
175
|
+
};
|
|
176
|
+
type StudioSelection = (SelectionMeta & {
|
|
177
|
+
kind: "empty";
|
|
178
|
+
}) | (SelectionMeta & {
|
|
179
|
+
kind: "worldview";
|
|
180
|
+
}) | (SelectionMetaWithFrom & {
|
|
181
|
+
kind: "episode";
|
|
182
|
+
episodeIdx: number;
|
|
183
|
+
}) | (SelectionMetaWithFrom & {
|
|
184
|
+
kind: "scene";
|
|
185
|
+
episodeIdx: number;
|
|
186
|
+
sceneIdx: number;
|
|
187
|
+
}) | (SelectionMetaWithFrom & {
|
|
188
|
+
kind: "clip";
|
|
189
|
+
episodeIdx: number;
|
|
190
|
+
sceneIdx?: number;
|
|
191
|
+
sceneId: string;
|
|
192
|
+
clipId: string;
|
|
193
|
+
}) | (SelectionMeta & {
|
|
194
|
+
kind: "actor";
|
|
195
|
+
actorId: string;
|
|
196
|
+
}) | (SelectionMeta & {
|
|
197
|
+
kind: "location";
|
|
198
|
+
locationId: string;
|
|
199
|
+
}) | (SelectionMeta & {
|
|
200
|
+
kind: "prop";
|
|
201
|
+
propId: string;
|
|
202
|
+
});
|
|
203
|
+
declare const EMPTY_SELECTION: StudioSelection;
|
|
204
|
+
/** 把 selection 复制一份并打上 origin 标记。 */
|
|
205
|
+
declare function withOrigin<T extends StudioSelection>(sel: T, origin: StudioSelectionOrigin): T;
|
|
206
|
+
/**
|
|
207
|
+
* 一个 selection「目标」的稳定字符串 key(忽略 origin / from)。既用于 scroll 同步
|
|
208
|
+
* 去重,也是 isSameSelectionTarget 的唯一判定依据 —— 两者不再各写一套。
|
|
209
|
+
*/
|
|
210
|
+
declare function selectionTargetKey(s: StudioSelection): string;
|
|
211
|
+
/** 判定两个 selection 是否指向同一个目标(忽略 origin / from)。 */
|
|
212
|
+
declare function isSameSelectionTarget(a: StudioSelection, b: StudioSelection): boolean;
|
|
213
|
+
declare function isSceneSelected(selection: StudioSelection, episodeIdx: number, sceneIdx: number): boolean;
|
|
214
|
+
declare function isClipSelected(selection: StudioSelection, episodeIdx: number, sceneId: string, clipId: string): boolean;
|
|
215
|
+
declare function getSelectionEpisodeIdx(selection: StudioSelection): number | null;
|
|
216
|
+
/** 该剧集当前是否处于"打开"状态(集页或集内某场被选中)。 */
|
|
217
|
+
declare function isEpisodeOpen(selection: StudioSelection, episodeIdx: number): boolean;
|
|
218
|
+
|
|
219
|
+
declare function getActorMap(actors?: ScriptActor[]): Map<string, ScriptActor>;
|
|
220
|
+
declare function getLocationMap(locations?: ScriptLocation[]): Map<string, ScriptLocation>;
|
|
221
|
+
declare function getPropMap(props?: ScriptProp[]): Map<string, ScriptProp>;
|
|
222
|
+
declare function getSpeakerMap(speakers?: ScriptSpeaker[]): Map<string, ScriptSpeaker>;
|
|
223
|
+
/**
|
|
224
|
+
* Reconcile the dual context storage. The refs live in BOTH scene.context.*
|
|
225
|
+
* and the legacy mirror scene.* — prefer whichever has entries so an EMPTY
|
|
226
|
+
* `context.actors: []` (e.g. from a partial upstream payload) does NOT shadow a
|
|
227
|
+
* populated mirror (which would silently drop the scene's cast/props).
|
|
228
|
+
*/
|
|
229
|
+
declare function getSceneContext(scene: Scene): {
|
|
230
|
+
actors: {
|
|
231
|
+
actor_id?: string;
|
|
232
|
+
state_id?: string | null;
|
|
233
|
+
}[];
|
|
234
|
+
locations: {
|
|
235
|
+
location_id?: string;
|
|
236
|
+
state_id?: string | null;
|
|
237
|
+
}[];
|
|
238
|
+
props: {
|
|
239
|
+
prop_id?: string;
|
|
240
|
+
state_id?: string | null;
|
|
241
|
+
}[];
|
|
242
|
+
};
|
|
243
|
+
declare function getEpisodeTitle(episode: ScriptEpisode, index: number): string;
|
|
244
|
+
|
|
245
|
+
interface SelectOption {
|
|
246
|
+
value: string;
|
|
247
|
+
label: string;
|
|
248
|
+
}
|
|
249
|
+
declare function SelectField({ value, options, onChange, disabled, title, placeholder, mono, className, style, emptyOptionLabel, }: {
|
|
250
|
+
value: string;
|
|
251
|
+
options: SelectOption[];
|
|
252
|
+
onChange: (next: string) => void;
|
|
253
|
+
disabled?: boolean;
|
|
254
|
+
title?: string;
|
|
255
|
+
placeholder?: string;
|
|
256
|
+
mono?: boolean;
|
|
257
|
+
className?: string;
|
|
258
|
+
style?: React.CSSProperties;
|
|
259
|
+
/** shown as a leading disabled option when value is empty */
|
|
260
|
+
emptyOptionLabel?: string;
|
|
261
|
+
}): react.JSX.Element;
|
|
262
|
+
|
|
263
|
+
type ScriptFormat = "standard" | "asian";
|
|
264
|
+
|
|
265
|
+
type SaveStatus = "idle" | "saving" | "saved" | "error";
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Coarse, pure diff between a baseline ScriptProject (pre-AI-revision) and the
|
|
269
|
+
* current one. Surfaces changed top-level fields and changed/added scenes so
|
|
270
|
+
* the overlay can show counts, navigate to changes, and accept/reject all.
|
|
271
|
+
* Scenes are matched by scene_id within an episode.
|
|
272
|
+
*/
|
|
273
|
+
|
|
274
|
+
interface FieldChange {
|
|
275
|
+
before: string;
|
|
276
|
+
after: string;
|
|
277
|
+
}
|
|
278
|
+
type SceneChangeKind = "added" | "modified";
|
|
279
|
+
interface ChangeSet {
|
|
280
|
+
title?: FieldChange;
|
|
281
|
+
worldview?: FieldChange;
|
|
282
|
+
style?: FieldChange;
|
|
283
|
+
/** "epIdx:sceneId" → kind, for scenes present in the current value */
|
|
284
|
+
changedScenes: Map<string, SceneChangeKind>;
|
|
285
|
+
/** scenes present in baseline but gone from current */
|
|
286
|
+
removedCount: number;
|
|
287
|
+
/** total surfaced changes */
|
|
288
|
+
count: number;
|
|
289
|
+
}
|
|
290
|
+
declare function sceneChangeKey(episodeIdx: number, sceneId: string | undefined): string;
|
|
291
|
+
declare function computeChangeSet(baseline: ScriptProject | null, current: ScriptProject): ChangeSet;
|
|
292
|
+
|
|
293
|
+
interface AssetDeleteRequest {
|
|
294
|
+
kind: "actor" | "location" | "prop";
|
|
295
|
+
id: string;
|
|
296
|
+
name: string;
|
|
297
|
+
description?: string;
|
|
298
|
+
/** -1 when the request originates from the asset library card (no scene) */
|
|
299
|
+
episodeIndex: number;
|
|
300
|
+
sceneIndex: number;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Adapter contracts — business is injected here so the editor stays pure (no
|
|
305
|
+
* direct API/fetch). The host (apps/web) implements these against its own
|
|
306
|
+
* services (script-output, chat, asset generation, comments).
|
|
307
|
+
*/
|
|
308
|
+
|
|
309
|
+
/** AI revision overlay: host supplies the pre-revision baseline; editor diffs. */
|
|
310
|
+
interface DiffAdapter {
|
|
311
|
+
/** the script as it was BEFORE the AI revision (null = no pending diff) */
|
|
312
|
+
baseline: ScriptProject | null;
|
|
313
|
+
/** accept all AI changes — host drops the baseline */
|
|
314
|
+
onAcceptAll?: () => void;
|
|
315
|
+
/** reject all AI changes — restore the baseline as the working value */
|
|
316
|
+
onRejectAll?: () => void;
|
|
317
|
+
}
|
|
318
|
+
/** Asset display + side-effecting generation/upload (kept in the host). */
|
|
319
|
+
interface AssetAdapter {
|
|
320
|
+
/** opaque payload the host uses to render thumbnails / connect galleries */
|
|
321
|
+
payload?: unknown;
|
|
322
|
+
isConnected?: boolean;
|
|
323
|
+
/** trigger generation/upload for an asset state (host side-effect) */
|
|
324
|
+
postAction?: (action: {
|
|
325
|
+
kind: "actor" | "location" | "prop";
|
|
326
|
+
id: string;
|
|
327
|
+
stateId?: string | null;
|
|
328
|
+
}) => void;
|
|
329
|
+
refresh?: () => void;
|
|
330
|
+
}
|
|
331
|
+
/** Agent bridge: send a chat message to the host's assistant. */
|
|
332
|
+
interface AgentAdapter {
|
|
333
|
+
sendMessage: (text: string) => void;
|
|
334
|
+
}
|
|
335
|
+
/** A reference (quoted text / selected block) to push into the chat composer. */
|
|
336
|
+
interface ChatReference {
|
|
337
|
+
id: string;
|
|
338
|
+
label: string;
|
|
339
|
+
text: string;
|
|
340
|
+
}
|
|
341
|
+
interface ScriptEditorAdapters {
|
|
342
|
+
diff?: DiffAdapter;
|
|
343
|
+
asset?: AssetAdapter;
|
|
344
|
+
agent?: AgentAdapter;
|
|
345
|
+
onAddChatReferences?: (refs: ChatReference[]) => void;
|
|
346
|
+
onRequestAssetDelete?: (target: AssetDeleteRequest) => void;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
interface ScriptEditorProps extends ScriptEditorAdapters {
|
|
350
|
+
value: ScriptProject;
|
|
351
|
+
onEdit: (patch: (prev: ScriptProject) => ScriptProject) => void;
|
|
352
|
+
selection?: StudioSelection;
|
|
353
|
+
onSelectionChange?: (next: StudioSelection) => void;
|
|
354
|
+
format?: ScriptFormat;
|
|
355
|
+
onFormatChange?: (format: ScriptFormat) => void;
|
|
356
|
+
disabled?: boolean;
|
|
357
|
+
className?: string;
|
|
358
|
+
dark?: boolean;
|
|
359
|
+
saveStatus?: SaveStatus;
|
|
360
|
+
canUndo?: boolean;
|
|
361
|
+
canRedo?: boolean;
|
|
362
|
+
onUndo?: () => void;
|
|
363
|
+
onRedo?: () => void;
|
|
364
|
+
/** fires true when an in-editor field opens for editing and false when the
|
|
365
|
+
* last one closes — lets the host pause adopting external revisions without
|
|
366
|
+
* reaching into the package's DOM / class names. */
|
|
367
|
+
onEditingChange?: (editing: boolean) => void;
|
|
368
|
+
}
|
|
369
|
+
declare function ScriptEditor({ value, onEdit, selection: controlledSelection, onSelectionChange, format: controlledFormat, onFormatChange, disabled, className, dark, saveStatus, canUndo, canRedo, onUndo, onRedo, onEditingChange, diff, asset, agent, onAddChatReferences, onRequestAssetDelete, }: ScriptEditorProps): react.JSX.Element;
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Pure ScriptProject mutations.
|
|
373
|
+
*
|
|
374
|
+
* ⚠️ INVARIANT — every mutation here MUST be immutable: never write into an
|
|
375
|
+
* existing scene / item / array in place; always return fresh spread-copied
|
|
376
|
+
* objects along the path from the root to the change (see cloneEpisodes /
|
|
377
|
+
* withSceneUpdated). Two things silently depend on it:
|
|
378
|
+
* 1. diff-engine's `base === scene` fast path — it treats a scene that keeps
|
|
379
|
+
* its baseline-snapshot reference as unchanged and skips serializing it; an
|
|
380
|
+
* in-place edit would keep the reference and the change would vanish from
|
|
381
|
+
* the diff overlay.
|
|
382
|
+
* 2. AssetCard / SceneEditor React.memo — they skip re-render when their slice
|
|
383
|
+
* keeps the same reference; an in-place edit would render stale UI.
|
|
384
|
+
* If you add a mutation, return new objects — do NOT `scene.actions.push(...)`
|
|
385
|
+
* or `Object.assign(scene, …)`.
|
|
386
|
+
*/
|
|
387
|
+
|
|
388
|
+
interface SceneDraft {
|
|
389
|
+
sceneId: string;
|
|
390
|
+
location: string;
|
|
391
|
+
space: string;
|
|
392
|
+
time: string;
|
|
393
|
+
actors: string;
|
|
394
|
+
}
|
|
395
|
+
interface ItemDraft {
|
|
396
|
+
kind: "dialogue" | "action";
|
|
397
|
+
actorName: string;
|
|
398
|
+
emotion: string;
|
|
399
|
+
content: string;
|
|
400
|
+
actionType: string;
|
|
401
|
+
}
|
|
402
|
+
declare function getSceneActorsText(scene: Scene): string;
|
|
403
|
+
declare function getPrimarySceneLocationId(scene: Scene): string;
|
|
404
|
+
declare function buildSceneDraft(sceneId: string, fallbackSceneIndex: number): SceneDraft;
|
|
405
|
+
declare function incrementSceneId(sceneId: string | undefined, fallbackEpisodeIndex: number, fallbackSceneIndex: number): string;
|
|
406
|
+
declare function nextEpisodeSceneId(data: ScriptProject, episodeIndex: number): string;
|
|
407
|
+
/**
|
|
408
|
+
* 基于 prev 递增,并在 existingScenes 里做冲突检测;若建议 id 已占用,继续递增直到不冲突。
|
|
409
|
+
* 上限 1000 次避免异常 id 格式引起死循环。
|
|
410
|
+
*/
|
|
411
|
+
declare function nextAvailableSceneId(prevSceneId: string | undefined, existingScenes: Scene[], fallbackEpisodeIndex: number, fallbackSceneIndex: number): string;
|
|
412
|
+
declare function decrementSceneId(sceneId: string | undefined, fallbackEpisodeIndex: number, fallbackSceneIndex: number): string;
|
|
413
|
+
declare function createSceneFromDraft(draft: SceneDraft): Scene;
|
|
414
|
+
declare function createItemFromDraft(draft: ItemDraft): ScriptItem;
|
|
415
|
+
declare function updateSceneField(data: ScriptProject, episodeIndex: number, sceneIndex: number, field: "scene_id" | "space" | "time" | "location" | "actors" | "props", value: string): ScriptProject;
|
|
416
|
+
declare function updateSceneActorState(data: ScriptProject, episodeIndex: number, sceneIndex: number, actorId: string, stateId: string | null): ScriptProject;
|
|
417
|
+
declare function updateSceneLocationState(data: ScriptProject, episodeIndex: number, sceneIndex: number, locationId: string, stateId: string | null): ScriptProject;
|
|
418
|
+
declare function updateScenePropState(data: ScriptProject, episodeIndex: number, sceneIndex: number, propId: string, stateId: string | null): ScriptProject;
|
|
419
|
+
declare function updateSceneItemContent(data: ScriptProject, episodeIndex: number, sceneIndex: number, itemIndex: number, content: string): ScriptProject;
|
|
420
|
+
declare function updateSceneItemActor(data: ScriptProject, episodeIndex: number, sceneIndex: number, itemIndex: number, actorId: string): ScriptProject;
|
|
421
|
+
declare function updateSceneItemEmotion(data: ScriptProject, episodeIndex: number, sceneIndex: number, itemIndex: number, emotion: string): ScriptProject;
|
|
422
|
+
declare function replaceSceneItem(data: ScriptProject, episodeIndex: number, sceneIndex: number, itemIndex: number, item: ScriptItem): ScriptProject;
|
|
423
|
+
/**
|
|
424
|
+
* Append a new (empty) episode at the end, or insert at `atIndex`. The new
|
|
425
|
+
* episode starts with no scenes — the empty-episode affordance lets the user
|
|
426
|
+
* add the first scene.
|
|
427
|
+
*/
|
|
428
|
+
declare function addEpisode(data: ScriptProject, atIndex?: number): ScriptProject;
|
|
429
|
+
/** Append a fresh blank scene to an episode (used by the empty-episode CTA). */
|
|
430
|
+
declare function addBlankScene(data: ScriptProject, episodeIndex: number): ScriptProject;
|
|
431
|
+
declare function insertScene(data: ScriptProject, episodeIndex: number, sceneIndex: number, scene: Scene): ScriptProject;
|
|
432
|
+
declare function splitScene(data: ScriptProject, episodeIndex: number, sceneIndex: number, splitAtItemIndex: number): ScriptProject;
|
|
433
|
+
/**
|
|
434
|
+
* 把 sceneIndex 对应的场并入 sceneIndex - 1。
|
|
435
|
+
* - actions 顺序拼接
|
|
436
|
+
* - actors / locations / props 按 id 去重合并(保留前场已有的 state_id)
|
|
437
|
+
* - 保留前场 scene_id 和 environment
|
|
438
|
+
* - **不再**对后续 scene_id 链式 -1:下游(video_map / asset state / 参考素材目录等)按
|
|
439
|
+
* scene_id 做主键,扰动 scene_id 会让已生成资产 / 视频孤立,代价远大于"id 连续"的收益。
|
|
440
|
+
* - sceneIndex <= 0 时无效,返回原 data
|
|
441
|
+
*/
|
|
442
|
+
declare function mergeSceneIntoPrev(data: ScriptProject, episodeIndex: number, sceneIndex: number): ScriptProject;
|
|
443
|
+
declare function deleteScene(data: ScriptProject, episodeIndex: number, sceneIndex: number): ScriptProject;
|
|
444
|
+
declare function insertSceneItem(data: ScriptProject, episodeIndex: number, sceneIndex: number, itemIndex: number, item: ScriptItem): ScriptProject;
|
|
445
|
+
declare function deleteSceneItem(data: ScriptProject, episodeIndex: number, sceneIndex: number, itemIndex: number): ScriptProject;
|
|
446
|
+
/**
|
|
447
|
+
* Reorder a row within a scene: pull the item at `fromIndex` out and re-insert
|
|
448
|
+
* it so it lands at insertion slot `toIndex` (0..length). No-op when the move
|
|
449
|
+
* wouldn't change order.
|
|
450
|
+
*/
|
|
451
|
+
declare function moveSceneItem(data: ScriptProject, episodeIndex: number, sceneIndex: number, fromIndex: number, toIndex: number): ScriptProject;
|
|
452
|
+
interface ItemLocation {
|
|
453
|
+
episodeIndex: number;
|
|
454
|
+
sceneIndex: number;
|
|
455
|
+
itemIndex: number;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Move a row to a target insertion slot, within the same scene OR across
|
|
459
|
+
* scenes. Cross-scene moves pull the item from the source scene's actions and
|
|
460
|
+
* splice it into the target scene's actions (the row's actor/emotion/etc. ride
|
|
461
|
+
* along unchanged). scene_id is never touched.
|
|
462
|
+
*/
|
|
463
|
+
declare function moveScriptItem(data: ScriptProject, from: ItemLocation, to: {
|
|
464
|
+
episodeIndex: number;
|
|
465
|
+
sceneIndex: number;
|
|
466
|
+
slot: number;
|
|
467
|
+
}): ScriptProject;
|
|
468
|
+
/** Remove an entire episode. */
|
|
469
|
+
declare function deleteEpisode(data: ScriptProject, episodeIndex: number): ScriptProject;
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* 切换某条行的 type,静默清理不相关字段:
|
|
473
|
+
* - 切到 dialogue / inner_thought:保留或继承 actor_id
|
|
474
|
+
* - 切到非人物行:删 actor_id / emotion
|
|
475
|
+
* - 切到 inner_thought:删 dialogue 专用的 emotion
|
|
476
|
+
*/
|
|
477
|
+
declare function updateSceneItemType(data: ScriptProject, episodeIndex: number, sceneIndex: number, itemIndex: number, type: ScriptContentType): ScriptProject;
|
|
478
|
+
/**
|
|
479
|
+
* 为 TypePicker 选完类型后构建一条空 item。新建对白/心声时可继承上一条人物行。
|
|
480
|
+
*/
|
|
481
|
+
declare function buildNewScriptItem(type: ScriptContentType, inheritedActorId?: string): ScriptItem;
|
|
482
|
+
/**
|
|
483
|
+
* 从 scene.actions 中取距离 beforeIndex 最近的上一条对白/心声 actor_id,没有则返回空串。
|
|
484
|
+
*/
|
|
485
|
+
declare function pickInheritedActorId(scene: Scene, beforeIndex: number): string;
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Pure mutations for the entity dictionary (actors / locations / props) and
|
|
489
|
+
* their asset states. Operate directly on ScriptProject; identity-preserving
|
|
490
|
+
* for untouched entries.
|
|
491
|
+
*/
|
|
492
|
+
|
|
493
|
+
type EntityKind = "actor" | "location" | "prop";
|
|
494
|
+
declare function updateEntityName(data: ScriptProject, kind: EntityKind, id: string, name: string): ScriptProject;
|
|
495
|
+
declare function updateEntityDescription(data: ScriptProject, kind: EntityKind, id: string, description: string): ScriptProject;
|
|
496
|
+
declare function updateEntityStateField(data: ScriptProject, kind: EntityKind, id: string, stateId: string, field: "state_name" | "description", value: string): ScriptProject;
|
|
497
|
+
declare function addEntityState(data: ScriptProject, kind: EntityKind, id: string, state: AssetState): ScriptProject;
|
|
498
|
+
declare function removeEntityState(data: ScriptProject, kind: EntityKind, id: string, stateId: string): ScriptProject;
|
|
499
|
+
|
|
500
|
+
type index_EntityKind = EntityKind;
|
|
501
|
+
type index_ItemDraft = ItemDraft;
|
|
502
|
+
type index_ItemLocation = ItemLocation;
|
|
503
|
+
type index_SceneDraft = SceneDraft;
|
|
504
|
+
declare const index_addBlankScene: typeof addBlankScene;
|
|
505
|
+
declare const index_addEntityState: typeof addEntityState;
|
|
506
|
+
declare const index_addEpisode: typeof addEpisode;
|
|
507
|
+
declare const index_buildNewScriptItem: typeof buildNewScriptItem;
|
|
508
|
+
declare const index_buildSceneDraft: typeof buildSceneDraft;
|
|
509
|
+
declare const index_createItemFromDraft: typeof createItemFromDraft;
|
|
510
|
+
declare const index_createSceneFromDraft: typeof createSceneFromDraft;
|
|
511
|
+
declare const index_decrementSceneId: typeof decrementSceneId;
|
|
512
|
+
declare const index_deleteEpisode: typeof deleteEpisode;
|
|
513
|
+
declare const index_deleteScene: typeof deleteScene;
|
|
514
|
+
declare const index_deleteSceneItem: typeof deleteSceneItem;
|
|
515
|
+
declare const index_getPrimarySceneLocationId: typeof getPrimarySceneLocationId;
|
|
516
|
+
declare const index_getSceneActorsText: typeof getSceneActorsText;
|
|
517
|
+
declare const index_incrementSceneId: typeof incrementSceneId;
|
|
518
|
+
declare const index_insertScene: typeof insertScene;
|
|
519
|
+
declare const index_insertSceneItem: typeof insertSceneItem;
|
|
520
|
+
declare const index_mergeSceneIntoPrev: typeof mergeSceneIntoPrev;
|
|
521
|
+
declare const index_moveSceneItem: typeof moveSceneItem;
|
|
522
|
+
declare const index_moveScriptItem: typeof moveScriptItem;
|
|
523
|
+
declare const index_nextAvailableSceneId: typeof nextAvailableSceneId;
|
|
524
|
+
declare const index_nextEpisodeSceneId: typeof nextEpisodeSceneId;
|
|
525
|
+
declare const index_pickInheritedActorId: typeof pickInheritedActorId;
|
|
526
|
+
declare const index_removeEntityState: typeof removeEntityState;
|
|
527
|
+
declare const index_replaceSceneItem: typeof replaceSceneItem;
|
|
528
|
+
declare const index_splitScene: typeof splitScene;
|
|
529
|
+
declare const index_updateEntityDescription: typeof updateEntityDescription;
|
|
530
|
+
declare const index_updateEntityName: typeof updateEntityName;
|
|
531
|
+
declare const index_updateEntityStateField: typeof updateEntityStateField;
|
|
532
|
+
declare const index_updateSceneActorState: typeof updateSceneActorState;
|
|
533
|
+
declare const index_updateSceneField: typeof updateSceneField;
|
|
534
|
+
declare const index_updateSceneItemActor: typeof updateSceneItemActor;
|
|
535
|
+
declare const index_updateSceneItemContent: typeof updateSceneItemContent;
|
|
536
|
+
declare const index_updateSceneItemEmotion: typeof updateSceneItemEmotion;
|
|
537
|
+
declare const index_updateSceneItemType: typeof updateSceneItemType;
|
|
538
|
+
declare const index_updateSceneLocationState: typeof updateSceneLocationState;
|
|
539
|
+
declare const index_updateScenePropState: typeof updateScenePropState;
|
|
540
|
+
declare namespace index {
|
|
541
|
+
export { type index_EntityKind as EntityKind, type index_ItemDraft as ItemDraft, type index_ItemLocation as ItemLocation, type index_SceneDraft as SceneDraft, index_addBlankScene as addBlankScene, index_addEntityState as addEntityState, index_addEpisode as addEpisode, index_buildNewScriptItem as buildNewScriptItem, index_buildSceneDraft as buildSceneDraft, index_createItemFromDraft as createItemFromDraft, index_createSceneFromDraft as createSceneFromDraft, index_decrementSceneId as decrementSceneId, index_deleteEpisode as deleteEpisode, index_deleteScene as deleteScene, index_deleteSceneItem as deleteSceneItem, index_getPrimarySceneLocationId as getPrimarySceneLocationId, index_getSceneActorsText as getSceneActorsText, index_incrementSceneId as incrementSceneId, index_insertScene as insertScene, index_insertSceneItem as insertSceneItem, index_mergeSceneIntoPrev as mergeSceneIntoPrev, index_moveSceneItem as moveSceneItem, index_moveScriptItem as moveScriptItem, index_nextAvailableSceneId as nextAvailableSceneId, index_nextEpisodeSceneId as nextEpisodeSceneId, index_pickInheritedActorId as pickInheritedActorId, index_removeEntityState as removeEntityState, index_replaceSceneItem as replaceSceneItem, index_splitScene as splitScene, index_updateEntityDescription as updateEntityDescription, index_updateEntityName as updateEntityName, index_updateEntityStateField as updateEntityStateField, index_updateSceneActorState as updateSceneActorState, index_updateSceneField as updateSceneField, index_updateSceneItemActor as updateSceneItemActor, index_updateSceneItemContent as updateSceneItemContent, index_updateSceneItemEmotion as updateSceneItemEmotion, index_updateSceneItemType as updateSceneItemType, index_updateSceneLocationState as updateSceneLocationState, index_updateScenePropState as updateScenePropState };
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* 角色对话名色板:按 actor_id 稳定 hash 到 8 色之一。
|
|
546
|
+
* 色板定义在 globals.css 的 --actor-cue-1..8(亮/暗各一份),
|
|
547
|
+
* 已调过亮度与饱和度,保证在牛皮纸底色上可读且互相错开。
|
|
548
|
+
*
|
|
549
|
+
* 没有 actor_id 时退回 --paper-cue-dialogue / --paper-cue-inner。
|
|
550
|
+
*/
|
|
551
|
+
declare function getActorCueVar(actorId: string | null | undefined, tone?: "dialogue" | "inner"): string;
|
|
552
|
+
|
|
553
|
+
interface EditableTextProps {
|
|
554
|
+
value: string;
|
|
555
|
+
onSave: (next: string) => void;
|
|
556
|
+
placeholder?: string;
|
|
557
|
+
/** multiline → <textarea> (auto-grow); else single-line <input>. */
|
|
558
|
+
multiline?: boolean;
|
|
559
|
+
disabled?: boolean;
|
|
560
|
+
className?: string;
|
|
561
|
+
/** start in edit mode + focus (for newly inserted rows) */
|
|
562
|
+
autoEdit?: boolean;
|
|
563
|
+
/** fires whenever edit mode is left (commit OR cancel) — lets the parent
|
|
564
|
+
* clear a one-shot autoEdit flag so a later row reshuffle can't re-trigger it. */
|
|
565
|
+
onEditEnd?: () => void;
|
|
566
|
+
/** forwarded to the display span (e.g. data-quote-target) */
|
|
567
|
+
spanProps?: React.HTMLAttributes<HTMLSpanElement>;
|
|
568
|
+
}
|
|
569
|
+
declare function EditableText({ value, onSave, placeholder, multiline, disabled, className, autoEdit, onEditEnd, spanProps, }: EditableTextProps): ReactElement;
|
|
570
|
+
|
|
571
|
+
interface PopoverProps {
|
|
572
|
+
trigger: (args: {
|
|
573
|
+
open: boolean;
|
|
574
|
+
toggle: () => void;
|
|
575
|
+
}) => ReactNode;
|
|
576
|
+
children: (args: {
|
|
577
|
+
close: () => void;
|
|
578
|
+
}) => ReactNode;
|
|
579
|
+
align?: "start" | "center" | "end";
|
|
580
|
+
side?: "bottom" | "top";
|
|
581
|
+
className?: string;
|
|
582
|
+
panelClassName?: string;
|
|
583
|
+
}
|
|
584
|
+
declare function Popover({ trigger, children, align, side, className, panelClassName, }: PopoverProps): react.JSX.Element;
|
|
585
|
+
|
|
586
|
+
declare function DeleteConfirmButton({ onConfirm, disabled, targetScope, title, }: {
|
|
587
|
+
onConfirm: () => void | Promise<void>;
|
|
588
|
+
disabled?: boolean;
|
|
589
|
+
/** drives the parent's hover-tint via data-delete-target */
|
|
590
|
+
targetScope?: "row" | "scene";
|
|
591
|
+
title?: string;
|
|
592
|
+
/** legacy prop, no longer rendered (kept for call-site compat) */
|
|
593
|
+
description?: string;
|
|
594
|
+
}): react.JSX.Element;
|
|
595
|
+
|
|
596
|
+
export { type AgentAdapter, type AssetAdapter, type AssetDeleteRequest, type AssetState, type ChangeSet, type ChatReference, DeleteConfirmButton, type DiffAdapter, EMPTY_SELECTION, EditableText, type EpisodeWorkspaceView, type FieldChange, Popover, type SaveStatus, type Scene, type SceneContext, type SceneEnvironment, type ScriptActor, ScriptContentType, type ScriptData, ScriptEditor, type ScriptEditorAdapters, type ScriptEditorProps, type ScriptEpisode, type ScriptFormat, type ScriptItem, type ScriptLocation, type ScriptProject, type ScriptProp, type ScriptSpeaker, type ScriptTargetKind, SelectField, type StateChange, type StudioSelection, type StudioSelectionFrom, type StudioSelectionOrigin, type TransitionPrompt, buildSelectionFrom, computeChangeSet, fromToSelection, getActorCueVar, getActorMap, getEpisodeTitle, getLocationMap, getPropMap, getSceneContext, getSelectionEpisodeIdx, getSpeakerMap, isClipSelected, isEpisodeOpen, isSameSelectionTarget, isSceneSelected, index as mutations, sceneChangeKey, selectionTargetKey, withOrigin };
|