@nodaro/prompts 1.47.0 → 1.48.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 (80) hide show
  1. package/dist/{catalog-packs-C9CXEWfl.d.cts → catalog-packs-BDsrv8St.d.cts} +1 -1
  2. package/dist/{catalog-packs-D7NJpo4k.d.ts → catalog-packs-CAK42voB.d.ts} +1 -1
  3. package/dist/{chunk-SMKIVT7P.js → chunk-36XMRVY4.js} +4 -4
  4. package/dist/{chunk-SMKIVT7P.js.map → chunk-36XMRVY4.js.map} +1 -1
  5. package/dist/{chunk-JHEZJKTX.cjs → chunk-54BYDWAM.cjs} +62 -52
  6. package/dist/chunk-54BYDWAM.cjs.map +1 -0
  7. package/dist/{chunk-IKHRZ5UQ.js → chunk-BTV2I7EN.js} +3 -3
  8. package/dist/{chunk-IKHRZ5UQ.js.map → chunk-BTV2I7EN.js.map} +1 -1
  9. package/dist/{chunk-57PTYJJX.js → chunk-CMEUYFBZ.js} +13 -13
  10. package/dist/chunk-CMEUYFBZ.js.map +1 -0
  11. package/dist/{chunk-2OIKQ4WB.js → chunk-GZVCBSFG.js} +5 -5
  12. package/dist/{chunk-2OIKQ4WB.js.map → chunk-GZVCBSFG.js.map} +1 -1
  13. package/dist/{chunk-FCTK7RGO.cjs → chunk-IMQB7GIK.cjs} +42 -39
  14. package/dist/chunk-IMQB7GIK.cjs.map +1 -0
  15. package/dist/{chunk-2HJJBXGA.js → chunk-JHRVNWBS.js} +6 -6
  16. package/dist/{chunk-2HJJBXGA.js.map → chunk-JHRVNWBS.js.map} +1 -1
  17. package/dist/{chunk-OSKABA64.cjs → chunk-JV2WSMAA.cjs} +8 -8
  18. package/dist/{chunk-OSKABA64.cjs.map → chunk-JV2WSMAA.cjs.map} +1 -1
  19. package/dist/{chunk-VAK4RUNU.cjs → chunk-KNAKOSKV.cjs} +13 -13
  20. package/dist/{chunk-VAK4RUNU.cjs.map → chunk-KNAKOSKV.cjs.map} +1 -1
  21. package/dist/{chunk-TXHFL725.js → chunk-LD47QOKS.js} +62 -53
  22. package/dist/chunk-LD47QOKS.js.map +1 -0
  23. package/dist/{chunk-YCCQXX3U.cjs → chunk-MYVJVOPB.cjs} +39 -39
  24. package/dist/{chunk-YCCQXX3U.cjs.map → chunk-MYVJVOPB.cjs.map} +1 -1
  25. package/dist/{chunk-PHR4UETI.cjs → chunk-PJFX3MFI.cjs} +18 -18
  26. package/dist/{chunk-PHR4UETI.cjs.map → chunk-PJFX3MFI.cjs.map} +1 -1
  27. package/dist/{chunk-NN4FL7SB.js → chunk-XBRW75LM.js} +4 -4
  28. package/dist/{chunk-NN4FL7SB.js.map → chunk-XBRW75LM.js.map} +1 -1
  29. package/dist/{chunk-C4FDHCEZ.cjs → chunk-XGNUOU4F.cjs} +125 -125
  30. package/dist/{chunk-C4FDHCEZ.cjs.map → chunk-XGNUOU4F.cjs.map} +1 -1
  31. package/dist/{chunk-CPKYIVWP.js → chunk-YXJSPQC6.js} +12 -9
  32. package/dist/chunk-YXJSPQC6.js.map +1 -0
  33. package/dist/{chunk-OY7XOPDG.cjs → chunk-Z755PH3K.cjs} +57 -57
  34. package/dist/chunk-Z755PH3K.cjs.map +1 -0
  35. package/dist/entries/assembly.cjs +28 -28
  36. package/dist/entries/assembly.d.cts +1 -2
  37. package/dist/entries/assembly.d.ts +1 -2
  38. package/dist/entries/assembly.js +5 -5
  39. package/dist/entries/catalog-packs.d.cts +3 -3
  40. package/dist/entries/catalog-packs.d.ts +3 -3
  41. package/dist/entries/person.d.cts +2 -2
  42. package/dist/entries/person.d.ts +2 -2
  43. package/dist/entries/picker-catalogs.cjs +56 -56
  44. package/dist/entries/picker-catalogs.d.cts +26 -4
  45. package/dist/entries/picker-catalogs.d.ts +26 -4
  46. package/dist/entries/picker-catalogs.js +4 -4
  47. package/dist/entries/pickers.cjs +377 -373
  48. package/dist/entries/pickers.d.cts +473 -2
  49. package/dist/entries/pickers.d.ts +473 -2
  50. package/dist/entries/pickers.js +2 -2
  51. package/dist/entries/prompt-builder.cjs +75 -75
  52. package/dist/entries/prompt-builder.d.cts +2 -3
  53. package/dist/entries/prompt-builder.d.ts +2 -3
  54. package/dist/entries/prompt-builder.js +4 -4
  55. package/dist/index.cjs +529 -525
  56. package/dist/index.d.cts +5 -6
  57. package/dist/index.d.ts +5 -6
  58. package/dist/index.js +8 -8
  59. package/dist/{picker-catalogs-C3utGMRB.d.cts → picker-catalogs-BiRCs_5G.d.cts} +8 -0
  60. package/dist/{picker-catalogs-BM8IphF1.d.ts → picker-catalogs-CX8pHi8q.d.ts} +8 -0
  61. package/dist/{subject-registry-DFiGx49v.d.ts → subject-registry-Cf802LQ5.d.ts} +8 -4
  62. package/dist/{subject-registry-CQi_CZfJ.d.cts → subject-registry-D2uMBVpP.d.cts} +8 -4
  63. package/package.json +2 -2
  64. package/src/__tests__/assemble-video-input.test.ts +13 -11
  65. package/src/__tests__/direction-registry.test.ts +5 -5
  66. package/src/__tests__/prompt-style-section.test.ts +2 -2
  67. package/src/__tests__/style-video-wording.test.ts +258 -0
  68. package/src/catalog-overlay.ts +15 -1
  69. package/src/direction-registry.ts +25 -7
  70. package/src/parameter-prompt-hint.ts +23 -7
  71. package/src/picker-catalogs.ts +11 -0
  72. package/src/style.ts +78 -49
  73. package/dist/chunk-57PTYJJX.js.map +0 -1
  74. package/dist/chunk-CPKYIVWP.js.map +0 -1
  75. package/dist/chunk-FCTK7RGO.cjs.map +0 -1
  76. package/dist/chunk-JHEZJKTX.cjs.map +0 -1
  77. package/dist/chunk-OY7XOPDG.cjs.map +0 -1
  78. package/dist/chunk-TXHFL725.js.map +0 -1
  79. package/dist/transitions-BLFfAJUH.d.cts +0 -450
  80. package/dist/transitions-BgwWM37i.d.ts +0 -450
package/src/style.ts CHANGED
@@ -39,58 +39,75 @@ export interface Style {
39
39
  * the term ("anime", "ukiyo-e", "cyberpunk") and nothing is authored.
40
40
  */
41
41
  readonly term?: string
42
+ /**
43
+ * VIDEO-ONLY wording: what the medium is, then its concrete techniques
44
+ * ("Stop-motion claymation, handmade: every person … sculpted from matte
45
+ * plasticine clay …"). A still's `promptHint` loses to real reference photos
46
+ * once the shot moves: a video model holds on to a photographed face or a
47
+ * filmed scene unless the wording names a MEDIUM strongly enough to override
48
+ * it (in video tests on Seedance 2.5, this pattern as the prompt's first line
49
+ * styled every shot). Every stock style carries one; the photographic styles
50
+ * name a live-action or photographic medium, so they stay photographed. A
51
+ * drawn style names a 2D medium, with its outline first among its techniques
52
+ * (in the tests, lines with an outline styled every shot, a shot no reference
53
+ * picture covers included; lines without one often left that shot
54
+ * photographed). Every video surface reads it through
55
+ * `getStyleVideoPromptHint`, which falls back to `promptHint` (a pack style
56
+ * without one). Images never read it.
57
+ */
58
+ readonly videoPromptHint?: string
42
59
  }
43
60
 
