@nodaro/prompts 1.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.
Files changed (150) hide show
  1. package/LICENSE +105 -0
  2. package/README.md +27 -0
  3. package/dist/index.cjs +21240 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +3599 -0
  6. package/dist/index.d.ts +3599 -0
  7. package/dist/index.js +20854 -0
  8. package/dist/index.js.map +1 -0
  9. package/package.json +49 -0
  10. package/src/__tests__/__snapshots__/prompt-builder-segments.test.ts.snap +65 -0
  11. package/src/__tests__/action-fx.test.ts +155 -0
  12. package/src/__tests__/apply-picker-json.test.ts +50 -0
  13. package/src/__tests__/assemble-image-input.test.ts +248 -0
  14. package/src/__tests__/assemble-suno-input.test.ts +283 -0
  15. package/src/__tests__/brand-tokens.test.ts +81 -0
  16. package/src/__tests__/build-image-prompt-element-injection.test.ts +118 -0
  17. package/src/__tests__/build-image-prompt-hybrid-format.test.ts +131 -0
  18. package/src/__tests__/build-image-prompt-mentions.test.ts +809 -0
  19. package/src/__tests__/build-image-prompt-reference-cap.test.ts +57 -0
  20. package/src/__tests__/build-image-prompt-reference-numbering.test.ts +237 -0
  21. package/src/__tests__/build-image-prompt-reference-order.test.ts +313 -0
  22. package/src/__tests__/camera-motions-from-connections.test.ts +71 -0
  23. package/src/__tests__/catalog-gapfill.test.ts +53 -0
  24. package/src/__tests__/character-convergence-image.test.ts +217 -0
  25. package/src/__tests__/character-default-role-image.test.ts +167 -0
  26. package/src/__tests__/character-default-role-video.test.ts +168 -0
  27. package/src/__tests__/character-default-role.test.ts +70 -0
  28. package/src/__tests__/character-fx.test.ts +200 -0
  29. package/src/__tests__/entity-prompts-location.test.ts +97 -0
  30. package/src/__tests__/entity-prompts.test.ts +240 -0
  31. package/src/__tests__/expand-extra-refs-role.test.ts +50 -0
  32. package/src/__tests__/factory-presets.test.ts +1045 -0
  33. package/src/__tests__/factory-snippets.test.ts +68 -0
  34. package/src/__tests__/framing-multi.test.ts +71 -0
  35. package/src/__tests__/framing-vantage.test.ts +39 -0
  36. package/src/__tests__/i18n-entry-completeness.test.ts +269 -0
  37. package/src/__tests__/identity-lock.test.ts +46 -0
  38. package/src/__tests__/instrumentation.test.ts +68 -0
  39. package/src/__tests__/lighting-multi.test.ts +68 -0
  40. package/src/__tests__/location-convergence-image.test.ts +124 -0
  41. package/src/__tests__/mention-lock-flag.test.ts +499 -0
  42. package/src/__tests__/multi-picker-spec.test.ts +71 -0
  43. package/src/__tests__/music-genre.test.ts +103 -0
  44. package/src/__tests__/music-mood.test.ts +87 -0
  45. package/src/__tests__/object-creature-convergence-image.test.ts +105 -0
  46. package/src/__tests__/parameter-prompt-hint.test.ts +270 -0
  47. package/src/__tests__/parameter-registry-sync.test.ts +243 -0
  48. package/src/__tests__/person-age.test.ts +80 -0
  49. package/src/__tests__/person-analyzer-invariants.test.ts +47 -0
  50. package/src/__tests__/person-body-axes.test.ts +67 -0
  51. package/src/__tests__/person-facial-geometry.test.ts +156 -0
  52. package/src/__tests__/person-regional-aesthetic.test.ts +161 -0
  53. package/src/__tests__/person-sections.test.ts +18 -0
  54. package/src/__tests__/picker-analyzer-registry.test.ts +108 -0
  55. package/src/__tests__/picker-catalogs-project.test.ts +85 -0
  56. package/src/__tests__/picker-catalogs.test.ts +53 -0
  57. package/src/__tests__/picker-limits.test.ts +20 -0
  58. package/src/__tests__/prompt-builder-segments.test.ts +183 -0
  59. package/src/__tests__/prompt-builder-structured-fields.test.ts +40 -0
  60. package/src/__tests__/prompt-builder.test.ts +1773 -0
  61. package/src/__tests__/prompt-wizard-categories.test.ts +31 -0
  62. package/src/__tests__/provider-prompt-doctrine.test.ts +49 -0
  63. package/src/__tests__/resolve-prompt-append.test.ts +58 -0
  64. package/src/__tests__/resolve-prompt.test.ts +44 -0
  65. package/src/__tests__/role-picker-shared.test.ts +208 -0
  66. package/src/__tests__/seedance-2-inputs.test.ts +173 -0
  67. package/src/__tests__/seedance-extend.test.ts +44 -0
  68. package/src/__tests__/sound-aggregator.test.ts +350 -0
  69. package/src/__tests__/style-presets.test.ts +34 -0
  70. package/src/__tests__/temporal-multi.test.ts +74 -0
  71. package/src/__tests__/transitions.test.ts +213 -0
  72. package/src/__tests__/video-reference-features.test.ts +41 -0
  73. package/src/__tests__/video-reference-leading-refs.test.ts +90 -0
  74. package/src/__tests__/video-reference-resolver.test.ts +233 -0
  75. package/src/__tests__/video-reference-roles.test.ts +96 -0
  76. package/src/__tests__/voice-character.test.ts +48 -0
  77. package/src/__tests__/voice-delivery.test.ts +41 -0
  78. package/src/__tests__/wardrobe.test.ts +25 -0
  79. package/src/action-fx.ts +255 -0
  80. package/src/aesthetic.ts +435 -0
  81. package/src/assemble-image-input.ts +236 -0
  82. package/src/assemble-suno-input.ts +147 -0
  83. package/src/atmosphere.ts +104 -0
  84. package/src/backdrop.ts +131 -0
  85. package/src/brand-tokens.ts +154 -0
  86. package/src/camera-format.ts +76 -0
  87. package/src/camera-motions.ts +615 -0
  88. package/src/character-fx.ts +274 -0
  89. package/src/color-look.ts +103 -0
  90. package/src/composition-effects.ts +67 -0
  91. package/src/entity-prompts.ts +231 -0
  92. package/src/era.ts +292 -0
  93. package/src/exposure-settings.ts +142 -0
  94. package/src/factory-presets/generate-image.ts +1644 -0
  95. package/src/factory-presets/generate-video.ts +1116 -0
  96. package/src/factory-presets/index.ts +46 -0
  97. package/src/factory-presets/lottie-overlay.ts +166 -0
  98. package/src/factory-presets/motion-graphics.ts +350 -0
  99. package/src/factory-presets/music.ts +734 -0
  100. package/src/factory-presets/sfx.ts +136 -0
  101. package/src/factory-presets/shared-image.ts +207 -0
  102. package/src/factory-presets/switchx.ts +65 -0
  103. package/src/factory-presets/text.ts +292 -0
  104. package/src/factory-presets/types.ts +51 -0
  105. package/src/factory-presets/video-edit.ts +136 -0
  106. package/src/factory-presets/voice.ts +172 -0
  107. package/src/factory-presets.ts +2 -0
  108. package/src/factory-snippets/catalog.ts +105 -0
  109. package/src/factory-snippets/index.ts +16 -0
  110. package/src/factory-snippets/types.ts +33 -0
  111. package/src/framing.ts +634 -0
  112. package/src/held-prop.ts +187 -0
  113. package/src/identity-lock.ts +213 -0
  114. package/src/index.ts +66 -0
  115. package/src/instrumentation.ts +337 -0
  116. package/src/lens.ts +59 -0
  117. package/src/lighting.ts +229 -0
  118. package/src/loop-subject.ts +276 -0
  119. package/src/materials.ts +184 -0
  120. package/src/mood.ts +186 -0
  121. package/src/music-genre.ts +662 -0
  122. package/src/music-mood.ts +137 -0
  123. package/src/object-asset-presets.ts +81 -0
  124. package/src/parameter-prompt-hint.ts +281 -0
  125. package/src/person.ts +1368 -0
  126. package/src/photo-genre.ts +151 -0
  127. package/src/photographer.ts +612 -0
  128. package/src/picker-analyzer-registry.ts +374 -0
  129. package/src/picker-catalogs.ts +858 -0
  130. package/src/pose.ts +246 -0
  131. package/src/post-process-effects.ts +94 -0
  132. package/src/prompt-builder-structured-fields.ts +116 -0
  133. package/src/prompt-builder.ts +2964 -0
  134. package/src/prompt-templates.ts +50 -0
  135. package/src/prompt-wizard-categories.ts +334 -0
  136. package/src/provider-prompt-doctrine.ts +85 -0
  137. package/src/render-quality.ts +89 -0
  138. package/src/resolve-prompt.ts +120 -0
  139. package/src/seedance-2-inputs.ts +100 -0
  140. package/src/setting.ts +130 -0
  141. package/src/sound-aggregator.ts +241 -0
  142. package/src/style-presets.ts +162 -0
  143. package/src/style.ts +99 -0
  144. package/src/styling.ts +585 -0
  145. package/src/temporal.ts +151 -0
  146. package/src/transitions.ts +333 -0
  147. package/src/video-reference-resolver.ts +823 -0
  148. package/src/voice-character.ts +237 -0
  149. package/src/voice-delivery.ts +142 -0
  150. package/src/wardrobe.ts +179 -0
