@nodaro/prompts 1.7.2 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/index.cjs +5453 -4271
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +1221 -63
  4. package/dist/index.d.ts +1221 -63
  5. package/dist/index.js +5366 -4273
  6. package/dist/index.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/__tests__/b7-person-pack-e2e.test.ts +37 -0
  9. package/src/__tests__/catalog-funnel-ratchet.test.ts +97 -0
  10. package/src/__tests__/catalog-packs.test.ts +130 -0
  11. package/src/__tests__/catalog-sidecar-coverage.test.ts +27 -0
  12. package/src/__tests__/catalog-terms.test.ts +162 -0
  13. package/src/__tests__/character-default-role.test.ts +3 -2
  14. package/src/__tests__/content-free-contract.test.ts +45 -0
  15. package/src/__tests__/dod-replace-pack-acceptance.test.ts +41 -0
  16. package/src/__tests__/fixtures/parameter-hint-golden.json +2959 -0
  17. package/src/__tests__/fixtures/person-sector-pack.ts +27 -0
  18. package/src/__tests__/i18n-entry-completeness.test.ts +5 -2
  19. package/src/__tests__/parameter-hint-mode.test.ts +385 -0
  20. package/src/__tests__/parameter-prompt-hint-pack-fallback.test.ts +25 -0
  21. package/src/__tests__/person-packs.test.ts +166 -0
  22. package/src/__tests__/project-all-catalogs.test.ts +26 -0
  23. package/src/__tests__/prompt-builder.test.ts +53 -0
  24. package/src/__tests__/registered-catalogs-funnel.test.ts +30 -0
  25. package/src/__tests__/registered-catalogs-guard.test.ts +11 -0
  26. package/src/__tests__/term.test.ts +104 -0
  27. package/src/__tests__/transitions.test.ts +8 -5
  28. package/src/__tests__/upstream-immutability.test.ts +23 -0
  29. package/src/action-fx.ts +67 -17
  30. package/src/aesthetic.ts +54 -6
  31. package/src/atmosphere.ts +64 -23
  32. package/src/backdrop.ts +44 -30
  33. package/src/camera-format.ts +33 -11
  34. package/src/camera-motions.ts +89 -0
  35. package/src/catalog-packs.ts +125 -0
  36. package/src/catalog-sidecar-coverage.ts +36 -0
  37. package/src/character-fx.ts +112 -39
  38. package/src/color-look.ts +44 -27
  39. package/src/composition-effects.ts +21 -7
  40. package/src/era.ts +24 -0
  41. package/src/exposure-settings.ts +76 -18
  42. package/src/framing.ts +100 -0
  43. package/src/held-prop.ts +125 -63
  44. package/src/identity-lock.ts +12 -5
  45. package/src/image-reference-doctrine.ts +55 -0
  46. package/src/index.ts +6 -0
  47. package/src/instrumentation.ts +148 -57
  48. package/src/lens.ts +31 -15
  49. package/src/lighting.ts +120 -59
  50. package/src/loop-subject.ts +27 -1
  51. package/src/materials.ts +123 -69
  52. package/src/mood.ts +123 -51
  53. package/src/music-genre.ts +171 -67
  54. package/src/music-mood.ts +85 -17
  55. package/src/parameter-prompt-hint.ts +168 -56
  56. package/src/person-packs.ts +182 -0
  57. package/src/person.ts +506 -408
  58. package/src/photo-genre.ts +37 -22
  59. package/src/photographer.ts +138 -1
  60. package/src/picker-catalogs.ts +86 -40
  61. package/src/picker-wiring.ts +1 -1
  62. package/src/pose.ts +105 -40
  63. package/src/post-process-effects.ts +51 -8
  64. package/src/prompt-builder.ts +16 -1
  65. package/src/provider-prompt-doctrine.ts +1 -2
  66. package/src/render-quality.ts +25 -7
  67. package/src/setting.ts +30 -14
  68. package/src/style-presets.ts +1 -1
  69. package/src/style.ts +33 -15
  70. package/src/styling.ts +155 -94
  71. package/src/surround-fill.ts +67 -0
  72. package/src/temporal.ts +80 -18
  73. package/src/term.ts +155 -0
  74. package/src/transitions.ts +73 -26
  75. package/src/voice-character.ts +190 -90
  76. package/src/voice-delivery.ts +83 -12
package/src/lighting.ts CHANGED
@@ -10,6 +10,8 @@
10
10
  * frontend DAG executor and the backend orchestrator.
11
11
  */
12
12
 
13
+ import { resolveTerm, type PickerHintMode } from "./term.js"
14
+
13
15
  export type LightingCategory =
14
16
  | "time-of-day"
15
17
  | "style"
@@ -23,93 +25,102 @@ export interface Lighting {
23
25
  readonly category: LightingCategory
24
26
  readonly description: string
25
27
  readonly promptHint: string
28
+ /**
29
+ * Compact professional term injected in compact hint mode (see `term.ts`).
30
+ *
31
+ * Lighting labels are bare MODIFIERS — "Short", "Broad", "Loop", "Split",
32
+ * "Hard" mean nothing on their own and collide head-on with common English
33
+ * words, so nearly every entry here authors the trade phrasing that carries
34
+ * its category noun ("short lighting", "1:4 lighting ratio").
35
+ */
36
+ readonly term?: string
26
37
  }
27
38
 
