@nodaro/prompts 1.7.3 → 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 (72) hide show
  1. package/dist/index.cjs +5422 -4269
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +1198 -61
  4. package/dist/index.d.ts +1198 -61
  5. package/dist/index.js +5336 -4271
  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 +5 -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/pose.ts +105 -40
  62. package/src/post-process-effects.ts +51 -8
  63. package/src/prompt-builder.ts +16 -1
  64. package/src/render-quality.ts +25 -7
  65. package/src/setting.ts +30 -14
  66. package/src/style.ts +33 -15
  67. package/src/styling.ts +155 -94
  68. package/src/temporal.ts +80 -18
  69. package/src/term.ts +155 -0
  70. package/src/transitions.ts +73 -26
  71. package/src/voice-character.ts +190 -90
  72. package/src/voice-delivery.ts +83 -12
@@ -19,6 +19,8 @@
19
19
  * backend orchestrator.
20
20
  */
21
21
 
22
+ import { resolveTerm, type PickerHintMode } from "./term.js"
23
+
22
24
  export type PhotographerCategory =
23
25
  | "editorial"
24
26
  | "documentary"
@@ -32,6 +34,27 @@ export interface Photographer {
32
34
  readonly category: PhotographerCategory
33
35
  readonly description: string
34
36
  readonly promptHint: string
37
+ /**
38
+ * Compact-mode term (see `term.ts`). Authored on EVERY entry here, which is
39
+ * the exception rather than the rule for a catalog — two reasons specific to
40
+ * artist styles:
41
+ *
42
+ * 1. The derived term would be a bare person's name. Injected raw into a
43
+ * generation prompt, "annie leibovitz" reads as the SUBJECT to render,
44
+ * not as an attribution — it asks for a picture OF the photographer.
45
+ * Consumers inject `term` verbatim (they render `label` and inject
46
+ * `term`), so the framing has to live in the term itself.
47
+ * 2. Per this file's own premise, the name token alone is too vague; the
48
+ * model needs a little of the surrounding visual vocabulary to lock onto
49
+ * the signature. So each term is `by <name>, <2-3 signature cues>` — a
50
+ * compression of the promptHint's own shape, never a copy of it.
51
+ * Cinematographers take the DP credit "shot by" instead.
52
+ *
53
+ * Optional per the `term.ts` convention, but in THIS catalog a new entry
54
+ * that omits it falls back to the bare-name derivation described above —
55
+ * author one alongside the promptHint.
56
+ */
57
+ readonly term?: string
35
58
  }
36
59
 
37
60
  export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
@@ -43,6 +66,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
43
66
  description: "Painterly fairytale fashion",
44
67
  promptHint:
45
68
  "in the style of Tim Walker, painterly fairytale fashion staging with elaborate hand-built sets and a soft pastel palette",
69
+ term: "by tim walker, painterly fairytale fashion",
46
70
  },
47
71
  {
48
72
  id: "paolo-roversi",
@@ -51,6 +75,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
51
75
  description: "Soft, ethereal Polaroid glow",
52
76
  promptHint:
53
77
  "in the style of Paolo Roversi, soft ethereal Polaroid glow with diffused window light and a warm milky bath",
78
+ term: "by paolo roversi, soft ethereal polaroid glow",
54
79
  },
55
80
  {
56
81
  id: "marta-bevacqua",
@@ -59,6 +84,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
59
84
  description: "Dreamy painterly portraiture",
60
85
  promptHint:
61
86
  "in the style of Marta Bevacqua, dreamy painterly portraiture with hushed natural light and faintly desaturated skin tones",
87
+ term: "by marta bevacqua, dreamy painterly portraiture",
62
88
  },
63
89
  {
64
90
  id: "patrick-demarchelier",
@@ -67,6 +93,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
67
93
  description: "Refined classic fashion portrait",
68
94
  promptHint:
69
95
  "in the style of Patrick Demarchelier, refined classic fashion portraiture with crisp catchlights and timeless restraint",
96
+ term: "by patrick demarchelier, refined classic fashion",
70
97
  },