44
61
  export const STYLES: ReadonlyArray<Style> = [
45
- { id: "3d-render", label: "3D Render", description: "Modern CGI render with clean shading", promptHint: "3D rendered style, modern CGI aesthetic with clean shading, subtle ambient occlusion and crisp materials" },
46
- { id: "anime", label: "Anime", description: "Japanese animation look", promptHint: "anime style, Japanese animation aesthetic with bold cel-shaded lines, expressive eyes and saturated colors" },
47
- { id: "children-book", label: "Children's Book", description: "Warm illustrated storybook", promptHint: "children's book illustration style, warm hand-drawn storybook look with soft shapes, friendly characters and inviting colors", term: "children's book illustration" },
48
- { id: "cinematic", label: "Cinematic", description: "Film-grade dramatic image", promptHint: "cinematic film style, dramatic lighting with cinematic color grading, widescreen aesthetic and film-like depth of field" },
49
- { id: "comic-book", label: "Comic Book", description: "Inked panels with flat color", promptHint: "comic book style, bold inked outlines, halftone shading and flat saturated comic panel colors", term: "comic book art" },
50
- { id: "digital-art", label: "Digital Art", description: "Polished digital illustration", promptHint: "digital art style, polished digital painting with smooth brushwork, vibrant colors and clean rendering" },
51
- { id: "fantasy", label: "Fantasy", description: "Epic high-fantasy illustration", promptHint: "fantasy art style, epic high-fantasy illustration with painterly detail, magical atmosphere and rich lore-driven mood", term: "fantasy art" },
52
- { id: "minimalist", label: "Minimalist", description: "Simple shapes, lots of whitespace", promptHint: "minimalist style, reduced composition with simple shapes, limited palette and generous negative space" },
53
- { id: "noir", label: "Noir", description: "High-contrast B&W film noir", promptHint: "film noir style, high-contrast black-and-white imagery, deep shadows, venetian-blind lighting and moody 1940s cinema feel", term: "film noir" },
54
- { id: "oil-painting", label: "Oil Painting", description: "Thick brush strokes, classical canvas", promptHint: "oil painting style, visible thick brush strokes on canvas with rich pigment, classical painterly texture and warm tonal blending" },
55
- { id: "pencil-sketch", label: "Pencil Sketch", description: "Hand-drawn graphite drawing", promptHint: "pencil sketch style, hand-drawn graphite drawing with visible hatching, soft smudges and raw paper texture" },
56
- { id: "photorealistic", label: "Photorealistic", description: "Indistinguishable from a photograph", promptHint: "photorealistic style, high-fidelity photographic realism with natural lighting, accurate materials and DSLR-grade detail" },
57
- { id: "pixel-art", label: "Pixel Art", description: "Retro game-style pixel grid", promptHint: "pixel art style, retro low-resolution pixel grid aesthetic with limited palette and hard-edged chunky sprites" },
58
- { id: "pop-art", label: "Pop Art", description: "Bold colors, Warhol/Lichtenstein", promptHint: "pop art style, bold saturated colors, Ben-Day dots and high-contrast Warhol/Lichtenstein-inspired graphic look" },
59
- { id: "retro-vintage", label: "Retro / Vintage", description: "Faded nostalgic film look", promptHint: "retro vintage style, faded nostalgic film look with muted colors, subtle grain and old-photograph warmth", term: "retro vintage film look" },
60
- { id: "watercolor", label: "Watercolor", description: "Soft transparent washes", promptHint: "watercolor style, soft transparent washes with bleeding edges, paper grain and delicate pigment pooling" },
61
- { id: "concept-art", label: "Concept Art", description: "Film/game pre-production painting", promptHint: "concept art style, painterly film and game pre-production illustration with dramatic lighting, moody atmosphere and loose brushwork emphasizing scale and storytelling" },
62
- { id: "impressionism", label: "Impressionism", description: "Monet-style dabbed brushwork", promptHint: "impressionist style, Monet-inspired visible dabbed brush strokes, soft natural light, pastel palette and loose color mixing that captures atmosphere over detail", term: "impressionist painting" },
63
- { id: "surrealism", label: "Surrealism", description: "Dreamlike Dalí-inspired", promptHint: "surrealist style, Dalí-inspired dreamlike imagery with impossible geometry, melting forms, floating elements and uncanny color combinations", term: "surrealist painting" },
64
- { id: "cyberpunk", label: "Cyberpunk", description: "Neon-lit dystopian future", promptHint: "cyberpunk style, neon-lit dystopian future aesthetic with magenta and cyan glow, rain-slick reflections, high-tech low-life mood and dense urban detail" },
65
- { id: "steampunk", label: "Steampunk", description: "Victorian brass + machinery", promptHint: "steampunk style, Victorian-era brass and copper machinery, exposed gears and pipes, sepia tones and retrofuturistic mechanical detail" },
66
- { id: "vaporwave", label: "Vaporwave", description: "80s pastel digital retro", promptHint: "vaporwave style, 1980s digital retro aesthetic with pastel pink and teal palette, chrome text, glitch artifacts, palm silhouettes and dreamlike sunset grids" },
67
- { id: "low-poly", label: "Low Poly", description: "Faceted geometric 3D", promptHint: "low poly style, faceted geometric 3D aesthetic with visible flat triangular faces, simplified forms and crisp shadow edges between facets" },
68
- { id: "ink-wash", label: "Ink Wash", description: "East-Asian sumi-e brush", promptHint: "ink wash sumi-e style, East-Asian brush painting on rice paper with bold gestural black brush strokes, soft ink bleeding and generous negative space", term: "sumi-e ink wash painting" },
69
- { id: "isometric", label: "Isometric", description: "3/4 axonometric view", promptHint: "isometric style, 3/4 axonometric projection with clean geometric forms, bright saturated flat colors and uniform lighting like a tile-based game or architectural diagram" },
70
- { id: "flat-vector", label: "Flat Vector", description: "Modern flat illustration", promptHint: "flat vector illustration style, modern SaaS-style flat shapes with bright solid colors, no gradients or shadows, clean geometry and friendly simplified forms", term: "flat vector illustration" },
71
- { id: "ukiyo-e", label: "Ukiyo-e", description: "Japanese woodblock print", promptHint: "ukiyo-e style, traditional Japanese woodblock print with bold outlined flat color planes, Hokusai-inspired palette and stylized natural elements" },
72
- { id: "graffiti", label: "Graffiti", description: "Street-art spray paint", promptHint: "graffiti street art style, vivid urban spray-paint aesthetic with bold tag lettering, drip textures, stencil edges and gritty wall surfaces", term: "graffiti street art" },
73
- { id: "claymation", label: "Claymation", description: "Tactile stop-motion clay", promptHint: "claymation stop-motion style, tactile handcrafted clay figures with visible fingerprints, rounded plasticine forms and warm diorama lighting reminiscent of Aardman productions" },
74
- { id: "glitch-art", label: "Glitch Art", description: "Digital corruption + datamosh", promptHint: "glitch art style, digital corruption aesthetic with chromatic aberration, RGB channel shifts, horizontal scanline tearing, pixel sorting and datamoshed compression artifacts" },
75
- { id: "ascii-art", label: "ASCII Art", description: "Monochrome terminal characters", promptHint: "ASCII art style, monochrome terminal aesthetic built from text characters (@ # %, . :) forming the image, green-on-black old-computer vibe, monospace typography and character-grid rendering" },
76
- { id: "blueprint", label: "Blueprint", description: "Technical drawing on blue", promptHint: "blueprint technical drawing style, white line work on deep cyan-blue paper with dimension lines, annotations, orthographic projections and engineering-schematic precision", term: "blueprint technical drawing" },
77
- { id: "stained-glass", label: "Stained Glass", description: "Leaded colored glass mosaic", promptHint: "stained glass window style, tessellated colored glass panels separated by thick black lead lines, luminous backlit jewel tones and church-window composition" },
78
- { id: "chalkboard", label: "Chalkboard", description: "White chalk on slate", promptHint: "chalkboard style, white and pastel chalk on dark slate with smudged edges, visible chalk dust, hand-drawn marks and classroom-lecture feel", term: "chalk drawing on blackboard" },
79
- { id: "paper-cutout", label: "Paper Cutout", description: "Layered cut paper + shadows", promptHint: "paper cutout papercraft style, Matisse-inspired layered cut paper shapes with visible paper texture, clean scissor edges and soft drop shadows between layered planes" },
80
- { id: "illuminated", label: "Illuminated Manuscript", description: "Gold leaf + calligraphy", promptHint: "illuminated manuscript style, medieval parchment with gold leaf accents, ornate decorative borders with vines and creatures, calligraphic script and jewel-toned miniature paintings" },
81
- { id: "pixar-3d", label: "Pixar 3D", description: "Polished character animation CG", promptHint: "Pixar-style 3D character animation, polished CG with appealing rounded character design, soft subsurface skin shading, cinematic key lighting and expressive animated feature-film quality", term: "pixar-style 3d animation" },
82
- { id: "caricature", label: "Caricature", description: "Exaggerated stylized portrait", promptHint: "caricature illustration style, an exaggerated stylized portrait with a comically oversized head on a small body, amplified signature features — large nose, wide grin, oversized eyes — drawn with confident ink lines and watery color washes in the tradition of street-fair sketch artists" },
83
- { id: "fresco", label: "Fresco", description: "Renaissance plaster wall painting", promptHint: "rendered as a fresco painting in the style of a Renaissance ceiling, mineral pigments soaked into wet lime plaster with a chalky matte surface, softly weathered tonal range, faint craquelure and warm earthen palette reminiscent of Michelangelo's Sistine Chapel" },
84
- { id: "mosaic", label: "Mosaic", description: "Byzantine tessera tile composition", promptHint: "rendered as a mosaic composed of small hand-cut tesserae in stone, ceramic and gilded glass, visible grout lines between every tile, faceted highlights catching the light and a Byzantine / ancient-Roman aesthetic with stylized figures on a shimmering gold ground" },
85
- { id: "woodcut", label: "Woodcut", description: "Dürer-era relief print woodblock", promptHint: "rendered as a woodcut relief print, bold stark black ink on cream paper with assertive carved lines, parallel hatching for tonal shading, high-contrast graphic shapes and the wiry expressive line-work of Dürer-era Northern Renaissance prints" },
86
- { id: "etching", label: "Etching", description: "Rembrandt-style intaglio print", promptHint: "rendered as an intaglio etching, dense fine cross-hatched lines bitten into a copper plate, rich velvety blacks against warm cream paper, delicate tonal gradations and the introspective chiaroscuro of a Rembrandt print" },
87
- { id: "lithograph", label: "Lithograph", description: "Toulouse-Lautrec stone-printed poster", promptHint: "rendered as a stone lithograph, soft graphite-like tonal range with grainy crayon textures, flat areas of limited spot color, slightly off-register edges and the bold poster-art sensibility of a Toulouse-Lautrec belle-époque print" },
88
- { id: "charcoal", label: "Charcoal Drawing", description: "Smudgeable black tonal study", promptHint: "rendered as a charcoal drawing on toothy paper, soft black and grey tonal masses with smudged blended midtones, sharp accented darks, expressive gestural strokes and the raw immediacy of a fine-art figure study" },
89
- { id: "pastel", label: "Pastel", description: "Degas-era soft chalk pastel", promptHint: "rendered as a soft chalk pastel drawing, dry powdery pigment laid in feathered strokes on tinted paper with luminous dusty colors, gently blended edges and the dreamy Degas-era atmosphere of dancers in stage light", term: "soft pastel drawing" },
90
- { id: "acrylic-paint", label: "Acrylic Paint", description: "Fast-drying opaque acrylic on canvas", promptHint: "rendered as an acrylic painting on canvas, fast-drying opaque pigment with crisp sharp edges, confident quick brush strokes, high-key saturated color and a flatter more graphic finish than traditional oil paint", term: "acrylic painting" },
91
- { id: "mixed-media", label: "Mixed Media", description: "Collage + paint + ink hybrid", promptHint: "rendered as a mixed-media artwork combining torn paper collage, acrylic paint, ink and graphite on a layered substrate, heterogeneous textures, visible tape and stitching, and an exuberant hand-assembled studio-art quality" },
92
- { id: "manga", label: "Manga", description: "Inked B&W Japanese comic panel", promptHint: "rendered as inked manga panel art, crisp black ink on white with confident line weight variation, screen-tone dot patterns for shading, dramatic speed lines and the distinctly Japanese black-and-white comic aesthetic — separate from full-color anime" },
93
- { id: "early-color-photo", label: "Early Color Photo", description: "Prokudin-Gorsky / autochrome early-1900s color", promptHint: "rendered as an early-1900s color photograph in the Prokudin-Gorsky / autochrome tradition — soft three-colour-separation registration, muted dye-toned palette, fine grain and a gentle antique warmth", term: "early autochrome color photograph" },
62
+ { id: "3d-render", label: "3D Render", description: "Modern CGI render with clean shading", promptHint: "3D rendered style, modern CGI aesthetic with clean shading, subtle ambient occlusion and crisp materials", videoPromptHint: "Stylised 3D render animation, computer-generated: every person, vehicle and room modelled in smooth matte CG surfaces, simplified clean forms, soft studio lighting, gentle ambient occlusion, bright clean colours." },
63
+ { id: "anime", label: "Anime", description: "Japanese animation look", promptHint: "anime style, Japanese animation aesthetic with bold cel-shaded lines, expressive eyes and saturated colors", videoPromptHint: "2D Japanese anime, hand-drawn cel animation: clean thin ink line art, flat cel shading with one hard shadow tone, large expressive eyes, hair drawn as solid shapes, saturated colours, painted backgrounds." },
64
+ { id: "children-book", label: "Children's Book", description: "Warm illustrated storybook", promptHint: "children's book illustration style, warm hand-drawn storybook look with soft shapes, friendly characters and inviting colors", term: "children's book illustration", videoPromptHint: "2D children's picture-book illustration, hand-drawn: soft pencil outlines, gentle gouache and coloured-pencil fills, rounded friendly shapes, warm inviting colours, simple storybook backgrounds." },
65
+ { id: "cinematic", label: "Cinematic", description: "Film-grade dramatic image", promptHint: "cinematic film style, dramatic lighting with cinematic color grading, widescreen aesthetic and film-like depth of field", videoPromptHint: "Live-action cinema footage, shot on film: dramatic motivated lighting, rich cinematic colour grading, shallow depth of field, widescreen framing, fine film grain." },
66
+ { id: "comic-book", label: "Comic Book", description: "Inked panels with flat color", promptHint: "comic book style, bold inked outlines, halftone shading and flat saturated comic panel colors", term: "comic book art", videoPromptHint: "2D comic-book illustration, hand-inked: bold black ink outlines, halftone dot shading, flat saturated panel colours, hard-edged shadow shapes, strong graphic contrast." },
67
+ { id: "digital-art", label: "Digital Art", description: "Polished digital illustration", promptHint: "digital art style, polished digital painting with smooth brushwork, vibrant colors and clean rendering", videoPromptHint: "2D digital illustration, hand-painted on a tablet: crisp ink outlines, smooth brushwork, soft blended shading, vibrant saturated colours, clean polished rendering, glowing highlights." },
68
+ { id: "fantasy", label: "Fantasy", description: "Epic high-fantasy illustration", promptHint: "fantasy art style, epic high-fantasy illustration with painterly detail, magical atmosphere and rich lore-driven mood", term: "fantasy art", videoPromptHint: "2D high-fantasy illustration, hand-painted: fine ink outlines, rich painterly detail, ornate costumes and settings, magical glowing light, deep atmospheric colours, epic dramatic mood." },
69
+ { id: "minimalist", label: "Minimalist", description: "Simple shapes, lots of whitespace", promptHint: "minimalist style, reduced composition with simple shapes, limited palette and generous negative space", videoPromptHint: "Minimalist 2D animation, flat graphic: simple geometric shapes, clean thin outlines, a limited palette of two or three flat colours, smooth untextured surfaces, generous empty space." },
70
+ { id: "noir", label: "Noir", description: "High-contrast B&W film noir", promptHint: "film noir style, high-contrast black-and-white imagery, deep shadows, venetian-blind lighting and moody 1940s cinema feel", term: "film noir", videoPromptHint: "Live-action black-and-white film noir, shot on film: every shot in high-contrast black and white, deep black shadows, hard venetian-blind light patterns, smoky 1940s atmosphere, fine film grain." },
71
+ { id: "oil-painting", label: "Oil Painting", description: "Thick brush strokes, classical canvas", promptHint: "oil painting style, visible thick brush strokes on canvas with rich pigment, classical painterly texture and warm tonal blending", videoPromptHint: "2D oil-painted illustration, hand-painted on canvas: dark painted outlines, thick visible brush strokes, rich layered pigment, canvas weave texture, warm tonal blending, classical painterly light." },
72
+ { id: "pencil-sketch", label: "Pencil Sketch", description: "Hand-drawn graphite drawing", promptHint: "pencil sketch style, hand-drawn graphite drawing with visible hatching, soft smudges and raw paper texture", videoPromptHint: "2D graphite pencil illustration, hand-drawn on paper: dark pencil outlines, loose sketchy pencil lines, cross-hatched shading, soft smudges, grey tones on raw off-white paper." },
73
+ { id: "photorealistic", label: "Photorealistic", description: "Indistinguishable from a photograph", promptHint: "photorealistic style, high-fidelity photographic realism with natural lighting, accurate materials and DSLR-grade detail", videoPromptHint: "Photorealistic live-action footage, shot on a high-end cinema camera: natural lighting, true-to-life skin and materials, accurate colour, sharp lifelike detail." },
74
+ { id: "pixel-art", label: "Pixel Art", description: "Retro game-style pixel grid", promptHint: "pixel art style, retro low-resolution pixel grid aesthetic with limited palette and hard-edged chunky sprites", videoPromptHint: "2D retro pixel-art animation, 16-bit video game sprites: dark one-pixel sprite outlines, a visible square pixel grid, hard-edged chunky sprites, a limited colour palette, dithered shading, crisp unsmoothed pixel edges." },
75
+ { id: "pop-art", label: "Pop Art", description: "Bold colors, Warhol/Lichtenstein", promptHint: "pop art style, bold saturated colors, Ben-Day dots and high-contrast Warhol/Lichtenstein-inspired graphic look", videoPromptHint: "Flat 2D cel-shaded comic illustration, hand-drawn: thick uniform black ink outlines, flat colour fills, Ben-Day dot shading, bold saturated primary colours, high contrast." },
76
+ { id: "retro-vintage", label: "Retro / Vintage", description: "Faded nostalgic film look", promptHint: "retro vintage style, faded nostalgic film look with muted colors, subtle grain and old-photograph warmth", term: "retro vintage film look", videoPromptHint: "Vintage live-action footage, shot on old film stock: faded muted colours, warm yellowed tones, soft halation, visible film grain and light scratches." },
77
+ { id: "watercolor", label: "Watercolor", description: "Soft transparent washes", promptHint: "watercolor style, soft transparent washes with bleeding edges, paper grain and delicate pigment pooling", videoPromptHint: "2D watercolour illustration, hand-painted: fine ink outlines, soft transparent washes, bleeding wet edges, pooled pigment, visible paper grain." },
78
+ { id: "concept-art", label: "Concept Art", description: "Film/game pre-production painting", promptHint: "concept art style, painterly film and game pre-production illustration with dramatic lighting, moody atmosphere and loose brushwork emphasizing scale and storytelling", videoPromptHint: "2D film concept-art illustration, digitally painted: rough ink outlines, loose expressive brushwork, dramatic cinematic lighting, moody atmospheric colours, an epic sense of scale." },
79
+ { id: "impressionism", label: "Impressionism", description: "Monet-style dabbed brushwork", promptHint: "impressionist style, Monet-inspired visible dabbed brush strokes, soft natural light, pastel palette and loose color mixing that captures atmosphere over detail", term: "impressionist painting", videoPromptHint: "2D impressionist illustration, Monet-inspired: thin dark outlines, visible dabbed brush strokes, broken colour, soft natural light, a pastel palette, loosely blended atmosphere." },
80
+ { id: "surrealism", label: "Surrealism", description: "Dreamlike Dalí-inspired", promptHint: "surrealist style, Dalí-inspired dreamlike imagery with impossible geometry, melting forms, floating elements and uncanny color combinations", term: "surrealist painting", videoPromptHint: "2D surrealist illustration, Dalí-inspired: fine dark outlines, smooth academic oil rendering, dreamlike impossible geometry, melting and floating forms, long hard shadows, uncanny colour." },
81
+ { id: "cyberpunk", label: "Cyberpunk", description: "Neon-lit dystopian future", promptHint: "cyberpunk style, neon-lit dystopian future aesthetic with magenta and cyan glow, rain-slick reflections, high-tech low-life mood and dense urban detail", videoPromptHint: "Live-action cyberpunk film, shot at night: every location lit by neon magenta and cyan light, wet reflective surfaces, haze and holographic glow, dense high-tech detail, deep night shadows." },
82
+ { id: "steampunk", label: "Steampunk", description: "Victorian brass + machinery", promptHint: "steampunk style, Victorian-era brass and copper machinery, exposed gears and pipes, sepia tones and retrofuturistic mechanical detail", videoPromptHint: "Live-action steampunk film: Victorian costumes and sets of brass and copper machinery, exposed gears and pipes, warm sepia lighting, retrofuturistic mechanical detail." },
83
+ { id: "vaporwave", label: "Vaporwave", description: "80s pastel digital retro", promptHint: "vaporwave style, 1980s digital retro aesthetic with pastel pink and teal palette, chrome text, glitch artifacts, palm silhouettes and dreamlike sunset grids", videoPromptHint: "2D vaporwave digital illustration, 1980s retro-digital: clean neon outlines, a pastel pink and teal palette, chrome gradients, neon grid horizons, glitch artifacts, palm silhouettes against a sunset." },
84
+ { id: "low-poly", label: "Low Poly", description: "Faceted geometric 3D", promptHint: "low poly style, faceted geometric 3D aesthetic with visible flat triangular faces, simplified forms and crisp shadow edges between facets", videoPromptHint: "Stylised low poly 3D animation, computer-generated: every person, face, vehicle and room built from large flat-shaded triangles, visible facets on every surface, flat untextured colours, crisp shadow edges between facets." },
85
+ { id: "ink-wash", label: "Ink Wash", description: "East-Asian sumi-e brush", promptHint: "ink wash sumi-e style, East-Asian brush painting on rice paper with bold gestural black brush strokes, soft ink bleeding and generous negative space", term: "sumi-e ink wash painting", videoPromptHint: "2D East-Asian sumi-e ink wash illustration, brushed on rice paper: bold black brush outlines in gestural strokes, soft ink bleeding, grey diluted washes, generous empty space." },
86
+ { id: "isometric", label: "Isometric", description: "3/4 axonometric view", promptHint: "isometric style, 3/4 axonometric projection with clean geometric forms, bright saturated flat colors and uniform lighting like a tile-based game or architectural diagram", videoPromptHint: "Isometric game-style 3D illustration: clean geometric blocky forms, bright saturated flat colours, uniform soft lighting, crisp edges, a miniature diorama look." },
87
+ { id: "flat-vector", label: "Flat Vector", description: "Modern flat illustration", promptHint: "flat vector illustration style, modern SaaS-style flat shapes with bright solid colors, no gradients or shadows, clean geometry and friendly simplified forms", term: "flat vector illustration", videoPromptHint: "Flat 2D vector illustration, motion-graphics style: thin dark outlines, clean geometric shapes, bright solid colour fills, crisp clean edges, simplified friendly forms, flat backgrounds." },
88
+ { id: "ukiyo-e", label: "Ukiyo-e", description: "Japanese woodblock print", promptHint: "ukiyo-e style, traditional Japanese woodblock print with bold outlined flat color planes, Hokusai-inspired palette and stylized natural elements", videoPromptHint: "Animated Japanese ukiyo-e woodblock print, Hokusai-inspired: bold black outlines, flat planes of colour, subtle woodgrain paper texture, an indigo and earth-tone palette, stylised waves, clouds and natural elements." },
89
+ { id: "graffiti", label: "Graffiti", description: "Street-art spray paint", promptHint: "graffiti street art style, vivid urban spray-paint aesthetic with bold tag lettering, drip textures, stencil edges and gritty wall surfaces", term: "graffiti street art", videoPromptHint: "Street-art graffiti animation, spray-painted on walls: vivid spray-paint colours, bold outlines, drips and overspray, stencil edges, gritty brick and concrete textures." },
90
+ { id: "claymation", label: "Claymation", description: "Tactile stop-motion clay", promptHint: "claymation stop-motion style, tactile handcrafted clay figures with visible fingerprints, rounded plasticine forms and warm diorama lighting reminiscent of Aardman productions", videoPromptHint: "Stop-motion claymation, handmade: every person, vehicle and set sculpted from matte plasticine clay with visible fingerprints and tool marks, rounded simplified forms, miniature handcrafted diorama sets, soft warm studio lighting." },
91
+ { id: "glitch-art", label: "Glitch Art", description: "Digital corruption + datamosh", promptHint: "glitch art style, digital corruption aesthetic with chromatic aberration, RGB channel shifts, horizontal scanline tearing, pixel sorting and datamoshed compression artifacts", videoPromptHint: "Glitch-art digital video, datamoshed in every frame: strong chromatic aberration with red and cyan fringes on every edge, RGB channel shifts, horizontal scanline tearing, pixel-sorting streaks, blocky compression artifacts." },
92
+ { id: "ascii-art", label: "ASCII Art", description: "Monochrome terminal characters", promptHint: "ASCII art style, monochrome terminal aesthetic built from text characters (@ # %, . :) forming the image, green-on-black old-computer vibe, monospace typography and character-grid rendering", videoPromptHint: "ASCII-art animation, rendered in text characters: every shape built from monospace characters (@ # % . :), green on black, a terminal character grid, old-computer screen glow." },
93
+ { id: "blueprint", label: "Blueprint", description: "Technical drawing on blue", promptHint: "blueprint technical drawing style, white line work on deep cyan-blue paper with dimension lines, annotations, orthographic projections and engineering-schematic precision", term: "blueprint technical drawing", videoPromptHint: "2D blueprint technical drawing, drafted by hand: crisp white outlines on deep cyan-blue paper, dimension lines and annotations, orthographic construction lines, engineering-schematic precision." },
94
+ { id: "stained-glass", label: "Stained Glass", description: "Leaded colored glass mosaic", promptHint: "stained glass window style, tessellated colored glass panels separated by thick black lead lines, luminous backlit jewel tones and church-window composition", videoPromptHint: "Animated stained-glass window: every shape made of coloured glass panels separated by thick black lead lines, luminous backlit jewel tones, a church-window composition." },
95
+ { id: "chalkboard", label: "Chalkboard", description: "White chalk on slate", promptHint: "chalkboard style, white and pastel chalk on dark slate with smudged edges, visible chalk dust, hand-drawn marks and classroom-lecture feel", term: "chalk drawing on blackboard", videoPromptHint: "2D chalk illustration, hand-drawn on a blackboard: bold white chalk outlines, pastel chalk colour on dark slate, smudged edges, visible chalk dust, hand-drawn classroom sketch marks." },
96
+ { id: "paper-cutout", label: "Paper Cutout", description: "Layered cut paper + shadows", promptHint: "paper cutout papercraft style, Matisse-inspired layered cut paper shapes with visible paper texture, clean scissor edges and soft drop shadows between layered planes", videoPromptHint: "2D paper cutout stop-motion animation, handcrafted: every person, vehicle and set cut from layered coloured paper, thin dark outlines, visible paper texture, clean scissor edges, drop shadows between layers, Matisse-inspired flat colours." },
97
+ { id: "illuminated", label: "Illuminated Manuscript", description: "Gold leaf + calligraphy", promptHint: "illuminated manuscript style, medieval parchment with gold leaf accents, ornate decorative borders with vines and creatures, calligraphic script and jewel-toned miniature paintings", videoPromptHint: "2D medieval illuminated-manuscript illustration, hand-painted: fine black ink outlines, parchment texture, gold leaf accents, ornate decorative borders with vines, jewel-toned miniature painting, flat medieval perspective." },
98
+ { id: "pixar-3d", label: "Pixar 3D", description: "Polished character animation CG", promptHint: "Pixar-style 3D character animation, polished CG with appealing rounded character design, soft subsurface skin shading, cinematic key lighting and expressive animated feature-film quality", term: "pixar-style 3d animation", videoPromptHint: "Pixar-style 3D animated feature film: appealing rounded character designs, soft subsurface skin shading, polished CG materials, cinematic key lighting, expressive animation." },
99
+ { id: "caricature", label: "Caricature", description: "Exaggerated stylized portrait", promptHint: "caricature illustration style, an exaggerated stylized portrait with a comically oversized head on a small body, amplified signature features — large nose, wide grin, oversized eyes — drawn with confident ink lines and watery color washes in the tradition of street-fair sketch artists", videoPromptHint: "2D caricature illustration, hand-drawn: confident black ink outlines, oversized heads on small bodies, exaggerated signature features, loose watercolour washes, a street-fair sketch-artist look." },
100
+ { id: "fresco", label: "Fresco", description: "Renaissance plaster wall painting", promptHint: "rendered as a fresco painting in the style of a Renaissance ceiling, mineral pigments soaked into wet lime plaster with a chalky matte surface, softly weathered tonal range, faint craquelure and warm earthen palette reminiscent of Michelangelo's Sistine Chapel", videoPromptHint: "2D Renaissance fresco illustration, painted on wet lime plaster: dark painted outlines, mineral pigments, a chalky matte surface, softly weathered tones, faint craquelure, a warm earthen palette." },
101
+ { id: "mosaic", label: "Mosaic", description: "Byzantine tessera tile composition", promptHint: "rendered as a mosaic composed of small hand-cut tesserae in stone, ceramic and gilded glass, visible grout lines between every tile, faceted highlights catching the light and a Byzantine / ancient-Roman aesthetic with stylized figures on a shimmering gold ground", videoPromptHint: "2D Byzantine mosaic: every shape built from small hand-cut tesserae of stone, ceramic and gilded glass, each figure outlined in a row of dark tesserae, visible grout lines between tiles, faceted glints, a shimmering gold ground." },
102
+ { id: "woodcut", label: "Woodcut", description: "Dürer-era relief print woodblock", promptHint: "rendered as a woodcut relief print, bold stark black ink on cream paper with assertive carved lines, parallel hatching for tonal shading, high-contrast graphic shapes and the wiry expressive line-work of Dürer-era Northern Renaissance prints", videoPromptHint: "2D woodcut relief-print illustration, Dürer-era: bold carved black outlines, stark black ink on cream paper, parallel hatching for shading, high-contrast graphic shapes." },
103
+ { id: "etching", label: "Etching", description: "Rembrandt-style intaglio print", promptHint: "rendered as an intaglio etching, dense fine cross-hatched lines bitten into a copper plate, rich velvety blacks against warm cream paper, delicate tonal gradations and the introspective chiaroscuro of a Rembrandt print", videoPromptHint: "2D intaglio etching illustration, Rembrandt-style: fine black etched outlines, dense cross-hatched lines, rich velvety blacks on warm cream paper, delicate tonal gradations, deep chiaroscuro." },
104
+ { id: "lithograph", label: "Lithograph", description: "Toulouse-Lautrec stone-printed poster", promptHint: "rendered as a stone lithograph, soft graphite-like tonal range with grainy crayon textures, flat areas of limited spot color, slightly off-register edges and the bold poster-art sensibility of a Toulouse-Lautrec belle-époque print", videoPromptHint: "2D stone-lithograph poster illustration, Toulouse-Lautrec style: every person and room drawn in fluid black brush outlines, flat areas of limited spot colour, grainy crayon textures on cream paper, off-register edges, bold poster shapes." },
105
+ { id: "charcoal", label: "Charcoal Drawing", description: "Smudgeable black tonal study", promptHint: "rendered as a charcoal drawing on toothy paper, soft black and grey tonal masses with smudged blended midtones, sharp accented darks, expressive gestural strokes and the raw immediacy of a fine-art figure study", videoPromptHint: "Rough 2D charcoal sketch, hand-drawn on white paper: every person and every face drawn in heavy black charcoal outlines and loose hatched strokes, white paper showing through, smudged edges, bold gestural lines." },
106
+ { id: "pastel", label: "Pastel", description: "Degas-era soft chalk pastel", promptHint: "rendered as a soft chalk pastel drawing, dry powdery pigment laid in feathered strokes on tinted paper with luminous dusty colors, gently blended edges and the dreamy Degas-era atmosphere of dancers in stage light", term: "soft pastel drawing", videoPromptHint: "2D soft-pastel illustration, hand-drawn on tinted paper: dark pastel outlines, dry powdery pigment in feathered strokes, luminous dusty colours, gently blended edges, a Degas-era softness." },
107
+ { id: "acrylic-paint", label: "Acrylic Paint", description: "Fast-drying opaque acrylic on canvas", promptHint: "rendered as an acrylic painting on canvas, fast-drying opaque pigment with crisp sharp edges, confident quick brush strokes, high-key saturated color and a flatter more graphic finish than traditional oil paint", term: "acrylic painting", videoPromptHint: "2D acrylic illustration, hand-painted on canvas: bold dark outlines, opaque fast-drying pigment, crisp sharp edges, confident quick brush strokes, high-key saturated colours, a flat graphic finish." },
108
+ { id: "mixed-media", label: "Mixed Media", description: "Collage + paint + ink hybrid", promptHint: "rendered as a mixed-media artwork combining torn paper collage, acrylic paint, ink and graphite on a layered substrate, heterogeneous textures, visible tape and stitching, and an exuberant hand-assembled studio-art quality", videoPromptHint: "2D mixed-media collage illustration, hand-assembled: bold ink outlines, torn paper collage, acrylic paint and graphite layers, varied textures, visible tape and stitching." },
109
+ { id: "manga", label: "Manga", description: "Inked B&W Japanese comic panel", promptHint: "rendered as inked manga panel art, crisp black ink on white with confident line weight variation, screen-tone dot patterns for shading, dramatic speed lines and the distinctly Japanese black-and-white comic aesthetic — separate from full-color anime", videoPromptHint: "Animated black-and-white Japanese manga, hand-inked: crisp black ink line art with varied line weight, screentone dot shading, speed lines, stark black and white." },
110
+ { id: "early-color-photo", label: "Early Color Photo", description: "Prokudin-Gorsky / autochrome early-1900s color", promptHint: "rendered as an early-1900s color photograph in the Prokudin-Gorsky / autochrome tradition — soft three-colour-separation registration, muted dye-toned palette, fine grain and a gentle antique warmth", term: "early autochrome color photograph", videoPromptHint: "Early-1900s autochrome colour photography, in motion: soft three-colour registration, a muted dye-toned palette, fine grain, gentle antique warmth." },
94
111
  ] as const