@@ -0,0 +1,3599 @@
1
+ import { ConnectedReference, GenericNode, GenericEdge, HintNodeLike, HintGraphContext, EntityStyle, SupportedFontName, CharacterDef, IdentityMeta, SceneData, CharacterMentionTokenInfo, LocationMentionTokenInfo, UsageMode, StyleDirectives } from '@nodaro/shared';
2
+ export { HintEdgeLike, HintGraphContext, HintNodeLike } from '@nodaro/shared';
3
+ import { z } from 'zod';
4
+
5
+ /**
6
+ * Identity Lock — strength control for facial likeness preservation when a
7
+ * Character node's reference photo is fed into downstream generation.
8
+ *
9
+ * Real prompts seen in the wild (especially on Nano-Banana-Pro and
10
+ * ChatGPT-Image) explicitly write `"identitylock": "priority absolute"` /
11
+ * `"strictvisualfidelity": true` to clamp the face to the reference. This
12
+ * helper produces the equivalent natural-language clause so the rest of the
13
+ * stack stays unchanged.
14
+ *
15
+ * Used by:
16
+ * - frontend DAG executor (`workflow-editor/execute-node.ts`)
17
+ * - backend orchestrator (`services/workflow-engine/payload-builder.ts`)
18
+ */
19
+
20
+ type IdentityLockMode = "off" | "soft" | "strict";
21
+ /** Default applied when a Character node was created before the field existed. */
22
+ declare const DEFAULT_IDENTITY_LOCK: IdentityLockMode;
23
+ /**
24
+ * Natural-language clause for each mode. Returns an empty string for "off"
25
+ * (or anything unrecognised) so callers can append unconditionally.
26
+ */
27
+ declare function getIdentityLockClause(mode: IdentityLockMode | undefined): string;
28
+ /** Coerce arbitrary node-data field into a valid `IdentityLockMode`. */
29
+ declare function toIdentityLockMode(value: unknown): IdentityLockMode;
30
+ /**
31
+ * Map a Character NODE's `identityLock` mode (off/soft/strict) → the per-reference
32
+ * lock shape (`{ enabled, text }`) stamped onto every `ConnectedReference` derived
33
+ * from that node. This is what makes the node's off/soft/strict control reach
34
+ * hybrid output via `buildIdentityLockLine` (below):
35
+ * - off → { enabled: false } (no lock line)
36
+ * - soft → { enabled: true, text: <soft clause> } (mild "preserve likeness")
37
+ * - strict → { enabled: true, text: <strict clause> }(strong "match exactly")
38
+ * `undefined` coerces to the runtime default (`"soft"`) via `toIdentityLockMode`,
39
+ * so existing nodes (which never set the field) emit the mild line in hybrid. The
40
+ * per-mention `~lock`/`~nolock` sentinel still overrides via `withForcedIdentityLock`.
41
+ */
42
+ declare function characterLockToRefLock(mode: IdentityLockMode | undefined): {
43
+ enabled: boolean;
44
+ text?: string;
45
+ };
46
+ /**
47
+ * @deprecated Since Fix 4 (character @-mentions revamp) the per-image
48
+ * identity directive in `buildImagePrompt` — via
49
+ * `resolveCharacterMentions` Phase 0 and the strengthened
50
+ * `buildIdentityDirective` for person/character labels — already folds
51
+ * the identity-preservation language directly into the bulleted reference
52
+ * section. The global trailing clause this function used to produce is
53
+ * now redundant for character-wired flows, and this function only ever
54
+ * fired for upstream Character nodes. It now returns "" unconditionally
55
+ * so existing callers stay safe; remove the call sites in a follow-up
56
+ * cleanup, then this helper, `IdentityLockMode`, and `getIdentityLockClause`
57
+ * can be retired.
58
+ */
59
+ declare function collectIdentityLockClause<N extends GenericNode, E extends GenericEdge>(_nodeId: string, _nodes: readonly N[], _edges: readonly E[]): string;
60
+ /**
61
+ * Return `true` when any Character node is upstream of `nodeId` (walking
62
+ * through pass-through types). Used to short-circuit
63
+ * `collectIdentityLockClause`: with the new per-image identity directives
64
+ * (Fix 4) the global trailing clause is redundant for character-wired flows.
65
+ *
66
+ * Non-character wired-image refs still get the global clause.
67
+ */
68
+ declare function hasUpstreamCharacter<N extends GenericNode, E extends GenericEdge>(nodeId: string, nodes: readonly N[], edges: readonly E[], visited?: Set<string>): boolean;
69
+ /**
70
+ * The identity-lock line for a reference, or `null` when the lock is off.
71
+ * Opt-in only: a line is returned ONLY when `identityLock.enabled === true`
72
+ * (absent or `enabled === false` → `null`). Custom `text` wins (with `{ref}` →
73
+ * binding); otherwise the source's built-in wording is used.
74
+ */
75
+ /**
76
+ * Apply a per-mention identity-lock OVERRIDE to `ref` — the tri-state
77
+ * `~lock` / `~nolock` sentinel (Unified Reference Roles, Task 4 + F4). The
78
+ * `lockOverride` argument is the token's parsed `lock`:
79
+ * - `undefined` → INHERIT: the ORIGINAL ref is returned UNCHANGED (never a
80
+ * copy), so a lock-less mention resolves byte-identically to before and the
81
+ * ref/source default governs.
82
+ * - `true` → FORCE ON: `identityLock.enabled = true` (any existing custom
83
+ * `text` is preserved) — the `~lock` sentinel.
84
+ * - `false` → FORCE OFF: `identityLock.enabled = false`, which
85
+ * `buildIdentityLockLine` renders as `null`, SUPPRESSING even a ref-level
86
+ * `identityLock.enabled = true` — the `~nolock` sentinel.
87
+ * Called by the three HYBRID mention resolvers right before
88
+ * `buildIdentityLockLine`. Never mutates `ref`.
89
+ */
90
+ declare function withForcedIdentityLock(ref: ConnectedReference, lockOverride?: boolean): ConnectedReference;
91
+ declare function buildIdentityLockLine(ref: ConnectedReference, binding: string): string | null;
92
+
93
+ /**
94
+ * Dispatch by parameter-node type to its prompt-hint string. For camera-motion,
95
+ * pass `ctx` to include the composed start/end clauses; otherwise only the
96
+ * bare motion description is returned.
97
+ */
98
+ declare function getParameterPromptHint(node: HintNodeLike | undefined, ctx?: HintGraphContext): string;
99
+
100
+ interface CharacterPromptInput {
101
+ name: string;
102
+ description?: string;
103
+ gender?: string;
104
+ style?: EntityStyle | string;
105
+ baseOutfit?: string;
106
+ }
107
+ declare function buildCharacterPrompt(input: CharacterPromptInput): string;
108
+ interface ObjectPromptInput {
109
+ name: string;
110
+ description?: string;
111
+ category?: string;
112
+ style?: EntityStyle | string;
113
+ }
114
+ declare function buildObjectPrompt(input: ObjectPromptInput): string;
115
+ interface CreaturePromptInput {
116
+ name: string;
117
+ description?: string;
118
+ /** Free-text species/type (e.g. "dragon", "wolf") — the creature delta vs object. */
119
+ species?: string;
120
+ category?: string;
121
+ style?: EntityStyle | string;
122
+ }
123
+ /**
124
+ * Creature establishing-shot prompt. Mirrors {@link buildObjectPrompt} but leads
125
+ * with the free-text `species` (a dragon/wolf/etc. IS the subject) and frames the
126
+ * subject as a living creature rather than a product. Falls back to "creature"
127
+ * when no species is given so the prompt always names a subject.
128
+ */
129
+ declare function buildCreaturePrompt(input: CreaturePromptInput): string;
130
+ interface LocationPromptInput {
131
+ name: string;
132
+ description?: string;
133
+ category?: string;
134
+ style?: EntityStyle | string;
135
+ }
136
+ declare function buildLocationPrompt(input: LocationPromptInput): string;
137
+ interface LocationRefinePromptInput {
138
+ /**
139
+ * The user's TRANSIENT edit/refine instruction (e.g. "make it night, add
140
+ * drifting fog"). Used only to build this one generation's prompt - it is
141
+ * never written back to the location row, so the stored name / description /
142
+ * canonical description stay untouched. This is the deliberate contrast with
143
+ * `LocationPromptInput.description`, which IS the persisted scene description
144
+ * that `buildLocationPrompt` weaves in.
145
+ */
146
+ editPrompt: string;
147
+ style?: EntityStyle | string;
148
+ }
149
+ /**
150
+ * Build a TRANSIENT prompt from a user-supplied edit/refine instruction.
151
+ *
152
+ * Used by `POST /v1/generate-location` when the caller passes `userPrompt`
153
+ * (the studio's "describe changes" / sparkle Edit flow). Paired with an i2i
154
+ * `sourceImageUrl` the provider edits the source establishing shot toward the
155
+ * instruction; with no source image it reads as a from-scratch custom scene
156
+ * prompt. Mirrors `characters.generate`'s seed/edit-prompt path, but locations
157
+ * have no stored seed prompt - this output is purely transient and the route
158
+ * persists nothing derived from it back to the row.
159
+ */
160
+ declare function buildLocationRefinePrompt(input: LocationRefinePromptInput): string;
161
+ interface FacePromptInput {
162
+ name: string;
163
+ description?: string;
164
+ style?: EntityStyle | string;
165
+ }
166
+ /**
167
+ * Face prompt uses the "face-generation" template (resolved via prompt-templates.ts).
168
+ * Returns the template inputs so callers can call resolveTemplate + applyTemplate.
169
+ */
170
+ declare function buildFaceTemplateInputs(input: FacePromptInput): {
171
+ description: string;
172
+ style: string;
173
+ };
174
+ interface CharacterMotionPromptInput {
175
+ name: string;
176
+ description?: string;
177
+ gender?: string;
178
+ style?: EntityStyle | string;
179
+ baseOutfit?: string;
180
+ motionPrompt: string;
181
+ }
182
+ declare function buildMotionPrompt(input: CharacterMotionPromptInput): string;
183
+ /**
184
+ * Input shape for buildLocationMotionPrompt.
185
+ *
186
+ * Mirrors CharacterMotionPromptInput's role. `canonicalDescription` is preferred
187
+ * (LLM-authored from the approved main image) but the helper falls back to
188
+ * category+name if not yet set, and to a generic placeholder if both are absent.
189
+ */
190
+ interface LocationMotionPromptInput {
191
+ name: string;
192
+ category?: string;
193
+ style?: EntityStyle | string;
194
+ motionPrompt: string;
195
+ canonicalDescription?: string;
196
+ }
197
+ /**
198
+ * Build the prompt sent to the i2v provider for a location atmosphere clip.
199
+ *
200
+ * Note: character's analog is named `buildMotionPrompt` (historical); location
201
+ * uses the more specific `buildLocationMotionPrompt`.
202
+ */
203
+ declare function buildLocationMotionPrompt(input: LocationMotionPromptInput): string;
204
+ /**
205
+ * Object asset-type enum — the kinds of variant a user can generate off an
206
+ * object's anchor main image. Mirrors the literal accepted by
207
+ * `POST /v1/generate-object-asset` (`backend/src/routes/generate-object-asset.ts`)
208
+ * and consumed by the MCP `generate_object` verb (kind="asset").
209
+ *
210
+ * The `motion` value is reserved for type-system exhaustiveness on the
211
+ * frontend; the route rejects it because motion variants flow through the
212
+ * dedicated `/v1/generate-object-motion` endpoint (worker-side it's a different
213
+ * BullMQ job type). `custom` is the free-form bucket — callers must supply
214
+ * `attachToColumn` explicitly since the worker can't infer it.
215
+ */
216
+ interface ObjectMotionPromptInput {
217
+ name: string;
218
+ category?: string;
219
+ style?: EntityStyle | string;
220
+ motionPrompt: string;
221
+ canonicalDescription?: string;
222
+ seedPromptHint?: string;
223
+ }
224
+ /**
225
+ * Build the prompt sent to the i2v provider for an object atmosphere/motion clip.
226
+ *
227
+ * Naming note: character's analog is `buildMotionPrompt`; location uses
228
+ * `buildLocationMotionPrompt`; object uses `buildObjectMotionPrompt` to make
229
+ * the entity type explicit at call sites.
230
+ *
231
+ * The `seedPromptHint` is appended verbatim — Phase C's route layer composes
232
+ * wired-picker hints (Material/Animal/Vehicle/Weapon/Furniture) into this
233
+ * field before passing the input. Empty hint = no-op (the trailing dot still
234
+ * reads cleanly: "...motion. " not "...motion. .").
235
+ */
236
+ declare function buildObjectMotionPrompt(input: ObjectMotionPromptInput): string;
237
+
238
+ /**
239
+ * Brand layer (Phase 3a). A pragmatic brand-token set — palette + fonts + logo —
240
+ * authored/selected ONCE and threaded through the shot-sequence pipeline as
241
+ * defaults. Preset palettes are adapted from HyperFrames' Apache-2.0
242
+ * `hyperframes-creative/frame-presets`, re-grounded on SUPPORTED_FONT_NAMES.
243
+ */
244
+ interface BrandPalette {
245
+ /** Canvas background. */
246
+ bg: string;
247
+ /** Secondary surface (cards/panels). Carried for forward-compat; unconsumed in 3a. */
248
+ bgAlt?: string;
249
+ /** Primary on-bg text. */
250
+ text: string;
251
+ /** Secondary text. Carried for forward-compat; unconsumed in 3a. */
252
+ textMuted?: string;
253
+ /** Primary accent — the brand color. */
254
+ accent: string;
255
+ /** Secondary accent. Carried for forward-compat; unconsumed in 3a. */
256
+ accent2?: string;
257
+ /** Hairline/divider. Carried for forward-compat; unconsumed in 3a. */
258
+ line?: string;
259
+ }
260
+ type BrandCasing = "uppercase" | "lowercase" | "none";
261
+ interface BrandTypeSpec {
262
+ /** CSS font-weight. MUST be a weight loaded for the role's font (guarded in remotion). */
263
+ weight?: number;
264
+ /** absent => inherit call-site; "none" => force no transform; else force that transform. */
265
+ casing?: BrandCasing;
266
+ /** letter-spacing in em; suppressed for Arabic at render time. */
267
+ tracking?: number;
268
+ }
269
+ interface BrandFonts {
270
+ heading: SupportedFontName;
271
+ body: SupportedFontName;
272
+ headingType?: BrandTypeSpec;
273
+ bodyType?: BrandTypeSpec;
274
+ }
275
+ interface BrandLogo {
276
+ name: string;
277
+ tagline?: string;
278
+ /** Optional logo image — an https URL on an allowlisted Nodaro-CDN host (v1: URL only; obtain from the upload tools). */
279
+ image?: string;
280
+ /** Optional hex color for a rounded panel rendered behind the logo. */
281
+ imageBackdrop?: string;
282
+ }
283
+ interface BrandTokens {
284
+ palette: BrandPalette;
285
+ fonts: BrandFonts;
286
+ logo?: BrandLogo;
287
+ }
288
+ interface BrandPresetMeta {
289
+ id: BrandPresetId;
290
+ label: string;
291
+ mood: string;
292
+ description: string;
293
+ }
294
+ type BrandPresetId = "midnight-violet" | "editorial-cream" | "cobalt-corporate" | "sandstone-warm" | "poster-contrast" | "mono-slate" | "vibrant-pulse" | "pastel-calm";
295
+ declare const BRAND_PRESET_IDS: readonly BrandPresetId[];
296
+ declare const BRAND_PRESETS: Record<BrandPresetId, BrandTokens>;
297
+ declare const BRAND_PRESET_META: Record<BrandPresetId, BrandPresetMeta>;
298
+ /** Resolve a preset-name string OR an inline BrandTokens object to BrandTokens. */
299
+ declare function resolveBrandInput(brand: string | BrandTokens): BrandTokens;
300
+
301
+ /**
302
+ * Image prompt assembly logic shared between frontend and backend.
303
+ * Handles character description expansion, style appending, negative prompt routing,
304
+ * provider-aware prompt truncation (default 5000 chars), and reference image filtering by model support.
305
+ */
306
+
307
+ interface ResolveCharacterMentionsResult {
308
+ /** Prompt with @-tokens replaced by display names + "Use these characters:" directive prepended. */
309
+ prompt: string;
310
+ /** Resolved URLs from matched mention tokens, in mention order, deduped via caller responsibility. */
311
+ additionalUrls: string[];
312
+ /**
313
+ * Set of character slugs that had at least one resolved mention token.
314
+ * Callers use this to gate the per-character "no mention → canonical
315
+ * fallback" behavior so a wired character with no `@-mention` still gets
316
+ * its canonical URL attached (existing pre-mention-feature behavior).
317
+ */
318
+ mentionedCharacterSlugs: Set<string>;
319
+ }
320
+ /**
321
+ * Resolve @-mention tokens in a prompt against connected references.
322
+ * Returns: augmented prompt (with directives prepended + tokens replaced
323
+ * by character display names) and the set of asset URLs to include as refs.
324
+ *
325
+ * Behavior:
326
+ * - Build two lookup Maps: `bySlug` for canonical entries, `byVariant` for variant entries.
327
+ * - Iterate tokens left-to-right so directives are emitted in mention order.
328
+ * - For each token, prefer the variant match when variantSlug present; fall back to canonical.
329
+ * - `charactersSeen` Set guards the long canonical description to appear AT MOST ONCE
330
+ * per character even when the character is mentioned in several tokens.
331
+ * - Build a `replacements` array (token + offset + replacement display name) and
332
+ * apply right-to-left so earlier replacements do not shift later offsets.
333
+ * - Prepend a "Use these characters:\n…" directive section when any directives were emitted.
334
+ * - Each directive bullet leads with the user-visible `Image N (Name)` index pulled
335
+ * directly from the typed token (e.g. `@kira:1:smile` → `Image 1 (Kira)`).
336
+ * This lets the user trace a literal slug in the prompt to its appearance in
337
+ * the final assembled identity-directive block.
338
+ */
339
+ declare function resolveCharacterMentions(prompt: string, tokens: readonly CharacterMentionTokenInfo[], refs: readonly ConnectedReference[]): ResolveCharacterMentionsResult;
340
+ interface ResolveLocationMentionsResult {
341
+ /** Prompt with `@location:N` tokens replaced by display names + a
342
+ * "Use these locations:" directive prepended when at least one bullet
343
+ * fires. */
344
+ prompt: string;
345
+ /** Resolved URLs from matched mention tokens, in mention order. Caller
346
+ * is responsible for deduping against the existing URL list (the same
347
+ * contract as `resolveCharacterMentions.additionalUrls`). */
348
+ additionalUrls: string[];
349
+ /** Set of location slugs that had at least one resolved mention. Callers
350
+ * use this to gate "no mention → canonical fallback" behavior (mirrors
351
+ * the character flow — Phase 2 #1 attached the canonical URL via
352
+ * `expandWiredLocationRefs` directly, but a future fallback path may
353
+ * use this set to suppress the canonical URL once the user has explicitly
354
+ * pinned a variant via @-mention). */
355
+ mentionedLocationSlugs: Set<string>;
356
+ }
357
+ /**
358
+ * Resolve `@oldlibrary:1:weather/rain` mentions in the prompt against the
359
+ * pre-expanded `wired-location` ConnectedReferences (from
360
+ * `expandWiredLocationRefs` / `expandLocationNodeIntoRefs`). Mirrors
361
+ * `resolveCharacterMentions` shape:
362
+ *
363
+ * 1. Look up the matching ref by `(locationSlug, bucket, variantSlug)`.
364
+ * 2. Append its URL to `additionalUrls`.
365
+ * 3. Substitute the inline token with the location's display name (or
366
+ * `Image N` for "none" mode — image attached without textual bias).
367
+ * 4. Emit a directive bullet under "Use these locations:" header, with
368
+ * mode-specific verb. "none" mode suppresses the bullet (just like
369
+ * character "none").
370
+ *
371
+ * Per-location single-bullet rule: each location emits AT MOST ONE bullet
372
+ * (the first non-none mention "claims" the slot). Subsequent mentions of the
373
+ * same location still produce inline substitution + URL but no additional
374
+ * bullet, mirroring `resolveCharacterMentions.firstBulletEmittedFor`.
375
+ *
376
+ * Returns `additionalUrls` deduplication is the caller's responsibility,
377
+ * matching the character contract.
378
+ */
379
+ declare function resolveLocationMentions(prompt: string, tokens: readonly LocationMentionTokenInfo[], refs: readonly ConnectedReference[]): ResolveLocationMentionsResult;
380
+ /**
381
+ * Reorder URLs by `referenceOrder` AND renumber `Image N` tokens in the
382
+ * prompt to match. Returns the new URL list + the rewritten prompt. When
383
+ * `referenceOrder` is empty / null / all-stale, the original URLs + prompt
384
+ * are returned unchanged (no-op contract).
385
+ *
386
+ * Renumbering rule: build an `original-pos → new-pos` map from the URL move
387
+ * indices, then regex-replace `Image N` substrings (word-boundary-anchored
388
+ * so we don't touch "Image 12" while remapping "Image 1"). Done in one pass
389
+ * via a callback that looks up each match in the map; unknown positions are
390
+ * left as-is.
391
+ *
392
+ * NB: `findCharacterMentionTokens` is already applied BEFORE this step, so
393
+ * any `@kira:1:smile` literals in the prompt have been replaced with display
394
+ * names — only positional `Image N` markers remain to be remapped.
395
+ *
396
+ * Exposed (non-export internal) — also called by video branches in
397
+ * payload-builder / execute-node via `applyReferenceOrderToVideo` so video
398
+ * prompts honor the same reorder semantics as image prompts.
399
+ */
400
+ declare function applyReferenceOrderToVideo(urls: readonly string[], prompt: string | undefined, refs: readonly ConnectedReference[], referenceOrder: readonly string[] | undefined, sourceNodeIdById?: ReadonlyMap<string, string>,
401
+ /**
402
+ * Number of LEADING reference images (e.g. plain image-refs that precede the
403
+ * asset URLs in the unified `@image_N` numbering — see
404
+ * `resolveVideoReferenceCore`'s `leadingRefUrls`). `urls` here are the ASSET
405
+ * URLs only; their prompt ordinals are `ordinalOffset + 1 …`, so the renumber
406
+ * remap is keyed by the offset ordinal and leading ordinals (`1 … offset`)
407
+ * pass through untouched. Defaults to 0 → behaviour unchanged.
408
+ */
409
+ ordinalOffset?: number): {
410
+ urls: string[];
411
+ prompt: string | undefined;
412
+ };
413
+ interface BuildImagePromptConfig {
414
+ /** Raw user prompt text */
415
+ prompt: string;
416
+ /** Image provider key (e.g. "nano-banana", "gpt-image") */
417
+ provider: string;
418
+ /** Style text to append (e.g. "cinematic") */
419
+ style?: string;
420
+ /** Negative prompt text */
421
+ negativePrompt?: string;
422
+ /** Character definitions selected for this node */
423
+ characterDefs?: CharacterDef[];
424
+ /** User-level prompt template overrides */
425
+ userTemplates?: Record<string, string>;
426
+ /** Flow-level prompt template overrides */
427
+ flowTemplates?: Record<string, string>;
428
+ /** Reference image URLs from direct connections, extracted refs, and character refs */
429
+ referenceImageUrls?: string[];
430
+ /** Ancestor reference image URLs (fallback when no direct refs exist) */
431
+ ancestorRefs?: string[];
432
+ /**
433
+ * Rich connected-reference data. When provided, supersedes `characterDefs`
434
+ * and `referenceImageUrls`: per-identity directives come from this list +
435
+ * any `{image:N:label}` mentions in the prompt, URLs come from this list
436
+ * in order, and tokens expand to "the {label} from image {N}".
437
+ */
438
+ connectedReferences?: ConnectedReference[];
439
+ /** Per-identity (imageIndex+label) user overrides for fidelity / custom text. */
440
+ identityMeta?: readonly IdentityMeta[];
441
+ /**
442
+ * Reference-prompt assembly format for the `{image:N:label}` connected-
443
+ * reference (non-character) path. Additive + opt-in:
444
+ * - "legacy" (default): the "Use these references:/Compose them naturally:"
445
+ * wrap with numeric `Image N` directives — unchanged behavior.
446
+ * - "hybrid": token expansion only — every `{image:N:label}` token → "the
447
+ * <label> from reference image <LETTER>". NO lock snippet is auto-injected
448
+ * (authors prepend their own). Images-only for now; characters/objects/
449
+ * locations still render legacy. v1 skips `referenceOrder` renumbering.
450
+ */
451
+ referenceFormat?: "legacy" | "hybrid";
452
+ /**
453
+ * OPTIONAL reference-lock snippet to prepend ahead of the hybrid scene. Only
454
+ * used when `referenceFormat === "hybrid"`. Nothing is prepended by default —
455
+ * authors include their own lock snippet in the prompt text. Provide this only
456
+ * if a caller wants to auto-prepend a lock.
457
+ */
458
+ referenceLockSnippet?: string;
459
+ /**
460
+ * User-defined reorder of the injected reference list. Each entry is a
461
+ * stable tile ID using the scheme from `compute-injected-refs.ts`:
462
+ * - `wired:<sourceNodeId>` (a wired upstream — manual / wired-image /
463
+ * wired-face / wired-object / wired-location / extra-ref)
464
+ * - `mention:<characterSlug>:<variantSlug|canonical>` (an `@-mention`
465
+ * resolved to a character variant URL)
466
+ * - `char-canonical:<characterSlug>` (the auto-attached canonical
467
+ * fallback for a wired character that the user did NOT `@-mention`)
468
+ *
469
+ * Behavior: after the existing assembly produces a URL list + a prompt
470
+ * with `Image N` directives, the URLs are re-ordered to match this list
471
+ * AND every `Image N` token in the prompt is renumbered consistently
472
+ * (so directive bullets, the user's typed `Image N` references, and the
473
+ * worker `referenceImageUrls` index all agree).
474
+ *
475
+ * IDs in this array that don't match any tile are silently dropped. Tiles
476
+ * whose ID is NOT in this array fall to the end in their natural order.
477
+ * Identical fixtures on frontend + backend MUST produce identical URL
478
+ * lists — the helper is shared via `compute-injected-refs.ts`.
479
+ *
480
+ * Stable-ID-per-URL mapping for the post-assembly re-order is computed
481
+ * from `connectedReferences` + the user's prompt; passing `referenceOrder`
482
+ * is a no-op when `connectedReferences` is missing (legacy path).
483
+ *
484
+ * Optional, omit to keep the existing natural order.
485
+ */
486
+ referenceOrder?: readonly string[];
487
+ /**
488
+ * Map of `connectedReferences[i].id → sourceNodeId` so wired-raw tile IDs
489
+ * match the upstream node IDs the consumer panel exposes. When omitted, the
490
+ * builder falls back to `connectedReferences[i].id` (which equals the
491
+ * upstream node ID for wired entries built by the existing image-configs +
492
+ * payload-builder flow).
493
+ */
494
+ sourceNodeIdById?: ReadonlyMap<string, string>;
495
+ /**
496
+ * Character slugs whose canonical-fallback the user has explicitly hidden
497
+ * via the × button. Mention URLs for the same character still attach.
498
+ */
499
+ suppressedCanonicalCharacterIds?: readonly string[];
500
+ /**
501
+ * Location slugs (or DB ids) whose canonical-fallback the user has hidden
502
+ * via the × button. Mirrors `suppressedCanonicalCharacterIds`: the upstream
503
+ * `wired-location` ref still attaches, but the canonical establishing-shot
504
+ * URL is dropped from the injected reference list.
505
+ *
506
+ * NOTE (Phase 1A): the location canonical-fallback path is wired up in a
507
+ * follow-up PR (`injected-reference-helpers.ts`). Until then, this
508
+ * parameter is accepted but inert — callers can pass it through without
509
+ * any behavior change. Once the canonical-fallback logic lands, the
510
+ * builder will filter `connectedReferences` with `source === "wired-location"`
511
+ * and a matching slug, exactly like the character path does.
512
+ */
513
+ suppressedCanonicalLocationIds?: readonly string[];
514
+ /**
515
+ * When true, skip the entire mention-resolution block (character identity
516
+ * directives, `Image N (Kira)` bullets, additional ref URLs from
517
+ * `connectedReferences`) AND strip raw `@slug[:V[:variant]]` tokens from
518
+ * the prompt. Used by the LoRA inference path
519
+ * (`flux-lora-character`) — the trigger word + LoRA carries identity, so
520
+ * the directive bullets are redundant and the wired-character refs
521
+ * shouldn't be injected as `Image N`.
522
+ */
523
+ skipCharacterMentions?: boolean;
524
+ }
525
+ interface BuildImagePromptResult {
526
+ /** Final assembled prompt */
527
+ prompt: string;
528
+ /** Native negative prompt (only for models that support it), undefined otherwise */
529
+ nativeNegativePrompt: string | undefined;
530
+ /** Filtered reference image URLs (only for models that support them) */
531
+ referenceImageUrls: string[] | undefined;
532
+ }
533
+ type PromptSegmentOrigin = "user" | "variable" | "picker" | "mention" | "style" | "negative";
534
+ interface PromptSegment {
535
+ readonly text: string;
536
+ readonly origin: PromptSegmentOrigin;
537
+ }
538
+ interface BuildImagePromptSegmentsResult extends BuildImagePromptResult {
539
+ /** Origin-tagged decomposition of `prompt`. INVARIANT (tested):
540
+ * segments.map(s => s.text).join("") === prompt. */
541
+ segments: PromptSegment[];
542
+ }
543
+ /**
544
+ * Build the final image generation prompt from config.
545
+ * Handles character description wrapping, style appending, negative prompt routing,
546
+ * truncation, and reference image filtering.
547
+ *
548
+ * Thin passthrough over `buildImagePromptInternal` — byte-identical behavior,
549
+ * no marks captured. Use `buildImagePromptSegments` when you also need the
550
+ * origin-tagged decomposition.
551
+ */
552
+ declare function buildImagePrompt(config: BuildImagePromptConfig): BuildImagePromptResult;
553
+ /**
554
+ * `buildImagePrompt` plus an origin-tagged decomposition of the assembled
555
+ * `prompt`. The string output (and all other fields) is byte-identical to
556
+ * `buildImagePrompt` — the segments are derived from assembly marks recorded
557
+ * during the same pass.
558
+ *
559
+ * ABSOLUTE INVARIANT (tested): `segments.map(s => s.text).join("") === prompt`.
560
+ * Anything the marks can't model — `{image:N}` token expansion, `referenceOrder`
561
+ * renumbering, mid-string Phase-0 directive splicing, truncation — breaks the
562
+ * join, and we collapse to a single `user` segment rather than ship a wrong
563
+ * decomposition. Callers pass `bodySegments` (origins user/variable/picker/…)
564
+ * for the body text; they survive only when the assembly didn't rewrite the
565
+ * body string.
566
+ */
567
+ declare function buildImagePromptSegments(config: BuildImagePromptConfig, bodySegments?: readonly PromptSegment[]): BuildImagePromptSegmentsResult;
568
+ /**
569
+ * Replace `{image:N:label}` and `{image:N}` tokens with natural-language
570
+ * phrases bound to a numbered image (Image 1 / 2 / 3 …).
571
+ *
572
+ * - `{image:N:label}` → `Image {N} ({label})`
573
+ * - `{image:N}` → `Image {N}` (no role specified)
574
+ *
575
+ * Same parenthetical form as the directive subject so the model sees a
576
+ * consistent identifier in both the bulleted list and the scene description.
577
+ * Numeric indices match the user-typed slug format (`@kira:1:smile`).
578
+ *
579
+ * Out-of-range indices are left untouched so they're visible in the output.
580
+ */
581
+ declare function expandImageRefTokens(prompt: string, imageCount: number): string;
582
+ /** Build the combined per-identity directive intro for previews.
583
+ * Each directive is emitted on its own line so the model (and the human
584
+ * reading the FinalPromptPreview) can see the structure clearly. */
585
+ declare function buildIdentityDirectives(prompt: string, refs: readonly ConnectedReference[], meta?: readonly IdentityMeta[], suppressedCanonicalLocationIds?: readonly string[]): string;
586
+ /** @deprecated Use `expandImageRefTokens` (label-aware). */
587
+ declare function expandImagePositionRefs(prompt: string, imageCount: number, names?: readonly string[]): string;
588
+ /** @deprecated Use `buildIdentityDirectives(prompt, refs, meta)`. */
589
+ declare function buildReferenceBlocks(refs: readonly ConnectedReference[], _meta?: readonly IdentityMeta[]): string;
590
+ declare const SCENE_PROMPT_MAX_LENGTH = 2000;
591
+ declare const SHOT_LABELS: Record<string, string>;
592
+ declare const ANGLE_LABELS: Record<string, string>;
593
+ declare const ASPECT_RATIO_LABELS: Record<string, string>;
594
+ declare const MOVEMENT_LABELS: Record<string, string>;
595
+ declare function truncateText(text: string, maxLen: number): string;
596
+ /**
597
+ * Build a rich image-generation prompt from scene node data + character
598
+ * definitions. Used by both the frontend DAG executor and the backend
599
+ * orchestrator so that scene prompts are identical regardless of
600
+ * execution path.
601
+ */
602
+ declare function buildScenePrompt(data: SceneData, assets: readonly CharacterDef[], options?: {
603
+ forDisplay?: boolean;
604
+ }): string;
605
+
606
+ /**
607
+ * Path-1 structured prompt fields → composed prompt fragment.
608
+ *
609
+ * Used by:
610
+ * - Nodaro's MCP server (Phase 6 v1.1) — generate_image / generate_video verbs
611
+ * accept these structured fields and run them through this helper before
612
+ * passing the composite prompt to the underlying route.
613
+ * - (Optional) Frontend editor — same logic so the editor and MCP produce
614
+ * identical prompts for the same inputs.
615
+ *
616
+ * NOTE: this is a parallel utility to `prompt-builder.ts`. The latter does
617
+ * image-specific composition (character/template/reference handling), while
618
+ * this module handles the Path-1 structured-field shape that MCP verbs accept
619
+ * (free-form strings under person/styling/setting/camera/lens/mood). Existing
620
+ * frontend `buildPersonHints` / `buildStylingHints` helpers operate on catalog
621
+ * IDs and are not interchangeable with this renderer.
622
+ */
623
+ interface StructuredPromptFields {
624
+ person?: {
625
+ age?: number;
626
+ gender?: "man" | "woman" | "child" | "non-binary";
627
+ hair?: string;
628
+ eyes?: string;
629
+ expression?: string;
630
+ profession?: string;
631
+ warriorType?: string;
632
+ };
633
+ styling?: {
634
+ mood?: string;
635
+ lighting?: string;
636
+ aesthetic?: string;
637
+ colorLook?: string;
638
+ };
639
+ setting?: {
640
+ era?: string;
641
+ atmosphere?: string;
642
+ backdrop?: string;
643
+ };
644
+ camera?: {
645
+ framing?: string;
646
+ motion?: string;
647
+ format?: string;
648
+ };
649
+ lens?: {
650
+ focalLength?: string;
651
+ aperture?: string;
652
+ };
653
+ /** Standalone shorthand mood (overrides styling.mood if both are set). */
654
+ mood?: string;
655
+ }
656
+ /**
657
+ * Render structured fields → composite prompt fragment to be appended to the
658
+ * user's free-text prompt. Returns "" if no fields populated.
659
+ */
660
+ declare function renderStructuredFields(fields: StructuredPromptFields): string;
661
+
662
+ /**
663
+ * Shared video-reference resolver CORE — the ONE pure implementation of the
664
+ * video-prompt `@-mention` + canonical-fallback + extras assembly that BOTH the
665
+ * frontend (`frontend/src/lib/video-prompt-assembly.ts`) and backend
666
+ * (`backend/src/services/workflow-engine/payload-builder.ts`) resolvers delegate
667
+ * to.
668
+ *
669
+ * Historically the FE and BE each hand-rolled a byte-for-byte copy of this logic
670
+ * (they had to stay in lock-step or single-node FE runs and orchestrator runs
671
+ * would diverge). This module is the lift-and-shift of the FRONTEND resolver's
672
+ * post-expansion body into one place so there is a single source of truth.
673
+ *
674
+ * Purity contract: NO FE/BE-only dependencies. The caller is responsible for the
675
+ * layer-specific work BEFORE calling in:
676
+ * - expanding wired Character upstreams into `ConnectedReference[]`
677
+ * (`wiredCharRefs`), and
678
+ * - looking up an extra-ref's character metadata by slug
679
+ * (`lookupCharacterBySlug` — FE: `nodes.find(...)`, BE: `buildCtx`).
680
+ *
681
+ * Behavior-preserving when first extracted (the FE resolver's post-expansion
682
+ * body was lifted verbatim). The ONE intended output change since is the
683
+ * reference-binding surface string: the per-image subject phrasing, the bullet
684
+ * ordinals, and the frame directive now emit `@image_N` / `@video_N` /
685
+ * `@audio_N` (the legacy form was `Image N`) — all routed through the single
686
+ * `REF_BINDING` swap-point below. The structural strings ("Use these
687
+ * characters:", the bullet layout, "… is the same subject as …") are otherwise
688
+ * unchanged.
689
+ */
690
+
691
+ /**
692
+ * The SINGLE swap-point for the reference-binding surface-string (design D1/D7).
693
+ *
694
+ * Every place that renders an `@image_N`-style binding into a video prompt — the
695
+ * per-image subject phrasing, the bare ordinal in a "Use these characters" /
696
+ * pair-back bullet, and the opening/closing frame directive — MUST go through
697
+ * these five arrows. The default form is `@image_N`; if the D7 probe shows a
698
+ * provider prefers the legacy `Image N` form, flipping is editing ONLY these five
699
+ * arrows (`@image_${n}` → `Image ${n}`), nothing downstream.
700
+ *
701
+ * This IS the live swap-point: `resolveVideoReferenceCore` routes the per-image
702
+ * subject phrasing, the "Use these characters" / pair-back bullet ordinals, and
703
+ * the frame directive through these arrows, and `resolveReferenceTokens` resolves
704
+ * the body `{image:N}` tokens through `REF_BINDING[kind]` — so the five arrows
705
+ * are the ONLY emission sites for the binding surface string.
706
+ */
707
+ declare const REF_BINDING: {
708
+ readonly image: (label: string, n: number) => string;
709
+ readonly video: (label: string, n: number) => string;
710
+ readonly audio: (label: string, n: number) => string;
711
+ /** ordinal as it appears in a "Use these characters" bullet / pair-back */
712
+ readonly ordinal: (n: number) => string;
713
+ readonly frame: (n: number, role: "opening" | "closing") => string;
714
+ };
715
+ /**
716
+ * Positional reference counts the editor tokens are resolved against — how many
717
+ * image / video / audio references are wired into the node, in worker-payload
718
+ * order. `{image:N:…}` is 1-based against `image`, `{video:N:…}` against `video`,
719
+ * etc. A token whose N exceeds its count (or whose kind has count 0) is dropped.
720
+ */
721
+ interface ReferenceCounts {
722
+ image: number;
723
+ video: number;
724
+ audio: number;
725
+ }
726
+ /**
727
+ * Rewrite the editor's `{image:N:label}` / `{video:N:label}` / `{audio:N:label}`
728
+ * reference tokens into `@image_N` / `@video_N` / `@audio_N` subject bindings.
729
+ *
730
+ * The token's `N` is POSITIONAL (1-based) against the matching `counts` entry —
731
+ * the worker-payload order of wired references of that kind. Per match:
732
+ * - `N < 1` or `N > counts[kind]` (out of range / no such reference) → drop to
733
+ * the bare `label` (or empty if label-less). This is the legacy
734
+ * `stripVideoImageTokens` strip behavior: drop the token, keep the label text.
735
+ * - in range, label present → `REF_BINDING[kind](label, N)`
736
+ * (e.g. `the person from @image_2`).
737
+ * - in range, no label → `the subject in @${kind}_${N}` so the binding still
738
+ * lands even when the author didn't name the subject.
739
+ *
740
+ * Runs of 2+ HORIZONTAL whitespace (left behind by a dropped label-less token)
741
+ * collapse to one space, the result is trimmed, and an empty result becomes
742
+ * `undefined` — matching the `stripVideoImageTokens` contract so this can replace
743
+ * it cleanly. The collapse class is `[^\S\r\n]` (NOT `\s`) on purpose: Task 2.4
744
+ * applies this to the FULLY-ASSEMBLED core prompt, which carries `\n\n` block
745
+ * separators between the "Use these characters:" directive block and the body —
746
+ * a `\s{2,}` collapse would silently merge those paragraphs. Horizontal-only
747
+ * collapse preserves newline structure while still tidying the dropped-token gap.
748
+ * The `kind` is lowercased before indexing `counts`/`REF_BINDING`, so a
749
+ * case-variant token (`{Image:1}`) resolves to the same binding rather than
750
+ * mis-classifying as out-of-range.
751
+ */
752
+ declare function resolveReferenceTokens(prompt: string | undefined, counts: ReferenceCounts): string | undefined;
753
+ /**
754
+ * A user-attached "extra reference image" row. Layer-agnostic shape of the
755
+ * frontend `ExtraRef` / backend extras: only the fields this core reads.
756
+ */
757
+ interface VideoExtraRef {
758
+ url: string;
759
+ description?: string;
760
+ characterSlug?: string;
761
+ variantSlug?: string;
762
+ usageMode?: UsageMode;
763
+ /**
764
+ * Wired scene-composition fragment (held-prop / styling / text) for this
765
+ * extra — the `ConnectedReference.elementInjection` analogue. Surfaced ONLY
766
+ * in hybrid mode on a FIRST-SIGHT character extra, as its own trailing scene
767
+ * directive (mirrors the canonical/mention hybrid paths). Absent → unchanged.
768
+ */
769
+ elementInjection?: string | null;
770
+ /**
771
+ * Optional, opt-in per-extra identity-lock (the `ConnectedReference.identityLock`
772
+ * analogue). Emitted ONLY in hybrid mode on a first-sight character extra, via
773
+ * `buildIdentityLockLine`. Default OFF (absent / `enabled === false`) → no lock.
774
+ * When absent, the first-sight branch falls back to the node's mapped lock
775
+ * from `CharacterMeta.identityLock`.
776
+ */
777
+ identityLock?: {
778
+ enabled: boolean;
779
+ text?: string;
780
+ };
781
+ /**
782
+ * The `ConnectedReference.defaultRole` analogue for ROUTE-supplied extras
783
+ * (generate-video / text-to-video / MCP verbs), whose adapter can only feed
784
+ * the COALESCED `defaultUsageMode` as `usageMode` — which would otherwise
785
+ * trip the meta-suppression gate and permanently ignore the node default.
786
+ * Preferred over `CharacterMeta.defaultRole` at the first-sight role site.
787
+ * The expander (`expandExtraRefsToConnectedReferences`) already suppresses
788
+ * the source field when a true per-ref override existed, so passing it
789
+ * through verbatim preserves the override-wins precedence. Canvas /
790
+ * orchestrator extras leave this unset (they resolve via `CharacterMeta`).
791
+ */
792
+ defaultRole?: string;
793
+ }
794
+ /**
795
+ * Character metadata resolved by the caller for an extra-ref's `characterSlug`.
796
+ * Mirrors the per-layer upstream lookup: FE reads `CharacterNodeData`
797
+ * (`characterName` / `defaultUsageMode` / `canonicalDescription`); BE reads its
798
+ * `buildExtraRefCharacterContextLookup` context (`displayName` →
799
+ * `characterName`, etc.).
800
+ */
801
+ interface CharacterMeta {
802
+ characterName?: string;
803
+ defaultUsageMode?: UsageMode;
804
+ canonicalDescription?: string;
805
+ /** Character node's hybrid `defaultRole` — takes precedence over
806
+ * `defaultUsageMode` at the video extras first-sight role site (via
807
+ * `resolveDefaultRole`). Absent when the node never set a role. */
808
+ defaultRole?: string;
809
+ /** Character node's `identityLock`, already mapped to the per-reference lock
810
+ * shape (`characterLockToRefLock`). Read at the video extras first-sight lock
811
+ * site; a per-extra `identityLock` still wins over it. */
812
+ identityLock?: {
813
+ enabled: boolean;
814
+ text?: string;
815
+ };
816
+ }
817
+ interface ResolveVideoReferenceCoreArgs {
818
+ prompt: string | undefined;
819
+ /** Already expanded by the caller's layer-specific expander. */
820
+ wiredCharRefs: ConnectedReference[];
821
+ extraRefs?: readonly VideoExtraRef[];
822
+ /** Look up an extra-ref's character metadata by slug (FE: nodes.find; BE: buildCtx). */
823
+ lookupCharacterBySlug?: (slug: string) => CharacterMeta | undefined;
824
+ referenceOrder?: readonly string[];
825
+ suppressedCanonicalCharacterIds?: readonly string[];
826
+ /**
827
+ * Positional counts the editor numbers `{image:N}` / `{video:N}` / `{audio:N}`
828
+ * body tokens against — the TOTAL reference-handle count of each kind wired
829
+ * into the node (base reference images + mention additions), in worker-payload
830
+ * order. Supplied by the callers in Tasks 3.2/4.1; when omitted, `image` falls
831
+ * back to the core's own merged-URL count and `video`/`audio` to 0 (the core
832
+ * only attaches image URLs).
833
+ */
834
+ imageRefCount?: number;
835
+ videoRefCount?: number;
836
+ audioRefCount?: number;
837
+ /**
838
+ * Plain image-reference URLs that LEAD the unified `@image_N` numbering
839
+ * (D5: image-refs-first). They occupy `@image_1 … @image_offset`; every
840
+ * character/asset directive this core emits is numbered AFTER them, and they
841
+ * are prepended to the returned `additionalUrls` so the worker payload order
842
+ * matches the ordinals. When provided, they OWN the image token count (so
843
+ * `imageRefCount` is ignored for the image modality); omitted → legacy
844
+ * behaviour (`imageRefCount ?? mergedLen`, asset URLs numbered from 1).
845
+ * Already deduped/reordered by the caller (e.g. `connectedRefImageOrder`).
846
+ */
847
+ leadingRefUrls?: readonly string[];
848
+ /**
849
+ * Number of leading image-refs the CALLER owns + merges itself (so the core
850
+ * offsets asset directive ordinals + the `{image:N}` count by this much WITHOUT
851
+ * prepending any URLs to `additionalUrls`). Used by i2v, whose frame-promotion
852
+ * consumes the asset URLs directly and can't have leading refs spliced in.
853
+ * Ignored when `leadingRefUrls` is set. D5 unified-asset-references.
854
+ */
855
+ ordinalOffset?: number;
856
+ /**
857
+ * Render character / canonical-fallback / extra-ref directives in the hybrid
858
+ * role-phrase form (`the {role} from @image_N`) instead of the legacy
859
+ * `Use these characters:` block; default false = today's behavior, unchanged.
860
+ * Wired in Phase B Tasks 2-3.
861
+ */
862
+ hybridRoles?: boolean;
863
+ }
864
+ /**
865
+ * Resolve `@kira:N` / `@kira:N:smile` mentions in a video-node prompt against
866
+ * the caller-supplied wired Character references AND apply the per-character
867
+ * canonical fallback for unmentioned wired characters, plus manual/extra refs.
868
+ *
869
+ * Per-character behavior contract (parity with image-side + backend):
870
+ * - wired-character with at least one `@-mention` → contribute ONLY the
871
+ * mentioned variant URLs (no canonical auto-attach), prepend the
872
+ * mention-derived directive block.
873
+ * - wired-character with NO `@-mention` → contribute the canonical URL
874
+ * + a strong identity directive (mode-aware via `defaultUsageMode`).
875
+ *
876
+ * Returns the mutated prompt + the asset URLs to slot into the worker payload.
877
+ * The caller decides where (i2v has both `imageUrl` and `referenceImageUrls`;
878
+ * v2v has only a single `referenceImageUrl`; t2v has `referenceImageUrls` only).
879
+ */
880
+ declare function resolveVideoReferenceCore(args: ResolveVideoReferenceCoreArgs): {
881
+ prompt: string | undefined;
882
+ additionalUrls: string[];
883
+ };
884
+
885
+ /**
886
+ * Aggregator that walks a consumer node's `audio-style` target handle, collects
887
+ * incoming Sound parameter nodes, and composes a SoundComposition (text +
888
+ * optional structured fields + warnings) used to enrich the consumer's prompt
889
+ * fields. Parallel to how cinematography hints aggregate via
890
+ * `collectCinematographyHints` in front+back, but exposes structured-field
891
+ * outputs for typed targets like MiniMax (genre/mood/instrumental).
892
+ *
893
+ * Called from:
894
+ * - frontend: `frontend/src/lib/audio-style-hints.ts` (canvas executor)
895
+ * - backend: `backend/src/services/workflow-engine/payload-builder.ts`
896
+ */
897
+
898
+ type SoundConsumerType = "suno-generate" | "generate-music" | "voice-design" | "voice-remix" | "text-to-audio";
899
+ interface SoundCompositionFields {
900
+ readonly genre?: string;
901
+ readonly mood?: string;
902
+ readonly instrumental?: boolean;
903
+ readonly voiceDescription?: string;
904
+ /**
905
+ * Suno's binary vocal-gender control. Extracted from a connected
906
+ * voice-character node's `gender` field when it's "male" or "female"
907
+ * ("androgynous" is left to prompt-only since Suno doesn't accept it).
908
+ * Set on suno-generate and generate-music consumers.
909
+ */
910
+ readonly vocalGender?: "male" | "female";
911
+ }
912
+ interface SoundComposition {
913
+ readonly text: string;
914
+ readonly fields: SoundCompositionFields;
915
+ readonly warnings: ReadonlyArray<string>;
916
+ }
917
+ declare function composeSoundHintFromConnections(consumer: HintNodeLike, consumerType: SoundConsumerType, ctx: HintGraphContext): SoundComposition;
918
+ /**
919
+ * Append `composedText` to `userText` with ", " separator. Empty inputs
920
+ * are tolerated; the non-empty side is returned alone.
921
+ */
922
+ declare function appendField(userText: string, composedText: string): string;
923
+ /**
924
+ * Truncate `composedText` so the final string `userText + ", " + composedText`
925
+ * fits within `maxTotalLen`. Returns "" when the budget is non-positive (user
926
+ * text already at limit). Cuts on word boundary when possible.
927
+ */
928
+ declare function truncateForField(composedText: string, userText: string, maxTotalLen: number): string;
929
+ /**
930
+ * Suno Generate auto-detects custom mode when the user typed style/title/lyrics,
931
+ * even without explicitly toggling `customMode`. The frontend executor, backend
932
+ * payload-builder, and the FinalAudioPromptPreview all need to agree on the
933
+ * resolved value or the preview lies about which field receives the audio-style
934
+ * hint.
935
+ *
936
+ * Accepts an unknown-keyed record so callers in both the typed frontend
937
+ * (SunoGenerateData) and the loosely-typed backend (WorkflowNodeData with
938
+ * `[k: string]: unknown`) can hand the node `data` straight in without casts.
939
+ */
940
+ declare function getEffectiveSunoCustomMode(data: {
941
+ readonly [k: string]: unknown;
942
+ }): boolean;
943
+ /**
944
+ * Fold a Generate Music node's genre / mood / instrumental selections into the
945
+ * prompt text. The music worker only reads `prompt`, so this enrichment is the
946
+ * ONLY channel by which those three controls reach the provider.
947
+ *
948
+ * Shared by the single-node route (`/v1/generate-music`) and the workflow
949
+ * orchestrator (`payload-builder.ts` `generate-music`) so a workflow / app /
950
+ * webhook run produces the same prompt — and the same music — as a Run-button
951
+ * run. Mirrors the route's original inline `[prompt, genre, mood, …].join(", ")`
952
+ * exactly (locked by `routes/__tests__/generate-music.test.ts`).
953
+ */
954
+ declare function appendMusicMeta(basePrompt: string, meta: {
955
+ genre?: string;
956
+ mood?: string;
957
+ instrumental?: boolean;
958
+ }): string;
959
+
960
+ interface AssembleSunoInput {
961
+ /** The `suno-generate` node; `data` is ALREADY field-mapped by the caller. */
962
+ node: HintNodeLike;
963
+ /** `{ nodes, edges }` for the connected-picker audio-style fold. */
964
+ graph: HintGraphContext;
965
+ /**
966
+ * Caller-resolved user prompt (FE: `overridePrompt ?? inputs.prompt ??
967
+ * resolveTextRefs(data.prompt)`). Folded into `prompt` in non-custom mode.
968
+ */
969
+ userPrompt: string;
970
+ /**
971
+ * Caller-resolved lyrics (divergence C — refMap-resolved by the caller, NOT
972
+ * read from `data.lyrics` here).
973
+ */
974
+ lyrics?: string;
975
+ /** Persona fields (FE/BE `resolvePersona(...)`), spread onto the result. */
976
+ persona?: {
977
+ personaId?: string;
978
+ personaModel?: "voice_persona" | "style_persona";
979
+ };
980
+ /**
981
+ * Reject an empty prompt+hint with `throw` (divergence A). FE run passes
982
+ * `true`; the BE run + the preview leave it `false`.
983
+ */
984
+ throwOnEmpty?: boolean;
985
+ }
986
+ interface AssembleSunoResult {
987
+ prompt: string;
988
+ style?: string;
989
+ lyrics?: string;
990
+ title?: string;
991
+ negativeStyle?: string;
992
+ vocalGender?: string;
993
+ styleWeight?: number;
994
+ weirdnessConstraint?: number;
995
+ audioWeight?: number;
996
+ customMode: boolean;
997
+ instrumental: boolean;
998
+ model?: string;
999
+ personaId?: string;
1000
+ personaModel?: "voice_persona" | "style_persona";
1001
+ }
1002
+ /**
1003
+ * Assemble a `suno-generate` node's inputs into the flat field set the Suno
1004
+ * provider receives. Byte-faithful to the FE `execute-node.ts` inline block.
1005
+ */
1006
+ declare function assembleSunoInput(input: AssembleSunoInput): AssembleSunoResult;
1007
+
1008
+ /**
1009
+ * `assembleImageInput` — the single source of truth for turning a node's
1010
+ * image-generation inputs (a prompt + cinematic direction + connected
1011
+ * references + the per-provider levers) into the flat `{ prompt,
1012
+ * nativeNegativePrompt, referenceImageUrls }` the `generate-image` route
1013
+ * expects.
1014
+ *
1015
+ * WHY THIS EXISTS (WI-1a): the same three-step assembly —
1016
+ * 1. compose the prompt text (fold cinematic id-hints + structured fields),
1017
+ * 2. call `buildImagePrompt(...)` (the pure core; the per-provider reference
1018
+ * gate lives INSIDE it),
1019
+ * 3. (optionally) reject a truly-empty FINAL prompt,
1020
+ * — was duplicated in THREE places kept in lockstep by hand: the frontend
1021
+ * `execute-node.ts` `generate-image` branch, the backend
1022
+ * `payload-builder.ts` `generate-image` case, and Studio's `assembly.ts`.
1023
+ * This wrapper collapses them into one.
1024
+ *
1025
+ * THE NO-OP CONTRACT (load-bearing — the platform-caller parity relies on it):
1026
+ * the two platform callers (`execute-node` / `payload-builder`) compose their
1027
+ * prompt from the canvas graph themselves and pass NO cinematic `direction`
1028
+ * ids and NO `structured` fields. In that case `composePromptText` MUST return
1029
+ * the caller's `userPrompt` byte-for-byte unchanged, so the wrapper degenerates
1030
+ * to exactly the `buildImagePrompt(...)` call those sites make today. Studio
1031
+ * (and the MCP route) supply `direction` / `structured` and get the id-hint
1032
+ * composition on top.
1033
+ *
1034
+ * THE EMPTY-CHECK FLAG (also load-bearing for parity): `execute-node` rejects a
1035
+ * truly-empty assembled prompt (its "type one, mention a character, or connect
1036
+ * a cinematography source" guard); `payload-builder` does NOT (it never threw
1037
+ * there). So the post-assembly throw is OPT-IN via `throwOnEmpty` — defaulting
1038
+ * to `false` preserves the backend's no-throw behavior. Callers that want the
1039
+ * guard (frontend, Studio, route) pass `throwOnEmpty: true`.
1040
+ */
1041
+
1042
+ /**
1043
+ * Flat cinematic-direction ids the Studio framing UI (and the MCP route)
1044
+ * expose — all optional. Promoted here from Studio's `assembly.ts` so the
1045
+ * id → hint composition lives in one place. The platform callers pass none of
1046
+ * these (they fold their hints from the graph into `userPrompt` themselves).
1047
+ */
1048
+ interface DirectionFields {
1049
+ /** Shot Type — the FRAMINGS shot-size/coverage/composition/vantage dimensions. */
1050
+ framingId?: string;
1051
+ /** Angle — the FRAMINGS angle dimension (separate pill, so it can coexist with Shot Type). */
1052
+ framingAngleId?: string;
1053
+ lightingId?: string;
1054
+ lensId?: string;
1055
+ cameraFormatId?: string;
1056
+ }
1057
+ /**
1058
+ * Input to `assembleImageInput`. A faithful SUPERSET of what the two platform
1059
+ * callers pass to `buildImagePrompt` today (so they can route through this
1060
+ * wrapper with byte-identical output), plus the id-based `direction` /
1061
+ * `structured` composition levers that Studio + the MCP route use.
1062
+ */
1063
+ interface AssembleImageInput {
1064
+ /** Pre-composed (caller's graph) or raw user prompt text. */
1065
+ userPrompt: string;
1066
+ /** Image model id / provider key (the catalog enum value, e.g. "flux-2-max"). */
1067
+ provider: string;
1068
+ /**
1069
+ * Connected references with URLs ALREADY resolved by the caller. Become
1070
+ * `referenceImageUrls` + identity directives inside `buildImagePrompt`
1071
+ * (gated per provider there). Omit when the caller wires only raw URLs.
1072
+ */
1073
+ connectedReferences?: ConnectedReference[];
1074
+ /**
1075
+ * Flat cinematic-direction ids → folded into the prompt as hints. Studio /
1076
+ * MCP-route use; the platform callers pass none (so `composePromptText` is a
1077
+ * no-op for them and the result is byte-identical to today).
1078
+ */
1079
+ direction?: DirectionFields;
1080
+ /** Path-1 structured fields → composed fragment appended to the prompt. */
1081
+ structured?: StructuredPromptFields;
1082
+ /**
1083
+ * Reference image URLs from direct connections / manual uploads — ride
1084
+ * `buildImagePrompt`'s reference-URL channel so they pass through the SAME
1085
+ * per-provider reference-image gate + ordering as `connectedReferences`.
1086
+ * (This is `buildImagePrompt`'s `referenceImageUrls` config field, named
1087
+ * `extra…` here to reflect that bound entities already carry their URLs.)
1088
+ */
1089
+ extraReferenceImageUrls?: string[];
1090
+ /** Negative prompt text (routed to native vs. "Avoid:" by `buildImagePrompt`). */
1091
+ negativePrompt?: string;
1092
+ /** Style text to append (e.g. "cinematic"). */
1093
+ style?: string;
1094
+ /** User-defined reorder of the injected reference list (stable tile ids). */
1095
+ referenceOrder?: readonly string[];
1096
+ /** Per-identity (imageIndex+label) user overrides for fidelity / custom text. */
1097
+ identityMeta?: readonly IdentityMeta[];
1098
+ /** Character slugs whose canonical-fallback the user explicitly hid. */
1099
+ suppressedCanonicalCharacterIds?: readonly string[];
1100
+ /** Location slugs whose canonical-fallback the user explicitly hid. */
1101
+ suppressedCanonicalLocationIds?: readonly string[];
1102
+ /**
1103
+ * Reference-prompt assembly format for the `{image:N:label}` path. Forwarded
1104
+ * verbatim to `buildImagePrompt` (default legacy). "hybrid" = images-only
1105
+ * reference-lock snippet + lettered inline scene.
1106
+ */
1107
+ referenceFormat?: "legacy" | "hybrid";
1108
+ /** Override the hybrid reference-lock snippet (forwarded to buildImagePrompt). */
1109
+ referenceLockSnippet?: string;
1110
+ /** Character definitions selected for this node (legacy `buildImagePrompt` path). */
1111
+ characterDefs?: CharacterDef[];
1112
+ /** User-level prompt template overrides. */
1113
+ userTemplates?: Record<string, string>;
1114
+ /** Flow-level prompt template overrides. */
1115
+ flowTemplates?: Record<string, string>;
1116
+ /** Ancestor reference image URLs (fallback when no direct refs exist). */
1117
+ ancestorRefs?: string[];
1118
+ /** Map of `connectedReferences[i].id → sourceNodeId` for wired-raw tile ids. */
1119
+ sourceNodeIdById?: ReadonlyMap<string, string>;
1120
+ /**
1121
+ * LoRA inference path: strip `@`-mention tokens + skip the connected-reference
1122
+ * machinery (the trigger word + LoRA carry identity).
1123
+ */
1124
+ skipCharacterMentions?: boolean;
1125
+ /**
1126
+ * Reject a truly-empty FINAL (post-assembly) prompt with `throw`. OFF by
1127
+ * default to match the backend `payload-builder`, which never threw. The
1128
+ * frontend / Studio / route pass `true` to keep their "type one, bind a
1129
+ * character, or pick a cinematography direction" guard. Checked POST-assembly
1130
+ * so a bound entity / `@`-mention / direction chip that filled an otherwise-
1131
+ * empty prompt still runs.
1132
+ */
1133
+ throwOnEmpty?: boolean;
1134
+ }
1135
+ /**
1136
+ * Assemble a node's image-generation inputs into a `BuildImagePromptResult`
1137
+ * (`{ prompt, nativeNegativePrompt, referenceImageUrls }`).
1138
+ *
1139
+ * Order: (1) compose the prompt text (no-op when no direction/structured),
1140
+ * (2) `buildImagePrompt(...)` — exactly the call the three sites make today,
1141
+ * (3) optional post-assembly empty-prompt throw (gated by `throwOnEmpty`).
1142
+ */
1143
+ declare function assembleImageInput(input: AssembleImageInput): BuildImagePromptResult;
1144
+
1145
+ type Seedance2Mode = "first-frame" | "first-last-frame" | "reference";
1146
+ interface Seedance2InputsArgs {
1147
+ firstFrameUrl?: string;
1148
+ lastFrameUrl?: string;
1149
+ refImageUrls?: readonly string[];
1150
+ refVideoUrls?: readonly string[];
1151
+ refAudioUrls?: readonly string[];
1152
+ }
1153
+ interface Seedance2InputsResult {
1154
+ mode: Seedance2Mode;
1155
+ firstFrameUrl?: string;
1156
+ lastFrameUrl?: string;
1157
+ referenceImageUrls: string[];
1158
+ referenceVideoUrls: string[];
1159
+ referenceAudioUrls: string[];
1160
+ promptSuffix: string;
1161
+ droppedRefImages: number;
1162
+ }
1163
+ /**
1164
+ * Single source of truth for how Seedance 2's three mutually-exclusive KIE input
1165
+ * modes are selected from connected inputs. Strict first/last-frame mode is used
1166
+ * only when nothing but frames is connected; any reference (image, video, OR
1167
+ * audio) switches to multimodal Reference mode, where the frames are appended to
1168
+ * reference_image_urls (after the user's own images, so their @Image ordinals do
1169
+ * not shift) and named in a doctrine-compliant prompt suffix.
1170
+ */
1171
+ declare function resolveSeedance2Inputs(args: Seedance2InputsArgs): Seedance2InputsResult;
1172
+
1173
+ /**
1174
+ * Canonical catalog of Person / subject-appearance choices.
1175
+ *
1176
+ * Multi-dimension parameter node. Unlike Setting / Style / Camera-Motion
1177
+ * (single pick) or Framing (5 dims, all shot composition), Person describes
1178
+ * *who the subject is*. Each dimension is mutually exclusive within itself
1179
+ * (pick one Type, one Age, one Cheekbones, etc.) and all are independently
1180
+ * optional. Dimensions are grouped into six sections (PERSON_DIMENSION_SECTIONS):
1181
+ * Identity, Body, Face, Hair, Skin & Eyes, Features.
1182
+ *
1183
+ * The Face section carries a dedicated facial-geometry layer — cheekbones,
1184
+ * facial fullness, eyelid type, canthal tilt, eye spacing, eye-to-brow set,
1185
+ * nose tip, and split lip fullness / lip shape — so the structured pickers
1186
+ * (not a single "supermodel" Type token) drive the feature geometry and ratios
1187
+ * that actually define a face's look. Neutral options (Average / Neutral /
1188
+ * Standard / Natural) carry an empty promptHint, so enabling a dimension
1189
+ * injects nothing until a real value is picked.
1190
+ *
1191
+ * Non-empty selections from each dimension are joined as a compound hint and
1192
+ * injected as cinematography context into downstream image/video prompts:
1193
+ * "a beautiful woman, in her 30s, East Asian, slim build, long wavy hair,
1194
+ * brown hair, fair skin, green eyes"
1195
+ *
1196
+ * Applies to BOTH image and video consumers (a person description is not
1197
+ * video-specific, unlike camera-motion / temporal). Not in
1198
+ * STILL_IMAGE_EXCLUDE_TYPES.
1199
+ *
1200
+ * Shared between the picker UI, the standalone Person parameter node, and
1201
+ * the prompt-hint injection on both the frontend DAG executor and the
1202
+ * backend orchestrator.
1203
+ */
1204
+ type PersonDimension = "type" | "age" | "ethnicity" | "regional-aesthetic" | "frame" | "body-mass" | "bust" | "waist" | "hips" | "silhouette" | "face-shape" | "jawline" | "cheekbones" | "facial-fullness" | "eye-shape" | "eyelid-type" | "canthal-tilt" | "eye-spacing" | "eye-set-brow" | "nose" | "nose-tip" | "lip-fullness" | "lip-shape" | "lip-state" | "hair-color" | "hair-base" | "eyebrows" | "skin-tone" | "skin-texture" | "eye-color" | "eye-state" | "facial-hair" | "distinctive-features";
1205
+ interface Person {
1206
+ readonly id: string;
1207
+ readonly label: string;
1208
+ readonly dimension: PersonDimension;
1209
+ readonly description: string;
1210
+ readonly promptHint: string;
1211
+ /** Optional sub-grouping within a dimension. Used by the picker to render
1212
+ * two-level selection (e.g. ethnicity grouped by region → specific). */
1213
+ readonly group?: string;
1214
+ /** Optional shorter label for the picker chip. When a dimension renders
1215
+ * with group headers (e.g. ethnicity), the group name already supplies
1216
+ * context — so a chip under the "Asian" header shows "East (any)"
1217
+ * instead of the redundant "East Asian (any)". Node cards + tooltips
1218
+ * keep the full `label` / `description`. */
1219
+ readonly shortLabel?: string;
1220
+ }
1221
+ declare const PEOPLE: ReadonlyArray<Person>;
1222
+ declare const PERSON_DIMENSION_ORDER: ReadonlyArray<PersonDimension>;
1223
+ declare const PERSON_DIMENSION_LABELS: Readonly<Record<PersonDimension, string>>;
1224
+ /**
1225
+ * Cross-dimension grouping for the compact Person picker view. The detailed
1226
+ * view renders one row per dimension (PERSON_DIMENSION_ORDER); the compact
1227
+ * view collapses those rows into these six labelled sections. This is the
1228
+ * machine-readable form of the section comments in PERSON_DIMENSION_ORDER —
1229
+ * the guard test (person-sections.test.ts) asserts it partitions every
1230
+ * PersonDimension exactly once, so a newly added dimension can't silently
1231
+ * drop out of the compact grouping.
1232
+ */
1233
+ interface PersonDimensionSection {
1234
+ readonly label: string;
1235
+ readonly dimensions: ReadonlyArray<PersonDimension>;
1236
+ }
1237
+ declare const PERSON_DIMENSION_SECTIONS: ReadonlyArray<PersonDimensionSection>;
1238
+ /**
1239
+ * Maps each PersonDimension to the consumer data field name holding the
1240
+ * selected entry id. Multi-dimension model: a consumer (PersonData) may
1241
+ * independently set a value in each of the dimensions.
1242
+ */
1243
+ declare const PERSON_FIELD_BY_DIMENSION: Record<PersonDimension, "type" | "age" | "ethnicity" | "regionalAesthetic" | "frame" | "bodyMass" | "bust" | "waist" | "hips" | "silhouette" | "faceShape" | "jawline" | "cheekbones" | "facialFullness" | "eyeShape" | "eyelidType" | "canthalTilt" | "eyeSpacing" | "eyeSetBrow" | "nose" | "noseTip" | "lipFullness" | "lipShape" | "lipState" | "hairColor" | "hairBase" | "eyebrows" | "skinTone" | "skinTexture" | "eyeColor" | "eyeState" | "facialHair" | "distinctiveFeature">;
1244
+ /** Per-dimension multi-select cap (single source of truth for the picker UI,
1245
+ * the image-analyzer tool schema, and the Zod validator).
1246
+ * - ethnicity / regional-aesthetic / hair-color / eye-color / lip-state /
1247
+ * eye-state / skin-texture: 2
1248
+ * - distinctive-features: 3
1249
+ * All other dims are single-select (absent → treated as 1). */
1250
+ declare const MAX_SELECTED_BY_DIMENSION: Partial<Record<PersonDimension, number>>;
1251
+ /** Selection limit for a dimension (1 when not multi-select). */
1252
+ declare function getPersonDimensionLimit(dimension: PersonDimension): number;
1253
+ /**
1254
+ * Shape of the per-dimension person fields. All optional — user may set
1255
+ * zero, one, or all ten dimensions.
1256
+ */
1257
+ interface PersonValue {
1258
+ type?: string;
1259
+ /** Selected age preset id (e.g. `"age-30s"`). When set to the special
1260
+ * `"age-custom"` sentinel, the literal age in years is read from
1261
+ * `customAge` and the hint is generated at build time. */
1262
+ age?: string;
1263
+ /** Specific age in years. Only consulted when `age === "age-custom"`. */
1264
+ customAge?: number;
1265
+ /** Single id, or an array of up to 2 ids for mixed heritage (e.g.
1266
+ * ["slavic","mediterranean"] → "of mixed Slavic and Mediterranean heritage"). */
1267
+ ethnicity?: string | ReadonlyArray<string>;
1268
+ /** Regional / cultural aesthetic vibe (e.g. `"cali-beach"`, `"parisienne"`,
1269
+ * `"kinshasa-sape"`). Composes with ethnicity, skin tone, hair, and
1270
+ * styling — the dimension's promptHints are vibe-only and never hard-code
1271
+ * the visuals those other dimensions own. Single id or up to 2 ids for
1272
+ * hybrid looks (e.g. ["nyc-fashion","parisienne"]). */
1273
+ regionalAesthetic?: string | ReadonlyArray<string>;
1274
+ /** Skeletal frame width / height (petite, slim, average, broad). Independent
1275
+ * of body mass — "slim frame + full bust" is expressible. */
1276
+ frame?: string;
1277
+ /** Body mass / leanness (lean, average, full, heavy). Independent of frame. */
1278
+ bodyMass?: string;
1279
+ /** Bust size (small, average, full, very full) — applicable subjects. */
1280
+ bust?: string;
1281
+ /** Waist definition (defined, average, straight). */
1282
+ waist?: string;
1283
+ /** Hip width (narrow, balanced, wide). */
1284
+ hips?: string;
1285
+ /** Overall body silhouette (hourglass, rectangular, pear, inverted-triangle,
1286
+ * athletic). Optional — only emits when picked. */
1287
+ silhouette?: string;
1288
+ /** Face silhouette (oval, round, square, heart…). */
1289
+ faceShape?: string;
1290
+ /** Jaw shape (strong, soft, pointed, wide). */
1291
+ jawline?: string;
1292
+ /** Cheekbone projection / height (low, average, high-defined, sculpted-high, wide). */
1293
+ cheekbones?: string;
1294
+ /** Face-specific leanness, independent of body mass (gaunt, lean, average, full, round). */
1295
+ facialFullness?: string;
1296
+ /** Eye shape — anatomical shape only (almond, round, monolid, double-eyelid,
1297
+ * wide, narrow). Lid type, canthal tilt, spacing and brow-set are separate. */
1298
+ eyeShape?: string;
1299
+ /** Upper-eyelid trait (standard, hooded, droopy, deep-set). */
1300
+ eyelidType?: string;
1301
+ /** Canthal tilt — outer-corner angle (neutral, upturned, downturned). */
1302
+ canthalTilt?: string;
1303
+ /** Horizontal eye spacing (close-set, average, wide-set). */
1304
+ eyeSpacing?: string;
1305
+ /** Brow-to-eye distance / eye set (low-set "hunter", average, high-set "doe"). */
1306
+ eyeSetBrow?: string;
1307
+ /** Nose bridge shape (straight, aquiline, snub, broad…). */
1308
+ nose?: string;
1309
+ /** Nose tip rotation / shape (natural, refined, upturned, rounded, drooping). */
1310
+ noseTip?: string;
1311
+ /** Lip fullness (thin, medium, full, full-lower). Replaces the legacy
1312
+ * combined `lips` field together with `lipShape`. */
1313
+ lipFullness?: string;
1314
+ /** Lip shape (natural, cupid's bow, wide, heart, small). Replaces the legacy
1315
+ * combined `lips` field together with `lipFullness`. */
1316
+ lipShape?: string;
1317
+ /** @deprecated Split into `lipFullness` + `lipShape`. Retained so legacy
1318
+ * workflow data keeps resolving — `buildPersonHints` reads it as a fallback
1319
+ * and `migratePersonValue` relocates it onto the new fields. */
1320
+ lips?: string;
1321
+ /** Lip state — what the lips are doing right now (chapped, glossy,
1322
+ * parted, biting, pursed, bold-red…). Distinct from `lips` which is
1323
+ * anatomical shape. Single id or up to 2 (e.g. glossy + parted). */
1324
+ lipState?: string | ReadonlyArray<string>;
1325
+ /** Single id or up to 2 ids for two-tone / ombre / highlighted hair
1326
+ * (e.g. ["hair-black","hair-platinum"]). */
1327
+ hairColor?: string | ReadonlyArray<string>;
1328
+ /** Natural hair texture + length (texture×length combos). The actual cut
1329
+ * / styling choice (bob, wolf cut, braids…) lives in Styling.hair-cut. */
1330
+ hairBase?: string;
1331
+ eyebrows?: string;
1332
+ skinTone?: string;
1333
+ /** Skin texture (smooth, porcelain, freckled, …). Single id or up to 2
1334
+ * combined (e.g. porcelain + freckled, sun-kissed + dewy). */
1335
+ skinTexture?: string | ReadonlyArray<string>;
1336
+ /** Single id or up to 2 ids for heterochromia (e.g.
1337
+ * ["eyes-blue","eyes-green"]). */
1338
+ eyeColor?: string | ReadonlyArray<string>;
1339
+ /** Eye state — what the eyes are doing (closed, half-lidded, wide-eyed,
1340
+ * staring at camera, gazing away/up/down, glassy). Distinct from
1341
+ * `eyeShape` (anatomy) and `eyeColor`. Single id or up to 2 (e.g.
1342
+ * half-lidded + glassy). */
1343
+ eyeState?: string | ReadonlyArray<string>;
1344
+ facialHair?: string;
1345
+ /** Single id or up to 3 ids for combined features (e.g. freckles +
1346
+ * glasses + sleeve tattoo). */
1347
+ distinctiveFeature?: string | ReadonlyArray<string>;
1348
+ /** Free-text appended BEFORE the dimension compound. Use when you want
1349
+ * context/framing to come first (e.g. "wet-haired" or "covered in paint"). */
1350
+ preText?: string;
1351
+ /** Free-text appended AFTER the dimension compound. Use for extra
1352
+ * specifics that dimensions can't capture (e.g. "wearing a leather
1353
+ * jacket", "with a silver necklace"). */
1354
+ postText?: string;
1355
+ }
1356
+ declare function getPerson(id: string | undefined | null): Person | undefined;
1357
+ declare function getPersonLabel(id: string | undefined | null, fallback?: string): string;
1358
+ declare function getPersonPromptHint(id: string | undefined | null): string;
1359
+ declare const PERSON_IDS: ReadonlyArray<string>;
1360
+ /**
1361
+ * Age hint with optional custom-numeric override. When the user picks the
1362
+ * "age-custom" sentinel and provides a specific number, generate a phrase
1363
+ * tuned to the life stage (toddler / child / teen wording for the lower
1364
+ * ranges, plain "{N} years old" for adults). Otherwise return the catalog
1365
+ * entry's static promptHint.
1366
+ *
1367
+ * Custom number is clamped to a sane range and rejected if non-finite.
1368
+ */
1369
+ declare function buildAgeHint(ageId: string | undefined | null, customAge: number | undefined | null): string;
1370
+ declare function buildPersonHints(data: Record<string, unknown> & PersonValue): string[];
1371
+ /**
1372
+ * Relocate legacy single-field Person values onto the post-split fields so the
1373
+ * picker UI shows them in their new home:
1374
+ *
1375
+ * - `eyeShape` ∈ {hooded, droopy, deep-set} → `eyelidType`
1376
+ * - `eyeShape` ∈ {upturned, downturned} → `canthalTilt`
1377
+ * - `eyeShape` ∈ {wide-set, close-set} → `eyeSpacing`
1378
+ * - `lips` ∈ {thin, medium, full} → `lipFullness`
1379
+ * - `lips` ∈ {wide, cupids-bow, small} → `lipShape`
1380
+ *
1381
+ * PROMPT OUTPUT IS UNAFFECTED either way — `getPersonPromptHint` resolves the
1382
+ * ids regardless of dimension and `buildPersonHints` has a `lips` fallback;
1383
+ * this is UI hygiene + clean re-saves only. Immutable + idempotent: returns the
1384
+ * same reference when nothing moves, never overwrites an already-set target,
1385
+ * clears the legacy source once relocated, and preserves every other key (node
1386
+ * data carries non-Person fields too).
1387
+ */
1388
+ declare function migratePersonValue<T extends Record<string, unknown>>(data: T): T;
1389
+
1390
+ /**
1391
+ * Public, discoverable registry of the parameter-picker catalogs.
1392
+ *
1393
+ * This is the pure-data mirror of the frontend picker registry
1394
+ * (`frontend/src/lib/parameter-picker-registry.tsx`). It contains NO React —
1395
+ * just the catalog metadata + flattened options — so it can be consumed by
1396
+ * the backend, the public SDK, docs tooling, and the editor alike from one
1397
+ * source of truth.
1398
+ *
1399
+ * Two kinds of entry (mirroring the frontend):
1400
+ * - "single": one value field whose value is a string id chosen from a
1401
+ * catalog. `options` carries the full flattened catalog (id/label/
1402
+ * description/category/promptHint), so a consumer can render a picker or
1403
+ * resolve an id → prompt fragment without importing the heavy frontend
1404
+ * registry.
1405
+ * - "multi": several value fields (e.g. Framing.shotSize + .angle + …).
1406
+ * Structured / multi-dimensional. There is no single catalog to flatten,
1407
+ * so instead of top-level `options` each multi entry carries a
1408
+ * `dimensions` array — one self-describing entry per field
1409
+ * ({ field, label, options }) in `fields` order — so a consumer can render
1410
+ * a per-field picker or resolve any field's id → prompt fragment without
1411
+ * importing the heavy frontend registry.
1412
+ *
1413
+ * A drift-guard test (`frontend/src/lib/__tests__/picker-catalogs-sync.test.ts`)
1414
+ * asserts parity between this registry and the frontend one so the two cannot
1415
+ * silently diverge.
1416
+ *
1417
+ * NOTE on `promptHint` for the four Object-entity catalogs (animal / vehicle /
1418
+ * weapon / furniture): those catalog entries do NOT carry a `promptHint`
1419
+ * field — at runtime `getParameterPromptHint` synthesizes the fragment from
1420
+ * `label` + `description` ("featuring a golden retriever, …"). We reproduce the
1421
+ * exact same phrasing here so each option's `promptHint` is non-empty AND
1422
+ * matches what actually gets injected downstream.
1423
+ */
1424
+ interface PickerOption {
1425
+ readonly id: string;
1426
+ readonly label: string;
1427
+ readonly description?: string;
1428
+ /** The group id (matches `categoryOrder` / `categoryLabels`). */
1429
+ readonly category?: string;
1430
+ readonly promptHint: string;
1431
+ /** Only present if the source catalog entry already carries a data icon/emoji/thumbnail field. */
1432
+ readonly icon?: string;
1433
+ }
1434
+ /**
1435
+ * A self-describing dimension of a multi-dim picker: one value field plus the
1436
+ * full option list valid for that field. `dimensions[i].field` mirrors the
1437
+ * frontend picker's `fields[i]` exactly (same order), so a consumer can render
1438
+ * a per-field picker or resolve an id → prompt fragment for any dimension
1439
+ * without importing the heavy frontend registry.
1440
+ */
1441
+ interface PickerDimension {
1442
+ /** The node-data field this dimension writes to (e.g. "shotSize"). */
1443
+ readonly field: string;
1444
+ /** Human-readable label for the dimension (e.g. "Shot Size"). */
1445
+ readonly label: string;
1446
+ /** Flattened options valid for this field. */
1447
+ readonly options: readonly PickerOption[];
1448
+ }
1449
+ interface PickerCatalog {
1450
+ readonly nodeType: string;
1451
+ readonly label: string;
1452
+ /** The i18n catalog id (mirrors the frontend entry's `catalogId`). */
1453
+ readonly catalogId: string;
1454
+ readonly kind: "single" | "multi";
1455
+ /** single only — the node-data field the chosen id is written to. */
1456
+ readonly valueField?: string;
1457
+ /** single only — the catalog id selected by default. */
1458
+ readonly defaultValue?: string;
1459
+ readonly categoryOrder?: readonly string[];
1460
+ readonly categoryLabels?: Readonly<Record<string, string>>;
1461
+ /** single-dim: flattened catalog options. */
1462
+ readonly options?: readonly PickerOption[];
1463
+ /** multi-dim: the dimension keys (no single catalog to flatten). */
1464
+ readonly fields?: readonly string[];
1465
+ /** multi-dim: one self-describing entry per dimension field, in `fields` order. */
1466
+ readonly dimensions?: readonly PickerDimension[];
1467
+ }
1468
+ declare const PICKER_CATALOGS: readonly PickerCatalog[];
1469
+ /** Resolve a catalog by `nodeType` first, then by `catalogId`. */
1470
+ declare function getPickerCatalog(nodeTypeOrCatalogId: string): PickerCatalog | undefined;
1471
+ declare function listPickerCatalogs(): readonly PickerCatalog[];
1472
+ interface PickerCatalogSummary {
1473
+ readonly nodeType: string;
1474
+ readonly label: string;
1475
+ readonly catalogId: string;
1476
+ readonly kind: "single" | "multi";
1477
+ /** single only. */
1478
+ readonly valueField?: string;
1479
+ /** multi only. */
1480
+ readonly fields?: readonly string[];
1481
+ /** single: options.length; multi: sum of every dimension's options. */
1482
+ readonly optionCount: number;
1483
+ }
1484
+ /** Lightweight directory of every picker catalog — no option payloads. */
1485
+ declare function summarizePickerCatalogs(): readonly PickerCatalogSummary[];
1486
+ type PickerCatalogDetail = "compact" | "full";
1487
+ interface ProjectPickerCatalogOptions {
1488
+ /** Default "compact" (id/label/category/icon). "full" adds description + promptHint. */
1489
+ readonly detail?: PickerCatalogDetail;
1490
+ /** single-dim: keep only options in this category. */
1491
+ readonly category?: string;
1492
+ /** multi-dim: keep only this dimension field. */
1493
+ readonly field?: string;
1494
+ }
1495
+ /** An option after projection — description/promptHint present only when detail="full". */
1496
+ interface ProjectedPickerOption {
1497
+ readonly id: string;
1498
+ readonly label: string;
1499
+ readonly description?: string;
1500
+ readonly category?: string;
1501
+ readonly promptHint?: string;
1502
+ readonly icon?: string;
1503
+ }
1504
+ interface ProjectedPickerDimension {
1505
+ readonly field: string;
1506
+ readonly label: string;
1507
+ readonly options: readonly ProjectedPickerOption[];
1508
+ }
1509
+ interface ProjectedPickerCatalog {
1510
+ readonly nodeType: string;
1511
+ readonly label: string;
1512
+ readonly catalogId: string;
1513
+ readonly kind: "single" | "multi";
1514
+ readonly valueField?: string;
1515
+ readonly defaultValue?: string;
1516
+ readonly categoryOrder?: readonly string[];
1517
+ readonly categoryLabels?: Readonly<Record<string, string>>;
1518
+ readonly options?: readonly ProjectedPickerOption[];
1519
+ readonly fields?: readonly string[];
1520
+ readonly dimensions?: readonly ProjectedPickerDimension[];
1521
+ readonly detail: PickerCatalogDetail;
1522
+ }
1523
+ /** Project a catalog to the wire shape: compact by default, optional category/field filter. */
1524
+ declare function projectPickerCatalog(c: PickerCatalog, opts?: ProjectPickerCatalogOptions): ProjectedPickerCatalog;
1525
+
1526
+ /** A catalog entry as the analyzer consumes it. Flat catalogs lack
1527
+ * dimension/category; discriminated catalogs carry exactly one. */
1528
+ interface AnalyzerEntry {
1529
+ readonly id: string;
1530
+ readonly label: string;
1531
+ readonly description: string;
1532
+ readonly dimension?: string;
1533
+ readonly category?: string;
1534
+ }
1535
+ type PickerApplyMode = "override" | "overwrite-detected" | "fill-empty";
1536
+ type ApplyCleanup = (patch: Record<string, unknown>, mode: PickerApplyMode) => void;
1537
+ /** Describes how to build an analyzer spec for one picker type. Three shapes:
1538
+ * - "discriminated": ONE catalog whose entries carry `dimension` or `category`;
1539
+ * `order`/`fieldByKey`/`labels` translate keys → fields/labels; `limitFn`
1540
+ * gives the per-key cardinality.
1541
+ * - "flat": a single-value catalog (lens, camera-format) → one limit-1
1542
+ * dimension whose key == the node-data field. */
1543
+ type PickerAnalyzerDescriptor = {
1544
+ readonly kind: "discriminated";
1545
+ readonly toolName: string;
1546
+ readonly discriminator: "dimension" | "category";
1547
+ readonly order: ReadonlyArray<string>;
1548
+ readonly fieldByKey: Readonly<Record<string, string>>;
1549
+ readonly labels: Readonly<Record<string, string>>;
1550
+ readonly entries: ReadonlyArray<AnalyzerEntry>;
1551
+ readonly limitFn: (key: string) => number;
1552
+ readonly excludedIds?: ReadonlySet<string>;
1553
+ readonly cleanup?: ApplyCleanup;
1554
+ } | {
1555
+ readonly kind: "flat";
1556
+ readonly toolName: string;
1557
+ readonly field: string;
1558
+ readonly label: string;
1559
+ readonly entries: ReadonlyArray<AnalyzerEntry>;
1560
+ };
1561
+ declare const PICKER_ANALYZER_REGISTRY: {
1562
+ person: {
1563
+ kind: "discriminated";
1564
+ toolName: string;
1565
+ discriminator: "dimension";
1566
+ order: ReadonlyArray<string>;
1567
+ fieldByKey: Readonly<Record<string, string>>;
1568
+ labels: Readonly<Record<string, string>>;
1569
+ entries: ReadonlyArray<AnalyzerEntry>;
1570
+ limitFn: (k: string) => number;
1571
+ excludedIds: Set<string>;
1572
+ cleanup: ApplyCleanup;
1573
+ };
1574
+ styling: {
1575
+ kind: "discriminated";
1576
+ toolName: string;
1577
+ discriminator: "dimension";
1578
+ order: ReadonlyArray<string>;
1579
+ fieldByKey: Readonly<Record<string, string>>;
1580
+ labels: Readonly<Record<string, string>>;
1581
+ entries: ReadonlyArray<AnalyzerEntry>;
1582
+ limitFn: (k: string) => number;
1583
+ };
1584
+ framing: {
1585
+ kind: "discriminated";
1586
+ toolName: string;
1587
+ discriminator: "category";
1588
+ order: ReadonlyArray<string>;
1589
+ fieldByKey: Readonly<Record<string, string>>;
1590
+ labels: Readonly<Record<string, string>>;
1591
+ entries: ReadonlyArray<AnalyzerEntry>;
1592
+ limitFn: (k: string) => number;
1593
+ };
1594
+ lens: {
1595
+ kind: "flat";
1596
+ toolName: string;
1597
+ field: string;
1598
+ label: string;
1599
+ entries: ReadonlyArray<AnalyzerEntry>;
1600
+ };
1601
+ "camera-format": {
1602
+ kind: "flat";
1603
+ toolName: string;
1604
+ field: string;
1605
+ label: string;
1606
+ entries: ReadonlyArray<AnalyzerEntry>;
1607
+ };
1608
+ };
1609
+ type PickerType = keyof typeof PICKER_ANALYZER_REGISTRY;
1610
+ declare const PICKER_TYPES: PickerType[];
1611
+ declare const ANALYZABLE_PICKER_TYPES: ReadonlySet<string>;
1612
+ declare function isAnalyzablePicker(t: string): t is PickerType;
1613
+ interface PickerDimensionSpec {
1614
+ /** Catalog dimension id, e.g. "hair-color". Also the JSON key in the emitted pickerJson. */
1615
+ readonly dimension: string;
1616
+ /** Target node-data field, e.g. "hairColor". */
1617
+ readonly field: string;
1618
+ /** Human label/description, for the system-prompt legend. */
1619
+ readonly label: string;
1620
+ /** 1 = single select; 2/3 = array with maxItems. */
1621
+ readonly limit: number;
1622
+ /** Allowed catalog entry ids (the forced enum). */
1623
+ readonly entryIds: ReadonlyArray<string>;
1624
+ /** id → human label/description, for the system-prompt legend. */
1625
+ readonly legend: ReadonlyArray<{
1626
+ id: string;
1627
+ label: string;
1628
+ description: string;
1629
+ }>;
1630
+ }
1631
+ interface PickerAnalyzerSpec {
1632
+ readonly pickerType: PickerType;
1633
+ readonly toolName: string;
1634
+ readonly dimensions: ReadonlyArray<PickerDimensionSpec>;
1635
+ readonly cleanup?: ApplyCleanup;
1636
+ }
1637
+ declare function buildPickerAnalyzerSpec(pickerType: PickerType): PickerAnalyzerSpec;
1638
+ /** Zod object: each dimension is an optional enum (single) or capped enum array
1639
+ * (multi). `.strict()` blocks unknown keys. Mirrors the field cardinality. */
1640
+ declare function buildPickerZodSchema(spec: PickerAnalyzerSpec): z.ZodType<Record<string, string | string[]>, z.ZodTypeDef, unknown>;
1641
+ interface PickerAnalyzer {
1642
+ readonly spec: PickerAnalyzerSpec;
1643
+ readonly schema: z.ZodType<Record<string, string | string[]>, z.ZodTypeDef, unknown>;
1644
+ readonly legend: string;
1645
+ }
1646
+ /** Memoized analyzer build: spec → Zod schema → legend, computed once per
1647
+ * picker type and cached at module level. The three artifacts are catalog-
1648
+ * derived and stable, so the per-request route handler can reuse them instead
1649
+ * of rebuilding all three on every analysis call. */
1650
+ declare function getPickerAnalyzer(pickerType: PickerType): PickerAnalyzer;
1651
+ declare const GAPS_SCHEMA: z.ZodDefault<z.ZodObject<{
1652
+ missingItems: z.ZodDefault<z.ZodArray<z.ZodObject<{
1653
+ picker: z.ZodString;
1654
+ dimension: z.ZodString;
1655
+ observed: z.ZodString;
1656
+ }, "strip", z.ZodTypeAny, {
1657
+ picker: string;
1658
+ dimension: string;
1659
+ observed: string;
1660
+ }, {
1661
+ picker: string;
1662
+ dimension: string;
1663
+ observed: string;
1664
+ }>, "many">>;
1665
+ missingCategories: z.ZodDefault<z.ZodArray<z.ZodObject<{
1666
+ picker: z.ZodString;
1667
+ suggestedDimension: z.ZodString;
1668
+ observed: z.ZodString;
1669
+ }, "strip", z.ZodTypeAny, {
1670
+ picker: string;
1671
+ observed: string;
1672
+ suggestedDimension: string;
1673
+ }, {
1674
+ picker: string;
1675
+ observed: string;
1676
+ suggestedDimension: string;
1677
+ }>, "many">>;
1678
+ }, "strip", z.ZodTypeAny, {
1679
+ missingItems: {
1680
+ picker: string;
1681
+ dimension: string;
1682
+ observed: string;
1683
+ }[];
1684
+ missingCategories: {
1685
+ picker: string;
1686
+ observed: string;
1687
+ suggestedDimension: string;
1688
+ }[];
1689
+ }, {
1690
+ missingItems?: {
1691
+ picker: string;
1692
+ dimension: string;
1693
+ observed: string;
1694
+ }[] | undefined;
1695
+ missingCategories?: {
1696
+ picker: string;
1697
+ observed: string;
1698
+ suggestedDimension: string;
1699
+ }[] | undefined;
1700
+ }>>;
1701
+ interface PickerGaps {
1702
+ readonly missingItems: ReadonlyArray<{
1703
+ picker: string;
1704
+ dimension: string;
1705
+ observed: string;
1706
+ }>;
1707
+ readonly missingCategories: ReadonlyArray<{
1708
+ picker: string;
1709
+ suggestedDimension: string;
1710
+ observed: string;
1711
+ }>;
1712
+ }
1713
+ interface MultiPickerAnalyzerSpec {
1714
+ readonly schema: z.ZodType<Record<string, unknown>, z.ZodTypeDef, unknown>;
1715
+ readonly toolName: string;
1716
+ readonly legend: string;
1717
+ }
1718
+ /** Build ONE forced-tool schema spanning the given pickers (each section
1719
+ * optional so an omitted picker doesn't trigger a validation retry) plus the
1720
+ * capped `gaps` sidecar. Memoized by the sorted picker-set key. */
1721
+ declare function buildMultiPickerAnalyzerSpec(types: ReadonlyArray<PickerType>): MultiPickerAnalyzerSpec;
1722
+ /** Human-readable legend appended to the system prompt so enum ids are meaningful. */
1723
+ declare function buildPickerLegend(spec: PickerAnalyzerSpec): string;
1724
+ /**
1725
+ * Produces the patch to merge into the picker node's data. Touches ONLY the
1726
+ * dimension fields (never label/preText/postText/maxItemsPerRow). `override`
1727
+ * also clears undetected dimension fields, and runs the picker's `cleanup`
1728
+ * (e.g. person resets customAge + clears the deprecated `lips` field).
1729
+ */
1730
+ declare function applyPickerJson(current: Record<string, unknown>, pickerJson: Record<string, unknown>, mode: PickerApplyMode, spec: PickerAnalyzerSpec): Record<string, unknown>;
1731
+ /** The analyzable picker node types wired to a producer's `picker-json` output
1732
+ * (deduped). The ONE definition of edge-derived selection; the frontend
1733
+ * execute path and the backend orchestrator both call this so they can't
1734
+ * drift. Accepts minimal structural node/edge shapes so both layers' richer
1735
+ * types satisfy it. */
1736
+ declare function pickerFanoutTargets(producerId: string, edges: ReadonlyArray<{
1737
+ source: string;
1738
+ target: string;
1739
+ sourceHandle?: string | null;
1740
+ }>, nodes: ReadonlyArray<{
1741
+ id: string;
1742
+ type?: string;
1743
+ }>): PickerType[];
1744
+
1745
+ /**
1746
+ * Canonical catalog of Action FX choices.
1747
+ *
1748
+ * Action FX describes a discrete, dramatic, high-energy event happening in the
1749
+ * scene — an explosion mid-blast, a lightning bolt striking, an earthquake
1750
+ * fracturing the ground, a magic fireball spell, a force field shimmering.
1751
+ *
1752
+ * Distinct from:
1753
+ * - Atmosphere — continuous environmental state (rain, fog, smoke, dust).
1754
+ * - Composition Effects — how the subject itself is rendered (smoke
1755
+ * sculpture, exploding-particle silhouette, glitch).
1756
+ * - Post-Process Effects — image-grading passes (vignette, grain, halation).
1757
+ * - Color Look — overall color grade direction.
1758
+ *
1759
+ * Multi-pick: 1–2 ids → composite FX clause. Pure prompt text, zero credits,
1760
+ * zero API calls. Shared between picker UI and prompt-hint injection on
1761
+ * frontend DAG executor + backend orchestrator.
1762
+ */
1763
+ type ActionFxCategory = "disaster" | "fire-blasts" | "electric" | "combat" | "sci-fi" | "magic";
1764
+ interface ActionFx {
1765
+ readonly id: string;
1766
+ readonly label: string;
1767
+ readonly category: ActionFxCategory;
1768
+ readonly description: string;
1769
+ readonly promptHint: string;
1770
+ }
1771
+ declare const ACTION_FX_CATEGORY_ORDER: ReadonlyArray<ActionFxCategory>;
1772
+ declare const ACTION_FX_CATEGORY_LABELS: Readonly<Record<ActionFxCategory, string>>;
1773
+ declare const ACTION_FX: ReadonlyArray<ActionFx>;
1774
+ declare const ACTION_FX_IDS: ReadonlyArray<string>;
1775
+ declare function getActionFx(id: string | undefined | null): ActionFx | undefined;
1776
+ declare function getActionFxLabel(id: string | undefined | null, fallback?: string): string;
1777
+ declare function getActionFxPromptHint(id: string | undefined | null): string;
1778
+ /**
1779
+ * Multi-pick: 1–2 ids → composite FX clause.
1780
+ *
1781
+ * Single id → entry's own promptHint as a single-element array.
1782
+ * Two ids → emit each independently and let the comma-join compose them.
1783
+ * Caps at 2 ids (silently drops the rest); the picker UI also enforces this
1784
+ * cap, but the cap here keeps the contract robust against stale workflow
1785
+ * data. Duplicate ids are deduplicated before the cap is applied.
1786
+ */
1787
+ declare function buildActionFxHints(value: unknown): string[];
1788
+
1789
+ /**
1790
+ * Canonical catalog of Aesthetic / Microtrend choices.
1791
+ *
1792
+ * Single-pick parameter node — user picks ONE microtrend bundle that
1793
+ * captures wardrobe + setting + grade + mood in a single descriptor.
1794
+ * Microtrends are dense, model-recognised tokens (Y2K, dark academia,
1795
+ * cottagecore, gorpcore...) that pull a coherent visual world along with
1796
+ * the name. Each promptHint expands the slang into the specific wardrobe
1797
+ * cues, environment cues and color treatment that define the look.
1798
+ *
1799
+ * Categories:
1800
+ * - mainstream: high-recognition microtrends with a stable visual signature
1801
+ * - niche: smaller -core / -kei / -punk movements
1802
+ * - era: fashion eras / sensibilities (minimalism, maximalism, glam)
1803
+ * - mood: cultural mood-bundles (effortless cool, main-character energy)
1804
+ *
1805
+ * Shared between the picker UI, the standalone Aesthetic parameter node,
1806
+ * and the prompt-hint injection on both the frontend DAG executor and the
1807
+ * backend orchestrator.
1808
+ */
1809
+ type AestheticCategory = "mainstream" | "niche" | "era" | "mood";
1810
+ interface Aesthetic {
1811
+ readonly id: string;
1812
+ readonly label: string;
1813
+ readonly category: AestheticCategory;
1814
+ readonly description: string;
1815
+ readonly promptHint: string;
1816
+ }
1817
+ declare const AESTHETICS: ReadonlyArray<Aesthetic>;
1818
+ declare function getAesthetic(id: string | undefined | null): Aesthetic | undefined;
1819
+ declare function getAestheticLabel(id: string | undefined | null, fallback?: string): string;
1820
+ declare function getAestheticPromptHint(id: string | undefined | null): string;
1821
+ /**
1822
+ * Multi-pick variant: 1-2 aesthetic ids → blended hint. Single → entry's
1823
+ * own promptHint. Two → "styled in a {A} + {B} aesthetic blend" with
1824
+ * canonical entry labels (Y2K, dark academia, etc. stay as written).
1825
+ */
1826
+ declare function buildAestheticHints(value: unknown): string;
1827
+ declare const AESTHETIC_IDS: ReadonlyArray<string>;
1828
+ declare const AESTHETIC_CATEGORY_LABELS: Readonly<Record<AestheticCategory, string>>;
1829
+ declare const AESTHETIC_CATEGORY_ORDER: ReadonlyArray<AestheticCategory>;
1830
+
1831
+ /**
1832
+ * Canonical catalog of atmosphere / environmental effects.
1833
+ *
1834
+ * Atmosphere dimension of a shot — environmental elements in the air that
1835
+ * affect visibility and mood (rain, fog, god rays, particles). Independent
1836
+ * of lighting (color/direction of light) and color/look (post-processing
1837
+ * tone). A sunny scene with fog has different atmosphere than a clear sunny
1838
+ * scene, even with identical subject, lighting and color grade.
1839
+ *
1840
+ * Shared between the picker UI and the prompt-hint injection on both the
1841
+ * frontend DAG executor and the backend orchestrator.
1842
+ */
1843
+ interface Atmosphere {
1844
+ readonly id: string;
1845
+ readonly label: string;
1846
+ readonly description: string;
1847
+ readonly promptHint: string;
1848
+ }
1849
+ declare const ATMOSPHERES: ReadonlyArray<Atmosphere>;
1850
+ declare function getAtmosphere(id: string | undefined | null): Atmosphere | undefined;
1851
+ declare function getAtmosphereLabel(id: string | undefined | null, fallback?: string): string;
1852
+ declare function getAtmospherePromptHint(id: string | undefined | null): string;
1853
+ /**
1854
+ * Multi-pick: 1-2 atmosphere ids → composite atmospheric clause. Single →
1855
+ * entry's own promptHint. Two → emit independently and join — atmospheres
1856
+ * are particle-effect descriptions that compose naturally
1857
+ * ("fog drifting in soft cool clouds, with golden god-rays cutting through").
1858
+ */
1859
+ declare function buildAtmosphereHints(value: unknown): string[];
1860
+ declare const ATMOSPHERE_IDS: ReadonlyArray<string>;
1861
+
1862
+ /**
1863
+ * Canonical catalog of Backdrop / studio-background presets.
1864
+ *
1865
+ * Single-pick parameter node — user picks ONE backdrop describing the
1866
+ * controlled wall / surface / effect *immediately behind the subject*.
1867
+ * Distinct from Setting (which describes the location or environment a
1868
+ * shot takes place in). Backdrop is the studio convention behind the
1869
+ * subject during a portrait, fashion, beauty, e-commerce, or product
1870
+ * shoot — the seamless paper, painted wall, gradient sweep, or lit
1871
+ * effect that frames the subject.
1872
+ *
1873
+ * For full environments (cafe, forest, alley) use the Setting node.
1874
+ * For artistic medium use Style. For "in the air" particles use
1875
+ * Atmosphere. Backdrop occupies the narrow, well-defined slot of
1876
+ * "what wall is this person standing in front of."
1877
+ *
1878
+ * Applies to both image and video consumers (a studio backdrop carries
1879
+ * over to motion shoots). Not in STILL_IMAGE_EXCLUDE_TYPES.
1880
+ *
1881
+ * Shared between the picker UI, the standalone Backdrop parameter
1882
+ * node, and the prompt-hint injection on both the frontend DAG executor
1883
+ * and the backend orchestrator.
1884
+ */
1885
+ type BackdropCategory = "solid" | "gradient" | "textured" | "fabric" | "effect" | "reflective";
1886
+ interface Backdrop {
1887
+ readonly id: string;
1888
+ readonly label: string;
1889
+ readonly category: BackdropCategory;
1890
+ readonly description: string;
1891
+ readonly promptHint: string;
1892
+ }
1893
+ declare const BACKDROPS: ReadonlyArray<Backdrop>;
1894
+ declare function getBackdrop(id: string | undefined | null): Backdrop | undefined;
1895
+ declare function getBackdropLabel(id: string | undefined | null, fallback?: string): string;
1896
+ declare function getBackdropPromptHint(id: string | undefined | null): string;
1897
+ declare const BACKDROP_IDS: ReadonlyArray<string>;
1898
+ declare const BACKDROP_CATEGORY_LABELS: Readonly<Record<BackdropCategory, string>>;
1899
+ declare const BACKDROP_CATEGORY_ORDER: ReadonlyArray<BackdropCategory>;
1900
+
1901
+ /**
1902
+ * Canonical catalog of camera / film-stock choices.
1903
+ *
1904
+ * Capture-medium dimension of a shot — the physical or simulated sensor / film
1905
+ * stock and its associated grain, color science, and aspect treatment. Independent
1906
+ * of optics (lens), framing (shot size + composition), and camera motion.
1907
+ *
1908
+ * Shared between the picker UI and the prompt-hint injection on both the
1909
+ * frontend DAG executor and the backend orchestrator.
1910
+ */
1911
+ interface CameraFormat {
1912
+ readonly id: string;
1913
+ readonly label: string;
1914
+ readonly description: string;
1915
+ readonly promptHint: string;
1916
+ }
1917
+ declare const CAMERA_FORMATS: ReadonlyArray<CameraFormat>;
1918
+ declare function getCameraFormat(id: string | undefined | null): CameraFormat | undefined;
1919
+ declare function getCameraFormatLabel(id: string | undefined | null, fallback?: string): string;
1920
+ declare function getCameraFormatPromptHint(id: string | undefined | null): string;
1921
+ declare const CAMERA_FORMAT_IDS: ReadonlyArray<string>;
1922
+
1923
+ /**
1924
+ * Canonical catalog of camera motions for video / image-to-video generation.
1925
+ *
1926
+ * Shared between frontend (picker UI, prompt hint injection) and backend
1927
+ * (orchestrator payload builder). The `promptHint` is a natural-language
1928
+ * cue that gets appended to the user prompt when the node has camera
1929
+ * motion enabled.
1930
+ */
1931
+ type CameraMotionCategory = "default" | "pan" | "tilt" | "zoom" | "dolly" | "truck" | "pedestal" | "roll" | "orbit" | "crane" | "tracking" | "special";
1932
+ interface CameraMotion {
1933
+ readonly id: string;
1934
+ readonly label: string;
1935
+ readonly category: CameraMotionCategory;
1936
+ readonly description: string;
1937
+ readonly promptHint: string;
1938
+ }
1939
+ declare const CAMERA_MOTIONS: ReadonlyArray<CameraMotion>;
1940
+ declare const CAMERA_MOTION_CATEGORY_ORDER: ReadonlyArray<CameraMotionCategory>;
1941
+ declare const CAMERA_MOTION_CATEGORY_LABELS: Record<CameraMotionCategory, string>;
1942
+ declare function getCameraMotion(id: string | undefined | null): CameraMotion | undefined;
1943
+ /** Human-readable label for the given motion id. Falls back to the id if unknown. */
1944
+ declare function getCameraMotionLabel(id: string | undefined | null, fallback?: string): string;
1945
+ /** Descriptive prompt hint for the given motion id. Empty string when motion is "auto" or unknown. */
1946
+ declare function getCameraMotionPromptHint(id: string | undefined | null): string;
1947
+ declare const CAMERA_MOTION_IDS: ReadonlyArray<string>;
1948
+ /**
1949
+ * Compose a structural prompt-hint sentence from a camera-motion id plus
1950
+ * arrays of start-state and end-state promptHints (collected by walking
1951
+ * the source camera-motion node's startState / endState input handles
1952
+ * upstream to find connected parameter nodes).
1953
+ *
1954
+ * - No connected nodes → bare motion promptHint.
1955
+ * - Start only → "<motion>, beginning with <start hints joined>".
1956
+ * - End only → "<motion>, ending with <end hints joined>".
1957
+ * - Both → "<motion>, beginning with <start>, ending with <end>".
1958
+ *
1959
+ * Hints within each side are joined with " and " for grammatical flow.
1960
+ * If multiple nodes are connected (e.g. Framing + Lighting + Tone), all
1961
+ * three contribute their hint to the clause.
1962
+ */
1963
+ declare function composeCameraMotionHintFromConnections(motionId: string | undefined, startHints: ReadonlyArray<string>, endHints: ReadonlyArray<string>): string;
1964
+
1965
+ /**
1966
+ * Canonical catalog of character-driven effects for AI-video generation.
1967
+ *
1968
+ * Shared between frontend (picker UI, prompt hint injection) and backend
1969
+ * (orchestrator payload builder). The `promptHint` is a natural-language
1970
+ * cue that gets composed into the user prompt when a character-fx node
1971
+ * is connected to a video consumer.
1972
+ *
1973
+ * Every `promptHint` references "the subject" at least once — the composer
1974
+ * does a global regex replace of "the subject" with the target ref's
1975
+ * display name (character/face/object/location) when a target is wired.
1976
+ *
1977
+ * Multi-pick supported: value field accepts `string | string[]` (cap 2).
1978
+ * Per-id substitution: each base hint is independently rewritten BEFORE
1979
+ * the join, so "Aria transforms into a werewolf, and Aria opens their
1980
+ * mouth and exhales..." reads correctly.
1981
+ *
1982
+ * null input is treated like undefined (falsy short-circuit → returns "")
1983
+ */
1984
+ type CharacterFxCategory = "transformation" | "power" | "body-mod" | "face-expression" | "aura-ambient";
1985
+ interface CharacterFx {
1986
+ readonly id: string;
1987
+ readonly label: string;
1988
+ readonly category: CharacterFxCategory;
1989
+ readonly description: string;
1990
+ readonly promptHint: string;
1991
+ }
1992
+ type CharacterFxPosition = "auto" | "start" | "middle" | "end" | "full";
1993
+ type CharacterFxDuration = "auto" | "instant" | "short" | "medium" | "long";
1994
+ type CharacterFxIntensity = "auto" | "subtle" | "natural" | "dynamic" | "crazy";
1995
+ interface CharacterFxTiming {
1996
+ position?: CharacterFxPosition;
1997
+ duration?: CharacterFxDuration;
1998
+ intensity?: CharacterFxIntensity;
1999
+ }
2000
+ declare const CHARACTER_FX: ReadonlyArray<CharacterFx>;
2001
+ declare const CHARACTER_FX_CATEGORY_ORDER: ReadonlyArray<CharacterFxCategory>;
2002
+ declare const CHARACTER_FX_CATEGORY_LABELS: Readonly<Record<CharacterFxCategory, string>>;
2003
+ declare function getCharacterFx(id: string | undefined | null): CharacterFx | undefined;
2004
+ declare function getCharacterFxLabel(id: string | undefined | null, fallback?: string): string;
2005
+ declare function getCharacterFxPromptHint(id: string | undefined | null): string;
2006
+ declare const CHARACTER_FX_IDS: ReadonlyArray<string>;
2007
+ /**
2008
+ * Compose a character-fx prompt-hint sentence from an effect id (or array
2009
+ * of 1-2 ids for multi-pick) plus target-ref display names (from upstream
2010
+ * character/face/object/location nodes wired to the `target` handle) plus
2011
+ * optional timing fields.
2012
+ *
2013
+ * Substitution: each base hint has every `"the subject"` occurrence
2014
+ * rewritten to the target name BEFORE the join. Empty targetHints leaves
2015
+ * "the subject" intact in the prompt.
2016
+ */
2017
+ declare function composeCharacterFxHintFromConnections(effectId: string | ReadonlyArray<string> | undefined, targetHints: ReadonlyArray<string>, timing?: CharacterFxTiming): string;
2018
+
2019
+ /**
2020
+ * Canonical catalog of color/look choices.
2021
+ *
2022
+ * Color/look is a multi-category dimension of a shot — it covers both
2023
+ * stylistic color palettes (warm, cool, teal-orange, etc.) and film-stock
2024
+ * emulations (Kodak Portra, Cinestill 800T, bleach bypass, etc.). Independent
2025
+ * of optics (lens), framing, camera motion, capture medium (camera-format),
2026
+ * and lighting setup.
2027
+ *
2028
+ * Shared between the picker UI and the prompt-hint injection on both the
2029
+ * frontend DAG executor and the backend orchestrator.
2030
+ */
2031
+ type ColorLookCategory = "palette" | "film-emulation" | "social-preset";
2032
+ interface ColorLook {
2033
+ readonly id: string;
2034
+ readonly label: string;
2035
+ readonly category: ColorLookCategory;
2036
+ readonly description: string;
2037
+ readonly promptHint: string;
2038
+ }
2039
+ declare const COLOR_LOOKS: ReadonlyArray<ColorLook>;
2040
+ declare const COLOR_LOOK_CATEGORY_ORDER: ReadonlyArray<ColorLookCategory>;
2041
+ declare const COLOR_LOOK_CATEGORY_LABELS: Record<ColorLookCategory, string>;
2042
+ declare function getColorLook(id: string | undefined | null): ColorLook | undefined;
2043
+ declare function getColorLookLabel(id: string | undefined | null, fallback?: string): string;
2044
+ declare function getColorLookPromptHint(id: string | undefined | null): string;
2045
+ declare const COLOR_LOOK_IDS: ReadonlyArray<string>;
2046
+
2047
+ /**
2048
+ * Canonical catalog of Composition Effects choices.
2049
+ *
2050
+ * Composition Effects describe a "compositional trick" applied to the subject
2051
+ * — how the subject interacts with the canvas/frame, what material it's made
2052
+ * of, or what compositional gimmick frames it. This is distinct from the post-
2053
+ * processing image grade (Post-Process Effects) and from the artistic style
2054
+ * (Style): an "exploding particles" composition effect can be applied to an
2055
+ * oil painting style or a photorealistic style equally well.
2056
+ *
2057
+ * Single-pick — only one composition trick is applied per consumer. Pure
2058
+ * prompt text, zero credits, zero API calls.
2059
+ *
2060
+ * Shared between picker UI and prompt-hint injection in the frontend DAG
2061
+ * executor and the backend orchestrator.
2062
+ */
2063
+ interface CompositionEffect {
2064
+ readonly id: string;
2065
+ readonly label: string;
2066
+ readonly description: string;
2067
+ readonly promptHint: string;
2068
+ }
2069
+ declare const COMPOSITION_EFFECTS: ReadonlyArray<CompositionEffect>;
2070
+ declare function getCompositionEffect(id: string | undefined | null): CompositionEffect | undefined;
2071
+ declare function getCompositionEffectLabel(id: string | undefined | null, fallback?: string): string;
2072
+ declare function getCompositionEffectPromptHint(id: string | undefined | null): string;
2073
+ declare const COMPOSITION_EFFECT_IDS: ReadonlyArray<string>;
2074
+
2075
+ /**
2076
+ * Canonical catalog of Era / Period choices.
2077
+ *
2078
+ * Single-pick parameter node — user picks ONE historical era or speculative
2079
+ * period. Each promptHint bundles wardrobe + environment + photographic
2080
+ * treatment so the model gets a coherent world rather than a stray decade
2081
+ * label. Color, lighting, grain and signature props are all part of the
2082
+ * descriptor because period-piece looks live or die on those cues.
2083
+ *
2084
+ * Categories:
2085
+ * - decade-20c: 20th-century decades from 1920s flapper to 2000s tabloid
2086
+ * - pre-modern: pre-20th-century historical eras (medieval -> Edwardian)
2087
+ * - speculative: future, retrofuture, post-apocalyptic, dieselpunk etc.
2088
+ *
2089
+ * Shared between the picker UI, the standalone Era parameter node, and the
2090
+ * prompt-hint injection on both the frontend DAG executor and the backend
2091
+ * orchestrator.
2092
+ */
2093
+ type EraCategory = "decade-20c" | "pre-modern" | "speculative";
2094
+ interface Era {
2095
+ readonly id: string;
2096
+ readonly label: string;
2097
+ readonly category: EraCategory;
2098
+ readonly description: string;
2099
+ readonly promptHint: string;
2100
+ }
2101
+ declare const ERAS: ReadonlyArray<Era>;
2102
+ declare function getEra(id: string | undefined | null): Era | undefined;
2103
+ declare function getEraLabel(id: string | undefined | null, fallback?: string): string;
2104
+ declare function getEraPromptHint(id: string | undefined | null): string;
2105
+ declare const ERA_IDS: ReadonlyArray<string>;
2106
+ declare const ERA_CATEGORY_LABELS: Readonly<Record<EraCategory, string>>;
2107
+ declare const ERA_CATEGORY_ORDER: ReadonlyArray<EraCategory>;
2108
+
2109
+ /**
2110
+ * Canonical catalog of Exposure Settings choices.
2111
+ *
2112
+ * Exposure Settings is a multi-category dimension covering the core photographic
2113
+ * triangle that controls exposure and visual character: aperture (depth of field
2114
+ * and subject isolation), shutter speed (motion treatment), and ISO sensitivity
2115
+ * (grain quality and noise). Independent of optics (lens), lighting, framing,
2116
+ * camera motion, and capture medium (camera-format).
2117
+ *
2118
+ * Each picked entry contributes a focused descriptive clause — the whole point
2119
+ * is to give the model a strong technical hint about what the photographer
2120
+ * "set the dial to", and the visual consequence of that choice.
2121
+ *
2122
+ * Typical applications: portraiture wide-aperture isolation, action freeze with
2123
+ * fast shutter, gritty high-ISO grain, light-trail long exposure, etc.
2124
+ *
2125
+ * Shared between the picker UI, the standalone Exposure Settings parameter
2126
+ * node, and the prompt-hint injection on both the frontend DAG executor and
2127
+ * the backend orchestrator.
2128
+ */
2129
+ type ExposureCategory = "aperture" | "shutter-speed" | "iso";
2130
+ interface ExposureSettings {
2131
+ readonly id: string;
2132
+ readonly label: string;
2133
+ readonly category: ExposureCategory;
2134
+ readonly description: string;
2135
+ readonly promptHint: string;
2136
+ }
2137
+ declare const EXPOSURE_SETTINGS: ReadonlyArray<ExposureSettings>;
2138
+ declare const EXPOSURE_CATEGORY_ORDER: ReadonlyArray<ExposureCategory>;
2139
+ declare const EXPOSURE_CATEGORY_LABELS: Record<ExposureCategory, string>;
2140
+ declare function getExposure(id: string | undefined | null): ExposureSettings | undefined;
2141
+ declare function getExposureLabel(id: string | undefined | null, fallback?: string): string;
2142
+ declare function getExposurePromptHint(id: string | undefined | null): string;
2143
+ declare const EXPOSURE_IDS: ReadonlyArray<string>;
2144
+ /**
2145
+ * Maps each ExposureCategory to the consumer data field name that holds the
2146
+ * selected entry id for that category. Multi-category exposure: a consumer
2147
+ * (image/video) can independently set a value in each of the 3 dimensions.
2148
+ */
2149
+ declare const EXPOSURE_FIELD_BY_CATEGORY: Record<ExposureCategory, "aperture" | "shutterSpeed" | "isoValue">;
2150
+ /**
2151
+ * Shape of the per-category exposure fields on ExposureSettingsData and any
2152
+ * consumer that opts in. All fields optional — user may set zero, one, or
2153
+ * all categories.
2154
+ */
2155
+ interface ExposureValue {
2156
+ aperture?: string;
2157
+ shutterSpeed?: string;
2158
+ isoValue?: string;
2159
+ }
2160
+ /**
2161
+ * Aggregate all enabled per-category exposure prompt hints from a consumer's
2162
+ * data, in canonical category order (aperture, shutter-speed, iso).
2163
+ */
2164
+ declare function buildExposureHints(data: Record<string, unknown> & {
2165
+ aperture?: unknown;
2166
+ shutterSpeed?: unknown;
2167
+ isoValue?: unknown;
2168
+ }): string[];
2169
+
2170
+ /**
2171
+ * Canonical catalog of framing / shot composition choices.
2172
+ *
2173
+ * Complements `camera-motions.ts`: motion is HOW the camera moves, framing is
2174
+ * WHAT the camera sees and from WHICH angle. They're independent dimensions
2175
+ * of a shot — users can pick both (e.g. "Dolly In" + "Medium Close-up").
2176
+ *
2177
+ * Shared between the picker UI and the prompt-hint injection on both the
2178
+ * frontend DAG executor and the backend orchestrator.
2179
+ */
2180
+ type FramingCategory = "shot-size" | "angle" | "coverage" | "composition" | "vantage";
2181
+ interface Framing {
2182
+ readonly id: string;
2183
+ readonly label: string;
2184
+ readonly category: FramingCategory;
2185
+ readonly description: string;
2186
+ readonly promptHint: string;
2187
+ }
2188
+ declare const FRAMINGS: ReadonlyArray<Framing>;
2189
+ declare const FRAMING_CATEGORY_ORDER: ReadonlyArray<FramingCategory>;
2190
+ declare const FRAMING_CATEGORY_LABELS: Record<FramingCategory, string>;
2191
+ declare function getFraming(id: string | undefined | null): Framing | undefined;
2192
+ declare function getFramingLabel(id: string | undefined | null, fallback?: string): string;
2193
+ declare function getFramingPromptHint(id: string | undefined | null): string;
2194
+ declare const FRAMING_IDS: ReadonlyArray<string>;
2195
+ declare function isVantageFraming(id: string | undefined | null): boolean;
2196
+ /**
2197
+ * Maps each FramingCategory to the consumer data field name that holds the
2198
+ * selected entry id for that category. Multi-category framing: a consumer
2199
+ * (image/video) can independently set a value in each of the 5 dimensions.
2200
+ */
2201
+ declare const FRAMING_FIELD_BY_CATEGORY: Record<FramingCategory, "shotSize" | "angle" | "coverage" | "composition" | "vantage">;
2202
+ /** Per-category multi-select cap. composition supports 2 picks
2203
+ * (rule-of-thirds + leading-lines, centered + negative-space). All other
2204
+ * categories single-select (absent → 1). */
2205
+ declare const MAX_SELECTED_BY_FRAMING_CATEGORY: Partial<Record<FramingCategory, number>>;
2206
+ /** Selection limit for a framing category (1 when not multi-select). */
2207
+ declare function getFramingCategoryLimit(category: FramingCategory): number;
2208
+ /**
2209
+ * Shape of the per-category framing fields on FramingData and all 9 consumer
2210
+ * data types. All fields optional — user may set zero, one, or all categories.
2211
+ */
2212
+ interface FramingValue {
2213
+ shotSize?: string;
2214
+ angle?: string;
2215
+ coverage?: string;
2216
+ /** Composition — single id or up to 2 ids for layered compositions
2217
+ * (e.g. ["rule-of-thirds", "leading-lines"], ["centered", "negative-space"]). */
2218
+ composition?: string | ReadonlyArray<string>;
2219
+ vantage?: string;
2220
+ }
2221
+ /**
2222
+ * Aggregate all enabled per-category framing prompt hints from a consumer's
2223
+ * data, in canonical category order (shot-size, angle, coverage, composition,
2224
+ * vantage).
2225
+ *
2226
+ * Accepts a loosely typed record (the helper is shared between strongly typed
2227
+ * frontend node data and the backend's `Record<string, unknown>` workflow
2228
+ * data). Non-string values are ignored.
2229
+ *
2230
+ * @param data the consumer data record (must include optional shotSize / angle
2231
+ * / coverage / composition / vantage fields)
2232
+ * @param skipVantage when true, skip the vantage hint (used by video consumers
2233
+ * where camera-motion v2 already declares spatial positioning — keeps the
2234
+ * pre-existing conflict-resolution behavior identical).
2235
+ */
2236
+ declare function buildFramingHints(data: Record<string, unknown> & {
2237
+ shotSize?: unknown;
2238
+ angle?: unknown;
2239
+ coverage?: unknown;
2240
+ composition?: unknown;
2241
+ vantage?: unknown;
2242
+ }, skipVantage?: boolean): string[];
2243
+
2244
+ /**
2245
+ * Canonical catalog of Held Prop / hand-prop presets.
2246
+ *
2247
+ * Single-pick parameter node — user picks ONE prop the subject is
2248
+ * actively holding or interacting with. Distinct from the Object node,
2249
+ * which describes a *separate* object somewhere in the scene. A held
2250
+ * prop is part of the subject's pose grammar — they're cradling it,
2251
+ * raising it, smoking it, gripping it. Each promptHint therefore
2252
+ * incorporates a small piece of pose / hand language so the prop reads
2253
+ * as actively held rather than just "near."
2254
+ *
2255
+ * There is intentional vocabulary overlap with the Weapon node (katana,
2256
+ * pistol) and with parts of the Material / Vehicle catalogs — Held Prop
2257
+ * uses the held-in-hand grammar ("holding…", "cradling…"), while the
2258
+ * Weapon node uses the descriptive scene grammar ("with a katana, …").
2259
+ *
2260
+ * Applies to both image and video consumers (the prop and pose carry
2261
+ * over to motion). Not in STILL_IMAGE_EXCLUDE_TYPES.
2262
+ *
2263
+ * Shared between the picker UI, the standalone Held Prop parameter
2264
+ * node, and the prompt-hint injection on both the frontend DAG executor
2265
+ * and the backend orchestrator.
2266
+ */
2267
+ type HeldPropCategory = "device" | "drink" | "smoking" | "reading-writing" | "bag-accessory" | "floral-nature" | "instrument" | "companion" | "occupational";
2268
+ interface HeldProp {
2269
+ readonly id: string;
2270
+ readonly label: string;
2271
+ readonly category: HeldPropCategory;
2272
+ readonly description: string;
2273
+ readonly promptHint: string;
2274
+ }
2275
+ declare const HELD_PROPS: ReadonlyArray<HeldProp>;
2276
+ declare function getHeldProp(id: string | undefined | null): HeldProp | undefined;
2277
+ declare function getHeldPropLabel(id: string | undefined | null, fallback?: string): string;
2278
+ declare function getHeldPropPromptHint(id: string | undefined | null): string;
2279
+ /**
2280
+ * Multi-pick: 1-2 prop ids → composite held-prop clause. Single → entry's
2281
+ * own promptHint (which already starts with "holding..." / "carrying..."
2282
+ * grammar). Two → emit independently, joined by buildPersonHints-style
2283
+ * comma-join. Common combos: book + coffee, cigarette + drink, phone + bag.
2284
+ */
2285
+ declare function buildHeldPropHints(value: unknown): string[];
2286
+ declare const HELD_PROP_IDS: ReadonlyArray<string>;
2287
+ declare const HELD_PROP_CATEGORY_LABELS: Readonly<Record<HeldPropCategory, string>>;
2288
+ declare const HELD_PROP_CATEGORY_ORDER: ReadonlyArray<HeldPropCategory>;
2289
+
2290
+ /**
2291
+ * Instrumentation catalog: instruments (multi-select) + production style +
2292
+ * vocal presence. Composed into "[production] [instruments-joined] with [vocalPresence]".
2293
+ *
2294
+ * `vocalPresence: "instrumental"` is the trigger that the Generate Music
2295
+ * (MiniMax) integration uses to flip its `instrumental: true` flag.
2296
+ *
2297
+ * INSTRUMENTS carries a `category` field used by the picker to render a
2298
+ * horizontal tab row mirroring Splice's instrument taxonomy
2299
+ * (https://splice.com/sounds/instruments) — Drums / Percussion / Keys /
2300
+ * Synth / Guitar / Bass / Brass / Woodwinds / Strings / World.
2301
+ */
2302
+ type InstrumentCategory = "drums" | "percussion" | "keys" | "synth" | "guitar" | "bass" | "brass" | "woodwinds" | "strings" | "world" | "middle-eastern";
2303
+ declare const INSTRUMENT_CATEGORY_ORDER: ReadonlyArray<InstrumentCategory>;
2304
+ declare const INSTRUMENT_CATEGORY_LABELS: Readonly<Record<InstrumentCategory, string>>;
2305
+ interface InstrumentationEntry {
2306
+ readonly id: string;
2307
+ readonly label: string;
2308
+ readonly description: string;
2309
+ readonly promptHint: string;
2310
+ }
2311
+ interface CategorizedInstrument extends InstrumentationEntry {
2312
+ readonly category: InstrumentCategory;
2313
+ }
2314
+ declare const INSTRUMENTS: ReadonlyArray<CategorizedInstrument>;
2315
+ declare const PRODUCTION_STYLES: ReadonlyArray<InstrumentationEntry>;
2316
+ declare const VOCAL_PRESENCE: ReadonlyArray<InstrumentationEntry>;
2317
+ /** "instrumental" is mutually exclusive with any other vocal presence —
2318
+ * picking it while others are selected clears the others, and picking
2319
+ * another while "instrumental" is selected clears it. */
2320
+ declare const VOCAL_PRESENCE_INSTRUMENTAL_ID = "instrumental";
2321
+ declare const SINGING_STYLES: ReadonlyArray<InstrumentationEntry>;
2322
+ declare function getInstrument(id: string | undefined): CategorizedInstrument | undefined;
2323
+ declare function getProductionStyle(id: string | undefined): InstrumentationEntry | undefined;
2324
+ declare function getVocalPresence(id: string | undefined): InstrumentationEntry | undefined;
2325
+ declare function getSingingStyle(id: string | undefined): InstrumentationEntry | undefined;
2326
+ declare function buildInstrumentationHints(data: {
2327
+ readonly preText?: string;
2328
+ readonly postText?: string;
2329
+ readonly instruments?: ReadonlyArray<string>;
2330
+ readonly production?: string;
2331
+ readonly vocalPresence?: string | ReadonlyArray<string>;
2332
+ readonly singingStyle?: string | ReadonlyArray<string>;
2333
+ }): string;
2334
+ declare function isInstrumentalVocal(value: unknown): boolean;
2335
+ declare const INSTRUMENTATION_DEFAULT_DATA: {
2336
+ preText?: string;
2337
+ postText?: string;
2338
+ instruments?: ReadonlyArray<string>;
2339
+ production?: string;
2340
+ vocalPresence?: string | ReadonlyArray<string>;
2341
+ singingStyle?: string | ReadonlyArray<string>;
2342
+ };
2343
+
2344
+ /**
2345
+ * Canonical catalog of lens / focal length choices.
2346
+ *
2347
+ * Optics dimension of a shot — focal length and depth-of-field character. Independent
2348
+ * of framing (which captures shot size and composition) and camera motion (which captures
2349
+ * how the camera moves). A close-up at 24mm looks completely different from a close-up
2350
+ * at 200mm — the lens choice carries that intent.
2351
+ *
2352
+ * Shared between the picker UI and the prompt-hint injection on both the
2353
+ * frontend DAG executor and the backend orchestrator.
2354
+ */
2355
+ interface Lens {
2356
+ readonly id: string;
2357
+ readonly label: string;
2358
+ readonly description: string;
2359
+ readonly promptHint: string;
2360
+ }
2361
+ declare const LENSES: ReadonlyArray<Lens>;
2362
+ declare function getLens(id: string | undefined | null): Lens | undefined;
2363
+ declare function getLensLabel(id: string | undefined | null, fallback?: string): string;
2364
+ declare function getLensPromptHint(id: string | undefined | null): string;
2365
+ declare const LENS_IDS: ReadonlyArray<string>;
2366
+
2367
+ /**
2368
+ * Canonical catalog of lighting choices.
2369
+ *
2370
+ * Lighting is a multi-category dimension of a shot — light comes from a
2371
+ * direction, has a stylistic intent (three-point, Rembrandt, low-key, etc.),
2372
+ * and is anchored to a time of day. Independent of optics (lens), framing,
2373
+ * camera motion, and capture medium (camera-format).
2374
+ *
2375
+ * Shared between the picker UI and the prompt-hint injection on both the
2376
+ * frontend DAG executor and the backend orchestrator.
2377
+ */
2378
+ type LightingCategory = "time-of-day" | "style" | "direction" | "lighting-ratio" | "color-temperature";
2379
+ interface Lighting {
2380
+ readonly id: string;
2381
+ readonly label: string;
2382
+ readonly category: LightingCategory;
2383
+ readonly description: string;
2384
+ readonly promptHint: string;
2385
+ }
2386
+ declare const LIGHTINGS: ReadonlyArray<Lighting>;
2387
+ declare const LIGHTING_CATEGORY_ORDER: ReadonlyArray<LightingCategory>;
2388
+ declare const LIGHTING_CATEGORY_LABELS: Record<LightingCategory, string>;
2389
+ declare function getLighting(id: string | undefined | null): Lighting | undefined;
2390
+ declare function getLightingLabel(id: string | undefined | null, fallback?: string): string;
2391
+ declare function getLightingPromptHint(id: string | undefined | null): string;
2392
+ declare const LIGHTING_IDS: ReadonlyArray<string>;
2393
+ /**
2394
+ * Maps each LightingCategory to the consumer data field name that holds the
2395
+ * selected entry id for that category. Multi-category lighting: a consumer
2396
+ * (image/video) can independently set a value in each of the 3 dimensions.
2397
+ *
2398
+ * Field names use 'lighting' prefix where the category name is generic or
2399
+ * would collide with other dimensions (e.g. Temporal also has a 'direction'
2400
+ * category; 'style' is generic across many dims).
2401
+ */
2402
+ declare const LIGHTING_FIELD_BY_CATEGORY: Record<LightingCategory, "timeOfDay" | "lightingStyle" | "lightingDirection" | "lightingRatio" | "colorTemperature">;
2403
+ /**
2404
+ * Shape of the per-category lighting fields on LightingData and all 9 consumer
2405
+ * data types. All fields optional — user may set zero, one, or all categories.
2406
+ */
2407
+ interface LightingValue {
2408
+ timeOfDay?: string;
2409
+ /** Lighting style — single id or up to 2 ids for layered setups
2410
+ * (e.g. ["key", "rim"], ["soft", "hard"], ["beauty-dish", "kicker"]). */
2411
+ lightingStyle?: string | ReadonlyArray<string>;
2412
+ lightingDirection?: string;
2413
+ /** Lighting ratio id from LIGHTINGS (relative key-to-shadow brightness, e.g. "ratio-1-2"). */
2414
+ lightingRatio?: string;
2415
+ /** Color temperature id from LIGHTINGS (Kelvin warmth/coolness, e.g. "temp-5600k"). */
2416
+ colorTemperature?: string;
2417
+ }
2418
+ /**
2419
+ * Aggregate all enabled per-category lighting prompt hints from a consumer's
2420
+ * data, in canonical category order (time-of-day, style, direction).
2421
+ *
2422
+ * Accepts a loosely typed record (the helper is shared between strongly typed
2423
+ * frontend node data and the backend's `Record<string, unknown>` workflow
2424
+ * data). Non-string values are ignored.
2425
+ *
2426
+ * @param data the consumer data record (must include optional timeOfDay /
2427
+ * lightingStyle / lightingDirection fields)
2428
+ */
2429
+ declare function buildLightingHints(data: Record<string, unknown> & {
2430
+ timeOfDay?: unknown;
2431
+ lightingStyle?: unknown;
2432
+ lightingDirection?: unknown;
2433
+ lightingRatio?: unknown;
2434
+ colorTemperature?: unknown;
2435
+ }): string[];
2436
+
2437
+ /**
2438
+ * Canonical catalog of loop-friendly subject presets ("Loop Subject").
2439
+ *
2440
+ * The Loop Subject parameter node emits one of these prompt fragments,
2441
+ * pre-tuned for VEO 3.1 perfect-loop generation. Each prompt is shaped to
2442
+ * either:
2443
+ * - have inherently cyclical / ambient motion the model knows from the
2444
+ * subject alone (clouds drift, aurora undulates, embers flicker), or
2445
+ * - anchor periodicity via the "fractal" / "self-similar" tokens, which
2446
+ * in user testing strongly biased VEO toward loop-tolerant output even
2447
+ * when the prompt also contained directional cues (vanishing points,
2448
+ * receding lines).
2449
+ *
2450
+ * These are NOT motion prompts — they describe the SCENE for the image
2451
+ * generator. The motion side (the perfect-loop seal phrase) is appended
2452
+ * separately at the i2v stage. Keeping the two concerns separated lets
2453
+ * users animate the same loop-friendly image with different motion intent
2454
+ * and lets us refine each library independently.
2455
+ */
2456
+ type LoopSubjectCategory = "realistic" | "abstract";
2457
+ interface LoopSubject {
2458
+ readonly id: string;
2459
+ readonly label: string;
2460
+ readonly category: LoopSubjectCategory;
2461
+ readonly description: string;
2462
+ /** Drop-in prompt text for Generate Image. Wired into the prompt input
2463
+ * via FieldMappings, same as Setting / Motion / Mood Parameter nodes. */
2464
+ readonly promptHint: string;
2465
+ }
2466
+ declare const LOOP_SUBJECT_CATEGORY_ORDER: ReadonlyArray<LoopSubjectCategory>;
2467
+ declare const LOOP_SUBJECT_CATEGORY_LABELS: Readonly<Record<LoopSubjectCategory, string>>;
2468
+ declare const LOOP_SUBJECTS: ReadonlyArray<LoopSubject>;
2469
+ declare function getLoopSubject(id: string): LoopSubject | undefined;
2470
+ declare function getLoopSubjectLabel(id: string): string;
2471
+ declare function getLoopSubjectPromptHint(id: string): string;
2472
+
2473
+ /**
2474
+ * Canonical catalog of material presets ("Material").
2475
+ *
2476
+ * Material dimension — *what something is made of*. Works universally across
2477
+ * subjects (clothing, skin, body) and objects (furniture, vehicles, props,
2478
+ * surfaces). The same catalog can describe a silk dress, a chrome sculpture of
2479
+ * a person, a leather pillow, or a plastic train.
2480
+ *
2481
+ * Grammar: every entry's `promptHint` begins with `"made of ..."` — this reads
2482
+ * correctly regardless of target ("a dress made of silk", "a human made of
2483
+ * glass", "a pillow made of leather", "a train made of plastic").
2484
+ *
2485
+ * For clothing-specific phrasing ("wearing silk"), see the `fabric` dimension
2486
+ * on the Styling node. There is intentional overlap in vocabulary (leather,
2487
+ * silk, velvet appear in both) — Material uses the universal `"made of"`
2488
+ * grammar, Fabric uses the wardrobe-native `"wearing"` grammar.
2489
+ *
2490
+ * Shared between the picker UI, the standalone Material parameter node, and
2491
+ * the prompt-hint injection on both the frontend DAG executor and the
2492
+ * backend orchestrator.
2493
+ */
2494
+ type MaterialCategory = "fabric" | "metal" | "stone" | "wood" | "glass-ceramic" | "natural" | "exotic";
2495
+ interface Material {
2496
+ readonly id: string;
2497
+ readonly label: string;
2498
+ readonly category: MaterialCategory;
2499
+ readonly description: string;
2500
+ readonly promptHint: string;
2501
+ }
2502
+ declare const MATERIALS: ReadonlyArray<Material>;
2503
+ declare function getMaterial(id: string | undefined | null): Material | undefined;
2504
+ declare function getMaterialLabel(id: string | undefined | null, fallback?: string): string;
2505
+ declare function getMaterialPromptHint(id: string | undefined | null): string;
2506
+ /**
2507
+ * Multi-pick: 1-2 material ids → composite material clause. Single → entry's
2508
+ * own promptHint. Two → "made of {A} and {B}" using lowercased entry labels.
2509
+ * Covers leather+brass handbag, wood+steel chair, glass+chrome lamp, etc.
2510
+ */
2511
+ declare function buildMaterialHints(value: unknown): string;
2512
+ declare const MATERIAL_IDS: ReadonlyArray<string>;
2513
+ declare const MATERIAL_CATEGORY_LABELS: Readonly<Record<MaterialCategory, string>>;
2514
+ declare const MATERIAL_CATEGORY_ORDER: ReadonlyArray<MaterialCategory>;
2515
+
2516
+ /**
2517
+ * Canonical catalog of Mood / emotional-state choices.
2518
+ *
2519
+ * Single-pick parameter node — user picks ONE mood that describes the
2520
+ * subject's emotional state. The promptHint captures the natural
2521
+ * consequence on face + body language (a happy mood → "with a warm smile
2522
+ * and bright eyes", a fierce mood → "with an intense, fierce expression").
2523
+ *
2524
+ * Separate from:
2525
+ * - Tone (the overall content/writing tone — sarcastic, playful, formal)
2526
+ * - Atmosphere (what's in the air — fog, rain, dust)
2527
+ * - Style (artistic medium — oil painting, photorealistic)
2528
+ *
2529
+ * Applies to both image and video consumers (mood describes the subject,
2530
+ * not video-specific). Not in STILL_IMAGE_EXCLUDE_TYPES.
2531
+ *
2532
+ * Includes pre/post free-text fields (same pattern as Person) for
2533
+ * specifics the catalog can't express ("restrained grief", "crying with
2534
+ * relief", etc.).
2535
+ *
2536
+ * Shared between the picker UI, the standalone Mood parameter node, and
2537
+ * the prompt-hint injection on both the frontend DAG executor and the
2538
+ * backend orchestrator.
2539
+ */
2540
+ type MoodCategory = "positive" | "negative" | "neutral" | "intense";
2541
+ interface Mood {
2542
+ readonly id: string;
2543
+ readonly label: string;
2544
+ readonly category: MoodCategory;
2545
+ readonly description: string;
2546
+ readonly promptHint: string;
2547
+ }
2548
+ declare const MOODS: ReadonlyArray<Mood>;
2549
+ declare function getMood(id: string | undefined | null): Mood | undefined;
2550
+ declare function getMoodLabel(id: string | undefined | null, fallback?: string): string;
2551
+ declare function getMoodPromptHint(id: string | undefined | null): string;
2552
+ declare const MOOD_IDS: ReadonlyArray<string>;
2553
+ declare const MOOD_CATEGORY_LABELS: Readonly<Record<MoodCategory, string>>;
2554
+ declare const MOOD_CATEGORY_ORDER: ReadonlyArray<MoodCategory>;
2555
+ /**
2556
+ * Shape of Mood parameter data. Single id OR array of up to 2 ids (mixed
2557
+ * mood like "smirking + aloof"). Plus optional pre/post free text.
2558
+ */
2559
+ interface MoodValue {
2560
+ mood?: string | ReadonlyArray<string>;
2561
+ preText?: string;
2562
+ postText?: string;
2563
+ }
2564
+ /**
2565
+ * Build prompt hints from MoodData: optional pre-text, the selected mood's
2566
+ * hint (single or mixed), optional post-text. Returns array — caller joins
2567
+ * with ", ".
2568
+ */
2569
+ declare function buildMoodHints(data: Record<string, unknown> & MoodValue): string[];
2570
+
2571
+ /**
2572
+ * Canonical catalog of music genres for Suno / MiniMax / Text-to-Audio
2573
+ * prompt composition. Shared between frontend (picker UI), backend
2574
+ * orchestrator (payload-builder), and frontend DAG executor.
2575
+ *
2576
+ * Each entry's `promptHint` is the natural-language fragment injected into
2577
+ * the consumer's style/prompt field by `composeSoundHintFromConnections`.
2578
+ *
2579
+ * Top-level genres carry a `category` field used by the picker to render a
2580
+ * horizontal tab row (mirrors PersonPicker.ethnicity grouping). Categories
2581
+ * are Splice-aligned (https://splice.com/sounds/genres) so the taxonomy
2582
+ * matches industry conventions.
2583
+ */
2584
+ type MusicGenreCategory = "hip-hop-rnb" | "electronic" | "pop" | "rock-metal" | "acoustic" | "global" | "cinematic";
2585
+ declare const MUSIC_GENRE_CATEGORY_ORDER: ReadonlyArray<MusicGenreCategory>;
2586
+ declare const MUSIC_GENRE_CATEGORY_LABELS: Readonly<Record<MusicGenreCategory, string>>;
2587
+ interface MusicSubgenre {
2588
+ readonly id: string;
2589
+ readonly label: string;
2590
+ readonly promptHint: string;
2591
+ }
2592
+ interface MusicGenre {
2593
+ readonly id: string;
2594
+ readonly label: string;
2595
+ readonly description: string;
2596
+ readonly promptHint: string;
2597
+ readonly category: MusicGenreCategory;
2598
+ readonly subgenres: ReadonlyArray<MusicSubgenre>;
2599
+ }
2600
+ interface MusicEra {
2601
+ readonly id: string;
2602
+ readonly label: string;
2603
+ readonly description: string;
2604
+ readonly promptHint: string;
2605
+ }
2606
+ declare const MUSIC_GENRES: ReadonlyArray<MusicGenre>;
2607
+ declare const MUSIC_ERAS: ReadonlyArray<MusicEra>;
2608
+ declare function getMusicGenre(id: string | undefined): MusicGenre | undefined;
2609
+ declare function getMusicGenreLabel(id: string | undefined): string;
2610
+ declare function getMusicSubgenre(genreId: string | undefined, subgenreId: string | undefined): MusicSubgenre | undefined;
2611
+ declare function getMusicEra(id: string | undefined): MusicEra | undefined;
2612
+ /**
2613
+ * Compose hints from MusicGenreData: optional preText, structured
2614
+ * [era] [subgenre|genre] (or " / "-joined genres for multi), optional
2615
+ * postText. Returns array — caller joins with ", " (matches buildMoodHints
2616
+ * / buildPersonHints pattern).
2617
+ *
2618
+ * Multi-genre (genre is an array): emit each genre's hint joined with " / "
2619
+ * — subgenre is ignored in multi-mode (subgenre is meaningful only against
2620
+ * a single chosen genre).
2621
+ */
2622
+ declare function buildMusicGenreHints(data: {
2623
+ readonly preText?: string;
2624
+ readonly postText?: string;
2625
+ readonly genre?: string | ReadonlyArray<string>;
2626
+ readonly subgenre?: string;
2627
+ readonly era?: string;
2628
+ }): string;
2629
+ /** Default data when a music-genre node is dropped on canvas. Empty by design — forces a deliberate pick. */
2630
+ declare const MUSIC_GENRE_DEFAULT_DATA: {
2631
+ preText?: string;
2632
+ postText?: string;
2633
+ genre?: string | ReadonlyArray<string>;
2634
+ subgenre?: string;
2635
+ era?: string;
2636
+ };
2637
+
2638
+ /**
2639
+ * Music mood catalog: energy + emotion + vibe sub-fields.
2640
+ * Composed by buildMusicMoodHints into "[energy] [emotion] [vibe]".
2641
+ */
2642
+ interface MusicMoodEntry {
2643
+ readonly id: string;
2644
+ readonly label: string;
2645
+ readonly description: string;
2646
+ readonly promptHint: string;
2647
+ }
2648
+ declare const MUSIC_ENERGIES: ReadonlyArray<MusicMoodEntry>;
2649
+ declare const MUSIC_EMOTIONS: ReadonlyArray<MusicMoodEntry>;
2650
+ declare const MUSIC_VIBES: ReadonlyArray<MusicMoodEntry>;
2651
+ declare function getMusicEnergy(id: string | undefined): MusicMoodEntry | undefined;
2652
+ declare function getMusicEmotion(id: string | undefined): MusicMoodEntry | undefined;
2653
+ declare function getMusicVibe(id: string | undefined): MusicMoodEntry | undefined;
2654
+ declare function buildMusicMoodHints(data: {
2655
+ readonly preText?: string;
2656
+ readonly postText?: string;
2657
+ readonly energy?: string;
2658
+ readonly emotion?: string | ReadonlyArray<string>;
2659
+ readonly vibe?: string | ReadonlyArray<string>;
2660
+ }): string;
2661
+ declare const MUSIC_MOOD_DEFAULT_DATA: {
2662
+ preText?: string;
2663
+ postText?: string;
2664
+ energy?: string;
2665
+ emotion?: string | ReadonlyArray<string>;
2666
+ vibe?: string | ReadonlyArray<string>;
2667
+ };
2668
+
2669
+ /**
2670
+ * Canonical catalog of Photo Genre / Photographic Intent presets.
2671
+ *
2672
+ * Single-pick parameter node — user picks ONE photographic genre that
2673
+ * bundles a packed set of conventions: lighting, framing, wardrobe
2674
+ * implications, color grading, and tabloid/editorial/selfie context. A
2675
+ * single photo-genre selection therefore acts as a meta-preset that
2676
+ * pushes the downstream prompt toward a recognizable style of image.
2677
+ *
2678
+ * Distinct from:
2679
+ * - Style (artistic medium — oil painting, anime, photorealistic)
2680
+ * - Setting (where the photo takes place)
2681
+ * - Framing (shot size + angle composition)
2682
+ * - Lighting (key/rim/fill direction and quality)
2683
+ *
2684
+ * Photo Genre is the "what kind of photograph is this trying to be"
2685
+ * dimension — paparazzi vs corporate headshot vs gym mirror selfie vs
2686
+ * Vogue editorial. Each promptHint is authored to bundle the canonical
2687
+ * markers of that genre in one descriptive clause, so connecting just
2688
+ * this node moves the image squarely into that recognizable genre.
2689
+ *
2690
+ * Applies to both image and video consumers (genre conventions cover
2691
+ * both still and motion). Not in STILL_IMAGE_EXCLUDE_TYPES.
2692
+ *
2693
+ * Shared between the picker UI, the standalone Photo Genre parameter
2694
+ * node, and the prompt-hint injection on both the frontend DAG executor
2695
+ * and the backend orchestrator.
2696
+ */
2697
+ type PhotoGenreCategory = "editorial" | "documentary" | "studio-formal" | "selfie" | "print-context" | "lifestyle" | "commercial";
2698
+ interface PhotoGenre {
2699
+ readonly id: string;
2700
+ readonly label: string;
2701
+ readonly category: PhotoGenreCategory;
2702
+ readonly description: string;
2703
+ readonly promptHint: string;
2704
+ }
2705
+ declare const PHOTO_GENRES: ReadonlyArray<PhotoGenre>;
2706
+ declare function getPhotoGenre(id: string | undefined | null): PhotoGenre | undefined;
2707
+ declare function getPhotoGenreLabel(id: string | undefined | null, fallback?: string): string;
2708
+ declare function getPhotoGenrePromptHint(id: string | undefined | null): string;
2709
+ declare const PHOTO_GENRE_IDS: ReadonlyArray<string>;
2710
+ declare const PHOTO_GENRE_CATEGORY_LABELS: Readonly<Record<PhotoGenreCategory, string>>;
2711
+ declare const PHOTO_GENRE_CATEGORY_ORDER: ReadonlyArray<PhotoGenreCategory>;
2712
+
2713
+ /**
2714
+ * Canonical catalog of Photographer / Artist Style choices.
2715
+ *
2716
+ * Single-pick parameter node — user picks ONE photographer or illustrator
2717
+ * whose visual signature should drive the look. Each promptHint pairs the
2718
+ * artist's name with a couple of distinguishing visual cues, because
2719
+ * generative models recognise both the name token and the descriptive
2720
+ * vocabulary that surrounds it. Names alone tend to be too vague.
2721
+ *
2722
+ * Categories:
2723
+ * - editorial: fashion / editorial photographers (dreamy painterly look)
2724
+ * - documentary: documentary, street, photojournalism
2725
+ * - cinematographer: working DPs whose work translates well to stills
2726
+ * - concept: digital painters, concept artists, fantasy illustrators
2727
+ * - illustrator: illustrators, animators, art-nouveau / classical artists
2728
+ *
2729
+ * Shared between the picker UI, the standalone Photographer parameter node,
2730
+ * and the prompt-hint injection on both the frontend DAG executor and the
2731
+ * backend orchestrator.
2732
+ */
2733
+ type PhotographerCategory = "editorial" | "documentary" | "cinematographer" | "concept" | "illustrator";
2734
+ interface Photographer {
2735
+ readonly id: string;
2736
+ readonly label: string;
2737
+ readonly category: PhotographerCategory;
2738
+ readonly description: string;
2739
+ readonly promptHint: string;
2740
+ }
2741
+ declare const PHOTOGRAPHERS: ReadonlyArray<Photographer>;
2742
+ declare function getPhotographer(id: string | undefined | null): Photographer | undefined;
2743
+ declare function getPhotographerLabel(id: string | undefined | null, fallback?: string): string;
2744
+ declare function getPhotographerPromptHint(id: string | undefined | null): string;
2745
+ /**
2746
+ * Multi-pick variant: 1-2 photographer ids → blended hint. Single → entry's
2747
+ * own promptHint. Two → "shot in the blended language of {A} and {B}" — the
2748
+ * model interprets this as referencing both creators' visual signatures.
2749
+ */
2750
+ declare function buildPhotographerHints(value: unknown): string;
2751
+ declare const PHOTOGRAPHER_IDS: ReadonlyArray<string>;
2752
+ declare const PHOTOGRAPHER_CATEGORY_LABELS: Readonly<Record<PhotographerCategory, string>>;
2753
+ declare const PHOTOGRAPHER_CATEGORY_ORDER: ReadonlyArray<PhotographerCategory>;
2754
+
2755
+ /**
2756
+ * Canonical catalog of Pose / posture + action choices.
2757
+ *
2758
+ * Single-pick parameter node — user picks ONE pose that describes the
2759
+ * subject's body position + action. Covers both static poses ("standing
2760
+ * upright") and dynamic action ("mid-stride, running").
2761
+ *
2762
+ * Separate from:
2763
+ * - Framing → Vantage (azimuth of camera around subject, not subject pose)
2764
+ * - Camera Motion (how the camera moves, not the subject)
2765
+ *
2766
+ * Applies to both image and video consumers (pose describes the subject,
2767
+ * not video-specific). Not in STILL_IMAGE_EXCLUDE_TYPES.
2768
+ *
2769
+ * Includes pre/post free-text fields (same pattern as Person) for
2770
+ * specifics the catalog can't express ("mid-fall, arms flailing", etc.).
2771
+ *
2772
+ * Shared between the picker UI, the standalone Pose parameter node, and
2773
+ * the prompt-hint injection on both the frontend DAG executor and the
2774
+ * backend orchestrator.
2775
+ */
2776
+ type PoseCategory = "standing" | "seated" | "movement" | "action" | "resting" | "hand-position" | "body-lean" | "head-tilt" | "activity";
2777
+ interface Pose {
2778
+ readonly id: string;
2779
+ readonly label: string;
2780
+ readonly category: PoseCategory;
2781
+ readonly description: string;
2782
+ readonly promptHint: string;
2783
+ }
2784
+ declare const POSES: ReadonlyArray<Pose>;
2785
+ declare function getPose(id: string | undefined | null): Pose | undefined;
2786
+ declare function getPoseLabel(id: string | undefined | null, fallback?: string): string;
2787
+ declare function getPosePromptHint(id: string | undefined | null): string;
2788
+ declare const POSE_IDS: ReadonlyArray<string>;
2789
+ declare const POSE_CATEGORY_LABELS: Readonly<Record<PoseCategory, string>>;
2790
+ declare const POSE_CATEGORY_ORDER: ReadonlyArray<PoseCategory>;
2791
+ /**
2792
+ * Shape of Pose parameter data. Multi-dimensional: pose + optional
2793
+ * orthogonal sub-pickers (hand position / body lean / head tilt) + optional
2794
+ * pre/post free text.
2795
+ */
2796
+ interface PoseValue {
2797
+ pose?: string;
2798
+ /** Optional hand-position pose id (orthogonal to pose). */
2799
+ handPosition?: string;
2800
+ /** Optional body-lean pose id (orthogonal to pose). */
2801
+ bodyLean?: string;
2802
+ /** Optional head-tilt pose id (orthogonal to pose). */
2803
+ headTilt?: string;
2804
+ /** Optional activity pose id — what the subject is DOING in the world
2805
+ * (smoking, eating, texting, driving…). Distinct from posture / movement /
2806
+ * action; orthogonal to the other sub-pickers. */
2807
+ activity?: string;
2808
+ preText?: string;
2809
+ postText?: string;
2810
+ }
2811
+ /**
2812
+ * Build prompt hints from PoseData: optional pre-text, the selected pose's
2813
+ * hint, the orthogonal hand-position / body-lean / head-tilt hints,
2814
+ * optional post-text. Returns array — caller joins with ", ".
2815
+ */
2816
+ declare function buildPoseHints(data: Record<string, unknown> & PoseValue): string[];
2817
+
2818
+ /**
2819
+ * Canonical catalog of Post-Process Effects choices.
2820
+ *
2821
+ * Post-process effects describe an image-level grade or processing pass
2822
+ * applied AFTER the image is captured / rendered — vignette, grain, halation,
2823
+ * bloom, chromatic aberration, light leaks, scratches, soft-focus diffusion,
2824
+ * dodge-and-burn, etc. These are the touches a colorist or photographer
2825
+ * applies in the darkroom or grading suite.
2826
+ *
2827
+ * Distinct from:
2828
+ * - Style — the artistic medium (oil paint, watercolor, anime).
2829
+ * - Composition Effects — what the subject is made of or how it interacts
2830
+ * with the frame (smoke sculpture, exploding particles, breaking the
2831
+ * fourth wall).
2832
+ * - Color Look — overall color grade direction (teal-orange, pastel, mono).
2833
+ * - Atmosphere — what's in the air (fog, dust, rain).
2834
+ *
2835
+ * Single-pick — only one post-process pass is applied per consumer.
2836
+ *
2837
+ * Shared between picker UI and prompt-hint injection in the frontend DAG
2838
+ * executor and the backend orchestrator.
2839
+ */
2840
+ interface PostProcessEffect {
2841
+ readonly id: string;
2842
+ readonly label: string;
2843
+ readonly description: string;
2844
+ readonly promptHint: string;
2845
+ }
2846
+ declare const POST_PROCESS_EFFECTS: ReadonlyArray<PostProcessEffect>;
2847
+ declare function getPostProcessEffect(id: string | undefined | null): PostProcessEffect | undefined;
2848
+ declare function getPostProcessEffectLabel(id: string | undefined | null, fallback?: string): string;
2849
+ declare function getPostProcessEffectPromptHint(id: string | undefined | null): string;
2850
+ /**
2851
+ * Multi-pick: 1-2 post-process effect ids → composite grading clause.
2852
+ * Common pairs: vignette + film-grain, halation + bloom, dodge-burn +
2853
+ * chromatic-aberration. Each entry already describes a complete grading
2854
+ * pass, so we emit independently and let the comma-join compose them.
2855
+ */
2856
+ declare function buildPostProcessHints(value: unknown): string[];
2857
+ declare const POST_PROCESS_EFFECT_IDS: ReadonlyArray<string>;
2858
+
2859
+ /**
2860
+ * Canonical catalog of Render Engine / Quality presets.
2861
+ *
2862
+ * "Render Quality" is the pure technical-stamp dimension — what tool the image
2863
+ * appears to have been rendered through, or what quality stamp it carries.
2864
+ * Distinct from Style (artistic medium), Lens (optics), and Camera Format
2865
+ * (capture medium): a "raytracing" hint says nothing about whether the look
2866
+ * is anime or photorealistic; it just promises ray-traced-grade reflections,
2867
+ * shadows, and global illumination.
2868
+ *
2869
+ * Three loose families, each adding a different kind of authority signal:
2870
+ * - Engines: name a real render package (Unreal 5, Octane, Cycles…). Useful
2871
+ * for hyper-stylized 3D illustration or game-trailer aesthetics.
2872
+ * - Render-quality keywords: the technical buzzwords that lock in modern
2873
+ * physically-correct lighting (raytracing, PBR, GI, lumen).
2874
+ * - Resolution / Detail: explicit "sharp + detailed" stamps (4K/8K/16K,
2875
+ * "ultra-detailed").
2876
+ * - Style stamps: portmanteau quality markers ("masterpiece", "raw photo",
2877
+ * "award-winning") that providers strongly weight.
2878
+ *
2879
+ * Single-pick — only one render-quality stamp is applied per consumer. Shared
2880
+ * between picker UI and prompt-hint injection in the frontend DAG executor
2881
+ * and the backend orchestrator.
2882
+ */
2883
+ interface RenderQuality {
2884
+ readonly id: string;
2885
+ readonly label: string;
2886
+ readonly description: string;
2887
+ readonly promptHint: string;
2888
+ }
2889
+ declare const RENDER_QUALITIES: ReadonlyArray<RenderQuality>;
2890
+ declare function getRenderQuality(id: string | undefined | null): RenderQuality | undefined;
2891
+ declare function getRenderQualityLabel(id: string | undefined | null, fallback?: string): string;
2892
+ declare function getRenderQualityPromptHint(id: string | undefined | null): string;
2893
+ declare const RENDER_QUALITY_IDS: ReadonlyArray<string>;
2894
+
2895
+ /**
2896
+ * Canonical catalog of place/environment presets ("Setting").
2897
+ *
2898
+ * Setting dimension of an image/video — *where* the shot takes place (coffee
2899
+ * shop, forest clearing, cyberpunk alley, cathedral, etc.). Orthogonal to the
2900
+ * other cinematography dimensions:
2901
+ *
2902
+ * - Style = artistic medium (Oil Painting, Pixar 3D, Photorealistic)
2903
+ * - Atmosphere = what's in the air (Fog, Rain, God rays, Dust)
2904
+ * - Lighting = direction / quality of light
2905
+ * - Setting = *where* (this file)
2906
+ *
2907
+ * Not to be confused with the Location **entity** node, which generates a
2908
+ * persistent reference image for a specific place via an AI provider call.
2909
+ * Setting is pure prompt text (zero credits, zero API calls), deterministic.
2910
+ *
2911
+ * Shared between the picker UI, the standalone Setting parameter node, and
2912
+ * the prompt-hint injection on both the frontend DAG executor and the
2913
+ * backend orchestrator.
2914
+ */
2915
+ type SettingCategory = "indoor" | "urban" | "nature" | "fantastical";
2916
+ interface Setting {
2917
+ readonly id: string;
2918
+ readonly label: string;
2919
+ readonly category: SettingCategory;
2920
+ readonly description: string;
2921
+ readonly promptHint: string;
2922
+ }
2923
+ declare const SETTINGS: ReadonlyArray<Setting>;
2924
+ declare function getSetting(id: string | undefined | null): Setting | undefined;
2925
+ declare function getSettingLabel(id: string | undefined | null, fallback?: string): string;
2926
+ declare function getSettingPromptHint(id: string | undefined | null): string;
2927
+ declare const SETTING_IDS: ReadonlyArray<string>;
2928
+ declare const SETTING_CATEGORY_LABELS: Readonly<Record<SettingCategory, string>>;
2929
+
2930
+ /**
2931
+ * Canonical catalog of image style presets.
2932
+ *
2933
+ * Style dimension of an image/video — the overall artistic rendering or
2934
+ * medium (anime, oil painting, photorealistic, etc.). Independent of
2935
+ * lighting (direction/color of light), color/look (post-processing grade),
2936
+ * atmosphere (environmental effects), lens (focal length distortion), and
2937
+ * framing (composition). Two shots with identical lighting, lens and
2938
+ * framing still look radically different when one is "Oil Painting" and
2939
+ * the other is "Pixel Art".
2940
+ *
2941
+ * Shared between the picker UI, the standalone Style parameter node, the
2942
+ * inline Style dropdown in image config panels (backward-compat), and the
2943
+ * prompt-hint injection on both the frontend DAG executor and the backend
2944
+ * orchestrator.
2945
+ *
2946
+ * The `id` values are kept in sync with `IMAGE_STYLE_PRESETS` in
2947
+ * `frontend/src/components/editor/config-panels/model-options.ts` so the
2948
+ * inline dropdown and the Style node resolve to the same richer promptHint
2949
+ * at execution time.
2950
+ */
2951
+ interface Style {
2952
+ readonly id: string;
2953
+ readonly label: string;
2954
+ readonly description: string;
2955
+ readonly promptHint: string;
2956
+ }
2957
+ declare const STYLES: ReadonlyArray<Style>;
2958
+ declare function getStyle(id: string | undefined | null): Style | undefined;
2959
+ declare function getStyleLabel(id: string | undefined | null, fallback?: string): string;
2960
+ declare function getStylePromptHint(id: string | undefined | null): string;
2961
+ declare const STYLE_IDS: ReadonlyArray<string>;
2962
+
2963
+ /**
2964
+ * Canonical catalog of Styling / beauty + wardrobe + accessories choices.
2965
+ *
2966
+ * Multi-dimension parameter node like Person and Framing:
2967
+ *
2968
+ * Beauty / Hair / Accessories
2969
+ * 1. makeup — Natural, glamour, smoky, goth, bold lips, editorial, dewy…
2970
+ * 2. hair-cut — Pixie, bob, buzz cut, pompadour, dreadlocks, braids (45 entries)
2971
+ * 3. hair-treatment — Babylights, balayage, ombré, highlights…
2972
+ * 4. hair-state — Wet, messy, windswept, voluminous, sleek, frizzy,
2973
+ * tousled, flowing… Hair motion / condition. Distinct
2974
+ * from cut (shape) and treatment (color).
2975
+ * 5. eyewear — Sunglasses (aviators / cat-eye / round), fashion glasses…
2976
+ * 6. headwear — Hats (beanie, cap, fedora…), headbands, hoods, crowns
2977
+ * 7. jewelry — Subtle, statement, gold, silver, layered, pearl
2978
+ * 8. nails — Polished, red, dark, long acrylic, French tips
2979
+ * 9. face-paint — Subtle, dramatic, costume, tribal markings
2980
+ *
2981
+ * Wardrobe (head-to-toe garments)
2982
+ * 10. outfit — Single-pick complete look (school uniform, business
2983
+ * suit, evening gown, scrubs, bikini, lingerie, kimono…).
2984
+ * Intended as an override that semantically supersedes
2985
+ * the per-piece selections; users are responsible for
2986
+ * not stacking conflicting pieces.
2987
+ * 11. top — Upper-body garment (t-shirt, hoodie, sweater, blouse,
2988
+ * crop top, bikini top, sports bra…)
2989
+ * 12. bottom — Lower-body garment (jeans, chinos, skirt, shorts,
2990
+ * leggings, sweatpants…)
2991
+ * 13. outerwear — Layered-over outer garment (leather jacket, blazer,
2992
+ * trench, puffer, cardigan, kimono robe…)
2993
+ * 14. legwear — Stockings / tights / socks worn between bottom and
2994
+ * footwear (sheer / opaque tights, fishnets, thigh-highs…)
2995
+ * 15. footwear — Shoes (sneakers, heels, boots, loafers, sandals…)
2996
+ *
2997
+ * Modifiers
2998
+ * 16. fabric — Clothing fabric (silk, leather, denim, velvet…) phrased
2999
+ * as "wearing X". Overlaps vocabulary with the universal
3000
+ * Material node in the Object category, but Fabric is
3001
+ * clothing-specific and scoped to the Subject workflow.
3002
+ * 17. wardrobe-state — How the clothes are worn (oversized, fitted, cropped,
3003
+ * sheer, wet, ripped, off-shoulder, tucked-in, layered,
3004
+ * unbuttoned…). Composes with any garment selection.
3005
+ *
3006
+ * Each dimension is mutually exclusive within itself; all are optional.
3007
+ * Applies to BOTH image and video consumers. Includes pre/post free-text
3008
+ * fields for specifics the catalog can't express.
3009
+ */
3010
+ type StylingDimension = "makeup" | "eyewear" | "headwear" | "hair-cut" | "hair-treatment" | "hair-state" | "jewelry" | "nails" | "face-paint" | "outfit" | "top" | "bottom" | "outerwear" | "legwear" | "footwear" | "fabric" | "wardrobe-state";
3011
+ interface Styling {
3012
+ readonly id: string;
3013
+ readonly label: string;
3014
+ readonly dimension: StylingDimension;
3015
+ readonly description: string;
3016
+ readonly promptHint: string;
3017
+ }
3018
+ declare const STYLINGS: ReadonlyArray<Styling>;
3019
+ declare const STYLING_DIMENSION_ORDER: ReadonlyArray<StylingDimension>;
3020
+ declare const STYLING_DIMENSION_LABELS: Readonly<Record<StylingDimension, string>>;
3021
+ declare const STYLING_FIELD_BY_DIMENSION: Record<StylingDimension, "makeup" | "eyewear" | "headwear" | "hairCut" | "hairTreatment" | "hairState" | "jewelry" | "nails" | "facePaint" | "outfit" | "top" | "bottom" | "outerwear" | "legwear" | "footwear" | "fabric" | "wardrobeState">;
3022
+ /** Per-dimension multi-select cap — single source of truth for the picker UI,
3023
+ * the image-analyzer tool schema, and the Zod validator. jewelry: 3
3024
+ * (necklace + earrings + rings), wardrobe-state: 3 (oversized + wet + ripped),
3025
+ * hair-state: 2 (wet + windswept). All others single-select (absent → 1). */
3026
+ declare const MAX_SELECTED_BY_STYLING_DIMENSION: Partial<Record<StylingDimension, number>>;
3027
+ /** Selection limit for a styling dimension (1 when not multi-select). */
3028
+ declare function getStylingDimensionLimit(dimension: StylingDimension): number;
3029
+ interface StylingValue {
3030
+ makeup?: string;
3031
+ eyewear?: string;
3032
+ headwear?: string;
3033
+ /** Hair cut / styling choice — bob, wolf cut, braids, ponytail, etc.
3034
+ * Pairs with Person.hair-base (texture + length). */
3035
+ hairCut?: string;
3036
+ hairTreatment?: string;
3037
+ /** Hair state / motion / condition — wet, messy, windswept, voluminous,
3038
+ * sleek, frizzy, tousled, flowing… Distinct from cut (shape) and
3039
+ * treatment (color processing). Single id or up to 2 (e.g.
3040
+ * ["wet", "windswept"], ["messy", "voluminous"]). */
3041
+ hairState?: string | ReadonlyArray<string>;
3042
+ /** Jewelry. Single id or up to 3 ids for stacked jewelry
3043
+ * (e.g. necklace + earrings + rings). */
3044
+ jewelry?: string | ReadonlyArray<string>;
3045
+ nails?: string;
3046
+ facePaint?: string;
3047
+ /** Single-pick complete outfit archetype (school uniform, business suit,
3048
+ * evening gown, scrubs, bikini, lingerie, kimono…). Intended as an override
3049
+ * that semantically supersedes the per-piece selections. */
3050
+ outfit?: string;
3051
+ /** Upper-body garment (t-shirt, sweater, blouse, sports bra, bikini top…). */
3052
+ top?: string;
3053
+ /** Lower-body garment (jeans, chinos, skirt, shorts, leggings…). */
3054
+ bottom?: string;
3055
+ /** Layered-over outer garment (jacket, blazer, coat, cardigan…). */
3056
+ outerwear?: string;
3057
+ /** Legwear worn between bottom and footwear (tights, fishnets, stockings, socks…). */
3058
+ legwear?: string;
3059
+ /** Shoes (sneakers, heels, boots, loafers, sandals…). */
3060
+ footwear?: string;
3061
+ /** Clothing fabric / material — silk, leather, denim, etc. Phrased as
3062
+ * "wearing X"; overlaps in vocabulary with the universal Material node
3063
+ * in the Object category. */
3064
+ fabric?: string;
3065
+ /** How the clothes are worn — oversized, fitted, cropped, sheer, wet,
3066
+ * ripped, off-shoulder, tucked-in, layered, unbuttoned… Composes with
3067
+ * any garment selection. Single id or up to 3 ids for stacked
3068
+ * modifiers (e.g. ["oversized", "wet", "ripped"]). */
3069
+ wardrobeState?: string | ReadonlyArray<string>;
3070
+ preText?: string;
3071
+ postText?: string;
3072
+ }
3073
+ declare function getStyling(id: string | undefined | null): Styling | undefined;
3074
+ declare function getStylingLabel(id: string | undefined | null, fallback?: string): string;
3075
+ declare function getStylingPromptHint(id: string | undefined | null): string;
3076
+ declare const STYLING_IDS: ReadonlyArray<string>;
3077
+ declare function buildStylingHints(data: Record<string, unknown> & StylingValue): string[];
3078
+
3079
+ /**
3080
+ * Canonical catalog of temporal modifiers.
3081
+ *
3082
+ * Temporal is the speed / freeze / direction / shutter dimension of a video —
3083
+ * how time flows through the shot. Distinct from the post-process Speed Ramp
3084
+ * FFmpeg node (which operates on an existing rendered video); these are
3085
+ * prompt-time guidance hints for the generator model so it produces footage
3086
+ * that already embeds the temporal intent. Independent of lighting, color,
3087
+ * lens, camera motion, etc.
3088
+ *
3089
+ * Video-only: stills can't have motion or a speed, so image-gen consumers
3090
+ * don't read this field.
3091
+ *
3092
+ * Shared between the picker UI and the prompt-hint injection on both the
3093
+ * frontend DAG executor and the backend orchestrator.
3094
+ */
3095
+ type TemporalCategory = "speed" | "freeze" | "direction" | "shutter";
3096
+ interface Temporal {
3097
+ readonly id: string;
3098
+ readonly label: string;
3099
+ readonly category: TemporalCategory;
3100
+ readonly description: string;
3101
+ readonly promptHint: string;
3102
+ }
3103
+ declare const TEMPORALS: ReadonlyArray<Temporal>;
3104
+ declare const TEMPORAL_CATEGORY_ORDER: ReadonlyArray<TemporalCategory>;
3105
+ declare const TEMPORAL_CATEGORY_LABELS: Record<TemporalCategory, string>;
3106
+ declare function getTemporal(id: string | undefined | null): Temporal | undefined;
3107
+ declare function getTemporalLabel(id: string | undefined | null, fallback?: string): string;
3108
+ declare function getTemporalPromptHint(id: string | undefined | null): string;
3109
+ declare const TEMPORAL_IDS: ReadonlyArray<string>;
3110
+ /**
3111
+ * Maps each TemporalCategory to the consumer data field name that holds the
3112
+ * selected entry id for that category. Multi-category temporal: a consumer
3113
+ * (video-only) can independently set a value in each of the 4 dimensions.
3114
+ *
3115
+ * Field names use 'temporal' prefix throughout to avoid collisions: 'direction'
3116
+ * collides with Lighting's 'direction' category; 'speed', 'shutter', and
3117
+ * 'freeze' are generic vocabulary.
3118
+ */
3119
+ declare const TEMPORAL_FIELD_BY_CATEGORY: Record<TemporalCategory, "temporalSpeed" | "temporalFreeze" | "temporalDirection" | "temporalShutter">;
3120
+ /**
3121
+ * Shape of the per-category temporal fields on TemporalData and the 5 video
3122
+ * consumer data types. All fields optional — user may set zero, one, or all
3123
+ * categories.
3124
+ */
3125
+ interface TemporalValue {
3126
+ temporalSpeed?: string;
3127
+ temporalFreeze?: string;
3128
+ temporalDirection?: string;
3129
+ temporalShutter?: string;
3130
+ }
3131
+ /**
3132
+ * Aggregate all enabled per-category temporal prompt hints from a consumer's
3133
+ * data, in canonical category order (speed, freeze, direction, shutter).
3134
+ *
3135
+ * Accepts a loosely typed record (the helper is shared between strongly typed
3136
+ * frontend node data and the backend's `Record<string, unknown>` workflow
3137
+ * data). Non-string values are ignored.
3138
+ *
3139
+ * @param data the consumer data record (must include optional temporalSpeed /
3140
+ * temporalFreeze / temporalDirection / temporalShutter fields)
3141
+ */
3142
+ declare function buildTemporalHints(data: Record<string, unknown> & {
3143
+ temporalSpeed?: unknown;
3144
+ temporalFreeze?: unknown;
3145
+ temporalDirection?: unknown;
3146
+ temporalShutter?: unknown;
3147
+ }): string[];
3148
+
3149
+ /**
3150
+ * Canonical catalog of cinematic transitions for AI-video generation.
3151
+ *
3152
+ * Shared between frontend (picker UI, prompt hint injection) and backend
3153
+ * (orchestrator payload builder). The `promptHint` is a natural-language
3154
+ * cue that gets composed into the user prompt when a transition node is
3155
+ * connected to a video consumer.
3156
+ *
3157
+ * Multi-pick supported: value field accepts `string | string[]` (cap 2).
3158
+ * Graph-aware: `startState` / `endState` input handles accept upstream
3159
+ * parameter nodes whose hints are folded into the composed clause as
3160
+ * "starting from <X>, ending at <Y>".
3161
+ */
3162
+ type TransitionCategory = "standard" | "time" | "element" | "morph" | "portal" | "physics" | "light" | "glitch";
3163
+ interface Transition {
3164
+ readonly id: string;
3165
+ readonly label: string;
3166
+ readonly category: TransitionCategory;
3167
+ readonly description: string;
3168
+ readonly promptHint: string;
3169
+ }
3170
+ type TransitionPosition = "auto" | "start" | "middle" | "end" | "full";
3171
+ type TransitionDuration = "auto" | "instant" | "short" | "medium" | "long";
3172
+ type TransitionIntensity = "auto" | "subtle" | "natural" | "dynamic" | "crazy";
3173
+ interface TransitionTiming {
3174
+ position?: TransitionPosition;
3175
+ duration?: TransitionDuration;
3176
+ intensity?: TransitionIntensity;
3177
+ }
3178
+ declare const TRANSITIONS: ReadonlyArray<Transition>;
3179
+ declare const TRANSITION_CATEGORY_ORDER: ReadonlyArray<TransitionCategory>;
3180
+ declare const TRANSITION_CATEGORY_LABELS: Readonly<Record<TransitionCategory, string>>;
3181
+ declare function getTransition(id: string | undefined | null): Transition | undefined;
3182
+ declare function getTransitionLabel(id: string | undefined | null, fallback?: string): string;
3183
+ declare function getTransitionPromptHint(id: string | undefined | null): string;
3184
+ declare const TRANSITION_IDS: ReadonlyArray<string>;
3185
+ /**
3186
+ * Compose a structural prompt-hint sentence from a transition id (or array
3187
+ * of 1-2 ids for multi-pick) plus optional start-state/end-state hints
3188
+ * (collected by walking the source node's startState / endState input
3189
+ * handle edges upstream) and optional timing fields.
3190
+ *
3191
+ * Behavior:
3192
+ * - 0 hints (no transition, empty array, or all-empty hints) → ""
3193
+ * - n base hints joined with ", and "
3194
+ * - Timing/start/end clauses apply ONCE at the outer layer, not per-id
3195
+ * - null input is treated like undefined (falsy short-circuit → returns "")
3196
+ */
3197
+ declare function composeTransitionHintFromConnections(transitionId: string | ReadonlyArray<string> | undefined, startHints: ReadonlyArray<string>, endHints: ReadonlyArray<string>, timing?: TransitionTiming): string;
3198
+
3199
+ /**
3200
+ * Voice-character catalog: age + gender + language + accent + timbre. Feeds
3201
+ * Voice Design's voiceDescription field via the Sound aggregator.
3202
+ *
3203
+ * `language` is multi-pick (up to 3) for codeswitching / multilingual
3204
+ * voice work. Distinct from `accent` — accent is HOW it sounds, language
3205
+ * is WHAT'S being spoken.
3206
+ */
3207
+ interface VoiceCharacterEntry {
3208
+ readonly id: string;
3209
+ readonly label: string;
3210
+ readonly description: string;
3211
+ readonly promptHint: string;
3212
+ }
3213
+ declare const VOICE_AGES: ReadonlyArray<VoiceCharacterEntry>;
3214
+ declare const VOICE_GENDERS: ReadonlyArray<VoiceCharacterEntry>;
3215
+ declare const VOICE_LANGUAGES: ReadonlyArray<VoiceCharacterEntry>;
3216
+ declare const VOICE_ACCENTS: ReadonlyArray<VoiceCharacterEntry>;
3217
+ declare const VOICE_TIMBRES: ReadonlyArray<VoiceCharacterEntry>;
3218
+ declare function getVoiceAge(id: string | undefined): VoiceCharacterEntry | undefined;
3219
+ declare function getVoiceGender(id: string | undefined): VoiceCharacterEntry | undefined;
3220
+ declare function getVoiceLanguage(id: string | undefined): VoiceCharacterEntry | undefined;
3221
+ declare function getVoiceAccent(id: string | undefined): VoiceCharacterEntry | undefined;
3222
+ declare function getVoiceTimbre(id: string | undefined): VoiceCharacterEntry | undefined;
3223
+ /**
3224
+ * Compose a natural-language voice character clause.
3225
+ * Examples (depending on which sub-fields are set):
3226
+ * { age, gender, timbre, accent } → "middle-aged male voice with warm timbre and British RP accent"
3227
+ * { timbre } → "warm timbre"
3228
+ * { accent } → "British RP accent"
3229
+ * { age, gender } → "middle-aged male voice"
3230
+ * { language: ["english","spanish"] } → "English / Spanish voice"
3231
+ * { } → ""
3232
+ *
3233
+ * `language` is multi-pick — multiple languages emit "English / Spanish"
3234
+ * for codeswitching / multilingual voices.
3235
+ */
3236
+ declare function buildVoiceCharacterHints(data: {
3237
+ readonly preText?: string;
3238
+ readonly postText?: string;
3239
+ readonly age?: string;
3240
+ readonly gender?: string;
3241
+ readonly language?: string | ReadonlyArray<string>;
3242
+ readonly accent?: string;
3243
+ readonly timbre?: string;
3244
+ }): string;
3245
+ declare const VOICE_CHARACTER_DEFAULT_DATA: {
3246
+ preText?: string;
3247
+ postText?: string;
3248
+ age?: string;
3249
+ gender?: string;
3250
+ language?: string | ReadonlyArray<string>;
3251
+ accent?: string;
3252
+ timbre?: string;
3253
+ };
3254
+
3255
+ /**
3256
+ * Voice-delivery catalog: pace + emotion + archetype. Feeds
3257
+ * Voice Design's voiceDescription via the Sound aggregator.
3258
+ */
3259
+ interface VoiceDeliveryEntry {
3260
+ readonly id: string;
3261
+ readonly label: string;
3262
+ readonly description: string;
3263
+ readonly promptHint: string;
3264
+ }
3265
+ declare const VOICE_PACES: ReadonlyArray<VoiceDeliveryEntry>;
3266
+ declare const VOICE_EMOTIONS: ReadonlyArray<VoiceDeliveryEntry>;
3267
+ declare const VOICE_ARCHETYPES: ReadonlyArray<VoiceDeliveryEntry>;
3268
+ declare function getVoicePace(id: string | undefined): VoiceDeliveryEntry | undefined;
3269
+ declare function getVoiceEmotion(id: string | undefined): VoiceDeliveryEntry | undefined;
3270
+ declare function getVoiceArchetype(id: string | undefined): VoiceDeliveryEntry | undefined;
3271
+ /**
3272
+ * Compose a delivery clause.
3273
+ * Examples:
3274
+ * { pace, archetype, emotion } → "measured documentary-narrator-style delivery, reassuring tone"
3275
+ * { archetype } → "documentary-narrator-style delivery"
3276
+ * { emotion } → "reassuring tone"
3277
+ * { pace } → "measured pace"
3278
+ */
3279
+ declare function buildVoiceDeliveryHints(data: {
3280
+ readonly preText?: string;
3281
+ readonly postText?: string;
3282
+ readonly pace?: string;
3283
+ readonly emotion?: string;
3284
+ readonly archetype?: string;
3285
+ }): string;
3286
+ declare const VOICE_DELIVERY_DEFAULT_DATA: {
3287
+ preText?: string;
3288
+ postText?: string;
3289
+ pace?: string;
3290
+ emotion?: string;
3291
+ archetype?: string;
3292
+ };
3293
+
3294
+ type WardrobeDimension = "archetype" | "top" | "bottom" | "outerwear" | "footwear" | "headwear" | "accessories" | "color-palette" | "material" | "era";
3295
+ interface WardrobeEntry {
3296
+ readonly id: string;
3297
+ readonly label: string;
3298
+ readonly dimension: WardrobeDimension;
3299
+ readonly promptHint: string;
3300
+ }
3301
+ interface WardrobeValue {
3302
+ archetype?: string;
3303
+ top?: string;
3304
+ bottom?: string;
3305
+ outerwear?: string;
3306
+ footwear?: string;
3307
+ headwear?: string | ReadonlyArray<string>;
3308
+ accessories?: string | ReadonlyArray<string>;
3309
+ colorPalette?: string;
3310
+ material?: string;
3311
+ era?: string;
3312
+ }
3313
+ declare const WARDROBE_DIMENSION_ORDER: ReadonlyArray<WardrobeDimension>;
3314
+ declare const WARDROBE_CATEGORY_LABELS: Readonly<Record<WardrobeDimension, string>>;
3315
+ declare const WARDROBE_FIELD_BY_DIMENSION: Record<WardrobeDimension, keyof WardrobeValue>;
3316
+ declare const WARDROBE: ReadonlyArray<WardrobeEntry>;
3317
+ declare function getWardrobeEntry(id: string | undefined | null): WardrobeEntry | undefined;
3318
+ declare function getWardrobePromptHint(id: string | undefined | null): string;
3319
+ declare function getWardrobeEntriesByDimension(dim: WardrobeDimension): WardrobeEntry[];
3320
+ declare function buildWardrobeHints(value: Record<string, unknown> & WardrobeValue): string[];
3321
+
3322
+ /**
3323
+ * Default prompt templates and template resolution/application functions.
3324
+ * Shared between frontend and backend.
3325
+ */
3326
+ declare const DEFAULT_TEMPLATES: Record<string, string>;
3327
+ /**
3328
+ * Resolve a template by key, checking flow-level overrides, then user overrides,
3329
+ * then the system defaults.
3330
+ */
3331
+ declare function resolveTemplate(key: string, userTemplates?: Record<string, string>, flowTemplates?: Record<string, string>): string;
3332
+ /**
3333
+ * Replace `{varName}` placeholders in a template string with values from vars.
3334
+ */
3335
+ declare function applyTemplate(template: string, vars: Record<string, string>): string;
3336
+
3337
+ /**
3338
+ * Per-provider prompting doctrine — the single source of truth for "how to
3339
+ * prompt model family X well". Consumed by:
3340
+ * 1. backend/src/prompts/prompt-wizard-system.ts (enhance/generate system prompts)
3341
+ * 2. backend/scripts/gen-skills (provider-prompting block in video node skills)
3342
+ * 3. backend/src/lib/mcp/tools/models.ts (list_models promptTips)
3343
+ * 4. compact recipes in MCP tool descriptions point here via get_node_skill
3344
+ *
3345
+ * Sources, in precedence order (conflicts resolve top-down):
3346
+ * - Official BytePlus ModelArk "Dreamina Seedance 2.0 series prompt guide"
3347
+ * https://docs.byteplus.com/en/docs/ModelArk/2222480
3348
+ * - Official launch post https://seed.bytedance.com/en/blog/official-launch-of-seedance-2-0
3349
+ * - KIE API docs https://docs.kie.ai/market/bytedance/seedance-2
3350
+ */
3351
+ interface ProviderPromptDoctrine {
3352
+ /** MODEL_CATALOG ids this doctrine covers. */
3353
+ readonly providers: readonly string[];
3354
+ /** Human heading for skill docs, e.g. "Seedance 2.0 (seedance-2, seedance-2-fast)". */
3355
+ readonly heading: string;
3356
+ /** Short bullets for compact surfaces (list_models promptTips). ≤220 chars each. */
3357
+ readonly tips: readonly string[];
3358
+ /** Full markdown doctrine for system prompts and generated skill docs. */
3359
+ readonly doctrine: string;
3360
+ }
3361
+ declare const PROVIDER_PROMPT_DOCTRINES: readonly ProviderPromptDoctrine[];
3362
+ /** Full doctrine for a provider id, or undefined when none exists. */
3363
+ declare function getPromptDoctrine(providerId: string): ProviderPromptDoctrine | undefined;
3364
+ /** Compact tips for a provider id ([] when none) — used by list_models. */
3365
+ declare function getPromptTips(providerId: string): readonly string[];
3366
+
3367
+ /**
3368
+ * Prompt Wizard — shared types, category definitions, and provider capabilities.
3369
+ *
3370
+ * Used by the backend (system prompt building) and frontend (type-checking, UI).
3371
+ */
3372
+ interface WizardCategory {
3373
+ readonly key: string;
3374
+ readonly label: string;
3375
+ readonly optional?: boolean;
3376
+ }
3377
+ interface WizardQuestion {
3378
+ category: string;
3379
+ label: string;
3380
+ options: WizardOption[];
3381
+ selected: string | string[] | null;
3382
+ allowCustom: boolean;
3383
+ multi?: boolean;
3384
+ }
3385
+ interface WizardOption {
3386
+ value: string;
3387
+ label: string;
3388
+ description?: string;
3389
+ }
3390
+ interface WizardSelection {
3391
+ category: string;
3392
+ value: string;
3393
+ isCustom: boolean;
3394
+ }
3395
+ interface RecommendedModel {
3396
+ provider: string;
3397
+ field: string;
3398
+ label: string;
3399
+ reason: string;
3400
+ }
3401
+ interface WizardNodeContext {
3402
+ connectedInputTypes?: string[];
3403
+ referenceImageCount?: number;
3404
+ referenceImageUrls?: string[];
3405
+ hasSourceVideo?: boolean;
3406
+ }
3407
+ interface ModelChange {
3408
+ field: string;
3409
+ value: string;
3410
+ }
3411
+ declare const IMAGE_WIZARD_CATEGORIES: readonly WizardCategory[];
3412
+ declare const VIDEO_WIZARD_CATEGORIES: readonly WizardCategory[];
3413
+ declare const MUSIC_WIZARD_CATEGORIES: readonly WizardCategory[];
3414
+ declare const AUDIO_WIZARD_CATEGORIES: readonly WizardCategory[];
3415
+ declare const TEXT_WIZARD_CATEGORIES: readonly WizardCategory[];
3416
+ declare const LLM_CHAT_WIZARD_CATEGORIES: readonly WizardCategory[];
3417
+ declare function getCategoriesForNodeType(nodeType: string): readonly WizardCategory[] | undefined;
3418
+ /** Node types that support the wizard (excludes edit-image, text-to-speech, lip-sync) */
3419
+ declare function isWizardSupported(nodeType: string): boolean;
3420
+ declare const PROVIDER_CAPABILITIES: Record<string, Record<string, string>>;
3421
+ /** Reference image role options (for multi-select) */
3422
+ declare const REFERENCE_IMAGE_ROLES: readonly WizardOption[];
3423
+
3424
+ interface ResolvePromptArgs {
3425
+ override?: string;
3426
+ typed?: ReadonlyArray<string | undefined>;
3427
+ wired?: string;
3428
+ refMap: ReadonlyMap<string, string>;
3429
+ /** Opt-in (generate-image / generate-video only): APPEND the wired
3430
+ * (connected-prompt) value to the TYPED base instead of treating wired as a
3431
+ * fallback, so a connected prompt auto-injects alongside the typed prompt. An
3432
+ * `override` (list fan-out item) still fully replaces — no wired append.
3433
+ * Off/undefined = exact legacy precedence (override > typed > wired) for every
3434
+ * other node type. */
3435
+ appendWired?: boolean;
3436
+ }
3437
+ /** SINGLE SOURCE OF TRUTH for prompt precedence across both DAG engines:
3438
+ * override (list fan-out) > first present typed candidate > wired > "".
3439
+ * "present" = non-empty after trim. {Label} refs are resolved on the chosen
3440
+ * branch via the shared resolveNodeRefs. With `appendWired`, the chosen base
3441
+ * AND the wired value are both emitted (joined ". "). */
3442
+ declare function resolvePrompt({ override, typed, wired, refMap, appendWired }: ResolvePromptArgs): string;
3443
+ /** Compose a final NEGATIVE prompt from a TYPED base + a WIRED (connected
3444
+ * negative-handle) value: both are emitted, joined ". " (mirrors `appendWired`
3445
+ * for the positive prompt). Pure join — the caller resolves `{label}` refs on
3446
+ * the typed value first, and the wired value is already a resolved output that
3447
+ * the input-resolver has filtered (referenced / Inject-Negative-off dropped).
3448
+ * Generate-image / generate-video only; empty parts are dropped. */
3449
+ declare function composeNegative(typed?: string, wired?: string): string;
3450
+ /** Ordered typed-candidate fields per node type — the precedence source of
3451
+ * truth (NOT NODE_MAPPABLE_FIELDS, which is field-mapping eligibility, omits
3452
+ * video-retake, and orders llm-chat wrong). */
3453
+ declare const NODE_PROMPT_CANDIDATE_FIELDS: Readonly<Record<string, readonly string[]>>;
3454
+ interface ComputeNodePromptArgs {
3455
+ override?: string;
3456
+ wired?: string;
3457
+ refMap: ReadonlyMap<string, string>;
3458
+ /** See ResolvePromptArgs.appendWired — generate-image / generate-video only. */
3459
+ appendWired?: boolean;
3460
+ }
3461
+ /** Resolve a single-prompt node's final prompt (typed-primary). Both engines
3462
+ * call this so field-selection + precedence are structurally identical. */
3463
+ declare function computeNodePrompt(nodeType: string, data: Record<string, unknown>, { override, wired, refMap, appendWired }: ComputeNodePromptArgs): string;
3464
+ interface LlmChatFieldArgs {
3465
+ override?: string;
3466
+ wiredUserInput?: string;
3467
+ wiredSystemPrompt?: string;
3468
+ refMap: ReadonlyMap<string, string>;
3469
+ }
3470
+ /** llm-chat resolves TWO independent fields. override applies to userInput only. */
3471
+ declare function computeLlmChatFields(data: Record<string, unknown>, { override, wiredUserInput, wiredSystemPrompt, refMap }: LlmChatFieldArgs): {
3472
+ userInput: string;
3473
+ systemPrompt: string;
3474
+ };
3475
+
3476
+ interface FactoryPreset {
3477
+ /** Stable slug "<nodeType>/<kebab-name>" — used as a React key and in exports. */
3478
+ readonly id: string;
3479
+ readonly name: string;
3480
+ readonly description?: string;
3481
+ /** Optional folder/section label this preset is grouped under in the picker.
3482
+ * Presets sharing a `group` render together; "variants of one idea" (e.g. the
3483
+ * character-sheet family) are simply siblings in the same group. */
3484
+ readonly group?: string;
3485
+ /** How the group renders: a collapsible "folder" (default) or a flat "section"
3486
+ * label. Taken from the first preset that opens the group. */
3487
+ readonly groupKind?: "folder" | "section";
3488
+ /** Capture-shaped config (no label / fieldMappings / runtime keys). */
3489
+ readonly data: Readonly<Record<string, unknown>>;
3490
+ }
3491
+ /** A render-ready bucket of factory presets sharing one `group` (or the leading
3492
+ * ungrouped bucket, `group: null`). Produced by {@link groupFactoryPresets}. */
3493
+ interface FactoryPresetGroup<T> {
3494
+ /** Stable key for React + collapse state ("__root__" for the ungrouped bucket). */
3495
+ readonly key: string;
3496
+ /** Group label, or null for the ungrouped bucket. */
3497
+ readonly group: string | null;
3498
+ readonly groupKind: "folder" | "section";
3499
+ readonly presets: T[];
3500
+ }
3501
+ /**
3502
+ * Bucket an ordered list of presets by their `group` field for rendering. Groups
3503
+ * appear in first-appearance order; presets keep their array order within a
3504
+ * group; ungrouped presets collect into a single leading `null` bucket. Pure and
3505
+ * UI-agnostic (operates on anything carrying `group`/`groupKind`) so the config
3506
+ * panel dropdown reuses it and it stays unit-testable.
3507
+ */
3508
+ declare function groupFactoryPresets<T extends {
3509
+ group?: string;
3510
+ groupKind?: "folder" | "section";
3511
+ }>(presets: readonly T[]): FactoryPresetGroup<T>[];
3512
+
3513
+ /** System/factory presets shipped with the app. Assembled here in the original
3514
+ * single-file key order; each value lives in its per-domain module. */
3515
+ declare const FACTORY_PRESETS: Readonly<Record<string, readonly FactoryPreset[]>>;
3516
+ declare function getFactoryPresets(nodeType: string): readonly FactoryPreset[];
3517
+
3518
+ /**
3519
+ * Style Gallery presets (north-star §6 ①).
3520
+ *
3521
+ * Each preset is a named "look" the user picks at Start. Picking one sets the
3522
+ * pipeline's `style_directives`, which the Showrunner folds into the plan's
3523
+ * `global_style` — and from there it propagates into every entity reference
3524
+ * sheet, scene keyframe, and shot prompt, plus the image/location critics. So
3525
+ * the whole film stays visually consistent in the chosen style.
3526
+ *
3527
+ * The catalog is intentionally style/genre-agnostic (not just "cinematic"):
3528
+ * films, explainers, animated ads, kids' content, education. A per-shot style
3529
+ * override lives in the Focus composer (follow-up).
3530
+ *
3531
+ * `swatch` is a CSS gradient used as a lightweight thumbnail until real sample
3532
+ * images ship — it gives each look a recognizable visual without bundling
3533
+ * assets.
3534
+ */
3535
+ interface StylePreset {
3536
+ /** Stable id stored on the pipeline (do not rename — breaks recall). */
3537
+ id: string;
3538
+ label: string;
3539
+ /** One-line description shown under the label. */
3540
+ description: string;
3541
+ /** CSS `background` value for the card's thumbnail swatch. */
3542
+ swatch: string;
3543
+ /** Conditioning fed to the Showrunner → plan.global_style → all generation. */
3544
+ directives: StyleDirectives;
3545
+ }
3546
+ declare const STYLE_PRESETS: readonly StylePreset[];
3547
+ /** Resolve a preset by id. Returns undefined for the "Auto" / unknown case. */
3548
+ declare function getStylePreset(id: string | undefined): StylePreset | undefined;
3549
+
3550
+ /** Angle preset → prompt fragment (slotted into "<name>, <fragment>. <base>"). */
3551
+ declare const OBJECT_ANGLE_PROMPTS: Record<string, string>;
3552
+ /** Material preset → prompt fragment. */
3553
+ declare const OBJECT_MATERIAL_PROMPTS: Record<string, string>;
3554
+ /** Variation preset → prompt fragment. */
3555
+ declare const OBJECT_VARIATION_PROMPTS: Record<string, string>;
3556
+ declare const OBJECT_ANGLE_PRESETS: readonly string[];
3557
+ declare const OBJECT_MATERIAL_PRESETS: readonly string[];
3558
+ declare const OBJECT_VARIATION_PRESETS: readonly string[];
3559
+ type ObjectPresetAssetType = "angles" | "materials" | "variations";
3560
+ /** Preset key lists per asset type — backend VARIANTS validation reads this. */
3561
+ declare const OBJECT_ASSET_PRESETS: Record<ObjectPresetAssetType, readonly string[]>;
3562
+ /** Prompt-fragment maps per asset type — backend buildVariantPrompt reads this. */
3563
+ declare const OBJECT_ASSET_PROMPTS: Record<ObjectPresetAssetType, Record<string, string>>;
3564
+
3565
+ /** Which prompt field a snippet belongs to. Negative-target snippets only
3566
+ * surface in negative-prompt fields, and are bare comma lists by convention
3567
+ * (per Google's Veo guidance, a negative FIELD must name the unwanted thing,
3568
+ * never "no X"). */
3569
+ type SnippetTarget = "prompt" | "negative";
3570
+ /** Node modality a snippet applies to. A node declares its modality once in
3571
+ * the frontend's NODE_PROMPT_FIELDS; the menu shows snippets whose `media`
3572
+ * contains it. */
3573
+ type SnippetMedia = "image" | "video" | "audio" | "text";
3574
+ declare const SNIPPET_MEDIA_VALUES: readonly SnippetMedia[];
3575
+ interface FactorySnippet {
3576
+ /** Stable kebab slug, e.g. "identity-lock". Unique across the catalog. */
3577
+ readonly id: string;
3578
+ readonly name: string;
3579
+ /** One-liner shown in the menu and matched by search. */
3580
+ readonly description?: string;
3581
+ /** The exact fragment inserted into the prompt. Single line; never contains
3582
+ * `{`, `}`, or `@` (guard-tested) so it can never form a mention/variable
3583
+ * token in the editor. */
3584
+ readonly text: string;
3585
+ readonly target: SnippetTarget;
3586
+ readonly media: readonly SnippetMedia[];
3587
+ /** Menu group AND the pill-swap sibling pool (swap lists same-category). */
3588
+ readonly category: string;
3589
+ }
3590
+
3591
+ /** Factory snippet catalog (v1: image + video; audio/text follow later).
3592
+ * Order within a category = menu order = pill quick-cycle order. */
3593
+
3594
+ declare const FACTORY_SNIPPETS: readonly FactorySnippet[];
3595
+
3596
+ /** Factory snippets for one field: target match + media membership. */
3597
+ declare function getFactorySnippets(target: SnippetTarget, media: SnippetMedia): readonly FactorySnippet[];
3598
+
3599
+ export { ACTION_FX, ACTION_FX_CATEGORY_LABELS, ACTION_FX_CATEGORY_ORDER, ACTION_FX_IDS, AESTHETICS, AESTHETIC_CATEGORY_LABELS, AESTHETIC_CATEGORY_ORDER, AESTHETIC_IDS, ANALYZABLE_PICKER_TYPES, ANGLE_LABELS, ASPECT_RATIO_LABELS, ATMOSPHERES, ATMOSPHERE_IDS, AUDIO_WIZARD_CATEGORIES, type ActionFx, type ActionFxCategory, type Aesthetic, type AestheticCategory, type AssembleImageInput, type AssembleSunoInput, type AssembleSunoResult, type Atmosphere, BACKDROPS, BACKDROP_CATEGORY_LABELS, BACKDROP_CATEGORY_ORDER, BACKDROP_IDS, BRAND_PRESETS, BRAND_PRESET_IDS, BRAND_PRESET_META, type Backdrop, type BackdropCategory, type BrandCasing, type BrandFonts, type BrandLogo, type BrandPalette, type BrandPresetId, type BrandPresetMeta, type BrandTokens, type BrandTypeSpec, type BuildImagePromptConfig, type BuildImagePromptResult, type BuildImagePromptSegmentsResult, CAMERA_FORMATS, CAMERA_FORMAT_IDS, CAMERA_MOTIONS, CAMERA_MOTION_CATEGORY_LABELS, CAMERA_MOTION_CATEGORY_ORDER, CAMERA_MOTION_IDS, CHARACTER_FX, CHARACTER_FX_CATEGORY_LABELS, CHARACTER_FX_CATEGORY_ORDER, CHARACTER_FX_IDS, COLOR_LOOKS, COLOR_LOOK_CATEGORY_LABELS, COLOR_LOOK_CATEGORY_ORDER, COLOR_LOOK_IDS, COMPOSITION_EFFECTS, COMPOSITION_EFFECT_IDS, type CameraFormat, type CameraMotion, type CameraMotionCategory, type CategorizedInstrument, type CharacterFx, type CharacterFxCategory, type CharacterFxDuration, type CharacterFxIntensity, type CharacterFxPosition, type CharacterFxTiming, type CharacterMeta, type CharacterMotionPromptInput, type CharacterPromptInput, type ColorLook, type ColorLookCategory, type CompositionEffect, type ComputeNodePromptArgs, type CreaturePromptInput, DEFAULT_IDENTITY_LOCK, DEFAULT_TEMPLATES, type DirectionFields, ERAS, ERA_CATEGORY_LABELS, ERA_CATEGORY_ORDER, ERA_IDS, EXPOSURE_CATEGORY_LABELS, EXPOSURE_CATEGORY_ORDER, EXPOSURE_FIELD_BY_CATEGORY, EXPOSURE_IDS, EXPOSURE_SETTINGS, type Era, type EraCategory, type ExposureCategory, type ExposureSettings, type ExposureValue, FACTORY_PRESETS, FACTORY_SNIPPETS, FRAMINGS, FRAMING_CATEGORY_LABELS, FRAMING_CATEGORY_ORDER, FRAMING_FIELD_BY_CATEGORY, FRAMING_IDS, type FacePromptInput, type FactoryPreset, type FactoryPresetGroup, type FactorySnippet, type Framing, type FramingCategory, type FramingValue, GAPS_SCHEMA, HELD_PROPS, HELD_PROP_CATEGORY_LABELS, HELD_PROP_CATEGORY_ORDER, HELD_PROP_IDS, type HeldProp, type HeldPropCategory, IMAGE_WIZARD_CATEGORIES, INSTRUMENTATION_DEFAULT_DATA, INSTRUMENTS, INSTRUMENT_CATEGORY_LABELS, INSTRUMENT_CATEGORY_ORDER, type IdentityLockMode, type InstrumentCategory, type InstrumentationEntry, LENSES, LENS_IDS, LIGHTINGS, LIGHTING_CATEGORY_LABELS, LIGHTING_CATEGORY_ORDER, LIGHTING_FIELD_BY_CATEGORY, LIGHTING_IDS, LLM_CHAT_WIZARD_CATEGORIES, LOOP_SUBJECTS, LOOP_SUBJECT_CATEGORY_LABELS, LOOP_SUBJECT_CATEGORY_ORDER, type Lens, type Lighting, type LightingCategory, type LightingValue, type LlmChatFieldArgs, type LocationMotionPromptInput, type LocationPromptInput, type LocationRefinePromptInput, type LoopSubject, type LoopSubjectCategory, MATERIALS, MATERIAL_CATEGORY_LABELS, MATERIAL_CATEGORY_ORDER, MATERIAL_IDS, MAX_SELECTED_BY_DIMENSION, MAX_SELECTED_BY_FRAMING_CATEGORY, MAX_SELECTED_BY_STYLING_DIMENSION, MOODS, MOOD_CATEGORY_LABELS, MOOD_CATEGORY_ORDER, MOOD_IDS, MOVEMENT_LABELS, MUSIC_EMOTIONS, MUSIC_ENERGIES, MUSIC_ERAS, MUSIC_GENRES, MUSIC_GENRE_CATEGORY_LABELS, MUSIC_GENRE_CATEGORY_ORDER, MUSIC_GENRE_DEFAULT_DATA, MUSIC_MOOD_DEFAULT_DATA, MUSIC_VIBES, MUSIC_WIZARD_CATEGORIES, type Material, type MaterialCategory, type ModelChange, type Mood, type MoodCategory, type MoodValue, type MultiPickerAnalyzerSpec, type MusicEra, type MusicGenre, type MusicGenreCategory, type MusicMoodEntry, type MusicSubgenre, NODE_PROMPT_CANDIDATE_FIELDS, OBJECT_ANGLE_PRESETS, OBJECT_ANGLE_PROMPTS, OBJECT_ASSET_PRESETS, OBJECT_ASSET_PROMPTS, OBJECT_MATERIAL_PRESETS, OBJECT_MATERIAL_PROMPTS, OBJECT_VARIATION_PRESETS, OBJECT_VARIATION_PROMPTS, type ObjectMotionPromptInput, type ObjectPresetAssetType, type ObjectPromptInput, PEOPLE, PERSON_DIMENSION_LABELS, PERSON_DIMENSION_ORDER, PERSON_DIMENSION_SECTIONS, PERSON_FIELD_BY_DIMENSION, PERSON_IDS, PHOTOGRAPHERS, PHOTOGRAPHER_CATEGORY_LABELS, PHOTOGRAPHER_CATEGORY_ORDER, PHOTOGRAPHER_IDS, PHOTO_GENRES, PHOTO_GENRE_CATEGORY_LABELS, PHOTO_GENRE_CATEGORY_ORDER, PHOTO_GENRE_IDS, PICKER_ANALYZER_REGISTRY, PICKER_CATALOGS, PICKER_TYPES, POSES, POSE_CATEGORY_LABELS, POSE_CATEGORY_ORDER, POSE_IDS, POST_PROCESS_EFFECTS, POST_PROCESS_EFFECT_IDS, PRODUCTION_STYLES, PROVIDER_CAPABILITIES, PROVIDER_PROMPT_DOCTRINES, type Person, type PersonDimension, type PersonDimensionSection, type PersonValue, type PhotoGenre, type PhotoGenreCategory, type Photographer, type PhotographerCategory, type PickerAnalyzer, type PickerAnalyzerDescriptor, type PickerAnalyzerSpec, type PickerApplyMode, type PickerCatalog, type PickerCatalogDetail, type PickerCatalogSummary, type PickerDimension, type PickerDimensionSpec, type PickerGaps, type PickerOption, type PickerType, type Pose, type PoseCategory, type PoseValue, type PostProcessEffect, type ProjectPickerCatalogOptions, type ProjectedPickerCatalog, type ProjectedPickerDimension, type ProjectedPickerOption, type PromptSegment, type PromptSegmentOrigin, type ProviderPromptDoctrine, REFERENCE_IMAGE_ROLES, REF_BINDING, RENDER_QUALITIES, RENDER_QUALITY_IDS, type RecommendedModel, type ReferenceCounts, type RenderQuality, type ResolveCharacterMentionsResult, type ResolveLocationMentionsResult, type ResolvePromptArgs, type ResolveVideoReferenceCoreArgs, SCENE_PROMPT_MAX_LENGTH, SETTINGS, SETTING_CATEGORY_LABELS, SETTING_IDS, SHOT_LABELS, SINGING_STYLES, SNIPPET_MEDIA_VALUES, STYLES, STYLE_IDS, STYLE_PRESETS, STYLINGS, STYLING_DIMENSION_LABELS, STYLING_DIMENSION_ORDER, STYLING_FIELD_BY_DIMENSION, STYLING_IDS, type Seedance2InputsArgs, type Seedance2InputsResult, type Seedance2Mode, type Setting, type SettingCategory, type SnippetMedia, type SnippetTarget, type SoundComposition, type SoundCompositionFields, type SoundConsumerType, type StructuredPromptFields, type Style, type StylePreset, type Styling, type StylingDimension, type StylingValue, TEMPORALS, TEMPORAL_CATEGORY_LABELS, TEMPORAL_CATEGORY_ORDER, TEMPORAL_FIELD_BY_CATEGORY, TEMPORAL_IDS, TEXT_WIZARD_CATEGORIES, TRANSITIONS, TRANSITION_CATEGORY_LABELS, TRANSITION_CATEGORY_ORDER, TRANSITION_IDS, type Temporal, type TemporalCategory, type TemporalValue, type Transition, type TransitionCategory, type TransitionDuration, type TransitionIntensity, type TransitionPosition, type TransitionTiming, VIDEO_WIZARD_CATEGORIES, VOCAL_PRESENCE, VOCAL_PRESENCE_INSTRUMENTAL_ID, VOICE_ACCENTS, VOICE_AGES, VOICE_ARCHETYPES, VOICE_CHARACTER_DEFAULT_DATA, VOICE_DELIVERY_DEFAULT_DATA, VOICE_EMOTIONS, VOICE_GENDERS, VOICE_LANGUAGES, VOICE_PACES, VOICE_TIMBRES, type VideoExtraRef, type VoiceCharacterEntry, type VoiceDeliveryEntry, WARDROBE, WARDROBE_CATEGORY_LABELS, WARDROBE_DIMENSION_ORDER, WARDROBE_FIELD_BY_DIMENSION, type WardrobeDimension, type WardrobeEntry, type WardrobeValue, type WizardCategory, type WizardNodeContext, type WizardOption, type WizardQuestion, type WizardSelection, appendField, appendMusicMeta, applyPickerJson, applyReferenceOrderToVideo, applyTemplate, assembleImageInput, assembleSunoInput, buildActionFxHints, buildAestheticHints, buildAgeHint, buildAtmosphereHints, buildCharacterPrompt, buildCreaturePrompt, buildExposureHints, buildFaceTemplateInputs, buildFramingHints, buildHeldPropHints, buildIdentityDirectives, buildIdentityLockLine, buildImagePrompt, buildImagePromptSegments, buildInstrumentationHints, buildLightingHints, buildLocationMotionPrompt, buildLocationPrompt, buildLocationRefinePrompt, buildMaterialHints, buildMoodHints, buildMotionPrompt, buildMultiPickerAnalyzerSpec, buildMusicGenreHints, buildMusicMoodHints, buildObjectMotionPrompt, buildObjectPrompt, buildPersonHints, buildPhotographerHints, buildPickerAnalyzerSpec, buildPickerLegend, buildPickerZodSchema, buildPoseHints, buildPostProcessHints, buildReferenceBlocks, buildScenePrompt, buildStylingHints, buildTemporalHints, buildVoiceCharacterHints, buildVoiceDeliveryHints, buildWardrobeHints, characterLockToRefLock, collectIdentityLockClause, composeCameraMotionHintFromConnections, composeCharacterFxHintFromConnections, composeNegative, composeSoundHintFromConnections, composeTransitionHintFromConnections, computeLlmChatFields, computeNodePrompt, expandImagePositionRefs, expandImageRefTokens, getActionFx, getActionFxLabel, getActionFxPromptHint, getAesthetic, getAestheticLabel, getAestheticPromptHint, getAtmosphere, getAtmosphereLabel, getAtmospherePromptHint, getBackdrop, getBackdropLabel, getBackdropPromptHint, getCameraFormat, getCameraFormatLabel, getCameraFormatPromptHint, getCameraMotion, getCameraMotionLabel, getCameraMotionPromptHint, getCategoriesForNodeType, getCharacterFx, getCharacterFxLabel, getCharacterFxPromptHint, getColorLook, getColorLookLabel, getColorLookPromptHint, getCompositionEffect, getCompositionEffectLabel, getCompositionEffectPromptHint, getEffectiveSunoCustomMode, getEra, getEraLabel, getEraPromptHint, getExposure, getExposureLabel, getExposurePromptHint, getFactoryPresets, getFactorySnippets, getFraming, getFramingCategoryLimit, getFramingLabel, getFramingPromptHint, getHeldProp, getHeldPropLabel, getHeldPropPromptHint, getIdentityLockClause, getInstrument, getLens, getLensLabel, getLensPromptHint, getLighting, getLightingLabel, getLightingPromptHint, getLoopSubject, getLoopSubjectLabel, getLoopSubjectPromptHint, getMaterial, getMaterialLabel, getMaterialPromptHint, getMood, getMoodLabel, getMoodPromptHint, getMusicEmotion, getMusicEnergy, getMusicEra, getMusicGenre, getMusicGenreLabel, getMusicSubgenre, getMusicVibe, getParameterPromptHint, getPerson, getPersonDimensionLimit, getPersonLabel, getPersonPromptHint, getPhotoGenre, getPhotoGenreLabel, getPhotoGenrePromptHint, getPhotographer, getPhotographerLabel, getPhotographerPromptHint, getPickerAnalyzer, getPickerCatalog, getPose, getPoseLabel, getPosePromptHint, getPostProcessEffect, getPostProcessEffectLabel, getPostProcessEffectPromptHint, getProductionStyle, getPromptDoctrine, getPromptTips, getRenderQuality, getRenderQualityLabel, getRenderQualityPromptHint, getSetting, getSettingLabel, getSettingPromptHint, getSingingStyle, getStyle, getStyleLabel, getStylePreset, getStylePromptHint, getStyling, getStylingDimensionLimit, getStylingLabel, getStylingPromptHint, getTemporal, getTemporalLabel, getTemporalPromptHint, getTransition, getTransitionLabel, getTransitionPromptHint, getVocalPresence, getVoiceAccent, getVoiceAge, getVoiceArchetype, getVoiceEmotion, getVoiceGender, getVoiceLanguage, getVoicePace, getVoiceTimbre, getWardrobeEntriesByDimension, getWardrobeEntry, getWardrobePromptHint, groupFactoryPresets, hasUpstreamCharacter, isAnalyzablePicker, isInstrumentalVocal, isVantageFraming, isWizardSupported, listPickerCatalogs, migratePersonValue, pickerFanoutTargets, projectPickerCatalog, renderStructuredFields, resolveBrandInput, resolveCharacterMentions, resolveLocationMentions, resolvePrompt, resolveReferenceTokens, resolveSeedance2Inputs, resolveTemplate, resolveVideoReferenceCore, summarizePickerCatalogs, toIdentityLockMode, truncateForField, truncateText, withForcedIdentityLock };