71
98
  {
72
99
  id: "nick-knight",
@@ -75,6 +102,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
75
102
  description: "High-gloss avant-garde fashion",
76
103
  promptHint:
77
104
  "in the style of Nick Knight, high-gloss avant-garde fashion with saturated color, precision sharpness and surreal staging",
105
+ term: "by nick knight, high-gloss avant-garde fashion",
78
106
  },
79
107
  {
80
108
  id: "mario-testino",
@@ -83,6 +111,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
83
111
  description: "Glamorous, sun-soaked fashion",
84
112
  promptHint:
85
113
  "in the style of Mario Testino, glamorous sun-soaked fashion energy with confident posing and bright editorial color",
114
+ term: "by mario testino, glamorous sun-soaked fashion",
86
115
  },
87
116
  {
88
117
  id: "steven-meisel",
@@ -91,6 +120,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
91
120
  description: "Polished mid-century editorial",
92
121
  promptHint:
93
122
  "in the style of Steven Meisel, polished mid-century editorial portraiture with controlled studio light and meticulous styling",
123
+ term: "by steven meisel, polished mid-century editorial",
94
124
  },
95
125
  {
96
126
  id: "helmut-newton",
@@ -99,6 +129,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
99
129
  description: "Bold black-and-white provocation",
100
130
  promptHint:
101
131
  "in the style of Helmut Newton, bold black-and-white provocation with hard flash, deep shadows and architectural composition",
132
+ term: "by helmut newton, hard-flash monochrome glamour",
102
133
  },
103
134
  {
104
135
  id: "mario-sorrenti",
@@ -107,6 +138,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
107
138
  description: "Intimate, grainy fashion",
108
139
  promptHint:
109
140
  "in the style of Mario Sorrenti, intimate grainy fashion photography with raw natural light and confessional closeness",
141
+ term: "by mario sorrenti, intimate grainy fashion",
110
142
  },
111
143
  {
112
144
  id: "annie-leibovitz",
@@ -115,6 +147,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
115
147
  description: "Cinematic celebrity portrait",
116
148
  promptHint:
117
149
  "in the style of Annie Leibovitz, cinematic celebrity portraiture with theatrical staging and warm dimensional lighting",
150
+ term: "by annie leibovitz, cinematic celebrity portraiture",
118
151
  },
119
152
  {
120
153
  id: "felicia-simion",
@@ -123,6 +156,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
123
156
  description: "Surreal pastoral fine art",
124
157
  promptHint:
125
158
  "in the style of Felicia Simion, surreal pastoral fine-art photography with quiet symbolism and a muted earthy palette",
159
+ term: "by felicia simion, surreal pastoral fine art",
126
160
  },
127
161
  {
128
162
  id: "oleg-oprisco",
@@ -131,6 +165,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
131
165
  description: "Cinematic film-grain storytelling",
132
166
  promptHint:
133
167
  "in the style of Oleg Oprisco, cinematic film-grain storytelling with painterly costuming and analogue color casts",
168
+ term: "by oleg oprisco, cinematic film-grain storytelling",
134
169
  },
135
170
  {
136
171
  id: "bella-kotak",
@@ -139,6 +174,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
139
174
  description: "Magical, fantasy-folkloric portraiture",
140
175
  promptHint:
141
176
  "in the style of Bella Kotak, magical fantasy-folkloric portraiture with golden light, florals and rich painterly grading",
177
+ term: "by bella kotak, fantasy-folkloric portraiture",
142
178
  },
143
179
  {
144
180
  id: "yigal-ozeri",
@@ -147,6 +183,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
147
183
  description: "Hyperreal painted portrait",
148
184
  promptHint:
149
185
  "in the style of Yigal Ozeri, hyperreal painted portraiture with luminous skin and dappled forest light",
186
+ term: "by yigal ozeri, hyperreal painted portraiture",
150
187
  },