95
112
 
96
113
  const styleById = new Map<string, Style>(STYLES.map((s) => [s.id, s]))
@@ -125,6 +142,18 @@ export function getStylePromptHint(id: string | undefined | null): string {
125
142
  return getStyle(id)?.promptHint ?? ""
126
143
  }
127
144
 
145
+ /**
146
+ * The wording a VIDEO prompt injects for this style: its `videoPromptHint`
147
+ * where one is authored, else the same `promptHint` an image uses. Resolved
148
+ * through `getStyle`, so a deployment's catalog packs apply exactly as they do
149
+ * to `getStylePromptHint` (see `overlayEntry` for how a pack's rewrite and the
150
+ * video wording pair up). `""` for an unknown or denied id.
151
+ */
152
+ export function getStyleVideoPromptHint(id: string | undefined | null): string {
153
+ const s = getStyle(id)
154
+ return s?.videoPromptHint ?? s?.promptHint ?? ""
155
+ }
156
+
128
157
  /** Compact counterpart of `getStylePromptHint` — see `term.ts`. */
129
158
  export function getStyleTerm(id: string | undefined | null): string {
130
159
  return resolveTerm(getStyle(id))
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/age-floor.ts","../src/parameter-prompt-hint.ts"],"names":[],"mappings":"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","file":"chunk-57PTYJJX.js","sourcesContent":["/**\n * The minor-age floor — Layer 1 of spec 2026-09-01-app-reports-triage-design.md\n * §3.3 (W1-a). Content-free: this module decides WHICH catalog entries a minor\n * subject may not carry; the clause a deployment appends lives in its\n * registered PromptPolicy (backend/src/lib/prompt-policies/), never here.\n *\n * `ADULT_ONLY_FLAG`, `ADULT_AGE_IDS`, `MINOR_IMPLYING_TYPE_IDS` and\n * `isMinorAge` live in the import-free leaf `age-signal.ts` and are\n * re-exported here unchanged — this module's own catalog-funnel imports\n * (`person-packs.js`, `picker-catalogs.js`) are exactly what `person.ts` /\n * `styling.ts` must NOT reach through, on pain of reopening the\n * person → age-floor → picker-catalogs load-time cycle (see `age-signal.ts`'s\n * header). `person.ts` / `styling.ts` import `isMinorAge` from\n * `age-signal.ts` directly instead of from here.\n */\n\nimport { getRegisteredPeople } from \"./person-packs.js\"\nimport { getRegisteredPickerCatalogs, type PickerCatalog, type PickerOption } from \"./picker-catalogs.js\"\nimport { isMinorAge, ADULT_AGE_IDS, MINOR_IMPLYING_TYPE_IDS } from \"./age-signal.js\"\n\nexport { ADULT_ONLY_FLAG, ADULT_AGE_IDS, MINOR_IMPLYING_TYPE_IDS, isMinorAge } from \"./age-signal.js\"\n\n/** Shape shared by every catalog entry the floor reads. */\nexport interface AdultOnlyEntry {\n readonly id: string\n readonly promptHint: string\n readonly term?: string\n readonly adultOnly?: true\n}\n\n/** The picker catalogs (by `catalogId`) this floor sweeps beside person.\n * Exported because it is the SINGLE source of truth for two things that used\n * to be maintained by hand and drifted: which catalogs `getAdultOnlyEntries`\n * sweeps for the flag, and which analyzer keys `FLOORED_PICKER_KEYS` strips\n * flagged ids out of (a `photo-genre` swept for the flag but absent from the\n * strip list let `glamour-portrait` survive on a minor). */\nexport const ADULT_SWEPT_CATALOG_IDS = [\"styling\", \"mood\", \"pose\", \"photo-genre\", \"character-motion\"] as const\n\n/** Membership form of the list above (the sweep does one lookup per catalog). */\nconst ADULT_SWEPT_CATALOG_ID_SET: ReadonlySet<string> = new Set(ADULT_SWEPT_CATALOG_IDS)\n\n/** Flatten a catalog's options regardless of shape: single-dim catalogs carry\n * `options` directly, multi-dim ones carry `dimensions[].options` (mirrors\n * `applyDeny` in catalog-packs.ts, the other consumer that has to handle\n * both shapes). */\nfunction optionsOf(catalog: PickerCatalog): ReadonlyArray<PickerOption> {\n if (catalog.kind === \"single\") return catalog.options ?? []\n return (catalog.dimensions ?? []).flatMap((d) => d.options)\n}\n\n/** Every entry, across the swept catalogs, that carries the flag. Reads every\n * catalog through the pack-composed funnel — `getRegisteredPeople()` for\n * person, `getRegisteredPickerCatalogs()` for styling/mood/pose/photo-genre —\n * so a pack-added or pack-replaced entry is included. */\nexport function getAdultOnlyEntries(): ReadonlyArray<AdultOnlyEntry> {\n const catalogEntries = getRegisteredPickerCatalogs()\n .filter((c) => ADULT_SWEPT_CATALOG_ID_SET.has(c.catalogId))\n .flatMap(optionsOf)\n const all: ReadonlyArray<AdultOnlyEntry> = [...getRegisteredPeople(), ...catalogEntries]\n return all.filter((e) => e.adultOnly === true)\n}\n\n/** The set of flagged ids (fast membership for the collectors). */\nexport function getAdultOnlyIds(): ReadonlySet<string> {\n return new Set(getAdultOnlyEntries().map((e) => e.id))\n}\n\n/**\n * The pre-rework `promptHint` of every `adultOnly` entry the spec\n * (2026-09-01-app-reports-triage-design §3.3) listed for rewording — including\n * `eye-state-half-lidded` and `feature-collarbone-visible`, which the W1-b\n * harness initially left byte-identical (0/10 and 0/22 render rate under\n * either wording) and a 2026-09-03 replay then found renderable wordings for\n * — plus the hard-coded midriff+navel fold clause. These strings are permanently part of the strip\n * set: a consumer that has not bumped `@nodaro/prompts` still emits them, and\n * the client-assembled `seedPrompt` path is exactly how the 2026-07-30\n * minor-age prompts reached a provider. Retiring can only ever cause an EXTRA\n * strip, and only for a subject `isMinorAge` has already judged a minor — so\n * the list only grows, never shrinks.\n *\n * `promptHint` ONLY, for the same reason `getAdultOnlyHintStrings` gives:\n * `term` is short display vocabulary and the composed-catalog projection\n * back-fills a derived `term` for every option, so terms collide with benign\n * everyday text. Assembled prompts and client seedPrompts are built from\n * hints, never from terms. The three W1-b entries that are NOT flagged —\n * `texture-dewy`, `texture-baby-soft`, `eye-state-staring-camera` (spec\n * §3.3's \"deliberately not flagged\" list) — are absent: their old wording\n * never belonged to the floor.\n *\n * 15 flagged hints + the fold literal = 16.\n */\nexport const RETIRED_ADULT_ONLY_HINT_STRINGS: ReadonlyArray<string> = [\n // bust-very-full\n \"very full bust\",\n // silhouette-hourglass\n \"hourglass silhouette\",\n // waist-defined\n \"defined waist\",\n // lip-state-glossy\n \"with high-shine glossy wet-look lips\",\n // lip-state-parted\n \"with lips slightly parted, taking a soft breath\",\n // lip-state-bitten\n \"playfully biting the lower lip\",\n // eye-state-half-lidded\n \"with heavy half-lidded sleepy eyes\",\n // texture-glistening\n \"with glistening skin, sweat or oil catching the light\",\n // texture-shower-fresh-wet\n \"with just-out-of-the-shower wet skin, water beading on the surface and rolling in slow droplets down the curves of the body\",\n // feature-bare-shoulders\n \"with bare shoulders exposed, the line of the collarbone and shoulder muscles uncovered\",\n // feature-collarbone-visible\n \"with a prominent collarbone clearly defined and catching the light\",\n // feature-midriff-visible\n \"wearing a cropped style with the midriff visible\",\n // state-fitted — the 2026-07-30 incident clause\n \"the clothing fitted and form-conscious, hugging the contours of the body\",\n // state-wet\n \"the clothing soaked and wet, the fabric clinging to the body and dripping water\",\n // pose `biting-lip` (the lip-state-bitten twin)\n \"biting the lower lip with a subtle playful expression\",\n // the hard-coded midriff+navel fold in emitIndependentFragments — not any\n // entry's hint, so retiring it ADDS a needle for a clause that really is\n // emitted verbatim.\n \"wearing a cropped style, midriff and navel visible\",\n]\n\n/** Every full prompt-hint string a flagged entry can inject, lower-cased,\n * longest first — the backend policy strips text that contains any of them\n * (Layer 2), which is how flagged wording arriving inside free text (a\n * client-assembled seedPrompt) is caught. Seeded with\n * `RETIRED_ADULT_ONLY_HINT_STRINGS` so a catalog rewording can never narrow\n * the strip set for a consumer still shipping the pre-rephrase wording.\n *\n * `promptHint` ONLY, deliberately — `term` is analyzer/UI vocabulary\n * (compact-mode display), and `picker-catalogs.ts`'s composed-catalog\n * projection back-fills a `term` for EVERY option via `deriveTerm(label)`\n * when no explicit term was authored (e.g. \"lounging\", \"cropped top\",\n * \"school uniform\", \"lying down\"). Those short, generic derived terms are\n * exactly the kind of everyday word that collides with unrelated, benign\n * text and over-strips it. Assembled prompts and client seedPrompts are\n * built from HINTS, never from terms, so hints are the only strings that\n * can actually arrive verbatim in free text — terms don't need to be (and\n * must not be) swept here. */\nexport function getAdultOnlyHintStrings(): ReadonlyArray<string> {\n const out = new Set<string>(RETIRED_ADULT_ONLY_HINT_STRINGS)\n for (const e of getAdultOnlyEntries()) {\n if (e.promptHint) out.add(e.promptHint.toLowerCase())\n }\n return [...out].filter((s) => s.length >= 8).sort((a, b) => b.length - a.length)\n}\n\n/**\n * Every full prompt-hint string that DESCRIBES A MINOR — the mirror of\n * `getAdultOnlyHintStrings`, and the needle list for the TEXT signal below.\n *\n * Why a text signal exists at all: `isMinorAge` reads the structured picker\n * value, and the P0 arrival path does not have one. A thin client can create a\n * character row carrying only `{nodeId, name, projectId}` and send the picker\n * selection as an already-assembled `seedPrompt`, so `row.person === null`\n * while the prompt itself says \"a young child around 5 years old\". That client\n * assembles the text FROM THESE HINTS, which is exactly why the catalog is the\n * drift-proof needle list: a new minor age entry is swept the day it is added,\n * with no second list to remember.\n *\n * Selection is DERIVED, never hand-listed: an `age` entry is a minor unless its\n * id is in the `ADULT_AGE_IDS` allow-list (so a new age id is inside the floor\n * by default — same ratchet as `isMinorAge`), plus every `type` entry named by\n * `MINOR_IMPLYING_TYPE_IDS`. Read through the pack-composed funnel\n * (`getRegisteredPeople()`), so a deployment pack's entries are swept too.\n *\n * `promptHint` ONLY — never `term` and never `label`, for the same reason\n * `getAdultOnlyHintStrings` gives: `term` is short display vocabulary\n * (\"in their teens\" as a compact chip) and the composed-catalog projection\n * back-fills a derived `term` for every option, so terms collide with benign\n * text. The `>= 8` filter drops `age-custom`'s empty hint (`\"\"`), which would\n * otherwise match every string ever written.\n */\nlet cachedMinorHints: ReadonlyArray<string> | null = null\nlet cachedMinorHintSourceCount = -1\nexport function getMinorAgeHintStrings(): ReadonlyArray<string> {\n const people = getRegisteredPeople()\n if (cachedMinorHints && cachedMinorHintSourceCount === people.length) return cachedMinorHints\n const out = new Set<string>()\n for (const e of people) {\n const minorAge = e.dimension === \"age\" && !ADULT_AGE_IDS.has(e.id)\n const minorType = e.dimension === \"type\" && MINOR_IMPLYING_TYPE_IDS.has(e.id)\n if (!minorAge && !minorType) continue\n if (e.promptHint) out.add(e.promptHint.toLowerCase())\n }\n cachedMinorHintSourceCount = people.length\n cachedMinorHints = [...out].filter((s) => s.length >= 8).sort((a, b) => b.length - a.length)\n return cachedMinorHints\n}\n\nfunction escapeReSource(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n}\n\n/** One needle's regex source: the phrase's tokens — split on whitespace AND\n * hyphens — escaped and rejoined by `[\\s-]+`, so it matches however the text\n * that carries it happened to be spaced or hyphenated. */\nfunction needleTokenSource(needle: string): string {\n return needle\n .trim()\n .split(/[\\s-]+/)\n .filter((t) => t.length > 0)\n .map(escapeReSource)\n .join(\"[\\\\s-]+\")\n}\n\n/**\n * The word-bounded alternation SOURCE for a needle list — the one place both\n * layers of the floor build their matcher, so they can never disagree about\n * what \"the same phrase\" means.\n *\n * Two properties, both load-bearing:\n * - **Separator tolerance.** A catalog hint is authored with single spaces\n * (\"very full bust\"), but the free text that carries it is written by a\n * human or an LLM and arrives as \"very-full bust\" or \"very full bust\".\n * A literal alternation misses those, and a miss is a flagged phrase\n * reaching the provider on a minor's prompt. Each needle's tokens are\n * joined by `[\\s-]+`, which requires AT LEAST one separator — so\n * \"very fullbust\" (no separator at all) is still not a match, and the\n * phrase can't silently widen into a substring rule.\n * - **Word boundaries.** `(?<![\\w-])` / `(?![\\w-])` keep a needle from\n * gluing onto an adjacent word's characters (\"mesh tops\" must survive a\n * \"mesh top\" needle).\n *\n * Ordering is the CALLER's: pass needles longest-first so the alternation\n * consumes the longest match at a given position instead of leaving debris.\n * Returns `null` when there is nothing to match (an empty list would otherwise\n * compile to `(?:)`, which matches everywhere). Flags are the caller's too —\n * `\"i\"` for a `.test()` instance, `\"gi\"` for one used with `String.replace`.\n */\nexport function buildNeedleAlternationSource(needles: ReadonlyArray<string>): string | null {\n const alts = needles.map(needleTokenSource).filter((s) => s.length > 0)\n if (alts.length === 0) return null\n return `(?<![\\\\w-])(?:${alts.join(\"|\")})(?![\\\\w-])`\n}\n\n/** Needle alternation over `getMinorAgeHintStrings()`, word-bounded on both\n * sides so a hint can only match a whole phrase. Deliberately NOT global:\n * this instance is only ever `.test()`ed, and a `/g` regex would carry\n * `lastIndex` across calls. Cached by needle count (packs are registered\n * before the first prompt is assembled). */\nlet cachedMinorNeedleRe: RegExp | null = null\nlet cachedMinorNeedleCount = -1\nfunction minorNeedleRegex(): RegExp | null {\n const needles = getMinorAgeHintStrings()\n if (cachedMinorNeedleRe && cachedMinorNeedleCount === needles.length) return cachedMinorNeedleRe\n cachedMinorNeedleCount = needles.length\n const src = buildNeedleAlternationSource(needles)\n cachedMinorNeedleRe = src === null ? null : new RegExp(src, \"i\")\n return cachedMinorNeedleRe\n}\n\n/**\n * NUMBER-FIRST age shapes: the ones `buildAgeFragment` (person.ts) emits for a\n * CUSTOM age (\"N years old\", \"N year old\", \"N-year-old\") and the catalog's own\n * \"2-3 years old\" range (the FIRST number decides), plus the colloquial tails a\n * human or an LLM writes instead — \"12yo\", \"12 yo\", \"12 y.o.\", \"12 y/o\",\n * \"12 yr old\", \"12-yr-old\", \"12yrs old\", \"12 years of age\". The cut is `< 20`,\n * the same boundary `isMinorAge` uses for `customAge` and the same one\n * `buildAgeFragment` switches to \"in their teens\" at.\n *\n * Both boundaries are load-bearing. The LEADING one stops a match inside a\n * larger token; the TRAILING one is what makes \"a 5 year older sibling\" a\n * non-hit (\"old\" may not glue onto \"older\") and what stops \"yo\" from firing\n * inside \"12 young\" or \"12 yoga\". Used via `matchAll`, which clones the regex\n * rather than advancing this instance's `lastIndex`.\n */\nconst NUMERIC_AGE_RE =\n /(?<![\\w-])(\\d{1,3})(?:\\s*-\\s*\\d{1,3})?\\s*-?\\s*(?:years?\\s*-?\\s*old|yrs?\\s*-?\\s*old|y(?:\\.\\s*o\\.?|\\/o|o)|years?\\s+of\\s+age)(?![\\w-])/gi\n\n/**\n * AGE-FIRST shapes, where the number trails the word instead of leading it:\n * \"age 12\", \"aged 12\", \"at the age of 12\". The leading boundary is what keeps\n * \"image 12\" / \"page 12\" out (the `age` there is glued to a preceding word\n * character), and the trailing one keeps \"aged 12th\" out.\n */\nconst PREFIXED_AGE_RE = /(?<![\\w-])aged?\\s+(?:of\\s+)?(\\d{1,3})(?![\\w-])/gi\n\n/** Every rule that reads a NUMBER out of the text, each capturing the age in\n * group 1. Iterated together below so a new shape is one array entry. */\nconst AGE_NUMBER_RULES: ReadonlyArray<RegExp> = [NUMERIC_AGE_RE, PREFIXED_AGE_RE]\n\n/** The one NON-numeric shape `buildAgeFragment` emits below 20 (`${n} years\n * old, in their teens`). Kept as its own rule rather than as a catalog term.\n * Separator-tolerant on the same terms as the needle alternation, so\n * \"in their teens\" and \"in-their-teens\" are the same phrase. */\nconst IN_THEIR_TEENS_RE = /(?<![\\w-])in[\\s-]+their[\\s-]+teens(?![\\w-])/i\n\n/**\n * True when free text describes a MINOR subject. Three rules, in order:\n * 1. any minor-age / minor-implying-type prompt hint, word-bounded;\n * 2. a numeric age below 20 in any shape `buildAgeFragment` emits;\n * 3. the literal \"in their teens\".\n *\n * Deliberately NOT a bare-word check: \"child\", \"teen\", \"kid\" alone must never\n * fire, or an adult prompt that merely MENTIONS a child (\"a mother holding her\n * child\") would be floored — the spec's \"adults are byte-identical\" is a hard\n * requirement, so every rule here is a full phrase or a bounded number.\n *\n * Pairs with `isMinorAge`, never replaces it: the structured picker value is\n * the primary signal; this catches the same subject when only the assembled\n * text survives.\n */\nexport function containsMinorAgeHint(text: string | null | undefined): boolean {\n if (typeof text !== \"string\" || text.trim().length === 0) return false\n const re = minorNeedleRegex()\n if (re && re.test(text)) return true\n for (const rule of AGE_NUMBER_RULES) {\n for (const m of text.matchAll(rule)) {\n const n = Number(m[1])\n if (Number.isFinite(n) && n < 20) return true\n }\n }\n return IN_THEIR_TEENS_RE.test(text)\n}\n\n/** The analyzer/import value keys the floor strips flagged ids out of:\n * `person` plus EVERY catalog the flag sweep reads. DERIVED, never\n * hand-listed — the hand-written version omitted `photo-genre` while the\n * sweep included it, so a minor kept `glamour-portrait`. The analyzer JSON is\n * keyed by picker type id (`describe-to-picker.ts`), which is the same string\n * as the catalog id, so this list IS the set of keys to visit. */\nexport const FLOORED_PICKER_KEYS = [\"person\", ...ADULT_SWEPT_CATALOG_IDS] as const\n\nfunction stripIds(obj: Record<string, unknown>, drop: ReadonlySet<string>): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(obj)) {\n if (typeof v === \"string\") {\n if (!drop.has(v)) out[k] = v\n } else if (Array.isArray(v)) {\n const kept = v.filter((x) => !(typeof x === \"string\" && drop.has(x)))\n if (kept.length > 0) out[k] = kept\n } else {\n out[k] = v\n }\n }\n return out\n}\n\n/** Analyzer / import post-filter: when the person value describes a minor,\n * remove every flagged id from the person, styling, pose and mood values.\n * Identity (same reference) for an adult. */\nexport function applyMinorAgeFloorToPickerValues<T extends Record<string, unknown>>(values: T): T {\n const person = values.person\n if (!person || typeof person !== \"object\" || !isMinorAge(person as { age?: string; customAge?: number; type?: string })) return values\n const drop = getAdultOnlyIds()\n const out: Record<string, unknown> = { ...values }\n for (const key of FLOORED_PICKER_KEYS) {\n const v = out[key]\n if (v && typeof v === \"object\" && !Array.isArray(v)) out[key] = stripIds(v as Record<string, unknown>, drop)\n }\n return out as T\n}\n","import type { HintNodeLike, HintEdgeLike, HintGraphContext } from \"@nodaro/shared/types\"\nexport type { HintNodeLike, HintEdgeLike, HintGraphContext }\n/**\n * Single source of truth for parameter-node prompt-hint text.\n *\n * Every parameter node (framing, lens, camera-format, lighting, color-look,\n * atmosphere, style, setting, person, mood, pose, styling, temporal, tone,\n * text-prompt, camera-motion) dispatches through `getParameterPromptHint` to\n * produce the descriptive clause it contributes to a consumer's prompt.\n *\n * The frontend DAG executor and backend workflow orchestrator both call this,\n * so the text injected via the `cinematography` handle is identical to the\n * text injected when the node is wired directly into a Text Prompt / LLM Chat\n * / Combine Text input.\n *\n * Camera-motion is graph-aware: when `ctx` is provided the function walks the\n * node's `startState`/`endState` incoming edges and composes a fully formed\n * sentence via `composeCameraMotionHintFromConnections`. Without `ctx` only\n * the bare motion description is returned.\n */\n\nimport { buildFramingHints } from \"./framing.js\"\nimport { buildLightingHints } from \"./lighting.js\"\nimport { getLensPromptHint, getLensTerm } from \"./lens.js\"\nimport { getCameraFormatPromptHint, getCameraFormatTerm } from \"./camera-format.js\"\nimport { getColorLookPromptHint, getColorLookTerm } from \"./color-look.js\"\nimport { buildAtmosphereHints } from \"./atmosphere.js\"\nimport { buildActionFxHints } from \"./action-fx.js\"\nimport { getStylePromptHint, getStyleTerm } from \"./style.js\"\nimport { getSettingPromptHint, getSettingTerm } from \"./setting.js\"\nimport { getLoopSubjectPromptHint, getLoopSubjectTerm } from \"./loop-subject.js\"\nimport { buildPersonHints } from \"./person.js\"\nimport { buildMoodHints } from \"./mood.js\"\nimport { buildPoseHints } from \"./pose.js\"\nimport { buildStylingHints } from \"./styling.js\"\nimport { buildTemporalHints } from \"./temporal.js\"\nimport { composeCameraMotionHintFromConnections } from \"./camera-motions.js\"\nimport { joinHintFragments } from \"./hint-join.js\"\nimport { composeTransitionHintFromConnections, readTransitionOptionValues, type TransitionDuration, type TransitionIntensity, type TransitionPosition, type TransitionTiming } from \"./transitions.js\"\nimport { composeCharacterFxHintFromConnections, type CharacterFxDuration, type CharacterFxIntensity, type CharacterFxPosition, type CharacterFxTiming } from \"./character-fx.js\"\nimport { composeCharacterMotionHintFromConnections, type CharacterMotionPace, type CharacterMotionPosition, type CharacterMotionTiming } from \"./character-motion.js\"\nimport { containsMinorAgeHint, isMinorAge } from \"./age-floor.js\"\nimport { buildMaterialHints } from \"./materials.js\"\nimport { curatedAnimalPromptHint, curatedAnimalTerm, curatedVehicleText, curatedWeaponText, curatedFurnitureText } from \"./shared-catalog-overlay.js\"\nimport { getPhotoGenrePromptHint, getPhotoGenreTerm } from \"./photo-genre.js\"\nimport { getBackdropPromptHint, getBackdropTerm } from \"./backdrop.js\"\nimport { buildHeldPropHints } from \"./held-prop.js\"\nimport { buildPhotographerHints } from \"./photographer.js\"\nimport { buildAestheticHints } from \"./aesthetic.js\"\nimport { getEraPromptHint, getEraTerm } from \"./era.js\"\nimport { buildExposureHints } from \"./exposure-settings.js\"\nimport { getRenderQualityPromptHint, getRenderQualityTerm } from \"./render-quality.js\"\nimport { getCompositionEffectPromptHint, getCompositionEffectTerm } from \"./composition-effects.js\"\nimport { buildPostProcessHints } from \"./post-process-effects.js\"\nimport { buildMusicGenreHints } from \"./music-genre.js\"\nimport { buildMusicMoodHints } from \"./music-mood.js\"\nimport { buildInstrumentationHints } from \"./instrumentation.js\"\nimport { buildVoiceCharacterHints } from \"./voice-character.js\"\nimport { buildVoiceDeliveryHints } from \"./voice-delivery.js\"\nimport { getPickerCatalog } from \"./picker-catalogs.js\"\nimport { resolveTerm, type PickerHintMode } from \"./term.js\"\n\n\nfunction asStr(v: unknown): string {\n return typeof v === \"string\" ? v : \"\"\n}\n\n/** Extract the display name from a character / face / object / location ref node. */\nfunction extractCharacterRefName(node: HintNodeLike): string | undefined {\n const d = (node.data ?? {}) as Record<string, unknown>\n const candidates = [d.characterName, d.faceName, d.objectName, d.locationName]\n for (const v of candidates) {\n if (typeof v === \"string\" && v.trim().length > 0) return v.trim()\n }\n return undefined\n}\n\n/** Character Motion's name read: the shared character / face / object / location\n * read, then a creature's `creatureName`. Local to Character Motion so the\n * Character FX prompt, which shares `extractCharacterRefName`, stays unchanged. */\nfunction extractCharacterMotionRefName(node: HintNodeLike): string | undefined {\n const name = extractCharacterRefName(node)\n if (name) return name\n const creatureName = asStr(((node.data ?? {}) as Record<string, unknown>).creatureName).trim()\n return creatureName.length > 0 ? creatureName : undefined\n}\n\n/** Free-text fields a character / face / object / location ref node describes its subject in.\n * A creature ref uses the same `description` / `canonicalDescription` names. */\nconst REF_DESCRIPTION_FIELDS = [\"description\", \"seedPrompt\", \"canonicalDescription\"] as const\n\n/** True when a character / face / object / location ref node describes a minor:\n * its structured `person` age (the primary signal) or an age phrase in its\n * free-text description. Feeds the Character Motion floor (adult-only moves\n * dropped) — errs toward flooring, never toward letting an adult-only move through. */\nfunction extractCharacterRefMinor(node: HintNodeLike): boolean {\n const d = (node.data ?? {}) as Record<string, unknown>\n const person = d.person\n if (person && typeof person === \"object\" && !Array.isArray(person) && isMinorAge(person as Parameters<typeof isMinorAge>[0])) {\n return true\n }\n return REF_DESCRIPTION_FIELDS.some((field) => containsMinorAgeHint(asStr(d[field])))\n}\n\n/** The preview, diagnostics and execution use identical graph bindings. */\nexport function getCharacterMotionBindings(node: HintNodeLike, ctx?: HintGraphContext) {\n const targetNames: string[] = []\n const partnerNames: string[] = []\n const targetIds = new Set<string>()\n const partnerIds = new Set<string>()\n let subjectMinor = false\n for (const edge of ctx?.edges ?? []) {\n if (edge.target !== node.id || (edge.targetHandle !== \"target\" && edge.targetHandle !== \"partner\")) continue\n const src = ctx?.nodes.find(n => n.id === edge.source)\n if (!src) continue\n if (edge.targetHandle === \"target\") targetIds.add(src.id)\n else partnerIds.add(src.id)\n if (extractCharacterRefMinor(src)) subjectMinor = true\n const name = extractCharacterMotionRefName(src)\n if (!name) continue\n const names = edge.targetHandle === \"target\" ? targetNames : partnerNames\n if (!names.includes(name)) names.push(name)\n }\n return { targetNames, partnerNames, subjectMinor, selfPairing: [...targetIds].some(id => partnerIds.has(id)) }\n}\n\n/** Compose `[preText, mainHint, postText]` into a comma-joined string,\n * honoring the user's free-text fragments around the structured hint.\n * Helpers like `getStylePromptHint` that already include preText/postText\n * composition (build*Hints in mood/person/etc.) bypass this — they\n * return the fully-composed string directly. */\nfunction withCustomText(data: Record<string, unknown>, mainHint: string): string {\n const fragments: string[] = []\n const pre = typeof data.preText === \"string\" ? data.preText.trim() : \"\"\n if (pre) fragments.push(pre)\n if (mainHint) fragments.push(mainHint)\n const post = typeof data.postText === \"string\" ? data.postText.trim() : \"\"\n if (post) fragments.push(post)\n return joinHintFragments(fragments)\n}\n\n/**\n * The node-level hint mode a picker declares via `data.hintMode`.\n *\n * Only the two documented values count; anything else (a stale value, a typo,\n * a non-string) is treated as UNDECLARED and falls back — to the inherited\n * mode when the node is resolved as an upstream input, and to `\"full\"`\n * otherwise. Compact is opt-in, so an unrecognized value can never silently\n * shorten a prompt.\n */\nfunction readHintMode(data: Record<string, unknown>): PickerHintMode | undefined {\n const raw = data.hintMode\n return raw === \"compact\" || raw === \"full\" ? raw : undefined\n}\n\n/** Pick the full-hint or the compact-term getter for the active mode. */\nfunction byMode<T>(mode: PickerHintMode, full: T, compact: T): T {\n return mode === \"compact\" ? compact : full\n}\n\n/** How much a shot moves (the Motion node's three steps), as the clause it\n * adds to a video prompt; the compact form is the bare term. */\nconst MOTION_INTENSITY_HINTS: Readonly<Record<string, { readonly full: string; readonly compact: string }>> = {\n subtle: { full: \"subtle, gentle motion with slow, minimal movement\", compact: \"subtle motion\" },\n moderate: { full: \"moderate, natural motion at an even pace\", compact: \"moderate motion\" },\n dynamic: { full: \"dynamic, energetic motion with fast, pronounced movement\", compact: \"dynamic motion\" },\n}\n\n/**\n * Dispatch by parameter-node type to its prompt-hint string. For camera-motion,\n * pass `ctx` to include the composed start/end clauses; otherwise only the\n * bare motion description is returned.\n *\n * VERBOSITY — a picker node may set `data.hintMode` to `\"compact\"` to inject\n * its short professional `term` (\"whip pan left\", \"hard cut\") instead of the\n * long `promptHint`. Absent, or any unrecognized value, means `\"full\"`, whose\n * output is byte-identical to what this function returned before hint modes\n * existed. ONLY the base catalog fragment swaps: `preText`/`postText`, the\n * transition / camera-motion / character-fx timing and start-state/end-state\n * clauses, multi-pick joining and multi-dimension composition are emitted the\n * same way in both modes.\n */\nexport function getParameterPromptHint(\n node: HintNodeLike | undefined,\n ctx?: HintGraphContext,\n): string {\n return resolveParameterHint(node, ctx)\n}\n\n/**\n * The dispatch body. `inherited` carries the mode DOWN into the nodes wired to\n * a composer's `startState` / `endState` handles, so a compact transition\n * composes compact start/end clauses rather than mixing a term with two\n * paragraphs. A node that declares its own `hintMode` still wins over what it\n * inherits.\n */\nfunction resolveParameterHint(\n node: HintNodeLike | undefined,\n ctx?: HintGraphContext,\n inherited?: PickerHintMode,\n): string {\n if (!node?.type) return \"\"\n const data = (node.data ?? {}) as Record<string, unknown>\n const mode: PickerHintMode = readHintMode(data) ?? inherited ?? \"full\"\n\n if (node.type === \"camera-motion\") {\n const motionId = asStr(data.cameraMotion) || undefined\n if (!ctx) return withCustomText(data, composeCameraMotionHintFromConnections(motionId, [], [], mode))\n const startHints: string[] = []\n const endHints: string[] = []\n for (const edge of ctx.edges) {\n if (edge.target !== node.id) continue\n const src = ctx.nodes.find((n) => n.id === edge.source)\n if (!src) continue\n // Pass no ctx for nested resolution: startState/endState inputs are\n // themselves parameter nodes (framing/tone/etc.) that don't need graph\n // context, and avoiding recursion keeps the walk cycle-safe. The mode\n // rides down so the composed clause stays at one level of detail.\n const hint = resolveParameterHint(src, undefined, mode)\n if (!hint) continue\n if (edge.targetHandle === \"startState\") startHints.push(hint)\n else if (edge.targetHandle === \"endState\") endHints.push(hint)\n }\n return withCustomText(data, composeCameraMotionHintFromConnections(motionId, startHints, endHints, mode))\n }\n\n if (node.type === \"transition\") {\n const raw = data.transition\n const transitionId: string | string[] | undefined =\n Array.isArray(raw)\n ? raw.filter((s): s is string => typeof s === \"string\" && s.length > 0)\n : (asStr(raw) || undefined)\n const timing: TransitionTiming = {\n position: asStr(data.position) as TransitionPosition | undefined,\n duration: asStr(data.duration) as TransitionDuration | undefined,\n intensity: asStr(data.intensity) as TransitionIntensity | undefined,\n }\n // A picked row's own options (a wipe's `wipeDirection`), off the same node data.\n const optionValues = readTransitionOptionValues(data)\n const hintOptions = optionValues ? { optionValues } : undefined\n if (!ctx) {\n return withCustomText(data, composeTransitionHintFromConnections(transitionId, [], [], timing, mode, hintOptions))\n }\n const startHints: string[] = []\n const endHints: string[] = []\n for (const edge of ctx.edges) {\n if (edge.target !== node.id) continue\n const src = ctx.nodes.find((n) => n.id === edge.source)\n if (!src) continue\n const hint = resolveParameterHint(src, undefined, mode) // no ctx — cycle-safe\n if (!hint) continue\n if (edge.targetHandle === \"startState\") startHints.push(hint)\n else if (edge.targetHandle === \"endState\") endHints.push(hint)\n }\n return withCustomText(data, composeTransitionHintFromConnections(transitionId, startHints, endHints, timing, mode, hintOptions))\n }\n\n if (node.type === \"character-fx\") {\n const raw = data.characterFx\n const effectId: string | string[] | undefined =\n Array.isArray(raw)\n ? raw.filter((s): s is string => typeof s === \"string\" && s.length > 0)\n : (asStr(raw) || undefined)\n const timing: CharacterFxTiming = {\n position: asStr(data.position) as CharacterFxPosition | undefined,\n duration: asStr(data.duration) as CharacterFxDuration | undefined,\n intensity: asStr(data.intensity) as CharacterFxIntensity | undefined,\n }\n if (!ctx) {\n return withCustomText(data, composeCharacterFxHintFromConnections(effectId, [], timing, mode))\n }\n const targetNames: string[] = []\n for (const edge of ctx.edges) {\n if (edge.target !== node.id) continue\n if (edge.targetHandle !== \"target\") continue\n const src = ctx.nodes.find((n) => n.id === edge.source)\n if (!src) continue\n const name = extractCharacterRefName(src)\n if (name) targetNames.push(name)\n }\n return withCustomText(data, composeCharacterFxHintFromConnections(effectId, targetNames, timing, mode))\n }\n\n if (node.type === \"character-motion\") {\n const raw = data.characterMotion\n const motionId: string | string[] | undefined =\n Array.isArray(raw)\n ? raw.filter((s): s is string => typeof s === \"string\" && s.length > 0)\n : (asStr(raw) || undefined)\n const timing: CharacterMotionTiming = {\n position: asStr(data.position) as CharacterMotionPosition | undefined,\n pace: asStr(data.pace) as CharacterMotionPace | undefined,\n }\n if (!ctx) {\n return withCustomText(data, composeCharacterMotionHintFromConnections(motionId, [], [], timing, mode))\n }\n const { targetNames, partnerNames, subjectMinor } = getCharacterMotionBindings(node, ctx)\n return withCustomText(\n data,\n composeCharacterMotionHintFromConnections(motionId, targetNames, partnerNames, timing, mode, { subjectMinor }),\n )\n }\n\n const base = resolveBaseHint(node.type, data, mode)\n if (base) return base\n // Pack-extend fallback: a single-dim pack entry the per-catalog getter (which\n // reads the frozen base array) can't resolve. Resolve it against the\n // registered (pack-composed) catalog's options. Composition already resolved\n // `PickerOption.term`; `resolveTerm` is idempotent over a resolved option and\n // is called anyway so a pack option that reached this array by some other\n // route still injects SOMETHING in compact mode rather than `undefined`.\n const cat = getPickerCatalog(node.type)\n if (cat?.kind === \"single\" && cat.valueField) {\n const id = typeof data[cat.valueField] === \"string\" ? (data[cat.valueField] as string) : \"\"\n const opt = cat.options?.find((o) => o.id === id)\n if (opt) return byMode(mode, opt.promptHint, resolveTerm(opt))\n }\n return base\n}\n\n/**\n * Base (upstream) hint dispatch by node type — the per-catalog getters read the\n * frozen base arrays. Pack-added single-dim ids are resolved by the caller\n * against the registered (pack-composed) catalog.\n *\n * `mode` selects the base fragment only: the compact `get<Name>Term` getter /\n * `build<Name>Terms` builder instead of the verbose one. The `withCustomText`\n * wrapper, the builders' own pre/post composition, and the free-text node\n * types (tone / style-guide / text-prompt — user prose, not catalog copy) are\n * identical in both modes.\n */\nfunction resolveBaseHint(\n type: string,\n data: Record<string, unknown>,\n mode: PickerHintMode = \"full\",\n): string {\n switch (type) {\n case \"framing\":\n return withCustomText(data, buildFramingHints(data, false, mode).join(\", \"))\n case \"lighting\":\n return withCustomText(data, buildLightingHints(data, mode).join(\", \"))\n case \"lens\":\n return withCustomText(data, byMode(mode, getLensPromptHint, getLensTerm)(asStr(data.lens)))\n case \"camera-format\":\n return withCustomText(data, byMode(mode, getCameraFormatPromptHint, getCameraFormatTerm)(asStr(data.cameraFormat)))\n case \"color-look\":\n return withCustomText(data, byMode(mode, getColorLookPromptHint, getColorLookTerm)(asStr(data.colorLook)))\n\n // build*Hints in music-* / voice-* / mood / person / etc. compose\n // preText/postText internally — bypass the wrapper to avoid double-\n // composition.\n case \"music-genre\":\n return buildMusicGenreHints((data ?? {}) as Parameters<typeof buildMusicGenreHints>[0], mode)\n case \"music-mood\":\n return buildMusicMoodHints((data ?? {}) as Parameters<typeof buildMusicMoodHints>[0], mode)\n case \"instrumentation\":\n return buildInstrumentationHints((data ?? {}) as Parameters<typeof buildInstrumentationHints>[0], mode)\n case \"voice-character\":\n return buildVoiceCharacterHints((data ?? {}) as Parameters<typeof buildVoiceCharacterHints>[0], mode)\n case \"voice-delivery\":\n return buildVoiceDeliveryHints((data ?? {}) as Parameters<typeof buildVoiceDeliveryHints>[0], mode)\n case \"person\":\n return buildPersonHints(data, mode).join(\", \")\n case \"mood\":\n return buildMoodHints(data, mode).join(\", \")\n case \"pose\":\n return buildPoseHints(data, mode).join(\", \")\n case \"styling\":\n return buildStylingHints(data, mode).join(\", \")\n\n case \"atmosphere\":\n return withCustomText(data, buildAtmosphereHints(data.atmosphere, mode).join(\", \"))\n case \"action-fx\":\n return withCustomText(data, buildActionFxHints(data.actionFx, mode).join(\", \"))\n case \"style\":\n return withCustomText(data, byMode(mode, getStylePromptHint, getStyleTerm)(asStr(data.style)))\n case \"setting\":\n return withCustomText(data, byMode(mode, getSettingPromptHint, getSettingTerm)(asStr(data.setting)))\n case \"loop-subject\":\n return withCustomText(data, byMode(mode, getLoopSubjectPromptHint, getLoopSubjectTerm)(asStr(data.loopSubject)))\n case \"material\":\n return withCustomText(data, buildMaterialHints(data.material, mode))\n // The four object-entity catalogs are owned by @nodaro/shared and overlaid\n // in shared-catalog-overlay.ts — the ONE module every prompt-text read of\n // them goes through (the subject fold uses it too). Each returns \"\" on a\n // miss, so the entry lookup is the module's job, not this switch's.\n case \"animal\":\n return withCustomText(data, byMode(mode, curatedAnimalPromptHint, curatedAnimalTerm)(asStr(data.animal)))\n case \"vehicle\": {\n const t = curatedVehicleText(asStr(data.vehicle))\n return withCustomText(data, byMode(mode, t.hint, t.term))\n }\n case \"weapon\": {\n const t = curatedWeaponText(asStr(data.weapon))\n return withCustomText(data, byMode(mode, t.hint, t.term))\n }\n case \"furniture\": {\n const t = curatedFurnitureText(asStr(data.furniture))\n return withCustomText(data, byMode(mode, t.hint, t.term))\n }\n case \"photo-genre\":\n return withCustomText(data, byMode(mode, getPhotoGenrePromptHint, getPhotoGenreTerm)(asStr(data.photoGenre)))\n case \"backdrop\":\n return withCustomText(data, byMode(mode, getBackdropPromptHint, getBackdropTerm)(asStr(data.backdrop)))\n case \"held-prop\":\n return withCustomText(data, buildHeldPropHints(data.heldProp, mode).join(\", \"))\n case \"photographer\":\n return withCustomText(data, buildPhotographerHints(data.photographer, mode))\n case \"aesthetic\":\n return withCustomText(data, buildAestheticHints(data.aesthetic, mode))\n case \"era\":\n return withCustomText(data, byMode(mode, getEraPromptHint, getEraTerm)(asStr(data.era)))\n case \"temporal\":\n return withCustomText(data, buildTemporalHints(data, mode).join(\", \"))\n case \"exposure-settings\":\n return withCustomText(data, buildExposureHints(data, mode).join(\", \"))\n case \"render-quality\":\n return withCustomText(data, byMode(mode, getRenderQualityPromptHint, getRenderQualityTerm)(asStr(data.renderQuality)))\n case \"composition-effects\":\n return withCustomText(data, byMode(mode, getCompositionEffectPromptHint, getCompositionEffectTerm)(asStr(data.compositionEffect)))\n case \"post-process-effects\":\n return withCustomText(data, buildPostProcessHints(data.postProcess, mode).join(\", \"))\n // Motion intensity: a Generation Settings node that a video node's\n // Settings input takes as a prompt fragment (video only).\n case \"motion\": {\n const hint = MOTION_INTENSITY_HINTS[asStr(data.motion)]\n return hint ? byMode(mode, hint.full, hint.compact) : \"\"\n }\n\n // Free text authored by the user, not catalog copy — there is no shorter\n // professional form to swap in, so these are identical in both modes.\n case \"tone\":\n return asStr(data.tone).trim()\n case \"style-guide\":\n // The node's whole purpose is injecting its style text into consumer\n // prompts; without this case, {Style Guide} refs stayed as literal\n // brace text and direct wires injected nothing (only fieldMappings\n // worked, via getParameterValue).\n return asStr(data.text).trim()\n case \"text-prompt\":\n return asStr(data.text).trim()\n default:\n return \"\"\n }\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/color-names.ts","../src/user-direction-refs.ts","../src/direction-registry.ts","../src/shared-catalog-overlay.ts"],"names":["HEX_RE"],"mappings":";;;;;AAaA,IAAM,KAAA,GAA6D;AAAA;AAAA,EAEjE,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,YAAY,SAAS,CAAA;AAAA,EACtB,CAAC,aAAa,SAAS,CAAA;AAAA,EACvB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,QAAQ,SAAS,CAAA;AAAA,EAClB,CAAC,aAAa,SAAS,CAAA;AAAA,EACvB,CAAC,UAAU,SAAS,CAAA;AAAA,EACpB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,aAAa,SAAS,CAAA;AAAA,EACvB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,YAAY,SAAS,CAAA;AAAA,EACtB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,aAAa,SAAS,CAAA;AAAA,EACvB,CAAC,SAAS,SAAS,CAAA;AAAA;AAAA,EAEnB,CAAC,QAAQ,SAAS,CAAA;AAAA,EAClB,CAAC,OAAO,SAAS,CAAA;AAAA,EACjB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,WAAW,SAAS,CAAA;AAAA,EACrB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,aAAa,SAAS,CAAA;AAAA,EACvB,CAAC,UAAU,SAAS,CAAA;AAAA,EACpB,CAAC,YAAY,SAAS,CAAA;AAAA,EACtB,CAAC,UAAU,SAAS,CAAA;AAAA,EACpB,CAAC,YAAY,SAAS,CAAA;AAAA,EACtB,CAAC,YAAY,SAAS,CAAA;AAAA,EACtB,CAAC,QAAQ,SAAS,CAAA;AAAA,EAClB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,UAAU,SAAS,CAAA;AAAA,EACpB,CAAC,UAAU,SAAS,CAAA;AAAA,EACpB,CAAC,SAAS,SAAS,CAAA;AAAA;AAAA,EAEnB,CAAC,gBAAgB,SAAS,CAAA;AAAA,EAC1B,CAAC,UAAU,SAAS,CAAA;AAAA,EACpB,CAAC,aAAa,SAAS,CAAA;AAAA,EACvB,CAAC,WAAW,SAAS,CAAA;AAAA,EACrB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,UAAU,SAAS,CAAA;AAAA;AAAA,EAEpB,CAAC,OAAO,SAAS,CAAA;AAAA,EACjB,CAAC,WAAW,SAAS,CAAA;AAAA,EACrB,CAAC,WAAW,SAAS,CAAA;AAAA,EACrB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,aAAa,SAAS,CAAA;AAAA,EACvB,CAAC,YAAY,SAAS,CAAA;AAAA,EACtB,CAAC,UAAU,SAAS,CAAA;AAAA,EACpB,CAAC,YAAY,SAAS,CAAA;AAAA,EACtB,CAAC,WAAW,SAAS,CAAA;AAAA;AAAA,EAErB,CAAC,aAAa,SAAS,CAAA;AAAA,EACvB,CAAC,QAAQ,SAAS,CAAA;AAAA,EAClB,CAAC,YAAY,SAAS,CAAA;AAAA,EACtB,CAAC,QAAQ,SAAS,CAAA;AAAA,EAClB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,SAAS,SAAS,CAAA;AAAA;AAAA,EAEnB,CAAC,WAAW,SAAS,CAAA;AAAA,EACrB,CAAC,UAAU,SAAS,CAAA;AAAA,EACpB,CAAC,QAAQ,SAAS,CAAA;AAAA,EAClB,CAAC,YAAY,SAAS,CAAA;AAAA,EACtB,CAAC,gBAAgB,SAAS,CAAA;AAAA,EAC1B,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,YAAY,SAAS,CAAA;AAAA,EACtB,CAAC,iBAAiB,SAAS,CAAA;AAAA,EAC3B,CAAC,YAAY,SAAS,CAAA;AAAA,EACtB,CAAC,UAAU,SAAS,CAAA;AAAA,EACpB,CAAC,UAAU,SAAS,CAAA;AAAA,EACpB,CAAC,UAAU,SAAS,CAAA;AAAA;AAAA,EAEpB,CAAC,aAAa,SAAS,CAAA;AAAA,EACvB,CAAC,iBAAiB,SAAS,CAAA;AAAA,EAC3B,CAAC,iBAAiB,SAAS,CAAA;AAAA,EAC3B,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,eAAe,SAAS,CAAA;AAAA,EACzB,CAAC,QAAQ,SAAS,CAAA;AAAA,EAClB,CAAC,mBAAmB,SAAS,CAAA;AAAA,EAC7B,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,YAAY,SAAS,CAAA;AAAA,EACtB,CAAC,aAAa,SAAS,CAAA;AAAA,EACvB,CAAC,eAAe,SAAS,CAAA;AAAA,EACzB,CAAC,YAAY,SAAS,CAAA;AAAA,EACtB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,YAAY,SAAS,CAAA;AAAA,EACtB,CAAC,eAAe,SAAS,CAAA;AAAA;AAAA,EAEzB,CAAC,QAAQ,SAAS,CAAA;AAAA,EAClB,CAAC,aAAa,SAAS,CAAA;AAAA,EACvB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,QAAQ,SAAS,CAAA;AAAA,EAClB,CAAC,aAAa,SAAS,CAAA;AAAA,EACvB,CAAC,mBAAmB,SAAS,CAAA;AAAA;AAAA,EAE7B,CAAC,aAAa,SAAS,CAAA;AAAA,EACvB,CAAC,iBAAiB,SAAS,CAAA;AAAA,EAC3B,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,iBAAiB,SAAS,CAAA;AAAA,EAC3B,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,eAAe,SAAS,CAAA;AAAA,EACzB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,gBAAgB,SAAS,CAAA;AAAA,EAC1B,CAAC,gBAAgB,SAAS,CAAA;AAAA,EAC1B,CAAC,gBAAgB,SAAS,CAAA;AAAA,EAC1B,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,eAAe,SAAS,CAAA;AAAA,EACzB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,cAAc,SAAS,CAAA;AAAA,EACxB,CAAC,aAAa,SAAS,CAAA;AAAA;AAAA,EAEvB,CAAC,UAAU,SAAS,CAAA;AAAA,EACpB,CAAC,gBAAgB,SAAS,CAAA;AAAA,EAC1B,CAAC,eAAe,SAAS,CAAA;AAAA,EACzB,CAAC,iBAAiB,SAAS,CAAA;AAAA,EAC3B,CAAC,kBAAkB,SAAS,CAAA;AAAA,EAC5B,CAAC,QAAQ,SAAS,CAAA;AAAA,EAClB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,SAAS,SAAS,CAAA;AAAA,EACnB,CAAC,WAAW,SAAS;AACvB,CAAA;AAEA,IAAM,MAAA,GAAS,iBAAA;AAIf,SAAS,QAAQ,CAAA,EAAmB;AAClC,EAAA,MAAM,IAAI,CAAA,GAAI,GAAA;AACd,EAAA,OAAO,KAAK,OAAA,GAAU,CAAA,GAAI,KAAA,GAAA,CAAA,CAAU,CAAA,GAAI,SAAS,KAAA,KAAU,GAAA;AAC7D;AAEA,SAAS,SAAS,CAAA,EAAmB;AACnC,EAAA,OAAO,CAAA,GAAI,GAAA,GAAM,KAAA,GAAQ,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,GAAA,CAAK,KAAA,GAAQ,EAAA,GAAK,CAAA,GAAI,EAAA,IAAM,GAAA;AAClE;AAGA,SAAS,MAAM,GAAA,EAAkB;AAC/B,EAAA,MAAM,CAAA,GAAI,QAAQ,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA,EAAG,CAAC,CAAA,EAAG,EAAE,CAAC,CAAA;AAC/C,EAAA,MAAM,CAAA,GAAI,QAAQ,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA,EAAG,CAAC,CAAA,EAAG,EAAE,CAAC,CAAA;AAC/C,EAAA,MAAM,CAAA,GAAI,QAAQ,QAAA,CAAS,GAAA,CAAI,MAAM,CAAA,EAAG,CAAC,CAAA,EAAG,EAAE,CAAC,CAAA;AAC/C,EAAA,MAAM,CAAA,GAAI,UAAU,SAAA,GAAY,CAAA,GAAI,YAAY,CAAA,GAAI,SAAA,GAAY,KAAK,OAAO,CAAA;AAC5E,EAAA,MAAM,IAAI,QAAA,CAAS,SAAA,GAAY,IAAI,SAAA,GAAY,CAAA,GAAI,WAAW,CAAC,CAAA;AAC/D,EAAA,MAAM,CAAA,GAAI,UAAU,SAAA,GAAY,CAAA,GAAI,WAAW,CAAA,GAAI,SAAA,GAAY,KAAK,OAAO,CAAA;AAC3E,EAAA,OAAO,CAAC,MAAM,CAAA,GAAI,EAAA,EAAI,OAAO,CAAA,GAAI,CAAA,CAAA,EAAI,GAAA,IAAO,CAAA,GAAI,CAAA,CAAE,CAAA;AACpD;AAEA,IAAI,QAAA,GAAyD,IAAA;AAMtD,SAAS,iBAAiB,GAAA,EAAqB;AACpD,EAAA,IAAI,CAAC,MAAA,CAAO,IAAA,CAAK,GAAG,GAAG,OAAO,EAAA;AAC9B,EAAA,QAAA,KAAa,KAAA,CAAM,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,KAAK,CAAA,KAAM,CAAC,IAAA,EAAM,KAAA,CAAM,KAAK,CAAC,CAAU,CAAA;AACvE,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,GAAI,MAAM,GAAG,CAAA;AAC3B,EAAA,IAAI,IAAA,GAAO,EAAA;AACX,EAAA,IAAI,YAAA,GAAe,QAAA;AACnB,EAAA,KAAA,MAAW,CAAC,MAAM,CAAC,EAAA,EAAI,IAAI,EAAE,CAAC,KAAK,QAAA,EAAU;AAC3C,IAAA,MAAM,CAAA,GAAA,CAAK,IAAI,EAAA,KAAO,CAAA,GAAA,CAAK,IAAI,EAAA,KAAO,CAAA,GAAA,CAAK,IAAI,EAAA,KAAO,CAAA;AACtD,IAAA,IAAI,IAAI,YAAA,EAAc;AACpB,MAAA,YAAA,GAAe,CAAA;AACf,MAAA,IAAA,GAAO,IAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;;;ACvKO,IAAM,wBAAA,GAAgE,CAAC,SAAA,EAAW,WAAW;AASpG,IAAM,OAAA,GAAU,iEAAA;AAST,SAAS,sBAAsB,KAAA,EAAyC;AAC7E,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,IAAA;AACtC,EAAA,KAAA,MAAW,QAAQ,wBAAA,EAA0B;AAC3C,IAAA,MAAM,MAAA,GAAS,GAAG,IAAI,CAAA,CAAA,CAAA;AACtB,IAAA,IAAI,KAAA,CAAM,UAAA,CAAW,MAAM,CAAA,EAAG;AAC5B,MAAA,MAAM,EAAA,GAAK,KAAA,CAAM,KAAA,CAAM,MAAA,CAAO,MAAM,CAAA;AACpC,MAAA,OAAO,EAAE,IAAA,EAAM,EAAA,EAAI,YAAY,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAA,EAAE;AAAA,IAClD;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,qBAAA,CAAsB,MAA4B,EAAA,EAAoB;AACpF,EAAA,OAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,EAAE,CAAA,CAAA;AACtB;AAKA,SAAS,QAAQ,IAAA,EAAyC;AACxD,EAAA,OAAA,CAAQ,QAAQ,EAAA,EAAI,OAAA,CAAQ,MAAA,EAAQ,GAAG,EAAE,IAAA,EAAK;AAChD;AAEA,IAAMA,OAAAA,GAAS,iBAAA;AAQR,SAAS,oBAAoB,MAAA,EAAuC;AACzE,EAAA,MAAM,KAAA,GAAQ,OACX,MAAA,CAAO,CAAC,MAAMA,OAAAA,CAAO,IAAA,CAAK,CAAC,CAAC,CAAA,CAC5B,IAAI,CAAC,CAAA,KAAM,GAAG,gBAAA,CAAiB,CAAC,CAAC,CAAA,CAAA,EAAI,CAAA,CAAE,WAAA,EAAa,CAAA,CAAE,CAAA;AACzD,EAAA,OAAO,KAAA,CAAM,SAAS,CAAA,GAAI,CAAA,eAAA,EAAkB,MAAM,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,GAAK,EAAA;AACnE;AAOO,SAAS,sBAAsB,WAAA,EAAgD;AACpF,EAAA,OAAO,QAAQ,WAAW,CAAA;AAC5B;AAeO,SAAS,yBAAA,CAA0B,OAAe,OAAA,EAA0B;AACjF,EAAA,MAAM,GAAA,GAAM,QAAQ,OAAO,CAAA;AAC3B,EAAA,MAAM,IAAA,GAAO,GAAA,GAAM,CAAA,EAAA,EAAK,GAAG,CAAA,CAAA,CAAA,GAAM,EAAA;AACjC,EAAA,OAAO,UAAU,CAAA,GACb,CAAA,iEAAA,EAAoE,IAAI,CAAA,2BAAA,CAAA,GACxE,0BAA0B,IAAI,CAAA,CAAA;AACpC;;;AC+BA,IAAM,QACJ,CAAC,IAAA,EAA8B,OAAA,KAC/B,CAAC,KAAwB,IAAA,KAAmC;AAC1D,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,KAAA,MAAW,MAAM,GAAA,EAAK;AACpB,IAAA,MAAM,OAAO,IAAA,KAAS,SAAA,GAAY,QAAQ,EAAE,CAAA,GAAI,KAAK,EAAE,CAAA;AACvD,IAAA,IAAI,IAAA,CAAK,MAAA,GAAS,CAAA,EAAG,GAAA,CAAI,KAAK,IAAI,CAAA;AAAA,EACpC;AACA,EAAA,OAAO,GAAA;AACT,CAAA;AAGF,IAAM,cAAA,GACJ,CAAC,KAAA,KACD,CAAC,GAAA,EAAwB,SACvB,KAAA,CAAM,GAAA,CAAI,MAAA,KAAW,CAAA,GAAI,GAAA,CAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAA,EAAG,IAAI,CAAA,CAAE,OAAO,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,GAAS,CAAC,CAAA;AAGhF,IAAM,gBAAA,GACJ,CAAC,KAAA,KACD,CAAC,KAAwB,IAAA,KAAmC;AAC1D,EAAA,MAAM,CAAA,GAAI,KAAA,CAAM,GAAA,CAAI,MAAA,KAAW,CAAA,GAAI,GAAA,CAAI,CAAC,CAAA,GAAI,CAAC,GAAG,GAAG,CAAA,EAAG,IAAI,CAAA;AAC1D,EAAA,OAAO,EAAE,MAAA,GAAS,CAAA,GAAI,CAAC,CAAC,IAAI,EAAC;AAC/B,CAAA;AAGF,IAAM,UAAU,CAAC,GAAA,EAAwB,SACvC,cAAA,CAAe,EAAE,MAAM,GAAA,CAAI,MAAA,KAAW,IAAI,GAAA,CAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAA,EAAE,EAAG,IAAI,CAAA,CAAE,MAAA;AAAA,EACnE,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,GAAS;AACpB,CAAA;AAEF,IAAM,OAAA,GAAU,KAAA,CAAM,oBAAA,EAAsB,cAAc,CAAA;AAC1D,IAAM,QAAA,GAAW,KAAA,CAAM,qBAAA,EAAuB,eAAe,CAAA;AAC7D,IAAM,QAAA,GAAW,KAAA,CAAM,qBAAA,EAAuB,eAAe,CAAA;AAC7D,IAAM,QAAA,GAAW,KAAA,CAAM,qBAAA,EAAuB,eAAe,CAAA;AAsCtD,IAAM,gBAAA,GAAmB;AAAA,EAC9B,EAAE,GAAA,EAAK,cAAA,EAAgB,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ,QAAA,EAAU,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,yBAAA,EAA2B,mBAAmB,CAAA,EAAE;AAAA;AAAA,EAGtI,EAAE,GAAA,EAAK,UAAA,EAAY,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,OAAA,EAAQ;AAAA,EACjF,EAAE,GAAA,EAAK,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,OAAA,EAAQ;AAAA,EAC9E,EAAE,GAAA,EAAK,UAAA,EAAY,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,OAAA,EAAQ;AAAA,EACjF,EAAE,GAAA,EAAK,aAAA,EAAe,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,OAAA,EAAQ;AAAA,EACpF,EAAE,GAAA,EAAK,SAAA,EAAW,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,OAAA,EAAQ;AAAA,EAChF,EAAE,GAAA,EAAK,MAAA,EAAQ,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,iBAAA,EAAmB,WAAW,CAAA,EAAE;AAAA,EAC3G,EAAE,GAAA,EAAK,mBAAA,EAAqB,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,8BAAA,EAAgC,wBAAwB,CAAA,EAAE;AAAA;AAAA,EAGlJ,EAAE,GAAA,EAAK,cAAA,EAAgB,OAAA,EAAS,QAAQ,MAAA,EAAQ,MAAA,EAAQ,UAAA,EAAY,MAAA,EAAQ,UAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,yBAAA,EAA2B,mBAAmB,CAAA,EAAE;AAAA,EACvJ,EAAE,GAAA,EAAK,MAAA,EAAQ,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,iBAAA,EAAmB,WAAW,CAAA,EAAE;AAAA;AAAA,EAG3G,EAAE,GAAA,EAAK,UAAA,EAAY,OAAA,EAAS,OAAA,EAAS,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,QAAA,EAAS;AAAA,EACnF,EAAE,GAAA,EAAK,cAAA,EAAgB,OAAA,EAAS,OAAA,EAAS,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,QAAA,EAAS;AAAA,EACvF,EAAE,GAAA,EAAK,UAAA,EAAY,OAAA,EAAS,OAAA,EAAS,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,QAAA,EAAS;AAAA;AAAA,EAGnF,EAAE,GAAA,EAAK,WAAA,EAAa,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,QAAA,EAAS;AAAA,EACnF,EAAE,GAAA,EAAK,eAAA,EAAiB,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,QAAA,EAAS;AAAA,EACvF,EAAE,GAAA,EAAK,mBAAA,EAAqB,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,QAAA,EAAS;AAAA,EAC3F,EAAE,GAAA,EAAK,eAAA,EAAiB,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,QAAA,EAAS;AAAA,EACvF,EAAE,GAAA,EAAK,kBAAA,EAAoB,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,QAAA,EAAS;AAAA,EAC1F,EAAE,GAAA,EAAK,WAAA,EAAa,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,UAAA,EAAY,MAAA,EAAQ,QAAA,EAAU,GAAG,OAAA,EAAS,SAAA,EAAW,QAAQ,KAAA,CAAM,sBAAA,EAAwB,gBAAgB,CAAA,EAAE;AAAA,EAClK,EAAE,GAAA,EAAK,YAAA,EAAc,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,cAAA,CAAe,oBAAoB,CAAA,EAAE;AAAA,EAChH,EAAE,GAAA,EAAK,aAAA,EAAe,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,cAAA,CAAe,qBAAqB,CAAA,EAAE;AAAA;AAAA,EAGnH,EAAE,GAAA,EAAK,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,UAAA,EAAY,MAAA,EAAQ,QAAA,EAAU,GAAG,OAAA,EAAS,WAAA,EAAa,QAAQ,KAAA,CAAM,kBAAA,EAAoB,YAAY,CAAA,EAAE;AAAA,EACxJ,EAAE,GAAA,EAAK,MAAA,EAAQ,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,OAAA,EAAQ;AAAA,EAC7E,EAAE,GAAA,EAAK,WAAA,EAAa,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,gBAAA,CAAiB,mBAAmB,CAAA,EAAE;AAAA,EAChH,EAAE,GAAA,EAAK,YAAA,EAAc,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,uBAAA,EAAyB,iBAAiB,CAAA,EAAE;AAAA,EAC9H,EAAE,GAAA,EAAK,cAAA,EAAgB,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,gBAAA,CAAiB,sBAAsB,CAAA,EAAE;AAAA,EACvH,EAAE,GAAA,EAAK,eAAA,EAAiB,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,0BAAA,EAA4B,oBAAoB,CAAA,EAAE;AAAA;AAAA,EAGvI,EAAE,GAAA,EAAK,SAAA,EAAW,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,oBAAA,EAAsB,cAAc,CAAA,EAAE;AAAA,EACpH,EAAE,GAAA,EAAK,KAAA,EAAO,OAAA,EAAS,QAAQ,MAAA,EAAQ,MAAA,EAAQ,UAAA,EAAY,MAAA,EAAQ,UAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,gBAAA,EAAkB,UAAU,CAAA,EAAE;AAAA,EAC5H,EAAE,GAAA,EAAK,UAAA,EAAY,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,qBAAA,EAAuB,eAAe,CAAA,EAAE;AAAA;AAAA,EAGvH,EAAE,GAAA,EAAK,UAAA,EAAY,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ,QAAA,EAAU,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,cAAA,CAAe,kBAAkB,CAAA,EAAE;AAAA,EAC/G,EAAE,GAAA,EAAK,eAAA,EAAiB,OAAA,EAAS,OAAA,EAAS,QAAQ,QAAA,EAAU,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,QAAA,EAAS;AAAA,EAC1F,EAAE,GAAA,EAAK,gBAAA,EAAkB,OAAA,EAAS,OAAA,EAAS,QAAQ,QAAA,EAAU,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,QAAA,EAAS;AAAA,EAC3F,EAAE,GAAA,EAAK,mBAAA,EAAqB,OAAA,EAAS,OAAA,EAAS,QAAQ,QAAA,EAAU,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,QAAA,EAAS;AAAA,EAC9F,EAAE,GAAA,EAAK,iBAAA,EAAmB,OAAA,EAAS,OAAA,EAAS,QAAQ,QAAA,EAAU,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,QAAA,EAAS;AAAA,EAC5F,EAAE,GAAA,EAAK,YAAA,EAAc,OAAA,EAAS,OAAA,EAAS,QAAQ,QAAA,EAAU,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,qBAAA,EAAsB;AAAA,EACpG,EAAE,GAAA,EAAK,aAAA,EAAe,OAAA,EAAS,OAAA,EAAS,MAAA,EAAQ,QAAA,EAAU,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,wBAAA,EAA0B,kBAAkB,CAAA,EAAE;AAAA;AAAA;AAAA,EAInI,EAAE,GAAA,EAAK,WAAA,EAAa,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,OAAA,EAAQ;AAAA,EAClF,EAAE,GAAA,EAAK,gBAAA,EAAkB,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,OAAA,EAAQ;AAAA,EACvF,EAAE,GAAA,EAAK,YAAA,EAAc,OAAA,EAAS,MAAA,EAAQ,QAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,QAAA,EAAS;AAAA,EACpF,EAAE,GAAA,EAAK,QAAA,EAAU,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,iBAAA,EAAmB,WAAW,CAAA,EAAE;AAAA,EAC7G,EAAE,GAAA,EAAK,gBAAA,EAAkB,OAAA,EAAS,QAAQ,MAAA,EAAQ,MAAA,EAAQ,UAAA,EAAY,MAAA,EAAQ,UAAU,CAAA,EAAG,MAAA,EAAQ,KAAA,CAAM,yBAAA,EAA2B,mBAAmB,CAAA;AACzJ;AAQA,IAAM,eAAA,GAAqD,gBAAA;AAsBpD,IAAM,iBAA8C,gBAAA,CAAiB,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,GAAG;AAQrF,IAAM,kBAA+C,eAAA,CAAgB,MAAA;AAAA,EAC1E,CAAC,CAAA,KAAM,CAAA,CAAE,UAAA,KAAe;AAC1B,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,GAAmB;AAM3B,SAAS,uBAAuB,IAAA,EAA0C;AAC/E,EAAA,MAAM,MAAM,eAAA,CAAgB,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,YAAY,IAAI,CAAA;AAC1D,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,KAAA,CAAM,CAAA,yBAAA,EAA4B,IAAI,CAAA,UAAA,CAAY,CAAA;AACtE,EAAA,OAAO,GAAA,CAAI,GAAA;AACb;AAGO,SAAS,0BAA0B,GAAA,EAA+C;AACvF,EAAA,OAAO,gBAAgB,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,GAAA,KAAQ,GAAG,CAAA,EAAG,OAAA;AACrD;AAqBO,IAAM,uBAAA,GAA6C;AAGnD,IAAM,uBAAA,GAA6C,EAAE,IAAA,EAAM,MAAA,EAAQ,QAAQ,SAAA;AAE3E,SAAS,aAAA,CAAc,MAAyB,MAAA,EAAyC;AAC9F,EAAA,OAAO,OAAO,SAAS,QAAA,GAAW,IAAA,GAAO,WAAW,QAAA,GAAW,IAAA,CAAK,SAAS,IAAA,CAAK,IAAA;AACpF;AAOO,IAAM,uBAAA,GAA0B;AAYhC,IAAM,sBAAA,GAAyB;AAYtC,SAAS,qBAAA,CAAsB,OAAgB,QAAA,EAA4B;AACzE,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,IAAI,KAAA,EAAO,GAAA,CAAI,IAAA,CAAK,KAAK,CAAA;AAAA,EAC3B,CAAA,MAAA,IAAW,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC/B,IAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,MAAA,IAAI,GAAA,CAAI,UAAU,QAAA,EAAU;AAC5B,MAAA,IAAI,OAAO,CAAA,KAAM,QAAA,IAAY,CAAA,IAAK,CAAC,GAAA,CAAI,QAAA,CAAS,CAAC,CAAA,EAAG,GAAA,CAAI,IAAA,CAAK,CAAC,CAAA;AAAA,IAChE;AAAA,EACF;AACA,EAAA,OAAO,GAAA,CAAI,KAAA,CAAM,CAAA,EAAG,QAAQ,CAAA;AAC9B;AASA,SAAS,SAAA,CACP,IAAA,EACA,GAAA,EACA,IAAA,EACA,IAAA,EACU;AACV,EAAA,IAAI,IAAA,CAAK,OAAA,KAAY,MAAA,IAAa,CAAC,GAAA,CAAI,IAAA,CAAK,CAAC,EAAA,KAAO,qBAAA,CAAsB,EAAE,CAAA,KAAM,IAAI,CAAA,EAAG;AACvF,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,GAAA,EAAK,IAAI,CAAA;AAAA,EAC9B;AACA,EAAA,OAAO,GAAA,CAAI,OAAA,CAAQ,CAAC,EAAA,KAAO;AACzB,IAAA,MAAM,GAAA,GAAM,sBAAsB,EAAE,CAAA;AACpC,IAAA,IAAI,GAAA,KAAQ,MAAM,OAAO,IAAA,CAAK,OAAO,CAAC,EAAE,GAAG,IAAI,CAAA;AAC/C,IAAA,MAAM,MAAA,GAAS,IAAI,IAAA,KAAS,IAAA,CAAK,UAAU,IAAA,EAAM,GAAA,CAAI,EAAE,CAAA,GAAI,MAAA;AAC3D,IAAA,OAAO,MAAA,GAAS,CAAC,MAAM,CAAA,GAAI,EAAC;AAAA,EAC9B,CAAC,CAAA;AACH;AAGO,SAAS,0BACd,OAAA,EACmC;AACnC,EAAA,OAAO,eAAA,CAAgB,OAAO,CAAC,CAAA,KAAM,EAAE,OAAA,KAAY,MAAA,IAAU,CAAA,CAAE,OAAA,KAAY,OAAO,CAAA;AACpF;AAgBO,SAAS,0BAAA,CACd,WACA,IAAA,EACuB;AACvB,EAAA,IAAI,CAAC,SAAA,EAAW,OAAO,EAAC;AACxB,EAAA,MAAM,IAAA,GAAO,KAAK,IAAA,IAAQ,MAAA;AAC1B,EAAA,MAAM,MAA6B,EAAC;AACpC,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,KAAA,MAAW,QAAQ,eAAA,EAAiB;AAClC,IAAA,IAAI,KAAK,OAAA,KAAY,MAAA,IAAU,IAAA,CAAK,OAAA,KAAY,KAAK,OAAA,EAAS;AAC9D,IAAA,MAAM,GAAA,GAAM,qBAAA;AAAA,MACT,SAAA,CAAsC,KAAK,GAAG,CAAA;AAAA,MAC/C,IAAA,CAAK;AAAA,KACP;AACA,IAAA,IAAI,GAAA,CAAI,WAAW,CAAA,EAAG;AACtB,IAAA,KAAA,MAAW,IAAA,IAAQ,SAAA,CAAU,IAAA,EAAM,GAAA,EAAK,aAAA,CAAc,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA,EAAG;AACpF,MAAA,IAAI,KAAK,MAAA,GAAS,CAAA,IAAK,CAAC,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA,EAAG;AACtC,QAAA,IAAA,CAAK,IAAI,IAAI,CAAA;AACb,QAAA,GAAA,CAAI,IAAA,CAAK;AAAA,UACP,KAAK,IAAA,CAAK,GAAA;AAAA,UACV,QAAQ,IAAA,CAAK,MAAA;AAAA,UACb,GAAI,KAAK,UAAA,KAAe,MAAA,GAAY,EAAE,UAAA,EAAY,IAAA,CAAK,UAAA,EAAW,GAAI,EAAC;AAAA,UACvE,IAAA,EAAM;AAAA,SACP,CAAA;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;AAyBO,SAAS,oBAAA,CACd,WACA,IAAA,EACU;AACV,EAAA,OAAO,0BAAA,CAA2B,WAAW,IAAI,CAAA,CAAE,IAAI,CAAC,CAAA,KAAM,EAAE,IAAI,CAAA;AACtE;AC9dO,SAAS,wBAAwB,EAAA,EAAoB;AAC1D,EAAA,IAAI,CAAC,IAAI,OAAO,EAAA;AAChB,EAAA,IAAI,CAAC,WAAA,CAAY,SAAA,EAAW,EAAE,GAAG,OAAO,EAAA;AACxC,EAAA,OAAO,eAAe,SAAA,EAAW,EAAE,CAAA,EAAG,UAAA,IAAc,oBAAoB,EAAE,CAAA;AAC5E;AACO,SAAS,kBAAkB,EAAA,EAAoB;AACpD,EAAA,IAAI,CAAC,IAAI,OAAO,EAAA;AAChB,EAAA,IAAI,CAAC,WAAA,CAAY,SAAA,EAAW,EAAE,GAAG,OAAO,EAAA;AACxC,EAAA,OAAO,eAAe,SAAA,EAAW,EAAE,CAAA,EAAG,IAAA,IAAQ,cAAc,EAAE,CAAA;AAChE;AAIA,SAAS,gBAAA,CACP,SAAA,EACA,EAAA,EACA,KAAA,EACA,WACA,SAAA,EACkD;AAClD,EAAA,IAAI,CAAC,EAAA,IAAM,CAAC,WAAA,CAAY,SAAA,EAAW,EAAE,CAAA,EAAG,OAAO,EAAE,IAAA,EAAM,EAAA,EAAI,IAAA,EAAM,EAAA,EAAG;AACpE,EAAA,MAAM,QAAA,GAAW,cAAA,CAAe,SAAA,EAAW,EAAE,CAAA;AAC7C,EAAA,IAAI,QAAA,SAAiB,EAAE,IAAA,EAAM,SAAS,UAAA,EAAY,IAAA,EAAM,SAAS,IAAA,EAAK;AACtE,EAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAE,IAAA,EAAM,EAAA,EAAI,MAAM,EAAA,EAAG;AACxC,EAAA,OAAO,EAAE,MAAM,SAAA,CAAU,KAAK,GAAG,IAAA,EAAM,SAAA,CAAU,KAAK,CAAA,EAAE;AAC1D;AAqBA,SAAS,iBAAiB,KAAA,EAA2C;AACnE,EAAA,OAAQ,KAAA,CAA4B,IAAA,IAAQ,UAAA,CAAW,KAAA,CAAM,KAAK,CAAA;AACpE;AAEO,SAAS,mBAAmB,EAAA,EAAY;AAC7C,EAAA,OAAO,iBAAiB,UAAA,EAAY,EAAA,EAAI,UAAA,CAAW,EAAE,GAAG,CAAC,CAAA,KAAM,CAAA,YAAA,EAAe,CAAA,CAAE,MAAM,WAAA,EAAa,KAAK,CAAA,CAAE,WAAW,IAAI,gBAAgB,CAAA;AAC3I;AACO,SAAS,kBAAkB,EAAA,EAAY;AAC5C,EAAA,OAAO,iBAAiB,SAAA,EAAW,EAAA,EAAI,SAAA,CAAU,EAAE,GAAG,CAAC,CAAA,KAAM,CAAA,OAAA,EAAU,CAAA,CAAE,MAAM,WAAA,EAAa,KAAK,CAAA,CAAE,WAAW,IAAI,gBAAgB,CAAA;AACpI;AACO,SAAS,qBAAqB,EAAA,EAAY;AAC/C,EAAA,OAAO,iBAAiB,WAAA,EAAa,EAAA,EAAI,YAAA,CAAa,EAAE,GAAG,CAAC,CAAA,KAAM,CAAA,YAAA,EAAe,CAAA,CAAE,MAAM,WAAA,EAAa,KAAK,CAAA,CAAE,WAAW,IAAI,gBAAgB,CAAA;AAC9I","file":"chunk-CPKYIVWP.js","sourcesContent":["/**\n * Plain colour names for a hex value — what a saved colour palette reads as\n * in a prompt (\"deep teal #0F4C5C\"). A model follows a named colour more\n * reliably than a bare hex code, and the hex keeps the exact value.\n *\n * NEAREST NAME, NOT A CLASSIFIER: a fixed table of everyday colour names, each\n * with a representative value, and the one closest to the input in CIE Lab\n * (ΔE 1976 — Euclidean distance in Lab, which tracks perceived difference far\n * better than RGB). Deterministic, dependency-free, and a name is always one a\n * person would say. Ties go to the earlier row.\n */\n\n/** Everyday colour names and a representative sRGB value for each. */\nconst NAMED: ReadonlyArray<readonly [name: string, hex: string]> = [\n // Neutrals\n [\"black\", \"#000000\"],\n [\"charcoal\", \"#36454F\"],\n [\"dark gray\", \"#555555\"],\n [\"slate gray\", \"#708090\"],\n [\"gray\", \"#808080\"],\n [\"warm gray\", \"#9A9088\"],\n [\"silver\", \"#C0C0C0\"],\n [\"light gray\", \"#D3D3D3\"],\n [\"off-white\", \"#F2F0EB\"],\n [\"white\", \"#FFFFFF\"],\n [\"ivory\", \"#FFFFF0\"],\n [\"cream\", \"#FFFDD0\"],\n [\"eggshell\", \"#F0EAD6\"],\n [\"linen\", \"#FAF0E6\"],\n [\"champagne\", \"#F7E7CE\"],\n [\"wheat\", \"#F5DEB3\"],\n // Earth tones and browns\n [\"sand\", \"#C2B280\"],\n [\"tan\", \"#D2B48C\"],\n [\"khaki\", \"#C3B091\"],\n [\"taupe\", \"#8B8589\"],\n [\"camel\", \"#C19A6B\"],\n [\"caramel\", \"#C68E17\"],\n [\"brown\", \"#964B00\"],\n [\"chocolate\", \"#7B3F00\"],\n [\"coffee\", \"#6F4E37\"],\n [\"espresso\", \"#4E312D\"],\n [\"walnut\", \"#773F1A\"],\n [\"chestnut\", \"#954535\"],\n [\"mahogany\", \"#C04000\"],\n [\"rust\", \"#B7410E\"],\n [\"terracotta\", \"#E2725B\"],\n [\"copper\", \"#B87333\"],\n [\"bronze\", \"#CD7F32\"],\n [\"ochre\", \"#CC7722\"],\n // Oranges\n [\"burnt orange\", \"#CC5500\"],\n [\"orange\", \"#FFA500\"],\n [\"tangerine\", \"#F28500\"],\n [\"apricot\", \"#FBCEB1\"],\n [\"peach\", \"#FFCBA4\"],\n [\"coral\", \"#FF7F50\"],\n [\"salmon\", \"#FA8072\"],\n // Reds\n [\"red\", \"#FF0000\"],\n [\"scarlet\", \"#FF2400\"],\n [\"crimson\", \"#DC143C\"],\n [\"cherry red\", \"#D2042D\"],\n [\"brick red\", \"#CB4154\"],\n [\"burgundy\", \"#800020\"],\n [\"maroon\", \"#800000\"],\n [\"wine red\", \"#722F37\"],\n [\"oxblood\", \"#4A0000\"],\n // Pinks\n [\"raspberry\", \"#E30B5C\"],\n [\"rose\", \"#FF007F\"],\n [\"hot pink\", \"#FF69B4\"],\n [\"pink\", \"#FFC0CB\"],\n [\"blush pink\", \"#E8B4B8\"],\n [\"dusty rose\", \"#C08081\"],\n [\"mauve\", \"#B784A7\"],\n // Purples\n [\"magenta\", \"#FF00FF\"],\n [\"orchid\", \"#DA70D6\"],\n [\"plum\", \"#8E4585\"],\n [\"eggplant\", \"#614051\"],\n [\"dusty purple\", \"#6E5A7E\"],\n [\"lilac\", \"#C8A2C8\"],\n [\"lavender\", \"#B57EDC\"],\n [\"pale lavender\", \"#E6E6FA\"],\n [\"amethyst\", \"#9966CC\"],\n [\"violet\", \"#8F00FF\"],\n [\"purple\", \"#800080\"],\n [\"indigo\", \"#4B0082\"],\n // Blues\n [\"navy blue\", \"#000080\"],\n [\"midnight blue\", \"#191970\"],\n [\"prussian blue\", \"#003153\"],\n [\"dusky blue\", \"#4B5E7D\"],\n [\"royal blue\", \"#4169E1\"],\n [\"cobalt blue\", \"#0047AB\"],\n [\"blue\", \"#0000FF\"],\n [\"cornflower blue\", \"#6495ED\"],\n [\"denim blue\", \"#1560BD\"],\n [\"steel blue\", \"#4682B4\"],\n [\"slate blue\", \"#6A5ACD\"],\n [\"periwinkle\", \"#CCCCFF\"],\n [\"sky blue\", \"#87CEEB\"],\n [\"baby blue\", \"#89CFF0\"],\n [\"powder blue\", \"#B0E0E6\"],\n [\"ice blue\", \"#D6ECEF\"],\n [\"azure\", \"#007FFF\"],\n [\"cerulean\", \"#007BA7\"],\n [\"petrol blue\", \"#005F6A\"],\n // Cyans and teals\n [\"cyan\", \"#00FFFF\"],\n [\"turquoise\", \"#40E0D0\"],\n [\"aquamarine\", \"#7FFFD4\"],\n [\"teal\", \"#008080\"],\n [\"dark teal\", \"#014D4E\"],\n [\"dark slate gray\", \"#2F4F4F\"],\n // Greens\n [\"sea green\", \"#2E8B57\"],\n [\"emerald green\", \"#50C878\"],\n [\"jade green\", \"#00A86B\"],\n [\"mint green\", \"#98FF98\"],\n [\"seafoam green\", \"#93E9BE\"],\n [\"sage green\", \"#9CAF88\"],\n [\"olive green\", \"#708238\"],\n [\"olive\", \"#808000\"],\n [\"moss green\", \"#8A9A5B\"],\n [\"forest green\", \"#228B22\"],\n [\"hunter green\", \"#355E3B\"],\n [\"bottle green\", \"#006A4E\"],\n [\"dark green\", \"#013220\"],\n [\"green\", \"#008000\"],\n [\"kelly green\", \"#4CBB17\"],\n [\"lime green\", \"#32CD32\"],\n [\"chartreuse\", \"#7FFF00\"],\n [\"pistachio\", \"#93C572\"],\n // Yellows and golds\n [\"yellow\", \"#FFFF00\"],\n [\"lemon yellow\", \"#FFF44F\"],\n [\"pale yellow\", \"#FDFD96\"],\n [\"canary yellow\", \"#FFEF00\"],\n [\"mustard yellow\", \"#E1AD01\"],\n [\"gold\", \"#FFD700\"],\n [\"amber\", \"#FFBF00\"],\n [\"honey\", \"#F0A830\"],\n [\"saffron\", \"#F4C430\"],\n]\n\nconst HEX_RE = /^#[0-9a-f]{6}$/i\n\ntype Lab = readonly [l: number, a: number, b: number]\n\nfunction channel(v: number): number {\n const c = v / 255\n return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4\n}\n\nfunction labPivot(t: number): number {\n return t > 216 / 24389 ? Math.cbrt(t) : (24389 / 27 * t + 16) / 116\n}\n\n/** sRGB hex → CIE Lab (D65). Only called with a value that passed `HEX_RE`. */\nfunction toLab(hex: string): Lab {\n const r = channel(parseInt(hex.slice(1, 3), 16))\n const g = channel(parseInt(hex.slice(3, 5), 16))\n const b = channel(parseInt(hex.slice(5, 7), 16))\n const x = labPivot((0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / 0.95047)\n const y = labPivot(0.2126729 * r + 0.7151522 * g + 0.072175 * b)\n const z = labPivot((0.0193339 * r + 0.119192 * g + 0.9503041 * b) / 1.08883)\n return [116 * y - 16, 500 * (x - y), 200 * (y - z)]\n}\n\nlet namedLab: ReadonlyArray<readonly [string, Lab]> | null = null\n\n/**\n * The everyday name nearest to `hex` (`#RRGGBB`, any case), or `\"\"` when the\n * value is not a `#RRGGBB` colour.\n */\nexport function nearestColorName(hex: string): string {\n if (!HEX_RE.test(hex)) return \"\"\n namedLab ??= NAMED.map(([name, value]) => [name, toLab(value)] as const)\n const [l, a, b] = toLab(hex)\n let best = \"\"\n let bestDistance = Infinity\n for (const [name, [nl, na, nb]] of namedLab) {\n const d = (l - nl) ** 2 + (a - na) ** 2 + (b - nb) ** 2\n if (d < bestDistance) {\n bestDistance = d\n best = name\n }\n }\n return best\n}\n","/**\n * USER-OWNED DIRECTION REFERENCES — a `direction` value that names one of the\n * caller's own saved resources instead of a catalog id.\n *\n * Two rows of the direction registry take one (their `userRef` column):\n * - `colorLook: \"palette:<uuid>\"` — a saved colour palette;\n * - `style: \"moodboard:<uuid>\"` — a saved moodboard.\n * The prefix namespaces them, so they never collide with a catalog id\n * (catalog ids are slugs; none carries a colon).\n *\n * The wire carries the id, never the resolved text, so a re-run resolves it\n * again and an edited palette reaches the next run. RESOLVING is a database\n * read, so it happens in the platform before the (pure, synchronous) fold:\n * the caller hands the fold a map of value → rendered clause\n * (`renderDirectionHintClauses`' `refs`, `assembleImageInput`'s\n * `directionRefs`), and a moodboard's images as fill-only style references\n * (`assembleImageInput`'s `styleReferences`). This module holds what is pure:\n * the grammar and the WORDING of those clauses and reference lines.\n */\nimport { nearestColorName } from \"./color-names.js\"\n\n/** The kinds of saved resource a direction value can name. */\nexport type UserDirectionRefKind = \"palette\" | \"moodboard\"\n\nexport const USER_DIRECTION_REF_KINDS: ReadonlyArray<UserDirectionRefKind> = [\"palette\", \"moodboard\"]\n\n/** A parsed user-owned reference. `wellFormed` = its id is a uuid. */\nexport interface UserDirectionRef {\n readonly kind: UserDirectionRefKind\n readonly id: string\n readonly wellFormed: boolean\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\n/**\n * Read one direction value. `null` when it is not a user-owned reference at\n * all (a catalog id, an empty string, anything that is not a string). A value\n * with a known prefix is ALWAYS a reference — `wellFormed: false` when what\n * follows is not a uuid, so a caller can refuse it rather than treat it as an\n * unknown catalog id and skip it in silence.\n */\nexport function parseUserDirectionRef(value: unknown): UserDirectionRef | null {\n if (typeof value !== \"string\") return null\n for (const kind of USER_DIRECTION_REF_KINDS) {\n const prefix = `${kind}:`\n if (value.startsWith(prefix)) {\n const id = value.slice(prefix.length)\n return { kind, id, wellFormed: UUID_RE.test(id) }\n }\n }\n return null\n}\n\n/** The wire value for a saved resource: `palette:<id>` / `moodboard:<id>`. */\nexport function userDirectionRefValue(kind: UserDirectionRefKind, id: string): string {\n return `${kind}:${id}`\n}\n\n/** Collapse all whitespace (newlines included) to single spaces and trim. User\n * text never opens a line of its own inside the assembled prompt — a newline\n * there could start a fake `[style]:` section. */\nfunction oneLine(text: string | null | undefined): string {\n return (text ?? \"\").replace(/\\s+/g, \" \").trim()\n}\n\nconst HEX_RE = /^#[0-9a-f]{6}$/i\n\n/**\n * A saved palette as a look clause: every colour by its everyday name and its\n * exact hex, in the palette's order — `color palette: dark teal #0F4C5C,\n * saffron #E3B23C`. An entry that is not a `#RRGGBB` colour is skipped; no\n * valid colour renders nothing.\n */\nexport function renderPaletteClause(colors: ReadonlyArray<string>): string {\n const named = colors\n .filter((c) => HEX_RE.test(c))\n .map((c) => `${nearestColorName(c)} ${c.toUpperCase()}`)\n return named.length > 0 ? `color palette: ${named.join(\", \")}` : \"\"\n}\n\n/**\n * A saved moodboard's written description as its look clause: the user's own\n * words, on one line. No description renders nothing (the moodboard's images\n * still go along as style references).\n */\nexport function renderMoodboardClause(description: string | null | undefined): string {\n return oneLine(description)\n}\n\n/** One style reference image (a moodboard's image) handed to the assembler. */\nexport interface StyleReferenceInput {\n readonly url: string\n /** What the image is for — rides its reference line. */\n readonly caption?: string\n}\n\n/**\n * The line a style reference carries in the assembled prompt (its\n * `description` as a reference). The first one says what to take from a style\n * reference and what not to; the rest stay short, so a full moodboard does not\n * bury the prompt. A caption rides along on one line.\n */\nexport function styleReferenceDescription(index: number, caption?: string): string {\n const cap = oneLine(caption)\n const tail = cap ? ` (${cap})` : \"\"\n return index === 0\n ? `match the colors, light, texture and mood of this style reference${tail}, not its subject or layout`\n : `another style reference${tail}`\n}\n","/**\n * THE DIRECTION REGISTRY — the single, ordered table of every cinematic\n * dimension the flat `direction` channel carries, plus the one renderer that\n * folds it into prompt text.\n *\n * WHY IT EXISTS: before this module, five of the ~35 cinematic dimensions rode\n * the `direction` wire channel and every other dimension was folded into prompt\n * TEXT by the client. A production copied between clients therefore froze stale\n * catalog wording, and each client re-implemented the fold. The table below is\n * the platform-owned replacement: the wire carries ids, the platform renders\n * the clauses, and the fold ORDER is exported so a client preview cannot drift\n * from what the server actually emits.\n *\n * WIRE VOCABULARY: the keys are the platform's OWN node-data field names — the\n * ones `SINGLE_PICKER_WIRING[].valueField` and the four `*_FIELD_BY_CATEGORY`\n * maps already use (`shotSize`, `lightingStyle`, `isoValue`, `style`, `mood`,\n * `cameraMotion`, …). A Studio-emitted graph and a hand-built canvas node\n * therefore speak ONE vocabulary for one catalog, and every `build*Hints`\n * already consumes these names.\n *\n * IMPORT RULE (hard): this module imports only `get*PromptHint` / `get*Term` /\n * `build*Hints` FUNCTIONS — never a raw UPPERCASE catalog array.\n * `catalog-funnel-ratchet.test.ts` derives its watch set from\n * `picker-catalogs.ts`'s uppercase value imports and can only SHRINK, so a raw\n * array import here would be a new offender. Nothing here reads an environment\n * variable either (`content-free-contract.test.ts`) — verbosity and surface are\n * threaded parameters, never deployment state.\n *\n * DELIBERATELY EXCLUDED, so neither is filed as a gap:\n * - `characterFx` — a per-shot composer with catalog timing levers\n * (`composeCharacterFxHintFromConnections`) positioned at an in-prose effect\n * token, not a bare id. A single-id channel cannot carry it.\n * - Subject / Styling / prop dimensions (`animal`, `heldProp`, `material`,\n * Person, Styling) — a separate `subject` channel, deliberately out of scope\n * here. It now exists: `subject-registry.ts`, same table-driven shape, its\n * key set DISJOINT from this one (pinned by a test) so nothing folds twice.\n *\n * PACK BLINDNESS (parity, not a regression): `get*PromptHint` reads the frozen\n * base arrays, so ids added by a deployment-registered catalog pack resolve to\n * `\"\"` and contribute no clause. This is identical to the behavior of the five\n * keys that shipped before this table; routing through `getPickerCatalog` is a\n * deliberate non-goal.\n */\nimport type { PickerHintMode } from \"./term.js\"\nimport { getFramingPromptHint, getFramingTerm } from \"./framing.js\"\nimport { getLightingPromptHint, getLightingTerm } from \"./lighting.js\"\nimport { getLensPromptHint, getLensTerm } from \"./lens.js\"\nimport { getCameraFormatPromptHint, getCameraFormatTerm } from \"./camera-format.js\"\nimport { getCameraMotionPromptHint, getCameraMotionTerm } from \"./camera-motions.js\"\nimport { getPosePromptHint, getPoseTerm } from \"./pose.js\"\nimport {\n getCompositionEffectPromptHint,\n getCompositionEffectTerm,\n} from \"./composition-effects.js\"\nimport { getExposurePromptHint, getExposureTerm } from \"./exposure-settings.js\"\nimport { getColorLookPromptHint, getColorLookTerm } from \"./color-look.js\"\nimport { buildAtmosphereHints } from \"./atmosphere.js\"\nimport { buildPostProcessHints } from \"./post-process-effects.js\"\nimport { getStylePromptHint, getStyleTerm } from \"./style.js\"\nimport { buildMoodHints } from \"./mood.js\"\nimport { buildAestheticHints } from \"./aesthetic.js\"\nimport { getPhotoGenrePromptHint, getPhotoGenreTerm } from \"./photo-genre.js\"\nimport { buildPhotographerHints } from \"./photographer.js\"\nimport { getRenderQualityPromptHint, getRenderQualityTerm } from \"./render-quality.js\"\nimport { getSettingPromptHint, getSettingTerm } from \"./setting.js\"\nimport { getEraPromptHint, getEraTerm } from \"./era.js\"\nimport { getBackdropPromptHint, getBackdropTerm } from \"./backdrop.js\"\nimport { buildActionFxHints } from \"./action-fx.js\"\nimport { getTemporalPromptHint, getTemporalTerm } from \"./temporal.js\"\nimport { renderTransitionBases } from \"./transitions.js\"\nimport { getLoopSubjectPromptHint, getLoopSubjectTerm } from \"./loop-subject.js\"\nimport { parseUserDirectionRef, type UserDirectionRefKind } from \"./user-direction-refs.js\"\n\n/** Which generation stages fold a dimension. */\nexport type DirectionSurface = \"image\" | \"video\" | \"both\"\n/**\n * Verbosity family — the video policy folds `motion` compact, `look` full.\n *\n * It is ALSO the body/section split (`prompt-style-section.ts`): `motion` stays\n * in the prompt body as shot prose, `look` moves to the `[style]` section. The\n * two meanings are deliberately the same column: camera motion is part of the\n * shot, not part of the look, on both axes, and a second column would let the\n * verbosity policy and the section boundary drift apart one row at a time.\n */\nexport type DirectionFamily = \"look\" | \"motion\"\n/**\n * Which `[style]` line a LOOK row renders on. `\"film\"` = the four dimensions\n * that describe the CAPTURE (stock, grade, style, era) plus the legacy camera\n * format key; every other look row falls to the scene line. Absent on `motion`\n * rows, which never reach the section at all.\n */\nexport type DirectionStyleGroup = \"film\"\n\nexport interface DirectionFieldSpec {\n /**\n * Wire key — also the `DirectionFields` property name and the canvas\n * node-data field name for the same catalog.\n */\n readonly key: string\n /**\n * Which generation stages fold this dimension. Filtering happens in the\n * RENDERER, never in the wire schema: an image-only key sent to\n * `/v1/generate-video` is accepted and simply contributes no hint.\n */\n readonly surface: DirectionSurface\n /** Verbosity family. The video policy folds `motion` compact, `look` full. */\n readonly family: DirectionFamily\n /**\n * `[style]`-section line for a `look` row. Omitted = the scene line. Meaningless\n * on a `motion` row (those stay in the body), which is why it is optional\n * rather than a required column with a null member.\n */\n readonly styleGroup?: DirectionStyleGroup\n /** Ids honored per dimension. Extras are SLICED at render, never a 400. */\n readonly maxPicks: number\n /**\n * The kind of the caller's OWN saved resource this row also takes, as\n * `<kind>:<uuid>` (`user-direction-refs.ts`) — a palette on `colorLook`, a\n * moodboard on `style`. Only single-pick rows carry one, so a pick budget can\n * never slice a reference away. The platform resolves the reference before\n * the fold and hands the rendered clause in as `refs`.\n */\n readonly userRef?: UserDirectionRefKind\n /**\n * Render selected ids in this catalog's own doctrine: per-id for independent\n * catalogs, ONE blended clause for Mood / Aesthetic / Photographer, the\n * catalog's own multi builder where it has one. `[]` when nothing resolves.\n */\n readonly render: (ids: readonly string[], mode: PickerHintMode) => string[]\n}\n\n// ── Render adapters (module-private) ────────────────────────────────────────\n\n/**\n * Independent per-id emission — the default doctrine.\n *\n * Only ever passes NON-EMPTY strings (the normalizer drops empties), which is\n * what makes `getLoopSubjectPromptHint(id: string)`'s required-string signature\n * safe here alongside the `string | undefined | null` getters.\n */\nconst perId =\n (full: (id: string) => string, compact: (id: string) => string) =>\n (ids: readonly string[], mode: PickerHintMode): string[] => {\n const out: string[] = []\n for (const id of ids) {\n const frag = mode === \"compact\" ? compact(id) : full(id)\n if (frag.length > 0) out.push(frag)\n }\n return out\n }\n\n/** Catalogs whose own builder returns a LIST (atmosphere, post-process, action FX). */\nconst viaListBuilder =\n (build: (v: unknown, mode: PickerHintMode) => string[]) =>\n (ids: readonly string[], mode: PickerHintMode): string[] =>\n build(ids.length === 1 ? ids[0] : [...ids], mode).filter((s) => s.length > 0)\n\n/** Catalogs whose own builder returns ONE blended clause (aesthetic, photographer). */\nconst viaStringBuilder =\n (build: (v: unknown, mode: PickerHintMode) => string) =>\n (ids: readonly string[], mode: PickerHintMode): string[] => {\n const s = build(ids.length === 1 ? ids[0] : [...ids], mode)\n return s.length > 0 ? [s] : []\n }\n\n/** Mood's builder takes a RECORD and returns a list — and blends multi picks. */\nconst viaMood = (ids: readonly string[], mode: PickerHintMode): string[] =>\n buildMoodHints({ mood: ids.length === 1 ? ids[0] : [...ids] }, mode).filter(\n (s) => s.length > 0,\n )\n\nconst framing = perId(getFramingPromptHint, getFramingTerm)\nconst lighting = perId(getLightingPromptHint, getLightingTerm)\nconst exposure = perId(getExposurePromptHint, getExposureTerm)\nconst temporal = perId(getTemporalPromptHint, getTemporalTerm)\n\n/**\n * THE TABLE. Declaration order IS fold order (`DIRECTION_KEYS`), pinned by\n * `__tests__/direction-registry.test.ts`.\n *\n * Group order: camera motion leads (matching the video hint order the canvas\n * and Studio both emit today), then composition → camera → exposure → light →\n * style → scene → motion, then the LEGACY BLOCK last.\n *\n * THE LEGACY BLOCK (the last five rows) is the pre-registry published\n * `DirectionFields`, placed LAST in today's exact `composePromptText` order so\n * every existing caller's fold is byte-identical. They are WHOLE-CATALOG keys —\n * `framingId` accepts ANY `FRAMINGS` id and `lightingId` ANY `LIGHTINGS` id —\n * so they are NOT aliases of `shotSize` / `lightingStyle`, and an alias table\n * would wrongly suppress a legal second selection. Overlap is handled instead\n * by the exact-string dedupe in `renderDirectionHints`.\n *\n * SECOND MEANING OF POSITION — SURVIVAL, NOT STRING POSITION: BOTH cap-aware\n * assemblers — `assembleImageInput` (stills) and `composeVideoPromptText`\n * (video) — shed hint clauses from the TAIL of this order when a provider's\n * prompt cap overflows, through the one shared arithmetic in\n * `hint-shedding.ts`. So a row's position is its survival order under the cap on\n * EVERY surface: reordering rows for one surface silently changes what the other\n * drops first, and the row a video-surface reorder would most likely touch\n * (`cameraMotion`) leads the fold. What position is NOT any more is the clause's\n * place in the assembled STRING: every `look` row is lifted out of the body into\n * the trailing `[style]` section (`prompt-style-section.ts`), so a look clause\n * reads after every motion clause however early it folds. That is a consequence\n * of reusing the fold order, not a ranking — this table stays a compatibility\n * order; anything that needs a real importance ranking should add an explicit\n * priority column rather than reorder these rows.\n *\n * WHERE THIS TABLE SITS IN THE COMBINED ORDER: both assemblers fold the SUBJECT\n * channel (`subject-registry.ts`) BEFORE this one and shed the combined list\n * tail-first, so every direction row here is dropped before any subject clause.\n * Deliberate — see `hint-shedding.ts` for the argument.\n */\nexport const DIRECTION_FIELDS = [\n { key: \"cameraMotion\", surface: \"video\", family: \"motion\", maxPicks: 1, render: perId(getCameraMotionPromptHint, getCameraMotionTerm) },\n\n // Composition (the Framing catalog, one row per category).\n { key: \"shotSize\", surface: \"both\", family: \"look\", maxPicks: 1, render: framing },\n { key: \"angle\", surface: \"both\", family: \"look\", maxPicks: 1, render: framing },\n { key: \"coverage\", surface: \"both\", family: \"look\", maxPicks: 1, render: framing },\n { key: \"composition\", surface: \"both\", family: \"look\", maxPicks: 2, render: framing },\n { key: \"vantage\", surface: \"both\", family: \"look\", maxPicks: 1, render: framing },\n { key: \"pose\", surface: \"both\", family: \"look\", maxPicks: 1, render: perId(getPosePromptHint, getPoseTerm) },\n { key: \"compositionEffect\", surface: \"both\", family: \"look\", maxPicks: 1, render: perId(getCompositionEffectPromptHint, getCompositionEffectTerm) },\n\n // Camera.\n { key: \"cameraFormat\", surface: \"both\", family: \"look\", styleGroup: \"film\", maxPicks: 1, render: perId(getCameraFormatPromptHint, getCameraFormatTerm) },\n { key: \"lens\", surface: \"both\", family: \"look\", maxPicks: 1, render: perId(getLensPromptHint, getLensTerm) },\n\n // Exposure (stills only — a video's exposure rides its own temporal levers).\n { key: \"aperture\", surface: \"image\", family: \"look\", maxPicks: 1, render: exposure },\n { key: \"shutterSpeed\", surface: \"image\", family: \"look\", maxPicks: 1, render: exposure },\n { key: \"isoValue\", surface: \"image\", family: \"look\", maxPicks: 1, render: exposure },\n\n // Light (the Lighting catalog, one row per category).\n { key: \"timeOfDay\", surface: \"both\", family: \"look\", maxPicks: 1, render: lighting },\n { key: \"lightingStyle\", surface: \"both\", family: \"look\", maxPicks: 2, render: lighting },\n { key: \"lightingDirection\", surface: \"both\", family: \"look\", maxPicks: 1, render: lighting },\n { key: \"lightingRatio\", surface: \"both\", family: \"look\", maxPicks: 1, render: lighting },\n { key: \"colorTemperature\", surface: \"both\", family: \"look\", maxPicks: 1, render: lighting },\n { key: \"colorLook\", surface: \"both\", family: \"look\", styleGroup: \"film\", maxPicks: 1, userRef: \"palette\", render: perId(getColorLookPromptHint, getColorLookTerm) },\n { key: \"atmosphere\", surface: \"both\", family: \"look\", maxPicks: 2, render: viaListBuilder(buildAtmosphereHints) },\n { key: \"postProcess\", surface: \"image\", family: \"look\", maxPicks: 2, render: viaListBuilder(buildPostProcessHints) },\n\n // Style.\n { key: \"style\", surface: \"both\", family: \"look\", styleGroup: \"film\", maxPicks: 1, userRef: \"moodboard\", render: perId(getStylePromptHint, getStyleTerm) },\n { key: \"mood\", surface: \"both\", family: \"look\", maxPicks: 2, render: viaMood },\n { key: \"aesthetic\", surface: \"both\", family: \"look\", maxPicks: 2, render: viaStringBuilder(buildAestheticHints) },\n { key: \"photoGenre\", surface: \"image\", family: \"look\", maxPicks: 1, render: perId(getPhotoGenrePromptHint, getPhotoGenreTerm) },\n { key: \"photographer\", surface: \"image\", family: \"look\", maxPicks: 2, render: viaStringBuilder(buildPhotographerHints) },\n { key: \"renderQuality\", surface: \"image\", family: \"look\", maxPicks: 1, render: perId(getRenderQualityPromptHint, getRenderQualityTerm) },\n\n // Scene.\n { key: \"setting\", surface: \"both\", family: \"look\", maxPicks: 1, render: perId(getSettingPromptHint, getSettingTerm) },\n { key: \"era\", surface: \"both\", family: \"look\", styleGroup: \"film\", maxPicks: 1, render: perId(getEraPromptHint, getEraTerm) },\n { key: \"backdrop\", surface: \"both\", family: \"look\", maxPicks: 1, render: perId(getBackdropPromptHint, getBackdropTerm) },\n\n // Motion & time.\n { key: \"actionFx\", surface: \"video\", family: \"motion\", maxPicks: 2, render: viaListBuilder(buildActionFxHints) },\n { key: \"temporalSpeed\", surface: \"video\", family: \"motion\", maxPicks: 1, render: temporal },\n { key: \"temporalFreeze\", surface: \"video\", family: \"motion\", maxPicks: 1, render: temporal },\n { key: \"temporalDirection\", surface: \"video\", family: \"motion\", maxPicks: 1, render: temporal },\n { key: \"temporalShutter\", surface: \"video\", family: \"motion\", maxPicks: 1, render: temporal },\n { key: \"transition\", surface: \"video\", family: \"motion\", maxPicks: 2, render: renderTransitionBases },\n { key: \"loopSubject\", surface: \"video\", family: \"motion\", maxPicks: 1, render: perId(getLoopSubjectPromptHint, getLoopSubjectTerm) },\n\n // ── LEGACY BLOCK — see the table doc above. Placed LAST, in today's exact\n // `composePromptText` order, so every pre-registry caller is byte-identical.\n { key: \"framingId\", surface: \"both\", family: \"look\", maxPicks: 1, render: framing },\n { key: \"framingAngleId\", surface: \"both\", family: \"look\", maxPicks: 1, render: framing },\n { key: \"lightingId\", surface: \"both\", family: \"look\", maxPicks: 1, render: lighting },\n { key: \"lensId\", surface: \"both\", family: \"look\", maxPicks: 1, render: perId(getLensPromptHint, getLensTerm) },\n { key: \"cameraFormatId\", surface: \"both\", family: \"look\", styleGroup: \"film\", maxPicks: 1, render: perId(getCameraFormatPromptHint, getCameraFormatTerm) },\n] as const satisfies ReadonlyArray<DirectionFieldSpec>\n\n/**\n * The table read at its DECLARED type. `styleGroup` is optional, so on the\n * `as const` tuple only the rows that carry it have the property at all — a\n * member-wise read would not compile. Every walk over the table goes through\n * this binding.\n */\nconst DIRECTION_SPECS: ReadonlyArray<DirectionFieldSpec> = DIRECTION_FIELDS\n\nexport type DirectionFieldRow = (typeof DIRECTION_FIELDS)[number]\nexport type DirectionKey = DirectionFieldRow[\"key\"]\nexport type ImageDirectionKey = Extract<DirectionFieldRow, { surface: \"image\" | \"both\" }>[\"key\"]\nexport type VideoDirectionKey = Extract<DirectionFieldRow, { surface: \"video\" | \"both\" }>[\"key\"]\n\n/**\n * Flat cinematic-direction ids (Studio / MCP / canvas node data).\n *\n * Every key accepts a single id OR an array: multi-pick dimensions always carry\n * an array, and a single-pick key may legitimately carry one (a client's\n * partition writer preserving legacy out-of-catalog ids). Absent ≠ empty — a\n * missing key means \"no hint\", never a default.\n */\nexport type DirectionFields = { readonly [K in DirectionKey]?: string | readonly string[] }\n\n/**\n * Table order — THE canonical fold order. Exported so a client's \"will inject\n * into prompt\" preview folds in the exact order the server does instead of\n * re-deriving one.\n */\nexport const DIRECTION_KEYS: ReadonlyArray<DirectionKey> = DIRECTION_FIELDS.map((f) => f.key)\n\n/**\n * The rows that render on the `[style]` section's FILM line, in table order —\n * derived from the table's `styleGroup` column so the grouping has exactly one\n * definition. Exported for clients that render the section themselves; the\n * platform's own renderer reads the column, not this list.\n */\nexport const FILM_STYLE_KEYS: ReadonlyArray<DirectionKey> = DIRECTION_SPECS.filter(\n (f) => f.styleGroup === \"film\",\n).map((f) => f.key as DirectionKey)\n\n/**\n * The direction key that takes a reference of this kind — `colorLook` for a\n * palette, `style` for a moodboard. Derived from the table's `userRef` column.\n */\nexport function directionKeyForUserRef(kind: UserDirectionRefKind): DirectionKey {\n const row = DIRECTION_SPECS.find((f) => f.userRef === kind)\n if (!row) throw new Error(`no direction row takes a ${kind} reference`)\n return row.key as DirectionKey\n}\n\n/** The kind of saved resource a direction key takes, or undefined (most keys). */\nexport function userRefKindOfDirectionKey(key: string): UserDirectionRefKind | undefined {\n return DIRECTION_SPECS.find((f) => f.key === key)?.userRef\n}\n\n/** Verbosity for a whole fold, or split per family. */\nexport type DirectionHintMode =\n | PickerHintMode\n | { readonly look: PickerHintMode; readonly motion: PickerHintMode }\n\n/** How a direction bag is folded. */\nexport interface DirectionRenderOptions {\n readonly surface: \"image\" | \"video\"\n readonly mode?: DirectionHintMode\n /**\n * Rendered clauses for the caller's OWN saved resources, keyed by the\n * direction value (`palette:<id>` → `color palette: …`), resolved by the\n * platform before the fold. A reference absent from the map renders nothing,\n * exactly like an unknown catalog id. Absent = no reference resolves.\n */\n readonly refs?: ReadonlyMap<string, string>\n}\n\n/** Image policy: full clause for every dimension (today's behavior). */\nexport const IMAGE_HINT_MODE_DEFAULT: DirectionHintMode = \"full\"\n\n/** Video policy: full look clauses, compact motion terms. */\nexport const VIDEO_HINT_MODE_DEFAULT: DirectionHintMode = { look: \"full\", motion: \"compact\" }\n\nexport function modeForFamily(mode: DirectionHintMode, family: DirectionFamily): PickerHintMode {\n return typeof mode === \"string\" ? mode : family === \"motion\" ? mode.motion : mode.look\n}\n\n/**\n * Wire tolerance ceiling for an array-valued direction key. The SEMANTIC cap is\n * the per-row render-time slice (`maxPicks`) — this is only the point past\n * which a body is malformed rather than merely over-generous.\n */\nexport const DIRECTION_ARRAY_CEILING = 8\n\n/**\n * Tolerance ceiling for the LENGTH of a single direction id. Catalog ids are\n * short slugs (<= ~40 chars); 100 is generous and closes an otherwise unbounded\n * string channel that lands verbatim in `jobs.input_data`.\n *\n * ONE literal for BOTH doors into the fold — the route's `directionSchema`\n * (`backend/src/lib/direction-schema.ts`) and the persisted-node reader\n * (`read-node-direction.ts`) — so the wire and the canvas cannot start\n * disagreeing about which strings are ids at all.\n */\nexport const DIRECTION_ID_MAX_CHARS = 100\n\n/**\n * `string | string[]` → deduped, non-empty, capped id list.\n *\n * The `ids.length >= maxPicks` bail is load-bearing, not an optimization: the\n * dedupe is an `includes` scan, so without it the cost is quadratic in the\n * CALLER's array length — and one caller (`readDirectionFields`) reads\n * untrusted persisted JSONB. Bailing is semantics-preserving: once `maxPicks`\n * unique ids exist, no later entry can change the sliced result (and\n * `maxPicks = 0` still yields `[]`).\n */\nfunction normalizeDirectionIds(value: unknown, maxPicks: number): string[] {\n const ids: string[] = []\n if (typeof value === \"string\") {\n if (value) ids.push(value)\n } else if (Array.isArray(value)) {\n for (const v of value) {\n if (ids.length >= maxPicks) break\n if (typeof v === \"string\" && v && !ids.includes(v)) ids.push(v)\n }\n }\n return ids.slice(0, maxPicks)\n}\n\n/**\n * One row's clauses. A row with no user-owned reference among its ids renders\n * through its catalog doctrine exactly as before (byte parity). On a row that\n * takes a reference (`userRef`), each id renders on its own, in order: a\n * reference of the row's kind becomes its resolved clause from `refs` (nothing\n * when unresolved), any other value goes through the catalog.\n */\nfunction renderRow(\n spec: DirectionFieldSpec,\n ids: readonly string[],\n mode: PickerHintMode,\n refs: ReadonlyMap<string, string> | undefined,\n): string[] {\n if (spec.userRef === undefined || !ids.some((id) => parseUserDirectionRef(id) !== null)) {\n return spec.render(ids, mode)\n }\n return ids.flatMap((id) => {\n const ref = parseUserDirectionRef(id)\n if (ref === null) return spec.render([id], mode)\n const clause = ref.kind === spec.userRef ? refs?.get(id) : undefined\n return clause ? [clause] : []\n })\n}\n\n/** The rows a given generation stage folds, in table order. */\nexport function directionFieldsForSurface(\n surface: \"image\" | \"video\",\n): ReadonlyArray<DirectionFieldSpec> {\n return DIRECTION_SPECS.filter((f) => f.surface === \"both\" || f.surface === surface)\n}\n\n/** One rendered clause, still carrying the table attributes it came from. */\nexport interface DirectionHintClause {\n readonly key: DirectionKey\n readonly family: DirectionFamily\n readonly styleGroup?: DirectionStyleGroup\n readonly text: string\n}\n\n/**\n * `renderDirectionHints` with the row each clause came from still attached —\n * what the `[style]` section needs to decide which line a clause belongs on\n * without a second table. Same order, same surface filter, same dedupe; the\n * plain renderer is this one's `.text` projection, so the two cannot drift.\n */\nexport function renderDirectionHintClauses(\n direction: DirectionFields | undefined,\n opts: DirectionRenderOptions,\n): DirectionHintClause[] {\n if (!direction) return []\n const mode = opts.mode ?? \"full\"\n const out: DirectionHintClause[] = []\n const seen = new Set<string>()\n for (const spec of DIRECTION_SPECS) {\n if (spec.surface !== \"both\" && spec.surface !== opts.surface) continue\n const ids = normalizeDirectionIds(\n (direction as Record<string, unknown>)[spec.key],\n spec.maxPicks,\n )\n if (ids.length === 0) continue\n for (const hint of renderRow(spec, ids, modeForFamily(mode, spec.family), opts.refs)) {\n if (hint.length > 0 && !seen.has(hint)) {\n seen.add(hint)\n out.push({\n key: spec.key as DirectionKey,\n family: spec.family,\n ...(spec.styleGroup !== undefined ? { styleGroup: spec.styleGroup } : {}),\n text: hint,\n })\n }\n }\n }\n return out\n}\n\n/**\n * Every clause the `direction` channel injects, in canonical table order.\n *\n * Iterates the TABLE (never the caller's object), so unknown wire keys are\n * ignored, the order is platform-owned, and off-surface dimensions are inert.\n * Unknown IDS are silently skipped too — every `get*PromptHint` returns `\"\"` on\n * a miss, so a retired or pack-only id contributes no clause rather than a 400.\n *\n * DEDUPE: the result is de-duplicated by exact clause string, FIRST OCCURRENCE\n * WINS (order-preserving). This is what lets the five legacy whole-catalog keys\n * (`framingId`, `lightingId`, …) coexist with their canonical counterparts\n * without an alias table: a caller sending `framingId` and `shotSize` with the\n * SAME id emits the clause once, while `lightingId: \"golden-hour\"` alongside\n * `lightingStyle: \"rembrandt\"` correctly emits BOTH (they are different ids in\n * the same catalog — an alias table would have wrongly suppressed one).\n * A caller sending two DIFFERENT ids for the same dimension gets both clauses,\n * exactly as two wired picker nodes of one family behave today.\n *\n * Exported so a client's \"will inject into prompt\" preview renders the exact\n * clauses the server does instead of re-implementing the fold. A preview of the\n * assembled STRING needs `prompt-style-section.ts` on top: the look clauses in\n * this list do not read in this position any more.\n */\nexport function renderDirectionHints(\n direction: DirectionFields | undefined,\n opts: DirectionRenderOptions,\n): string[] {\n return renderDirectionHintClauses(direction, opts).map((c) => c.text)\n}\n","import { getAnimalPromptHint, getAnimalTerm, getVehicle, getWeapon, getFurniture } from \"@nodaro/shared/catalogs\"\nimport { composedHas, composedOption } from \"./catalog-overlay.js\"\nimport { deriveTerm } from \"./term.js\"\n\n/**\n * The four object-entity catalogs — animals, vehicles, weapons, furniture —\n * are OWNED by `@nodaro/shared`, which cannot depend on this package, so\n * their getters cannot carry the `overlayEntry` the other 34 catalogs do.\n * These wrappers are the overlay for them, and EVERY prompt-text read of\n * those catalogs goes through here: the parameter-node dispatcher and the\n * subject fold both. Two call sites resolving the same id to different text\n * — one curated, one stock — is exactly what a second, un-overlaid path\n * produced during review.\n *\n * Precedence per id, same four outcomes as catalog-overlay.ts:\n * - no pack on the catalog → the stock getter, untouched\n * - denied / not in the pack → \"\" (nothing reaches the prompt)\n * - composed option present → ITS promptHint / term. A pack author\n * who rewrote an entry wrote the hint they want injected; rebuilding it\n * from label + description would discard that\n * - pack-added id (no stock row) → the composed option (covered by the\n * branch above — the stock getter is never consulted when a pack exists)\n */\n\nexport function curatedAnimalPromptHint(id: string): string {\n if (!id) return \"\"\n if (!composedHas(\"animals\", id)) return \"\"\n return composedOption(\"animals\", id)?.promptHint ?? getAnimalPromptHint(id)\n}\nexport function curatedAnimalTerm(id: string): string {\n if (!id) return \"\"\n if (!composedHas(\"animals\", id)) return \"\"\n return composedOption(\"animals\", id)?.term ?? getAnimalTerm(id)\n}\n\ntype ObjectEntity = { readonly label: string; readonly description: string }\n\nfunction objectEntityText(\n catalogId: string,\n id: string,\n stock: ObjectEntity | undefined,\n stockHint: (e: ObjectEntity) => string,\n stockTerm: (e: ObjectEntity) => string,\n): { readonly hint: string; readonly term: string } {\n if (!id || !composedHas(catalogId, id)) return { hint: \"\", term: \"\" }\n const composed = composedOption(catalogId, id)\n if (composed) return { hint: composed.promptHint, term: composed.term }\n if (!stock) return { hint: \"\", term: \"\" }\n return { hint: stockHint(stock), term: stockTerm(stock) }\n}\n\n/**\n * The compact fragment for an OBJECT-entity entry (animal / vehicle / weapon /\n * furniture). Those catalogs carry no `promptHint` of their own — the full\n * fragment is synthesized as \"featuring a {label}, {description}\" — so the\n * compact form is the authored `term` when there is one and the derived label\n * otherwise (a concrete object's label IS its trade term). The framing verb\n * (\"featuring a\", \"with a\") belongs to the HINT; a term drops bare into\n * whatever sentence the consumer is building, and \"the object is in the scene\"\n * is precisely what these four nodes mean.\n *\n * The fallback MUST be `deriveTerm` and not a bare `toLowerCase()`: it is the\n * same fallback `objectOptions` uses to build the `/v1/catalogs` projection,\n * so a parenthetical label (\"Rifle (bolt-action)\") must strip identically here\n * or the injected fragment and the projected term would disagree.\n *\n * `term` is read structurally because it is being added to the shared entity\n * interfaces separately; this stays correct before and after that lands.\n */\n\nfunction objectEntityTerm(entry: { readonly label: string }): string {\n return (entry as { term?: string }).term ?? deriveTerm(entry.label)\n}\n\nexport function curatedVehicleText(id: string) {\n return objectEntityText(\"vehicles\", id, getVehicle(id), (e) => `featuring a ${e.label.toLowerCase()}, ${e.description}`, objectEntityTerm)\n}\nexport function curatedWeaponText(id: string) {\n return objectEntityText(\"weapons\", id, getWeapon(id), (e) => `with a ${e.label.toLowerCase()}, ${e.description}`, objectEntityTerm)\n}\nexport function curatedFurnitureText(id: string) {\n return objectEntityText(\"furniture\", id, getFurniture(id), (e) => `including a ${e.label.toLowerCase()}, ${e.description}`, objectEntityTerm)\n}\n"]}