28
39
  export const LIGHTINGS: ReadonlyArray<Lighting> = [
29
40
  // Time of day (15)
30
- { id: "dawn", label: "Dawn", category: "time-of-day", description: "Pre-sunrise pale glow", promptHint: "dawn lighting, the pre-sunrise pale glow with deep blue ambient tones transitioning to soft pink and orange at the horizon, low contrast, cool ambient" },
31
- { id: "sunrise", label: "Sunrise", category: "time-of-day", description: "Warm low sun, long shadows", promptHint: "sunrise lighting, warm low-angle sun with long shadows and soft golden tones" },
32
- { id: "morning", label: "Morning", category: "time-of-day", description: "Bright fresh morning light", promptHint: "morning lighting, bright fresh ambient daylight with soft directional sun, warm white tones and clean shadows" },
33
- { id: "noon", label: "Noon", category: "time-of-day", description: "Harsh overhead midday sun", promptHint: "midday noon lighting, harsh overhead sun with high contrast and strong vertical shadows" },
34
- { id: "harsh-midday", label: "Harsh Midday", category: "time-of-day", description: "Bleached white-sun zenith", promptHint: "harsh midday white-sun lighting, sun directly overhead at zenith, blown-out white highlights and short hard shadows pooled directly beneath the subject" },
35
- { id: "afternoon", label: "Afternoon", category: "time-of-day", description: "Warm late afternoon glow", promptHint: "afternoon lighting, warm directional late-afternoon sun with elongated shadows, saturated amber tones leading into golden hour" },
36
- { id: "overcast", label: "Overcast", category: "time-of-day", description: "Soft diffused daylight", promptHint: "overcast daylight, soft diffused light from a uniformly cloudy sky with no harsh shadows" },
41
+ { id: "dawn", label: "Dawn", category: "time-of-day", description: "Pre-sunrise pale glow", promptHint: "dawn lighting, the pre-sunrise pale glow with deep blue ambient tones transitioning to soft pink and orange at the horizon, low contrast, cool ambient", term: "dawn lighting" },
42
+ { id: "sunrise", label: "Sunrise", category: "time-of-day", description: "Warm low sun, long shadows", promptHint: "sunrise lighting, warm low-angle sun with long shadows and soft golden tones", term: "sunrise lighting" },
43
+ { id: "morning", label: "Morning", category: "time-of-day", description: "Bright fresh morning light", promptHint: "morning lighting, bright fresh ambient daylight with soft directional sun, warm white tones and clean shadows", term: "morning lighting" },
44
+ { id: "noon", label: "Noon", category: "time-of-day", description: "Harsh overhead midday sun", promptHint: "midday noon lighting, harsh overhead sun with high contrast and strong vertical shadows", term: "overhead noon sun" },
45
+ { id: "harsh-midday", label: "Harsh Midday", category: "time-of-day", description: "Bleached white-sun zenith", promptHint: "harsh midday white-sun lighting, sun directly overhead at zenith, blown-out white highlights and short hard shadows pooled directly beneath the subject", term: "harsh midday sun" },
46
+ { id: "afternoon", label: "Afternoon", category: "time-of-day", description: "Warm late afternoon glow", promptHint: "afternoon lighting, warm directional late-afternoon sun with elongated shadows, saturated amber tones leading into golden hour", term: "afternoon lighting" },
47
+ { id: "overcast", label: "Overcast", category: "time-of-day", description: "Soft diffused daylight", promptHint: "overcast daylight, soft diffused light from a uniformly cloudy sky with no harsh shadows", term: "overcast daylight" },
37
48
  { id: "golden-hour", label: "Golden Hour", category: "time-of-day", description: "Warm sunset glow", promptHint: "golden hour lighting, warm sunset glow with soft directional sunlight and saturated golden tones" },
38
- { id: "dusk", label: "Dusk", category: "time-of-day", description: "Post-sunset fading light", promptHint: "dusk lighting, the post-sunset fading light with deepening blue sky, residual warm horizon glow, and rising ambient cool tones" },
49
+ { id: "dusk", label: "Dusk", category: "time-of-day", description: "Post-sunset fading light", promptHint: "dusk lighting, the post-sunset fading light with deepening blue sky, residual warm horizon glow, and rising ambient cool tones", term: "dusk lighting" },
39
50
  { id: "blue-hour", label: "Blue Hour", category: "time-of-day", description: "Cool dusk twilight", promptHint: "blue hour twilight lighting, cool desaturated tones just after sunset with soft ambient light" },
40
- { id: "twilight", label: "Twilight", category: "time-of-day", description: "Between blue hour and night", promptHint: "twilight lighting, the transitional dusk between blue hour and full night, deep indigo sky with the last residual ambient glow on the horizon and emerging artificial city lights" },
41
- { id: "night", label: "Night", category: "time-of-day", description: "Deep night, low ambient", promptHint: "night lighting, deep dark scene with minimal ambient illumination and high contrast highlights" },
42
- { id: "midnight", label: "Midnight", category: "time-of-day", description: "Deepest night, near-black sky", promptHint: "midnight lighting, the deepest part of night with a near-black sky, minimal ambient illumination, scattered cool moonlight or starlight as the only natural source" },
43
- { id: "moonlight", label: "Moonlight", category: "time-of-day", description: "Cool blue moonlit scene", promptHint: "moonlight, cool blue ambient illumination with soft directional moonlit highlights and deep shadows" },
44
- { id: "neon-night", label: "Neon Night", category: "time-of-day", description: "Saturated neon city night", promptHint: "neon night lighting, saturated magenta and cyan neon glow against deep night ambient, urban cyberpunk feel" },
51
+ { id: "twilight", label: "Twilight", category: "time-of-day", description: "Between blue hour and night", promptHint: "twilight lighting, the transitional dusk between blue hour and full night, deep indigo sky with the last residual ambient glow on the horizon and emerging artificial city lights", term: "twilight lighting" },
52
+ { id: "night", label: "Night", category: "time-of-day", description: "Deep night, low ambient", promptHint: "night lighting, deep dark scene with minimal ambient illumination and high contrast highlights", term: "night lighting" },
53
+ { id: "midnight", label: "Midnight", category: "time-of-day", description: "Deepest night, near-black sky", promptHint: "midnight lighting, the deepest part of night with a near-black sky, minimal ambient illumination, scattered cool moonlight or starlight as the only natural source", term: "midnight lighting" },
54
+ { id: "moonlight", label: "Moonlight", category: "time-of-day", description: "Cool blue moonlit scene", promptHint: "moonlight, cool blue ambient illumination with soft directional moonlit highlights and deep shadows", term: "cool blue moonlight" },
55
+ { id: "neon-night", label: "Neon Night", category: "time-of-day", description: "Saturated neon city night", promptHint: "neon night lighting, saturated magenta and cyan neon glow against deep night ambient, urban cyberpunk feel", term: "neon night lighting" },
45
56
 
46
57
  // Style (31)
47
- { id: "three-point", label: "Three-Point", category: "style", description: "Classic key + fill + back", promptHint: "three-point lighting setup, balanced key light with fill and rim back-light, classical studio look" },
48
- { id: "rembrandt", label: "Rembrandt", category: "style", description: "Triangle of light on cheek", promptHint: "Rembrandt lighting, distinctive triangle of light on the shadow-side cheek, painterly chiaroscuro" },
49
- { id: "chiaroscuro", label: "Chiaroscuro", category: "style", description: "Strong light/dark contrast", promptHint: "chiaroscuro lighting, dramatic strong contrast between deep shadows and bright highlights" },
50
- { id: "silhouette", label: "Silhouette", category: "style", description: "Subject as pure shape", promptHint: "silhouette lighting, subject rendered as a pure dark shape against a much brighter background" },
51
- { id: "high-key", label: "High-Key", category: "style", description: "Bright, low-contrast", promptHint: "high-key lighting, bright low-contrast scene with minimal shadows and a light overall tone" },
52
- { id: "low-key", label: "Low-Key", category: "style", description: "Dark, high-contrast", promptHint: "low-key lighting, dark high-contrast scene with deep shadows and selective highlights" },
53
- { id: "split", label: "Split", category: "style", description: "Half-lit half-shadow face", promptHint: "split lighting, light hitting only one half of the face with the other half in deep shadow" },
58
+ { id: "three-point", label: "Three-Point", category: "style", description: "Classic key + fill + back", promptHint: "three-point lighting setup, balanced key light with fill and rim back-light, classical studio look", term: "three-point lighting" },
59
+ { id: "rembrandt", label: "Rembrandt", category: "style", description: "Triangle of light on cheek", promptHint: "Rembrandt lighting, distinctive triangle of light on the shadow-side cheek, painterly chiaroscuro", term: "rembrandt lighting" },
60
+ { id: "chiaroscuro", label: "Chiaroscuro", category: "style", description: "Strong light/dark contrast", promptHint: "chiaroscuro lighting, dramatic strong contrast between deep shadows and bright highlights", term: "chiaroscuro lighting" },
61
+ { id: "silhouette", label: "Silhouette", category: "style", description: "Subject as pure shape", promptHint: "silhouette lighting, subject rendered as a pure dark shape against a much brighter background", term: "silhouette lighting" },
62
+ { id: "high-key", label: "High-Key", category: "style", description: "Bright, low-contrast", promptHint: "high-key lighting, bright low-contrast scene with minimal shadows and a light overall tone", term: "high-key lighting" },
63
+ { id: "low-key", label: "Low-Key", category: "style", description: "Dark, high-contrast", promptHint: "low-key lighting, dark high-contrast scene with deep shadows and selective highlights", term: "low-key lighting" },
64
+ { id: "split", label: "Split", category: "style", description: "Half-lit half-shadow face", promptHint: "split lighting, light hitting only one half of the face with the other half in deep shadow", term: "split lighting" },
54
65
  // Classical portrait lighting setups
55
- { id: "butterfly", label: "Butterfly", category: "style", description: "Glamour, nose-shadow butterfly", promptHint: "butterfly portrait lighting, key light placed directly above and slightly in front of the subject casting a small symmetrical butterfly-shaped shadow under the nose, classic Hollywood glamour with even illumination across both cheeks" },
56
- { id: "loop", label: "Loop", category: "style", description: "Most natural portrait setup", promptHint: "loop portrait lighting, key light slightly to one side and above eye level casting a small loop-shaped nose shadow on the cheek that does not touch the shadow side, the most natural and flattering classical portrait setup" },
57
- { id: "broad", label: "Broad", category: "style", description: "Wider face, friendly key", promptHint: "broad portrait lighting, key light striking the side of the face turned toward the camera so the larger lit cheek dominates the frame, makes the face appear wider and more open with a friendly approachable feel" },
58
- { id: "short", label: "Short", category: "style", description: "Slimming, dramatic key", promptHint: "short portrait lighting, key light striking the side of the face turned away from the camera so the larger plane of the face falls into shadow, slims the face and adds dramatic dimension favored in editorial and male portraiture" },
59
- { id: "hatchet", label: "Hatchet", category: "style", description: "Overhead skim, deep side shadow", promptHint: "hatchet portrait lighting, hard overhead light skimming the face from one side and leaving the opposite side in deep unrelieved shadow, theatrical and severe with a sharply divided contour" },
60
- { id: "clamshell", label: "Clamshell", category: "style", description: "Beauty key + bottom reflector", promptHint: "clamshell beauty lighting, soft key light above the subject paired with a reflector or fill below the chin sandwiching the face evenly between two light sources, glossy commercial beauty look with twin catchlights and minimal shadow under the jaw" },
61
- { id: "hard", label: "Hard", category: "style", description: "Sharp-edged shadows", promptHint: "hard lighting, sharp-edged crisp shadows from an undiffused direct light source" },
62
- { id: "soft", label: "Soft", category: "style", description: "Diffused gentle light", promptHint: "soft diffused lighting, gentle wraparound light with smooth shadow transitions" },
63
- { id: "practical", label: "Practical", category: "style", description: "In-scene visible lights", promptHint: "practical lighting, illumination from visible in-scene sources (lamps, windows, screens, candles)" },
66
+ { id: "butterfly", label: "Butterfly", category: "style", description: "Glamour, nose-shadow butterfly", promptHint: "butterfly portrait lighting, key light placed directly above and slightly in front of the subject casting a small symmetrical butterfly-shaped shadow under the nose, classic Hollywood glamour with even illumination across both cheeks", term: "butterfly lighting" },
67
+ { id: "loop", label: "Loop", category: "style", description: "Most natural portrait setup", promptHint: "loop portrait lighting, key light slightly to one side and above eye level casting a small loop-shaped nose shadow on the cheek that does not touch the shadow side, the most natural and flattering classical portrait setup", term: "loop lighting" },
68
+ { id: "broad", label: "Broad", category: "style", description: "Wider face, friendly key", promptHint: "broad portrait lighting, key light striking the side of the face turned toward the camera so the larger lit cheek dominates the frame, makes the face appear wider and more open with a friendly approachable feel", term: "broad lighting" },
69
+ { id: "short", label: "Short", category: "style", description: "Slimming, dramatic key", promptHint: "short portrait lighting, key light striking the side of the face turned away from the camera so the larger plane of the face falls into shadow, slims the face and adds dramatic dimension favored in editorial and male portraiture", term: "short lighting" },
70
+ { id: "hatchet", label: "Hatchet", category: "style", description: "Overhead skim, deep side shadow", promptHint: "hatchet portrait lighting, hard overhead light skimming the face from one side and leaving the opposite side in deep unrelieved shadow, theatrical and severe with a sharply divided contour", term: "hatchet lighting" },
71
+ { id: "clamshell", label: "Clamshell", category: "style", description: "Beauty key + bottom reflector", promptHint: "clamshell beauty lighting, soft key light above the subject paired with a reflector or fill below the chin sandwiching the face evenly between two light sources, glossy commercial beauty look with twin catchlights and minimal shadow under the jaw", term: "clamshell lighting" },
72
+ { id: "hard", label: "Hard", category: "style", description: "Sharp-edged shadows", promptHint: "hard lighting, sharp-edged crisp shadows from an undiffused direct light source", term: "hard light" },
73
+ { id: "soft", label: "Soft", category: "style", description: "Diffused gentle light", promptHint: "soft diffused lighting, gentle wraparound light with smooth shadow transitions", term: "soft diffused light" },
74
+ { id: "practical", label: "Practical", category: "style", description: "In-scene visible lights", promptHint: "practical lighting, illumination from visible in-scene sources (lamps, windows, screens, candles)", term: "practical lighting" },
64
75
  // Modern social-video lighting styles
65
76
  { id: "ring-light", label: "Ring Light", category: "style", description: "Beauty/vlog ring catchlight", promptHint: "ring light setup, even frontal illumination with the unmistakable circular catchlight in the eyes typical of beauty and vlog content" },
66
77
  { id: "phone-screen-glow", label: "Phone Screen Glow", category: "style", description: "Cool screen underlight", promptHint: "phone screen glow lighting, cool blue underlighting from a phone screen casting upward onto the subject's face" },
67
- { id: "selfie-natural", label: "Selfie Natural", category: "style", description: "Window-light selfie", promptHint: "window-light selfie aesthetic, soft natural daylight from a single window with casual handheld framing" },
68
- { id: "natural", label: "Natural", category: "style", description: "Available ambient light", promptHint: "natural lighting, available ambient light with no artificial setup, organic and unpolished" },
69
- { id: "volumetric", label: "Volumetric", category: "style", description: "Visible light beams in haze", promptHint: "volumetric lighting, visible god-ray light beams cutting through hazy atmosphere with strong directional shafts" },
70
- { id: "noir", label: "Noir", category: "style", description: "High-contrast B&W film noir", promptHint: "film noir lighting, high-contrast black-and-white aesthetic with hard chiaroscuro shadows, venetian-blind slat shadows, and crushed deep blacks" },
78
+ { id: "selfie-natural", label: "Selfie Natural", category: "style", description: "Window-light selfie", promptHint: "window-light selfie aesthetic, soft natural daylight from a single window with casual handheld framing", term: "natural window-light selfie" },
79
+ { id: "natural", label: "Natural", category: "style", description: "Available ambient light", promptHint: "natural lighting, available ambient light with no artificial setup, organic and unpolished", term: "natural available light" },
80
+ { id: "volumetric", label: "Volumetric", category: "style", description: "Visible light beams in haze", promptHint: "volumetric lighting, visible god-ray light beams cutting through hazy atmosphere with strong directional shafts", term: "volumetric lighting" },
81
+ { id: "noir", label: "Noir", category: "style", description: "High-contrast B&W film noir", promptHint: "film noir lighting, high-contrast black-and-white aesthetic with hard chiaroscuro shadows, venetian-blind slat shadows, and crushed deep blacks", term: "film noir lighting" },
71
82
  // Flash & camera-flash styles
72
83
  { id: "on-camera-flash", label: "On-Camera Flash", category: "style", description: "Paparazzi/iPhone direct flash", promptHint: "on-camera flash lighting, harsh direct frontal flash with blown-out highlights on skin, hard shadow falloff behind the subject and a darkened background, paparazzi and iPhone-flash signature" },
73
- { id: "mirror-bounce-flash", label: "Mirror-Bounce Flash", category: "style", description: "Mirror-selfie flash bounce", promptHint: "mirror-selfie flash lighting, yellowish uneven LED-or-flash bouncing off the mirror surface with a hot flare spot, partially obscured face by the phone, classic mirror-selfie aesthetic" },
84
+ { id: "mirror-bounce-flash", label: "Mirror-Bounce Flash", category: "style", description: "Mirror-selfie flash bounce", promptHint: "mirror-selfie flash lighting, yellowish uneven LED-or-flash bouncing off the mirror surface with a hot flare spot, partially obscured face by the phone, classic mirror-selfie aesthetic", term: "mirror-selfie flash" },
74
85
  { id: "bounced-flash", label: "Bounced Flash", category: "style", description: "Soft ceiling-bounced fill", promptHint: "bounced flash lighting, on-camera flash redirected off a ceiling or wall to create soft top-down fill with gentle shadows, even skin tones and natural ambient feel" },
75
- { id: "softbox-key", label: "Softbox Key", category: "style", description: "Large diffused fashion key", promptHint: "softbox key lighting, large diffused fashion-studio key light producing gentle wraparound illumination, soft falloff and clean even skin rendering" },
86
+ { id: "softbox-key", label: "Softbox Key", category: "style", description: "Large diffused fashion key", promptHint: "softbox key lighting, large diffused fashion-studio key light producing gentle wraparound illumination, soft falloff and clean even skin rendering", term: "softbox key light" },
76
87
  { id: "beauty-dish", label: "Beauty Dish", category: "style", description: "Hero light, crisp falloff", promptHint: "beauty dish lighting, semi-hard hero light with crisp shadow falloff and a distinctive round catchlight, slightly punchy contour and contrast favored in beauty and editorial portraits" },
77
88
  { id: "gridded-snoot", label: "Gridded Snoot", category: "style", description: "Tight focused pool of light", promptHint: "gridded snoot lighting, tightly focused circular pool of light isolating the subject's face or shoulders against deep surrounding shadow, theatrical and controlled" },
78
89
  { id: "silk-diffusion", label: "Silk Diffusion", category: "style", description: "Silk-softened gentle key", promptHint: "silk diffusion lighting, gentle key light passed through a large silk to soften shadow edges, producing creamy gradients and flattering skin tones" },
79
- { id: "kicker-rim", label: "Kicker / Rim Accent", category: "style", description: "Low-side accent separator", promptHint: "kicker rim accent lighting, low side-rear accent light skimming the subject's edge to separate them from a darker background, adds dimension and depth" },
80
- { id: "candlelight", label: "Candlelight", category: "style", description: "Warm flickering firelight", promptHint: "candlelight or firelight, warm flickering tungsten glow with soft falloff, low color temperature and gentle dancing shadows on nearby surfaces" },
81
- { id: "edison-tungsten", label: "Edison Tungsten", category: "style", description: "Cozy warm globe-bulb glow", promptHint: "Edison-bulb tungsten lighting, warm low-CRI globe-bulb glow with visible filament hot-spots, cozy bar or cafe atmosphere with amber-orange ambient" },
82
- { id: "dappled-light", label: "Dappled / Leaf-Filtered", category: "style", description: "Speckled foliage light", promptHint: "dappled leaf-filtered lighting, sunlight broken into a speckled pattern of bright spots and soft shadows as it passes through overhead foliage, organic and painterly" },
90
+ { id: "kicker-rim", label: "Kicker / Rim Accent", category: "style", description: "Low-side accent separator", promptHint: "kicker rim accent lighting, low side-rear accent light skimming the subject's edge to separate them from a darker background, adds dimension and depth", term: "kicker rim light" },
91
+ { id: "candlelight", label: "Candlelight", category: "style", description: "Warm flickering firelight", promptHint: "candlelight or firelight, warm flickering tungsten glow with soft falloff, low color temperature and gentle dancing shadows on nearby surfaces", term: "warm flickering candlelight" },
92
+ { id: "edison-tungsten", label: "Edison Tungsten", category: "style", description: "Cozy warm globe-bulb glow", promptHint: "Edison-bulb tungsten lighting, warm low-CRI globe-bulb glow with visible filament hot-spots, cozy bar or cafe atmosphere with amber-orange ambient", term: "warm edison-bulb tungsten glow" },
93
+ { id: "dappled-light", label: "Dappled / Leaf-Filtered", category: "style", description: "Speckled foliage light", promptHint: "dappled leaf-filtered lighting, sunlight broken into a speckled pattern of bright spots and soft shadows as it passes through overhead foliage, organic and painterly", term: "dappled leaf-filtered light" },
83
94
  { id: "raking-sidelight", label: "Raking Sidelight", category: "style", description: "Extreme low side, texture", promptHint: "raking sidelight, extreme low-angle side light skimming across the surface to exaggerate texture and microcontour, long parallel shadows reveal every detail" },
84
95
  { id: "stage-spotlight", label: "Stage Spotlight", category: "style", description: "Single hard overhead spot", promptHint: "stage spotlight lighting, single hard overhead theatre spotlight isolating the subject in a circular pool of light against pure black surroundings, dust motes catching the beam" },
85
96
  { id: "underwater-caustics", label: "Underwater Caustics", category: "style", description: "Rippled refracted patterns", promptHint: "underwater caustics lighting, rippled wavy refracted light patterns dancing across the subject and surroundings, cool aquatic blue-green palette with shimmering highlights" },
86
- { id: "bioluminescence", label: "Bioluminescence", category: "style", description: "Cool eerie biological glow", promptHint: "bioluminescence lighting, cool eerie cyan-green glow emanating from biological sources, soft self-illuminated highlights against deep ambient darkness, otherworldly atmosphere" },
97
+ { id: "bioluminescence", label: "Bioluminescence", category: "style", description: "Cool eerie biological glow", promptHint: "bioluminescence lighting, cool eerie cyan-green glow emanating from biological sources, soft self-illuminated highlights against deep ambient darkness, otherworldly atmosphere", term: "bioluminescent glow" },
87
98
 
88
99
  // Direction (8)
89
- { id: "front", label: "Front", category: "direction", description: "Light from camera direction", promptHint: "front lighting, light coming from the camera direction, flat even illumination across the subject" },
90
- { id: "three-quarter", label: "3/4 Light", category: "direction", description: "Classic portrait key angle", promptHint: "three-quarter light, classic portrait key angle split between front and side at roughly 45 degrees off-camera, sculpts the face with a visible shadow on the far cheek and a defined nose shadow" },
91
- { id: "side", label: "Side", category: "direction", description: "Light from one side", promptHint: "side lighting, light coming from the side of the subject, emphasizing texture and form" },
92
- { id: "back-rim", label: "Back / Rim", category: "direction", description: "Backlight rim around subject", promptHint: "back-light or rim-light, light coming from behind the subject creating a bright rim around their silhouette" },
100
+ { id: "front", label: "Front", category: "direction", description: "Light from camera direction", promptHint: "front lighting, light coming from the camera direction, flat even illumination across the subject", term: "front lighting" },
101
+ { id: "three-quarter", label: "3/4 Light", category: "direction", description: "Classic portrait key angle", promptHint: "three-quarter light, classic portrait key angle split between front and side at roughly 45 degrees off-camera, sculpts the face with a visible shadow on the far cheek and a defined nose shadow", term: "three-quarter key light" },
102
+ { id: "side", label: "Side", category: "direction", description: "Light from one side", promptHint: "side lighting, light coming from the side of the subject, emphasizing texture and form", term: "side lighting" },
103
+ { id: "back-rim", label: "Back / Rim", category: "direction", description: "Backlight rim around subject", promptHint: "back-light or rim-light, light coming from behind the subject creating a bright rim around their silhouette", term: "rim backlight" },
93
104
  { id: "silhouette-backlight", label: "Silhouette Backlight", category: "direction", description: "Bright halo, dark subject", promptHint: "silhouette backlight, strong light source directly behind the subject rendering them as a dark shape with a luminous halo edge and bright background bloom, dramatic contour against the sky or window" },
94
- { id: "top-overhead", label: "Top / Overhead",category: "direction", description: "Light from directly above", promptHint: "top-down overhead lighting, light coming from directly above the subject creating shadows under the eyes and chin" },
95
- { id: "under-uplight", label: "Under / Uplight",category: "direction", description: "Light from below", promptHint: "uplighting from below, light coming from below the subject creating an unsettling theatrical look" },
96
- { id: "window", label: "Window", category: "direction", description: "Soft sidelight from window", promptHint: "window lighting, soft directional light from a single window source with natural falloff" },
105
+ { id: "top-overhead", label: "Top / Overhead",category: "direction", description: "Light from directly above", promptHint: "top-down overhead lighting, light coming from directly above the subject creating shadows under the eyes and chin", term: "overhead top light" },
106
+ { id: "under-uplight", label: "Under / Uplight",category: "direction", description: "Light from below", promptHint: "uplighting from below, light coming from below the subject creating an unsettling theatrical look", term: "uplighting from below" },
107
+ { id: "window", label: "Window", category: "direction", description: "Soft sidelight from window", promptHint: "window lighting, soft directional light from a single window source with natural falloff", term: "window light" },
97
108
 
98
109
  // Lighting ratio (6) — relative key-to-shadow brightness
99
- { id: "ratio-1-1", label: "1:1", category: "lighting-ratio", description: "Flat, no shadow contrast", promptHint: "1:1 lighting ratio, flat even illumination across the subject with no contrast between key and fill, beauty and catalog look that flattens dimension" },
100
- { id: "ratio-1-2", label: "1:2", category: "lighting-ratio", description: "Soft one-stop falloff", promptHint: "1:2 lighting ratio, gentle soft modeling with roughly one stop of falloff from key to shadow side, classic flattering portraiture with mild dimension" },
101
- { id: "ratio-1-3", label: "1:3", category: "lighting-ratio", description: "Moderate two-stop contrast", promptHint: "1:3 lighting ratio, moderate contrast with about two stops between the lit and shadow sides, well-defined facial dimension and visible but recovered shadow detail" },
102
- { id: "ratio-1-4", label: "1:4", category: "lighting-ratio", description: "Strong editorial contrast", promptHint: "1:4 lighting ratio, strong contrast with deepening shadows on the unlit side, dramatic editorial feel with sculpted form and minimal shadow detail" },
103
- { id: "ratio-1-8", label: "1:8", category: "lighting-ratio", description: "Extreme low-key chiaroscuro", promptHint: "1:8 lighting ratio, extreme chiaroscuro with near-black shadow side balanced against a single bright key, classic low-key cinema atmosphere" },
104
- { id: "ratio-1-16", label: "1:16", category: "lighting-ratio", description: "Single-source film-noir falloff", promptHint: "1:16 lighting ratio, single-source key against pitch-black shadow side, theatrical film-noir falloff with no fill and crushed unlit detail" },
110
+ { id: "ratio-1-1", label: "1:1", category: "lighting-ratio", description: "Flat, no shadow contrast", promptHint: "1:1 lighting ratio, flat even illumination across the subject with no contrast between key and fill, beauty and catalog look that flattens dimension", term: "1:1 lighting ratio" },
111
+ { id: "ratio-1-2", label: "1:2", category: "lighting-ratio", description: "Soft one-stop falloff", promptHint: "1:2 lighting ratio, gentle soft modeling with roughly one stop of falloff from key to shadow side, classic flattering portraiture with mild dimension", term: "1:2 lighting ratio" },
112
+ { id: "ratio-1-3", label: "1:3", category: "lighting-ratio", description: "Moderate two-stop contrast", promptHint: "1:3 lighting ratio, moderate contrast with about two stops between the lit and shadow sides, well-defined facial dimension and visible but recovered shadow detail", term: "1:3 lighting ratio" },
113
+ { id: "ratio-1-4", label: "1:4", category: "lighting-ratio", description: "Strong editorial contrast", promptHint: "1:4 lighting ratio, strong contrast with deepening shadows on the unlit side, dramatic editorial feel with sculpted form and minimal shadow detail", term: "1:4 lighting ratio" },
114
+ { id: "ratio-1-8", label: "1:8", category: "lighting-ratio", description: "Extreme low-key chiaroscuro", promptHint: "1:8 lighting ratio, extreme chiaroscuro with near-black shadow side balanced against a single bright key, classic low-key cinema atmosphere", term: "1:8 lighting ratio" },
115
+ { id: "ratio-1-16", label: "1:16", category: "lighting-ratio", description: "Single-source film-noir falloff", promptHint: "1:16 lighting ratio, single-source key against pitch-black shadow side, theatrical film-noir falloff with no fill and crushed unlit detail", term: "1:16 lighting ratio" },
105
116
 
106
117
  // Color temperature (6) — Kelvin from warm to cool
107
- { id: "temp-2700k", label: "2700K Candle", category: "color-temperature", description: "Deep amber candle/tungsten", promptHint: "2700K warm candle and low-tungsten color temperature, deep amber and orange cast across the scene, intimate and cozy mood with rich golden highlights" },
108
- { id: "temp-3200k", label: "3200K Tungsten", category: "color-temperature", description: "Warm yellow interior", promptHint: "3200K tungsten color temperature, warm yellow-orange cast typical of classic incandescent home interiors, lived-in domestic ambient" },
109
- { id: "temp-4000k", label: "4000K Mixed", category: "color-temperature", description: "Neutral white", promptHint: "4000K neutral white color temperature, balanced midpoint between warm tungsten and cool daylight, clean office and mixed-source feel without strong color cast" },
110
- { id: "temp-5600k", label: "5600K Daylight", category: "color-temperature", description: "Daylight-balanced midday sun", promptHint: "5600K daylight-balanced color temperature, neutral midday white sun with accurate color rendering and no warm or cool bias" },
111
- { id: "temp-6500k", label: "6500K Overcast", category: "color-temperature", description: "Slightly cool blue cast", promptHint: "6500K overcast-cool color temperature, slightly blue cast typical of overcast skies and high-noon shadow areas, subtly cool and clinical" },
112
- { id: "temp-9000k", label: "9000K Shade", category: "color-temperature", description: "Distinctly cool blue shade", promptHint: "9000K open-shade color temperature, distinctly cool blue cast found in deep shade and cloud-shadowed mountain air, chilled and atmospheric" },
118
+ { id: "temp-2700k", label: "2700K Candle", category: "color-temperature", description: "Deep amber candle/tungsten", promptHint: "2700K warm candle and low-tungsten color temperature, deep amber and orange cast across the scene, intimate and cozy mood with rich golden highlights", term: "2700k candlelight color temperature" },
119
+ { id: "temp-3200k", label: "3200K Tungsten", category: "color-temperature", description: "Warm yellow interior", promptHint: "3200K tungsten color temperature, warm yellow-orange cast typical of classic incandescent home interiors, lived-in domestic ambient", term: "3200k tungsten color temperature" },
120
+ { id: "temp-4000k", label: "4000K Mixed", category: "color-temperature", description: "Neutral white", promptHint: "4000K neutral white color temperature, balanced midpoint between warm tungsten and cool daylight, clean office and mixed-source feel without strong color cast", term: "4000k neutral white color temperature" },
121
+ { id: "temp-5600k", label: "5600K Daylight", category: "color-temperature", description: "Daylight-balanced midday sun", promptHint: "5600K daylight-balanced color temperature, neutral midday white sun with accurate color rendering and no warm or cool bias", term: "5600k daylight color temperature" },
122
+ { id: "temp-6500k", label: "6500K Overcast", category: "color-temperature", description: "Slightly cool blue cast", promptHint: "6500K overcast-cool color temperature, slightly blue cast typical of overcast skies and high-noon shadow areas, subtly cool and clinical", term: "6500k overcast color temperature" },
123
+ { id: "temp-9000k", label: "9000K Shade", category: "color-temperature", description: "Distinctly cool blue shade", promptHint: "9000K open-shade color temperature, distinctly cool blue cast found in deep shade and cloud-shadowed mountain air, chilled and atmospheric", term: "9000k open-shade color temperature" },
113
124
  ] as const