151
188
  {
152
189
  id: "jimmy-marble",
@@ -155,6 +192,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
155
192
  description: "Pastel, candy-bright editorial",
156
193
  promptHint:
157
194
  "in the style of Jimmy Marble, pastel candy-bright editorial photography with playful color blocking and clean studio shapes",
195
+ term: "by jimmy marble, pastel candy-bright editorial",
158
196
  },
159
197
  {
160
198
  id: "rinko-kawauchi",
@@ -163,6 +201,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
163
201
  description: "Quiet, light-suffused everyday",
164
202
  promptHint:
165
203
  "in the style of Rinko Kawauchi, quiet light-suffused everyday photography with a dreamy pastel haze and gentle overexposure",
204
+ term: "by rinko kawauchi, quiet light-suffused everyday",
166
205
  },
167
206
  {
168
207
  id: "ellen-von-unwerth",
@@ -171,6 +210,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
171
210
  description: "Playful retro pin-up energy",
172
211
  promptHint:
173
212
  "in the style of Ellen von Unwerth, playful retro pin-up energy with monochrome flash and mischievous body language",
213
+ term: "by ellen von unwerth, playful retro pin-up",
174
214
  },
175
215
  {
176
216
  id: "mapplethorpe",
@@ -179,6 +219,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
179
219
  description: "Formalist B&W studio nudes and flowers",
180
220
  promptHint:
181
221
  "in the style of Robert Mapplethorpe, strict formalist black-and-white studio portraiture with dramatic chiaroscuro lighting, sculpted classical nudes and tightly controlled lily and orchid still lifes",
222
+ term: "by robert mapplethorpe, formalist studio monochrome",
182
223
  },
183
224
  {
184
225
  id: "sherman",
@@ -187,6 +228,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
187
228
  description: "Conceptual self-portrait character study",
188
229
  promptHint:
189
230
  "in the style of Cindy Sherman, staged conceptual self-portraiture with costumed character studies, film-still references and a dispassionate often unsettling gaze",
231
+ term: "by cindy sherman, staged conceptual film-still portraiture",
190
232
  },
191
233
  {
192
234
  id: "crewdson",
@@ -195,6 +237,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
195
237
  description: "Cinematic suburban dread tableau",
196
238
  promptHint:
197
239
  "in the style of Gregory Crewdson, large-format staged tableau of suburban dread with hyper-cinematic twilight blue-hour lighting and every detail meticulously composed",
240
+ term: "by gregory crewdson, cinematic suburban tableau",
198
241
  },
199
242
  {
200
243
  id: "lachapelle",
@@ -203,6 +246,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
203
246
  description: "Surreal hyper-saturated celebrity camp",
204
247
  promptHint:
205
248
  "in the style of David LaChapelle, hyper-saturated surrealist celebrity tableau with religious iconography, candy-gloss color and theatrical excess",
249
+ term: "by david lachapelle, hyper-saturated surrealist camp",
206
250
  },
207
251
  {
208
252
  id: "klein",
@@ -211,6 +255,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
211
255
  description: "Hard-edged glamour and controlled aggression",
212
256
  promptHint:
213
257
  "in the style of Steven Klein, hard-edged high-fashion glamour with leather and latex wardrobe, dramatic shadowed lighting and a charge of controlled aggression",
258
+ term: "by steven klein, hard-edged fashion glamour",
214
259
  },
215
260
  {
216
261
  id: "lindbergh",
@@ -219,6 +264,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
219
264
  description: "Minimalist B&W natural-light fashion",
220
265
  promptHint:
221
266
  "in the style of Peter Lindbergh, minimalist black-and-white fashion in natural light with bare makeup, supermodel-era documentary feel, windswept beach settings and untouched skin",
267
+ term: "by peter lindbergh, minimalist monochrome fashion",
222
268
  },
223
269
  {
224
270
  id: "tillmans",
@@ -227,6 +273,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
227
273
  description: "Candid queer intimacy and casual flash",
228
274
  promptHint:
229
275
  "in the style of Wolfgang Tillmans, democratic mix of intimate snapshot portraiture and abstract still life with casual on-camera flash and party, club and nightlife candor",
276
+ term: "by wolfgang tillmans, candid on-camera-flash snapshot",
230
277
  },
