@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,255 @@
1
+ /**
2
+ * Canonical catalog of Action FX choices.
3
+ *
4
+ * Action FX describes a discrete, dramatic, high-energy event happening in the
5
+ * scene — an explosion mid-blast, a lightning bolt striking, an earthquake
6
+ * fracturing the ground, a magic fireball spell, a force field shimmering.
7
+ *
8
+ * Distinct from:
9
+ * - Atmosphere — continuous environmental state (rain, fog, smoke, dust).
10
+ * - Composition Effects — how the subject itself is rendered (smoke
11
+ * sculpture, exploding-particle silhouette, glitch).
12
+ * - Post-Process Effects — image-grading passes (vignette, grain, halation).
13
+ * - Color Look — overall color grade direction.
14
+ *
15
+ * Multi-pick: 1–2 ids → composite FX clause. Pure prompt text, zero credits,
16
+ * zero API calls. Shared between picker UI and prompt-hint injection on
17
+ * frontend DAG executor + backend orchestrator.
18
+ */
19
+
20
+ export type ActionFxCategory =
21
+ | "disaster"
22
+ | "fire-blasts"
23
+ | "electric"
24
+ | "combat"
25
+ | "sci-fi"
26
+ | "magic"
27
+
28
+ export interface ActionFx {
29
+ readonly id: string
30
+ readonly label: string
31
+ readonly category: ActionFxCategory
32
+ readonly description: string
33
+ readonly promptHint: string
34
+ }
35
+
36
+ export const ACTION_FX_CATEGORY_ORDER: ReadonlyArray<ActionFxCategory> = [
37
+ "disaster",
38
+ "fire-blasts",
39
+ "electric",
40
+ "combat",
41
+ "sci-fi",
42
+ "magic",
43
+ ] as const
44
+
45
+ export const ACTION_FX_CATEGORY_LABELS: Readonly<Record<ActionFxCategory, string>> = {
46
+ disaster: "Disaster",
47
+ "fire-blasts": "Fire & Blasts",
48
+ electric: "Electric",
49
+ combat: "Combat",
50
+ "sci-fi": "Sci-Fi",
51
+ magic: "Magic",
52
+ } as const
53
+
54
+ export const ACTION_FX: ReadonlyArray<ActionFx> = [
55
+ // ── Disaster ──
56
+ { id: "earthquake-tremor", category: "disaster", label: "Earthquake Tremor", description: "Mild ground shake, hanging objects sway",
57
+ promptHint: "a mild earthquake tremor rippling through the scene, hanging objects swaying gently and dust shaking loose from surfaces with a faint trembling motion across the frame" },
58
+ { id: "earthquake-major", category: "disaster", label: "Major Earthquake", description: "Ground splitting, debris falling",
59
+ promptHint: "a major earthquake violently shaking the scene, ground splitting open with deep cracks radiating outward and chunks of debris tumbling from above as everything trembles" },
60
+ { id: "building-collapse", category: "disaster", label: "Building Collapse", description: "Structure crumbling mid-fall",
61
+ promptHint: "a building collapsing mid-fall, walls buckling and concrete fragmenting outward in a cascade of debris with billowing dust clouds rolling out from the base of the structure" },
62
+ { id: "tsunami-wave", category: "disaster", label: "Tsunami Wave", description: "Towering wall of water bearing down",
63
+ promptHint: "a towering tsunami wave bearing down on the scene, wall of dark churning water curling overhead with white foam crests and debris carried inside the surge" },
64
+ { id: "tornado", category: "disaster", label: "Tornado", description: "Funnel cloud touching down",
65
+ promptHint: "a massive tornado funnel cloud touching down in the scene, dark spiraling vortex tearing across the landscape with debris ripped into the air and a trailing dust cloud at its base" },
66
+ { id: "hurricane", category: "disaster", label: "Hurricane", description: "Howling winds bending trees, sheets of rain",
67
+ promptHint: "a hurricane raging through the scene, howling sideways winds bending trees and palm fronds nearly horizontal, sheets of driving rain blurring the air with debris airborne in every direction" },
68
+ { id: "blizzard-whiteout", category: "disaster", label: "Blizzard Whiteout", description: "Heavy snow obliterating visibility",
69
+ promptHint: "a blinding blizzard whiteout consuming the scene, near-zero visibility through dense windswept snowfall and howling drifts that bury everything under a roaring white veil" },
70
+ { id: "sandstorm", category: "disaster", label: "Sandstorm", description: "Wall of orange dust engulfing scene",
71
+ promptHint: "a towering sandstorm wall of orange-brown dust engulfing the scene, swirling fine particles reducing visibility to feet and burying surfaces under shifting waves of grit" },
72
+ { id: "dust-storm-haboob", category: "disaster", label: "Dust Storm (Haboob)", description: "Towering desert dust front",
73
+ promptHint: "a towering haboob dust storm rolling across the scene, mountainous wall of dense ochre dust front billowing forward and swallowing the horizon in a dramatic monolithic curtain" },
74
+ { id: "wildfire-distant", category: "disaster", label: "Distant Wildfire", description: "Orange glow + smoke on horizon",
75
+ promptHint: "a distant wildfire raging on the horizon, orange-red glow lighting up dark plumes of smoke billowing into a hazy sky with embers visible at the treeline" },
76
+ { id: "wildfire-engulfing", category: "disaster", label: "Engulfing Wildfire", description: "Flames closing in, intense heat shimmer",
77
+ promptHint: "an engulfing wildfire closing in on the scene, walls of orange flame consuming nearby trees with intense heat shimmer warping the air and embers spiraling upward into a smoke-darkened sky" },
78
+ { id: "volcanic-eruption", category: "disaster", label: "Volcanic Eruption", description: "Lava spewing, ash plume",
79
+ promptHint: "a volcanic eruption with molten lava spewing skyward and a towering ash plume billowing into the atmosphere, glowing orange streams cascading down the slope and pyroclastic clouds rolling outward" },
80
+ { id: "lava-flow", category: "disaster", label: "Lava Flow", description: "Glowing molten river creeping across ground",
81
+ promptHint: "a glowing molten lava flow creeping across the ground, bright orange-red rivers of fire snaking through cooled black crust with shimmering heat distortion above and wisps of sulfurous smoke" },
82
+ { id: "ash-rain", category: "disaster", label: "Falling Ash Rain", description: "Apocalyptic grey ash falling like snow",
83
+ promptHint: "thick grey volcanic ash falling like dirty snow across the scene, apocalyptic post-eruption atmosphere with fine flakes settling on every surface and a hazy desaturated sky" },
84
+ { id: "avalanche", category: "disaster", label: "Avalanche", description: "Wall of snow tumbling down mountainside",
85
+ promptHint: "a massive avalanche tumbling down a mountainside, wall of churning snow and ice cascading at speed with a billowing powder cloud rolling forward and crushing everything in its path" },
86
+ { id: "hailstorm", category: "disaster", label: "Hailstorm", description: "Large hailstones bouncing off surfaces",
87
+ promptHint: "a violent hailstorm pummeling the scene, large hailstones bouncing off surfaces and shattering glass with white streaks of falling ice cutting through dark stormy clouds" },
88
+ // ── Fire & Blasts ──
89
+ { id: "explosion-small", category: "fire-blasts", label: "Small Explosion", description: "Compact blast with focal flash",
90
+ promptHint: "a compact small explosion with a sharp focal flash, contained orange fireball expanding outward with a shockwave of dust and a brief plume of smoke rising directly above" },
91
+ { id: "explosion-large", category: "fire-blasts", label: "Large Explosion", description: "Vehicle-scale fireball with debris",
92
+ promptHint: "a large explosion at vehicle scale, churning fireball of orange and yellow flames expanding outward with debris hurled into the air and a thick black smoke crown billowing skyward" },
93
+ { id: "explosion-massive", category: "fire-blasts", label: "Massive Explosion", description: "Building-leveling fireball with shockwave",
94
+ promptHint: "a massive explosion erupting in the scene with a building-leveling fireball, dense orange-red flame core expanding outward and a visible shockwave displacing dust and debris in a radial blast" },
95
+ { id: "nuclear-detonation", category: "fire-blasts", label: "Nuclear Detonation", description: "Mushroom cloud + horizon-bright flash",
96
+ promptHint: "a nuclear detonation flashing on the horizon, blinding white core followed by a towering mushroom cloud column rising into the upper atmosphere with concentric shockwave ripples and an apocalyptic glow lighting the entire landscape" },
97
+ { id: "fireball-airborne", category: "fire-blasts", label: "Airborne Fireball", description: "Mid-air rolling ball of flame",
98
+ promptHint: "an airborne fireball rolling through mid-air, churning sphere of orange-red flame with trailing smoke streamers and a halo of heat distortion warping the surrounding light" },
99
+ { id: "gas-explosion", category: "fire-blasts", label: "Gas Explosion", description: "Bright propane-style burst",
100
+ promptHint: "a propane gas explosion bursting outward, bright bluish-orange flash at the core fading into a radiating fireball with the distinctive sharp flame profile and glass shattering at the periphery" },
101
+ { id: "oil-fire", category: "fire-blasts", label: "Oil Fire", description: "Tall greasy flames + thick black smoke",
102
+ promptHint: "an oil fire burning in the scene, tall greasy orange flames licking upward with dense roiling black smoke pouring into the sky and a hellish heat shimmer obscuring the background" },
103
+ { id: "blazing-inferno", category: "fire-blasts", label: "Blazing Inferno", description: "Wall of fire consuming everything",
104
+ promptHint: "a blazing inferno consuming the scene, wall of roaring orange flames climbing every surface with thick black smoke pouring upward and embers swirling in the convection currents above" },
105
+ { id: "flame-burst", category: "fire-blasts", label: "Flame Burst", description: "Quick directional jet of flame",
106
+ promptHint: "a directional flame burst shooting through the scene, sharp jet of orange-yellow fire projecting forward like a flamethrower stream with trailing smoke and visible heat warping the air behind it" },
107
+ { id: "ember-shower", category: "fire-blasts", label: "Ember Shower", description: "Cascade of glowing orange embers",
108
+ promptHint: "a dramatic ember shower cascading through the scene, glowing orange and gold embers tumbling and drifting through the air like fiery snowfall with trails of smoke and ash" },
109
+ { id: "smoke-pillar", category: "fire-blasts", label: "Smoke Pillar", description: "Tall vertical column of black smoke",
110
+ promptHint: "a tall vertical column of dense black smoke rising into the sky, twisting upward with internal turbulence and a faint orange glow at the base hinting at flames below" },
111
+ { id: "mushroom-cloud", category: "fire-blasts", label: "Mushroom Cloud", description: "Classic dome-and-stem detonation cloud",
112
+ promptHint: "a classic mushroom cloud rising in the distance, dome-and-stem detonation column with internal orange glow and turbulent grey-brown smoke swirling outward at the cap" },
113
+ // ── Electric ──
114
+ { id: "lightning-bolt", category: "electric", label: "Lightning Bolt", description: "Branching strike across stormy sky",
115
+ promptHint: "a brilliant lightning bolt forking across a dark stormy sky, blinding white-blue branching arcs cutting through the clouds with a momentary illumination of the surrounding scene" },
116
+ { id: "lightning-strike-impact", category: "electric", label: "Lightning Strike Impact", description: "Bolt hitting the ground with explosion of light",
117
+ promptHint: "a lightning bolt striking the ground in the scene, blinding white-blue column of electricity slamming into a surface with a radial burst of light, scattering sparks and a thunderclap shockwave displacing nearby dust" },
118
+ { id: "lightning-storm", category: "electric", label: "Lightning Storm", description: "Multiple simultaneous strikes",
119
+ promptHint: "a violent lightning storm with multiple simultaneous strikes branching across the heavens, several jagged white-blue bolts forking down from low clouds and lighting the whole scene in stark intermittent flashes" },
120
+ { id: "ball-lightning", category: "electric", label: "Ball Lightning", description: "Glowing orb of electric plasma floating mid-air",
121
+ promptHint: "a rare ball lightning phenomenon floating in mid-air, glowing blue-white orb of electric plasma drifting slowly with crackling tendrils of energy spitting outward and a faint hum implied by visible field distortion" },
122
+ { id: "plasma-arc", category: "electric", label: "Plasma Arc", description: "High-voltage continuous arc between two points",
123
+ promptHint: "a continuous high-voltage plasma arc crackling between two points in the scene, white-violet electric current branching and writhing with intense glow and small showers of sparks at each terminal" },
124
+ { id: "taser-sparks", category: "electric", label: "Taser Sparks", description: "Compact crackling electric discharge on contact",
125
+ promptHint: "a compact taser-style electric discharge crackling on contact, bright blue-white sparks branching outward in a small radial spray with sharp little arcs jumping between contact points" },
126
+ { id: "electric-discharge", category: "electric", label: "Electric Discharge", description: "Burst of arcing energy from a malfunctioning device",
127
+ promptHint: "a sudden electric discharge bursting from a malfunctioning device, branching arcs of blue-white current spraying outward with showers of sparks and faint smoke trails curling from blackened contact points" },
128
+ { id: "transformer-blowout", category: "electric", label: "Transformer Blowout", description: "Blue-white explosion atop a power pole",
129
+ promptHint: "a transformer blowout atop a power pole, brilliant blue-white explosion of electric energy with showers of sparks raining downward and a brief mushroom of smoke followed by a blackout shadow falling across the scene" },
130
+ { id: "st-elmos-fire", category: "electric", label: "St. Elmo's Fire", description: "Eerie blue plasma glow on metal extremities",
131
+ promptHint: "an eerie St. Elmo's Fire phenomenon, soft blue-violet plasma glow flickering along metal extremities and pointed surfaces with a corona-like halo and faint crackling discharge" },
132
+ { id: "static-shock-burst", category: "electric", label: "Static Shock Burst", description: "Tiny visible static-electricity zap",
133
+ promptHint: "a small static shock burst visible at point of contact, tiny crackling blue-white spark jumping between two surfaces with a brief micro-arc of electricity and a hint of ozone-tinted air" },
134
+ // ── Combat ──
135
+ { id: "muzzle-flash", category: "combat", label: "Muzzle Flash", description: "Bright orange flash from gun barrel",
136
+ promptHint: "a bright muzzle flash erupting from a gun barrel, sharp orange-yellow burst of light at the barrel tip with smoke trailing and the firearm in mid-recoil" },
137
+ { id: "gunshot-impact", category: "combat", label: "Gunshot Impact", description: "Bullet hitting a surface with debris spray",
138
+ promptHint: "a gunshot impact on a surface, sharp burst of debris spraying outward from the bullet hole with small fragments and dust scattering radially in the moment of strike" },
139
+ { id: "bullet-trail", category: "combat", label: "Bullet Trail", description: "Visible bullet streak through air",
140
+ promptHint: "a streaking bullet trail cutting through the air, thin bright tracer line accompanied by faint vapor wake suggesting hypersonic velocity and a sense of forward motion through the frame" },
141
+ { id: "sword-spark", category: "combat", label: "Sword Spark", description: "Macro shower of metal-on-metal friction sparks",
142
+ promptHint: "a macro close-up of bright sparks at the moment of metal-on-metal friction, white-hot incandescent flecks scattering radially with brief streaks of friction-light, captured at extreme close range with no swords or blades visible in the frame" },
143
+ { id: "blade-clash", category: "combat", label: "Blade Clash", description: "Two blades meeting with impact wave",
144
+ promptHint: "two blades clashing together at the moment of impact, sparks flying outward from the contact line and a brief shockwave of displaced air rippling around the steel edges" },
145
+ { id: "ricochet-spark", category: "combat", label: "Ricochet Spark", description: "Bullet bouncing off metal with sparks",
146
+ promptHint: "a bullet ricocheting off a metal surface, sharp burst of orange-white sparks at the deflection point with the bullet visibly trailing off at a new angle and a thin streak of vapor in its wake" },
147
+ { id: "debris-field", category: "combat", label: "Debris Field", description: "Frozen mid-air shrapnel scattering",
148
+ promptHint: "a debris field frozen in mid-air, fragments of wood, metal, and concrete scattering outward in a radial pattern from a central impact point with dust and smoke swirling among the larger pieces" },
149
+ { id: "glass-shatter-airborne", category: "combat", label: "Airborne Glass Shatter", description: "Glass exploding outward in mid-air shards",
150
+ promptHint: "a window or glass surface shattering outward in mid-air, hundreds of jagged crystalline shards exploding into the scene catching the light and tumbling in suspended chaos at the moment of impact" },
151
+ { id: "shockwave-ground", category: "combat", label: "Ground Shockwave", description: "Visible expanding ring at ground level",
152
+ promptHint: "a visible shockwave expanding at ground level, dust and small debris pushed outward in a clear radial ring from the impact origin with a momentary distortion in the air above" },
153
+ { id: "sonic-boom", category: "combat", label: "Sonic Boom", description: "Cone of compressed air at supersonic speed",
154
+ promptHint: "a sonic boom cone of compressed air visible around a supersonic object, vapor cone forming a sharp white halo with a trailing condensation cloud and a sense of audible thunder implied by the violent rippling distortion" },
155
+ { id: "smoke-grenade", category: "combat", label: "Smoke Grenade", description: "Thick colored smoke blooming outward",
156
+ promptHint: "a smoke grenade billowing colored smoke outward, thick clouds of dense vapor blooming in red-orange or grey rolling across the scene at low height and obscuring the background tactical-style" },
157
+ { id: "flashbang", category: "combat", label: "Flashbang", description: "Blinding white-out burst of light",
158
+ promptHint: "a flashbang detonation, intense blinding white-out burst of light filling the frame with a shockwave of compressed air and a fast-fading core of pure white at the explosion's center" },
159
+ { id: "blood-spray", category: "combat", label: "Blood Spray", description: "Cinematic arc of blood droplets",
160
+ promptHint: "a cinematic arc of blood droplets spraying outward in slow-motion, suspended red flecks tracing a curved path through the air with the dramatic stylized aesthetic of action cinema" },
161
+ { id: "arrow-hit-spark", category: "combat", label: "Arrow Hit Spark", description: "Arrow striking with small sparks at impact",
162
+ promptHint: "an arrow striking a surface with a small burst of sparks at the impact point, shaft quivering on contact and tiny incandescent flecks scattering outward from the arrowhead" },
163
+ // ── Sci-Fi ──
164
+ { id: "laser-blast", category: "sci-fi", label: "Laser Blast", description: "Bright coherent beam of energy",
165
+ promptHint: "a bright coherent laser blast cutting through the scene, vivid red or green beam of focused energy with a glowing core and a halo of scattered light along its path" },
166
+ { id: "energy-beam", category: "sci-fi", label: "Energy Beam", description: "Wide pulsing beam of plasma energy",
167
+ promptHint: "a wide pulsing energy beam projecting forward, swirling plasma core wrapped in concentric pulses of light and a halo of bright glow saturating the surrounding atmosphere" },
168
+ { id: "plasma-bolt", category: "sci-fi", label: "Plasma Bolt", description: "Glowing projectile leaving a vapor trail",
169
+ promptHint: "a glowing plasma bolt streaking through the air, bright cyan or violet projectile with a trailing vapor wake and small radiating arcs of energy spitting from its surface" },
170
+ { id: "force-field-shimmer", category: "sci-fi", label: "Force Field Shimmer", description: "Translucent hex-pattern energy barrier",
171
+ promptHint: "a translucent hexagonal force field shimmering in the scene, faint blue-cyan energy panels rippling with electric edges and refracting whatever lies behind it" },
172
+ { id: "force-field-impact", category: "sci-fi", label: "Force Field Impact", description: "Visible ripple where projectile hits shield",
173
+ promptHint: "a force field absorbing an impact, visible ripple spreading outward from the strike point with hexagonal energy panels glowing brightly at the contact site and discharge arcs branching across the surface" },
174
+ { id: "portal-opening", category: "sci-fi", label: "Portal Opening", description: "Swirling vortex of energy tearing open in space",
175
+ promptHint: "a sci-fi portal tearing open in space, swirling vortex of bluish energy with edges flickering between dimensions and a glowing event horizon framing a glimpse of the destination beyond" },
176
+ { id: "warp-distortion", category: "sci-fi", label: "Warp Distortion", description: "Spacetime bending around an object",
177
+ promptHint: "a spacetime warp distortion bending the air around an object, light streaks curving inward and the background visibly stretched and refracted in the gravitational well of the effect" },
178
+ { id: "hologram-flicker", category: "sci-fi", label: "Hologram Flicker", description: "Translucent projection glitching",
179
+ promptHint: "a translucent holographic projection flickering and glitching in the scene, scanlines and chromatic noise distorting the cyan-blue figure with brief signal dropouts revealing the air behind it" },
180
+ { id: "ion-storm", category: "sci-fi", label: "Ion Storm", description: "Crackling field of charged particles against a cosmic backdrop",
181
+ promptHint: "a crackling ion storm filling the scene, field of charged particles flickering with ionized streamers and ribbons of plasma weaving through the air with auroral colors washing across the cosmic backdrop" },
182
+ { id: "antimatter-flash", category: "sci-fi", label: "Antimatter Flash", description: "Reality-tearing burst of pure white energy",
183
+ promptHint: "an antimatter annihilation flash, blinding burst of pure white energy radiating outward with the surrounding space appearing to tear and warp around the explosion's perfectly spherical core" },
184
+
185
+ // ── Magic ──
186
+ { id: "fireball-spell", category: "magic", label: "Fireball Spell", description: "Hand-cast orb of swirling fire",
187
+ promptHint: "a hand-cast fireball spell, swirling orb of bright orange-red flame held mid-air with embers spinning around its surface and a halo of heat distortion warping the air at the caster's fingertips" },
188
+ { id: "magic-aura", category: "magic", label: "Magic Aura", description: "Glowing energy halo around a figure",
189
+ promptHint: "a glowing magic aura surrounding a figure, soft luminous halo of golden or violet energy radiating outward with shimmer particles drifting upward and faint runes hovering in the field" },
190
+ { id: "summoning-glyph", category: "magic", label: "Summoning Glyph", description: "Glowing magical circle on the ground",
191
+ promptHint: "a glowing summoning circle inscribed on the ground, intricate concentric runic glyphs blazing with golden light and pillars of energy rising from the perimeter to form a column of arcane power" },
192
+ { id: "lightning-magic", category: "magic", label: "Lightning Magic", description: "Electric sorcery arcing from caster's hands",
193
+ promptHint: "lightning magic arcing from a caster's outstretched hands, branching white-blue bolts of electric sorcery crackling forward with sparks spitting from fingertips and a halo of power glowing around the wrist" },
194
+ { id: "ice-shard-burst", category: "magic", label: "Ice Shard Burst", description: "Crystalline shards spraying outward",
195
+ promptHint: "a burst of crystalline ice shards spraying outward, dozens of jagged frozen splinters flying radially through cold mist with frost-blue refractive edges catching the light" },
196
+ { id: "energy-rune", category: "magic", label: "Energy Rune", description: "Glowing arcane symbol hanging in the air",
197
+ promptHint: "a glowing arcane energy rune hovering in the air, intricate symbolic geometry burning bright with golden or cyan light and a soft pulse of power emanating in concentric waves around the symbol" },
198
+ { id: "portal-magic", category: "magic", label: "Magic Portal", description: "Swirling mystical doorway in space",
199
+ promptHint: "a swirling mystical portal opening in space, ring of arcane fire encircling a vortex of dimensional energy with sparks swirling around the rim and a glimpse of an otherworldly realm visible through the opening" },
200
+ { id: "healing-glow", category: "magic", label: "Healing Glow", description: "Warm golden light emanating from caster",
201
+ promptHint: "a warm healing glow emanating from a caster's hands, gentle golden-white radiance spreading outward with motes of soft light drifting upward and a sense of restorative energy permeating the surrounding air" },
202
+ { id: "dark-vortex", category: "magic", label: "Dark Vortex", description: "Ominous black-purple swirling void",
203
+ promptHint: "an ominous dark vortex swirling in the scene, churning black-and-purple void with tendrils of shadow energy reaching outward and a sense of consuming power drawing light into its center" },
204
+ { id: "light-explosion", category: "magic", label: "Light Explosion", description: "Burst of pure white-gold radiance",
205
+ promptHint: "a brilliant explosion of pure white-gold radiance, divine burst of light radiating outward with rays of beam-light fanning across the scene and motes of golden particles suspended in the afterglow" },
206
+ ] as const
207
+
208
+ export const ACTION_FX_IDS: ReadonlyArray<string> = ACTION_FX.map((fx) => fx.id)
209
+
210
+ const actionFxById = new Map<string, ActionFx>(ACTION_FX.map((fx) => [fx.id, fx]))
211
+
212
+ export function getActionFx(id: string | undefined | null): ActionFx | undefined {
213
+ if (!id) return undefined
214
+ return actionFxById.get(id)
215
+ }
216
+
217
+ export function getActionFxLabel(id: string | undefined | null, fallback?: string): string {
218
+ const fx = getActionFx(id)
219
+ if (fx) return fx.label
220
+ if (fallback !== undefined) return fallback
221
+ return (id ?? "").replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())
222
+ }
223
+
224
+ export function getActionFxPromptHint(id: string | undefined | null): string {
225
+ return getActionFx(id)?.promptHint ?? ""
226
+ }
227
+
228
+ /**
229
+ * Multi-pick: 1–2 ids → composite FX clause.
230
+ *
231
+ * Single id → entry's own promptHint as a single-element array.
232
+ * Two ids → emit each independently and let the comma-join compose them.
233
+ * Caps at 2 ids (silently drops the rest); the picker UI also enforces this
234
+ * cap, but the cap here keeps the contract robust against stale workflow
235
+ * data. Duplicate ids are deduplicated before the cap is applied.
236
+ */
237
+ export function buildActionFxHints(value: unknown): string[] {
238
+ const ids: string[] = []
239
+ if (typeof value === "string" && value) {
240
+ ids.push(value)
241
+ } else if (Array.isArray(value)) {
242
+ for (const v of value) {
243
+ if (typeof v === "string" && v && !ids.includes(v)) {
244
+ ids.push(v)
245
+ if (ids.length >= 2) break
246
+ }
247
+ }
248
+ }
249
+ const hints: string[] = []
250
+ for (const id of ids) {
251
+ const hint = getActionFxPromptHint(id)
252
+ if (hint) hints.push(hint)
253
+ }
254
+ return hints
255
+ }