114
125
 
115
126
  export const LIGHTING_CATEGORY_ORDER: ReadonlyArray<LightingCategory> = [
@@ -146,6 +157,16 @@ export function getLightingPromptHint(id: string | undefined | null): string {
146
157
  return getLighting(id)?.promptHint ?? ""
147
158
  }
148
159
 
160
+ /**
161
+ * The COMPACT counterpart of `getLightingPromptHint`: the short professional
162
+ * term ("rembrandt lighting", "1:4 lighting ratio", "rim backlight") a
163
+ * consumer injects instead of the full mechanism description. Same lookup,
164
+ * same empty-string-on-miss behavior.
165
+ */
166
+ export function getLightingTerm(id: string | undefined | null): string {
167
+ return resolveTerm(getLighting(id))
168
+ }
169
+
149
170
  export const LIGHTING_IDS: ReadonlyArray<string> = LIGHTINGS.map((l) => l.id)
150
171
 
151
172
  /**
@@ -207,7 +228,9 @@ export function buildLightingHints(
207
228
  lightingRatio?: unknown
208
229
  colorTemperature?: unknown
209
230
  },
231
+ mode: PickerHintMode = "full",
210
232
  ): string[] {
233
+ if (mode === "compact") return buildLightingTerms(data)
211
234
  const hints: string[] = []
212
235
  for (const category of LIGHTING_CATEGORY_ORDER) {
213
236
  const field = LIGHTING_FIELD_BY_CATEGORY[category]
@@ -227,3 +250,41 @@ export function buildLightingHints(
227
250
  }
228
251
  return hints
229
252
  }
253
+
254
+ /**
255
+ * The COMPACT counterpart of `buildLightingHints`: the same per-category walk
256
+ * in the same canonical order, emitting each selection's short professional
257
+ * term ("dusk lighting", "rembrandt lighting", "1:4 lighting ratio") instead
258
+ * of its full mechanism description.
259
+ *
260
+ * @param data the consumer data record (must include optional timeOfDay /
261
+ * lightingStyle / lightingDirection fields)
262
+ */
263
+ export function buildLightingTerms(
264
+ data: Record<string, unknown> & {
265
+ timeOfDay?: unknown
266
+ lightingStyle?: unknown
267
+ lightingDirection?: unknown
268
+ lightingRatio?: unknown
269
+ colorTemperature?: unknown
270
+ },
271
+ ): string[] {
272
+ const terms: string[] = []
273
+ for (const category of LIGHTING_CATEGORY_ORDER) {
274
+ const field = LIGHTING_FIELD_BY_CATEGORY[category]
275
+ const raw = data[field]
276
+ // lightingStyle accepts string | string[] (multi-pick max 2). Other
277
+ // categories are single-pick and may also tolerate arrays defensively.
278
+ if (typeof raw === "string" && raw.length > 0) {
279
+ const term = getLightingTerm(raw)
280
+ if (term) terms.push(term)
281
+ } else if (Array.isArray(raw)) {
282
+ for (const item of raw) {
283
+ if (typeof item !== "string" || item.length === 0) continue
284
+ const term = getLightingTerm(item)
285
+ if (term) terms.push(term)
286
+ }
287
+ }
288
+ }
289
+ return terms
290
+ }
@@ -18,6 +18,8 @@
18
18
  * and lets us refine each library independently.
19
19
  */
20
20
 
21
+ import { resolveTerm } from "./term.js"
22
+
21
23
  export type LoopSubjectCategory = "realistic" | "abstract"
22
24
 
23
25
  export interface LoopSubject {
@@ -28,6 +30,11 @@ export interface LoopSubject {
28
30
  /** Drop-in prompt text for Generate Image. Wired into the prompt input
29
31
  * via FieldMappings, same as Setting / Motion / Mood Parameter nodes. */
30
32
  readonly promptHint: string
33
+ /** Compact professional term for hint-compact mode (see `term.ts`). Authored
34
+ * only where the lowercased label is not what a professional would write —
35
+ * the "Tunnel — Exciting" style UI compounds and the generic subject
36
+ * labels ("Galaxy", "Underwater Light") that need their trade wording. */
37
+ readonly term?: string
31
38
  }
32
39
 
33
40
  export const LOOP_SUBJECT_CATEGORY_ORDER: ReadonlyArray<LoopSubjectCategory> = [
@@ -48,6 +55,7 @@ export const LOOP_SUBJECTS: ReadonlyArray<LoopSubject> = [
48
55
  category: "realistic",
49
56
  description: "Aurora borealis ribbons over a horizon",
50
57
  promptHint: "aurora borealis ribbons in green and violet over a snowy mountain horizon, wide centered framing, low ambient starlight, deep cosmic backdrop, no foreground subject",
58
+ term: "aurora borealis",
51
59
  },
52
60
  {
53
61
  id: "clouds",
@@ -104,6 +112,7 @@ export const LOOP_SUBJECTS: ReadonlyArray<LoopSubject> = [
104
112
  category: "realistic",
105
113
  description: "Spiral galaxy in deep space",
106
114
  promptHint: "spiral galaxy with swirling arms of stars and luminous gas, dust lanes radiating from a bright core, centered radial composition, deep cosmic black background, no perspective depth",
115
+ term: "spiral galaxy",
107
116
  },
108
117
  {
109
118
  id: "nebula",
@@ -118,6 +127,7 @@ export const LOOP_SUBJECTS: ReadonlyArray<LoopSubject> = [
118
127
  category: "realistic",
119
128
  description: "Light rays through forest canopy",
120
129
  promptHint: "golden sunbeams cutting through a tall forest canopy with floating dust motes catching the light, centered vertical composition, deep green ambient tone, no human figures, no foreground subject",
130
+ term: "sunbeams through forest canopy",
121
131
  },
122
132
  {
123
133
  id: "cherry-blossoms",
@@ -132,6 +142,7 @@ export const LOOP_SUBJECTS: ReadonlyArray<LoopSubject> = [
132
142
  category: "realistic",
133
143
  description: "Sunbeams and bubbles below water",
134
144
  promptHint: "sunbeams cutting down through deep blue ocean water with rising silver air bubbles and floating particulate, centered cathedral-light composition, no surface horizon visible, no foreground subject",
145
+ term: "underwater god rays",
135
146
  },
136
147
  {
137
148
  id: "embers",
@@ -148,6 +159,7 @@ export const LOOP_SUBJECTS: ReadonlyArray<LoopSubject> = [
148
159
  category: "abstract",
149
160
  description: "Fractal neon tunnel with depth",
150
161
  promptHint: "infinite fractal tunnel of glowing neon ribbons receding into a vanishing point, centered symmetric composition, deep volumetric light, no foreground subject",
162
+ term: "infinite fractal neon tunnel",
151
163
  },
152
164
  {
153
165
  id: "tunnel-clean",
@@ -155,6 +167,7 @@ export const LOOP_SUBJECTS: ReadonlyArray<LoopSubject> = [
155
167
  category: "abstract",
156
168
  description: "Periodic tunnel of geometric filaments",
157
169
  promptHint: "infinite fractal tunnel of glowing neon geometric filaments, self-similar repeating depth that recurses to infinity, centered symmetric composition, deep volumetric light, dark void background, no foreground subject",
170
+ term: "self-similar geometric neon tunnel",
158
171
  },
159
172
  {
160
173
  id: "kaleidoscope",
@@ -204,6 +217,7 @@ export const LOOP_SUBJECTS: ReadonlyArray<LoopSubject> = [
204
217
  category: "abstract",
205
218
  description: "Pulsing audio visualizer",
206
219
  promptHint: "vertical audio equalizer bars in vibrant neon gradient pulsing at different heights, centered symmetric composition, dark backdrop with soft glow, repeating periodic structure, no foreground subject",
220
+ term: "audio equalizer bars",
207
221
  },
208
222
  {
209
223
  id: "dna-helix",
@@ -211,6 +225,7 @@ export const LOOP_SUBJECTS: ReadonlyArray<LoopSubject> = [
211
225
  category: "abstract",
212
226
  description: "Rotating double helix",
213
227
  promptHint: "glowing neon DNA double helix structure with periodic identical rungs, centered vertical symmetric composition, electric cyan and magenta strands, dark void background, fractal repeating geometry, no foreground subject",
228
+ term: "dna double helix",
214
229
  },
215
230
  {
216
231
  id: "liquid-chrome",
@@ -260,10 +275,11 @@ export const LOOP_SUBJECTS: ReadonlyArray<LoopSubject> = [
260
275
  category: "abstract",
261
276
  description: "Shifting platonic solids",
262
277
  promptHint: "abstract array of glowing neon platonic solid wireframes morphing through self-similar fractal subdivisions, centered radial symmetric composition, deep dark backdrop, electric rim lighting, no foreground subject",
278
+ term: "morphing platonic solid wireframes",
263
279
  },
264
280
  ]
265
281
 
266
- export function getLoopSubject(id: string): LoopSubject | undefined {
282
+ export function getLoopSubject(id: string | undefined | null): LoopSubject | undefined {
267
283
  return LOOP_SUBJECTS.find((s) => s.id === id)
268
284
  }
269
285
 
@@ -274,3 +290,13 @@ export function getLoopSubjectLabel(id: string): string {
274
290
  export function getLoopSubjectPromptHint(id: string): string {
275
291
  return getLoopSubject(id)?.promptHint ?? ""
276
292
  }
293
+
294
+ /**
295
+ * Compact professional term for the subject — the short phrase a VJ or
296
+ * cinematographer would write when the consumer wants a term instead of the
297
+ * full scene paragraph. Mirrors `getLoopSubjectPromptHint`'s lookup so the two
298
+ * can never describe different entries.
299
+ */
300
+ export function getLoopSubjectTerm(id: string | undefined | null): string {
301
+ return resolveTerm(getLoopSubject(id))
302
+ }