231
278
  {
232
279
  id: "teller",
@@ -235,6 +282,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
235
282
  description: "Anti-glamour direct-flash snapshot",
236
283
  promptHint:
237
284
  "in the style of Juergen Teller, direct on-camera flash snapshot fashion with deadpan unfiltered models, anti-airbrush rawness and an awkward off-kilter staging",
285
+ term: "by juergen teller, deadpan direct-flash snapshot",
238
286
  },
239
287
  {
240
288
  id: "penn",
@@ -243,6 +291,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
243
291
  description: "Austere mid-century studio portrait",
244
292
  promptHint:
245
293
  "in the style of Irving Penn, austere mid-century studio portraiture against a commanding gray seamless backdrop with controlled grace, sculptural fashion staging and refined still-life precision",
294
+ term: "by irving penn, austere mid-century studio portraiture",
246
295
  },
247
296
  {
248
297
  id: "mcginley",
@@ -251,6 +300,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
251
300
  description: "Naturalistic youth + nudity in landscape, sun-flared candid",
252
301
  promptHint:
253
302
  "shot in the language of Ryan McGinley, naturalistic youth and nudity roaming through open landscape, sun-flared candid 35mm with euphoric movement and unposed freedom",
303
+ term: "by ryan mcginley, sun-flared candid youth",
254
304
  },
255
305
  {
256
306
  id: "mitchell",
@@ -259,6 +309,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
259
309
  description: "Contemporary Black portraiture, soft natural light, fashion-meets-documentary",
260
310
  promptHint:
261
311
  "shot in the language of Tyler Mitchell, contemporary Black portraiture in soft natural light with a fashion-meets-documentary tenderness, pastel wardrobe and sun-warmed skin",
312
+ term: "by tyler mitchell, soft-light contemporary portraiture",
262
313
  },
263
314
  {
264
315
  id: "collins",
@@ -267,6 +318,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
267
318
  description: "Pink-saturated dreamy female-gaze fashion, hazy 35mm",
268
319
  promptHint:
269
320
  "shot in the language of Petra Collins, dreamy pink-saturated female-gaze fashion, hazy 35mm grain, soft window light",
321
+ term: "by petra collins, dreamy pink-saturated 35mm",
270
322
  },
271
323
  {
272
324
  id: "weston",
@@ -275,6 +327,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
275
327
  description: "Modernist B&W still life, sculptural nudes, sharp formalism",
276
328
  promptHint:
277
329
  "in the style of Edward Weston, modernist black-and-white still life and sculptural nudes with sharp formalism, large-format clarity and sensuous tonal gradation",
330
+ term: "by edward weston, modernist monochrome still life",
278
331
  },
279
332
  {
280
333
  id: "beaton",
@@ -283,6 +336,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
283
336
  description: "Classical Hollywood-era portraiture, theatrical staging, opulent backdrops",
284
337
  promptHint:
285
338
  "in the style of Cecil Beaton, classical Hollywood-era portraiture with theatrical staging, opulent painted backdrops and elegant silver-screen glamour",
339
+ term: "by cecil beaton, theatrical hollywood-era portraiture",
286
340
  },
287
341
 
288
342
  // -------------------- Documentary / Street --------------------
@@ -293,6 +347,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
293
347
  description: "Decisive-moment street photography",
294
348
  promptHint:
295
349
  "in the style of Henri Cartier-Bresson, decisive-moment black-and-white street photography with geometric framing and natural light",
350
+ term: "by henri cartier-bresson, decisive-moment street",
296
351
  },
297
352
  {
298
353
  id: "vivian-maier",
@@ -301,6 +356,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
301
356
  description: "Mid-century American street",
302
357
  promptHint:
303
358
  "in the style of Vivian Maier, mid-century American street photography with square format, observed candor and silver-rich blacks",
359
+ term: "by vivian maier, mid-century american street",
304
360
  },
305
361
  {
306
362
  id: "saul-leiter",
@@ -309,6 +365,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
309
365
  description: "Painterly color street through glass",
310
366
  promptHint:
311
367
  "in the style of Saul Leiter, painterly color street photography seen through fogged glass and rain, with abstract layered framing",
368
+ term: "by saul leiter, painterly color street",
312
369
  },
313
370
  {
314
371
  id: "daido-moriyama",
@@ -317,6 +374,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
317
374
  description: "Grainy, high-contrast Tokyo street",
318
375
  promptHint:
319
376
  "in the style of Daido Moriyama, grainy high-contrast Tokyo street photography with blown highlights and a restless handheld feel",
377
+ term: "by daido moriyama, grainy high-contrast street",
320
378
  },
321
379
  {
322
380
  id: "robert-capa",
@@ -325,6 +383,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
325
383
  description: "Visceral combat photojournalism",
326
384
  promptHint:
327
385
  "in the style of Robert Capa, visceral combat photojournalism with motion blur, gritty grain and an immediate handheld viewpoint",
386
+ term: "by robert capa, visceral combat photojournalism",
328
387
  },
329
388
  {
330
389
  id: "sebastiao-salgado",
@@ -333,6 +392,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
333
392
  description: "Epic monochrome social documentary",
334
393
  promptHint:
335
394
  "in the style of Sebastiao Salgado, epic monochrome social documentary with sweeping landscape scale and chiaroscuro tonality",
395
+ term: "by sebastiao salgado, epic monochrome documentary",
336
396
  },
337
397
  {
338
398
  id: "diane-arbus",
@@ -341,6 +401,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
341
401
  description: "Stark, confrontational portrait",
342
402
  promptHint:
343
403
  "in the style of Diane Arbus, stark confrontational portraiture with direct gaze, square format and unflinching daylight",
404
+ term: "by diane arbus, stark confrontational portraiture",
344
405
  },
345
406
 
346
407
  // -------------------- Cinematographers --------------------
@@ -351,6 +412,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
351
412
  description: "Painterly cinematic naturalism",
352
413
  promptHint:
353
414
  "in the cinematic style of Roger Deakins, painterly natural light with carved silhouettes, deep negative space and restrained color",
415
+ term: "shot by roger deakins, painterly natural light",
354
416
  },
355
417
  {
356
418
  id: "emmanuel-lubezki",
@@ -359,6 +421,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
359
421
  description: "Floating natural-light cinematography",
360
422
  promptHint:
361
423
  "in the cinematic style of Emmanuel Lubezki, floating handheld natural-light cinematography with golden-hour glow and wide-lens immersion",
424
+ term: "shot by emmanuel lubezki, floating natural-light immersion",
362
425
  },
363
426
  {
364
427
  id: "greig-fraser",
@@ -367,6 +430,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
367
430
  description: "Rich tactile genre cinematography",
368
431
  promptHint:
369
432
  "in the cinematic style of Greig Fraser, rich tactile genre cinematography with anamorphic flares, deep blacks and atmospheric haze",
433
+ term: "shot by greig fraser, tactile anamorphic cinematography",
370
434
  },
371
435
  {
372
436
  id: "christopher-doyle",
@@ -375,6 +439,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
375
439
  description: "Saturated handheld neon mood",
376
440
  promptHint:
377
441
  "in the cinematic style of Christopher Doyle, saturated handheld neon mood with smeared light trails and dreamy slow-shutter blur",
442
+ term: "shot by christopher doyle, saturated handheld neon",
378
443
  },
379
444
 
380
445
  // -------------------- Concept / Digital Painters --------------------
@@ -385,6 +450,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
385
450
  description: "Epic painterly fantasy concept",
386
451
  promptHint:
387
452
  "in the style of Greg Rutkowski, epic painterly fantasy concept art with sweeping composition, dramatic god-rays and oil-painting brushwork",
453
+ term: "by greg rutkowski, epic painterly fantasy concept art",
388
454
  },
389
455
  {
390
456
  id: "magali-villeneuve",
@@ -393,6 +459,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
393
459
  description: "Heroic fantasy character art",
394
460
  promptHint:
395
461
  "in the style of Magali Villeneuve, heroic fantasy character art with detailed armor, painterly skin and warm golden lighting",
462
+ term: "by magali villeneuve, heroic fantasy character art",
396
463
  },
397
464
  {
398
465
  id: "charlie-bowater",
@@ -401,6 +468,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
401
468
  description: "Atmospheric digital portraiture",
402
469
  promptHint:
403
470
  "in the style of Charlie Bowater, atmospheric digital portraiture with painterly textures, moody color and intimate close framing",
471
+ term: "by charlie bowater, atmospheric digital portraiture",
404
472
  },
405
473
  {
406
474
  id: "sam-spratt",
@@ -409,6 +477,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
409
477
  description: "Allegorical hyperreal portrait",
410
478
  promptHint:
411
479
  "in the style of Sam Spratt, allegorical hyperreal portraiture with sculpted lighting, symbolic detail and old-master tonal depth",
480
+ term: "by sam spratt, allegorical hyperreal portraiture",
412
481
  },
413
482
  {
414
483
  id: "ruan-jia",
@@ -417,6 +486,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
417
486
  description: "Lush painterly fantasy portrait",
418
487
  promptHint:
419
488
  "in the style of Ruan Jia, lush painterly fantasy portraiture with rich fabrics, gilded accents and warm directional light",
489
+ term: "by ruan jia, lush painterly fantasy portraiture",
420
490
  },
421
491
  {
422
492
  id: "ilya-kuvshinov",
@@ -425,6 +495,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
425
495
  description: "Anime-inflected stylized portrait",
426
496
  promptHint:
427
497
  "in the style of Ilya Kuvshinov, anime-inflected stylized portraiture with soft cell-shading, oversized eyes and pastel rim light",
498
+ term: "by ilya kuvshinov, anime-inflected stylized portrait",
428
499
  },
429
500
  {
430
501
  id: "wlop",
@@ -433,6 +504,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
433
504
  description: "Ethereal painterly fantasy",
434
505
  promptHint:
435
506
  "in the style of WLOP, ethereal painterly fantasy portraiture with flowing hair, glowing rim light and a cool monochromatic palette",
507
+ term: "by wlop, ethereal painterly fantasy portraiture",
436
508
  },
437
509
  {
438
510
  id: "artgerm",
@@ -441,6 +513,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
441
513
  description: "Polished comic-book-inspired pinup",
442
514
  promptHint:
443
515
  "in the style of Artgerm, polished comic-book-inspired pinup illustration with smooth gradients and crisp graphic edge highlights",
516
+ term: "by artgerm, polished comic-book pinup illustration",
444
517
  },
445
518
 
446
519
  // -------------------- Illustrators / Animators --------------------
@@ -451,6 +524,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
451
524
  description: "Cinematic anime sky and light",
452
525
  promptHint:
453
526
  "in the style of Makoto Shinkai, cinematic anime sky and light with luminous clouds, lens-flared sun and saturated dusk gradients",
527
+ term: "by makoto shinkai, luminous cinematic anime skies",
454
528
  },
455
529
  {
456
530
  id: "studio-ghibli",
@@ -459,6 +533,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
459
533
  description: "Hand-painted Ghibli warmth",
460
534
  promptHint:
461
535
  "in the style of Studio Ghibli, hand-painted animation warmth with soft pastel skies, lush vegetation and gentle character expressions",
536
+ term: "by studio ghibli, hand-painted animation warmth",
462
537
  },
463
538
  {
464
539
  id: "alphonse-mucha",
@@ -467,6 +542,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
467
542
  description: "Art-nouveau decorative panel",
468
543
  promptHint:
469
544
  "in the style of Alphonse Mucha, art-nouveau decorative panel with ornamental floral borders, flowing hair and warm gilded tones",
545
+ term: "by alphonse mucha, art-nouveau decorative panel",
470
546
  },
471
547
  {
472
548
  id: "carne-griffiths",
@@ -475,6 +551,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
475
551
  description: "Ink-bleed botanical portrait",
476
552
  promptHint:
477
553
  "in the style of Carne Griffiths, ink-bleed botanical portraiture with calligraphic linework, splashed tea washes and tangled florals",
554
+ term: "by carne griffiths, ink-bleed botanical portraiture",
478
555
  },
479
556
  {
480
557
  id: "conrad-roset",
@@ -483,6 +560,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
483
560
  description: "Gentle watercolor figure",
484
561
  promptHint:
485
562
  "in the style of Conrad Roset, gentle watercolor figure illustration with soft graphite line, blooming pigment and pale skin tones",
563
+ term: "by conrad roset, gentle watercolor figure",
486
564
  },
487
565
  {
488
566
  id: "akihito-yoshida",
@@ -491,6 +569,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
491
569
  description: "Quiet ink-and-grain monochrome",
492
570
  promptHint:
493
571
  "in the style of Akihito Yoshida, quiet ink-and-grain monochrome portraiture with sketchy line and contemplative negative space",
572
+ term: "by akihito yoshida, quiet ink-and-grain monochrome",
494
573
  },
495
574
  {
496
575
  id: "karol-bak",
@@ -499,6 +578,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
499
578
  description: "Symbolist painted muse",
500
579
  promptHint:
501
580
  "in the style of Karol Bak, symbolist painted muse with gilded-leaf accents, art-nouveau ornament and warm earthen pigment",
581
+ term: "by karol bak, symbolist gilded muse",
502
582
  },
503
583
  {
504
584
  id: "ismail-inceoglu",
@@ -507,6 +587,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
507
587
  description: "Mythic painterly landscape",
508
588
  promptHint:
509
589
  "in the style of Ismail Inceoglu, mythic painterly landscape with monumental scale, layered atmospheric haze and storybook lighting",
590
+ term: "by ismail inceoglu, mythic painterly landscape",
510
591
  },
511
592
  {
512
593
  id: "stefan-gesell",
@@ -515,6 +596,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
515
596
  description: "Dark surreal portraiture",
516
597
  promptHint:
517
598
  "in the style of Stefan Gesell, dark surreal portraiture with high-contrast monochrome, masked figures and uneasy theatrical lighting",
599
+ term: "by stefan gesell, dark surreal portraiture",
518
600
  },
519
601
  {
520
602
  id: "andrew-atroshenko",
@@ -523,6 +605,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
523
605
  description: "Romantic impressionist figure",
524
606
  promptHint:
525
607
  "in the style of Andrew Atroshenko, romantic impressionist figure painting with loose visible brushwork and shimmering candlelight",
608
+ term: "by andrew atroshenko, romantic impressionist figure",
526
609
  },
527
610
  {
528
611
  id: "peter-gric",
@@ -531,6 +614,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
531
614
  description: "Architectural surrealist landscape",
532
615
  promptHint:
533
616
  "in the style of Peter Gric, architectural surrealist landscape with crystalline geometric structures and a cool muted palette",
617
+ term: "by peter gric, architectural surrealist landscape",
534
618
  },
535
619
  {
536
620
  id: "ingrid-baars",
@@ -539,6 +623,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
539
623
  description: "Sculptural fashion-art collage",
540
624
  promptHint:
541
625
  "in the style of Ingrid Baars, sculptural fashion-art collage with elongated forms, smooth painted skin and ornate textile drapery",
626
+ term: "by ingrid baars, sculptural fashion-art collage",
542
627
  },
543
628
  {
544
629
  id: "guido-van-helten",
@@ -547,6 +632,7 @@ export const PHOTOGRAPHERS: ReadonlyArray<Photographer> = [
547
632
  description: "Monumental muralist portrait",
548
633
  promptHint:
549
634
  "in the style of Guido van Helten, monumental muralist portraiture with weathered concrete texture and quiet grayscale tonality",
635
+ term: "by guido van helten, monumental muralist portraiture",
550
636
  },
551
637
  ] as const
552
638
 
@@ -570,12 +656,22 @@ export function getPhotographerPromptHint(id: string | undefined | null): string
570
656
  return getPhotographer(id)?.promptHint ?? ""
571
657
  }
572
658
 
659
+ /**
660
+ * Compact-mode sibling of `getPhotographerPromptHint` — same arity, same
661
+ * lookup, same empty-string-on-miss behavior, so the two can never disagree
662
+ * about which entry they are describing.
663
+ */
664
+ export function getPhotographerTerm(id: string | undefined | null): string {
665
+ return resolveTerm(getPhotographer(id))
666
+ }
667
+
573
668
  /**
574
669
  * Multi-pick variant: 1-2 photographer ids → blended hint. Single → entry's
575
670
  * own promptHint. Two → "shot in the blended language of {A} and {B}" — the
576
671
  * model interprets this as referencing both creators' visual signatures.
577
672
  */
578
- export function buildPhotographerHints(value: unknown): string {
673
+ export function buildPhotographerHints(value: unknown, mode: PickerHintMode = "full"): string {
674
+ if (mode === "compact") return buildPhotographerTerms(value)
579
675
  const ids: string[] = []
580
676
  if (typeof value === "string" && value) ids.push(value)
581
677
  else if (Array.isArray(value)) {
@@ -593,6 +689,47 @@ export function buildPhotographerHints(value: unknown): string {
593
689
  return `shot in the blended visual language of ${labels[0]} and ${labels[1]}`
594
690
  }
595
691
 
692
+ /**
693
+ * The 1-2 ids a photographer value carries, de-duplicated, in pick order —
694
+ * the same shapes `buildPhotographerHints` accepts (a bare id string, or an
695
+ * array of them).
696
+ */
697
+ function photographerIds(value: unknown): string[] {
698
+ const ids: string[] = []
699
+ if (typeof value === "string" && value) ids.push(value)
700
+ else if (Array.isArray(value)) {
701
+ for (const v of value) {
702
+ if (typeof v === "string" && v && !ids.includes(v)) ids.push(v)
703
+ }
704
+ }
705
+ return ids
706
+ }
707
+
708
+ /** The credit an authored term opens with — "by ", or a DP's "shot by ". */
709
+ const TERM_CREDIT_PREFIX = /^(?:shot\s+)?by\s+/
710
+
711
+ /**
712
+ * Compact-mode sibling of `buildPhotographerHints`, mirroring its structure:
713
+ * one id → that entry's term, two → a blend. The blend drops the per-entry
714
+ * signature cues and keeps only the credited names, because stacking two
715
+ * `by <name>, <cues>` fragments is longer than the compact mode exists to be.
716
+ *
717
+ * The credit verb is READ OFF the resolved terms rather than hardcoded, so a
718
+ * cinematographer's "shot by" survives the blend and the one-pick and two-pick
719
+ * paths can never disagree about how the same entry is credited.
720
+ */
721
+ export function buildPhotographerTerms(value: unknown): string {
722
+ const ids = photographerIds(value)
723
+ if (ids.length === 0) return ""
724
+ if (ids.length === 1) return getPhotographerTerm(ids[0])
725
+ const credits = ids
726
+ .slice(0, 2)
727
+ .map((id) => getPhotographerTerm(id).split(",")[0].trim())
728
+ .filter((s): s is string => Boolean(s))
729
+ if (credits.length < 2) return getPhotographerTerm(ids[0])
730
+ return `${credits[0]} and ${credits[1].replace(TERM_CREDIT_PREFIX, "")}`
731
+ }
732
+
596
733
  export const PHOTOGRAPHER_IDS: ReadonlyArray<string> = PHOTOGRAPHERS.map((p) => p.id)
597
734
 
598
735
  export const PHOTOGRAPHER_CATEGORY_LABELS: Readonly<Record<PhotographerCategory, string>> = {