@nodaro/prompts 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/LICENSE +105 -0
  2. package/README.md +27 -0
  3. package/dist/index.cjs +21240 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +3599 -0
  6. package/dist/index.d.ts +3599 -0
  7. package/dist/index.js +20854 -0
  8. package/dist/index.js.map +1 -0
  9. package/package.json +49 -0
  10. package/src/__tests__/__snapshots__/prompt-builder-segments.test.ts.snap +65 -0
  11. package/src/__tests__/action-fx.test.ts +155 -0
  12. package/src/__tests__/apply-picker-json.test.ts +50 -0
  13. package/src/__tests__/assemble-image-input.test.ts +248 -0
  14. package/src/__tests__/assemble-suno-input.test.ts +283 -0
  15. package/src/__tests__/brand-tokens.test.ts +81 -0
  16. package/src/__tests__/build-image-prompt-element-injection.test.ts +118 -0
  17. package/src/__tests__/build-image-prompt-hybrid-format.test.ts +131 -0
  18. package/src/__tests__/build-image-prompt-mentions.test.ts +809 -0
  19. package/src/__tests__/build-image-prompt-reference-cap.test.ts +57 -0
  20. package/src/__tests__/build-image-prompt-reference-numbering.test.ts +237 -0
  21. package/src/__tests__/build-image-prompt-reference-order.test.ts +313 -0
  22. package/src/__tests__/camera-motions-from-connections.test.ts +71 -0
  23. package/src/__tests__/catalog-gapfill.test.ts +53 -0
  24. package/src/__tests__/character-convergence-image.test.ts +217 -0
  25. package/src/__tests__/character-default-role-image.test.ts +167 -0
  26. package/src/__tests__/character-default-role-video.test.ts +168 -0
  27. package/src/__tests__/character-default-role.test.ts +70 -0
  28. package/src/__tests__/character-fx.test.ts +200 -0
  29. package/src/__tests__/entity-prompts-location.test.ts +97 -0
  30. package/src/__tests__/entity-prompts.test.ts +240 -0
  31. package/src/__tests__/expand-extra-refs-role.test.ts +50 -0
  32. package/src/__tests__/factory-presets.test.ts +1045 -0
  33. package/src/__tests__/factory-snippets.test.ts +68 -0
  34. package/src/__tests__/framing-multi.test.ts +71 -0
  35. package/src/__tests__/framing-vantage.test.ts +39 -0
  36. package/src/__tests__/i18n-entry-completeness.test.ts +269 -0
  37. package/src/__tests__/identity-lock.test.ts +46 -0
  38. package/src/__tests__/instrumentation.test.ts +68 -0
  39. package/src/__tests__/lighting-multi.test.ts +68 -0
  40. package/src/__tests__/location-convergence-image.test.ts +124 -0
  41. package/src/__tests__/mention-lock-flag.test.ts +499 -0
  42. package/src/__tests__/multi-picker-spec.test.ts +71 -0
  43. package/src/__tests__/music-genre.test.ts +103 -0
  44. package/src/__tests__/music-mood.test.ts +87 -0
  45. package/src/__tests__/object-creature-convergence-image.test.ts +105 -0
  46. package/src/__tests__/parameter-prompt-hint.test.ts +270 -0
  47. package/src/__tests__/parameter-registry-sync.test.ts +243 -0
  48. package/src/__tests__/person-age.test.ts +80 -0
  49. package/src/__tests__/person-analyzer-invariants.test.ts +47 -0
  50. package/src/__tests__/person-body-axes.test.ts +67 -0
  51. package/src/__tests__/person-facial-geometry.test.ts +156 -0
  52. package/src/__tests__/person-regional-aesthetic.test.ts +161 -0
  53. package/src/__tests__/person-sections.test.ts +18 -0
  54. package/src/__tests__/picker-analyzer-registry.test.ts +108 -0
  55. package/src/__tests__/picker-catalogs-project.test.ts +85 -0
  56. package/src/__tests__/picker-catalogs.test.ts +53 -0
  57. package/src/__tests__/picker-limits.test.ts +20 -0
  58. package/src/__tests__/prompt-builder-segments.test.ts +183 -0
  59. package/src/__tests__/prompt-builder-structured-fields.test.ts +40 -0
  60. package/src/__tests__/prompt-builder.test.ts +1773 -0
  61. package/src/__tests__/prompt-wizard-categories.test.ts +31 -0
  62. package/src/__tests__/provider-prompt-doctrine.test.ts +49 -0
  63. package/src/__tests__/resolve-prompt-append.test.ts +58 -0
  64. package/src/__tests__/resolve-prompt.test.ts +44 -0
  65. package/src/__tests__/role-picker-shared.test.ts +208 -0
  66. package/src/__tests__/seedance-2-inputs.test.ts +173 -0
  67. package/src/__tests__/seedance-extend.test.ts +44 -0
  68. package/src/__tests__/sound-aggregator.test.ts +350 -0
  69. package/src/__tests__/style-presets.test.ts +34 -0
  70. package/src/__tests__/temporal-multi.test.ts +74 -0
  71. package/src/__tests__/transitions.test.ts +213 -0
  72. package/src/__tests__/video-reference-features.test.ts +41 -0
  73. package/src/__tests__/video-reference-leading-refs.test.ts +90 -0
  74. package/src/__tests__/video-reference-resolver.test.ts +233 -0
  75. package/src/__tests__/video-reference-roles.test.ts +96 -0
  76. package/src/__tests__/voice-character.test.ts +48 -0
  77. package/src/__tests__/voice-delivery.test.ts +41 -0
  78. package/src/__tests__/wardrobe.test.ts +25 -0
  79. package/src/action-fx.ts +255 -0
  80. package/src/aesthetic.ts +435 -0
  81. package/src/assemble-image-input.ts +236 -0
  82. package/src/assemble-suno-input.ts +147 -0
  83. package/src/atmosphere.ts +104 -0
  84. package/src/backdrop.ts +131 -0
  85. package/src/brand-tokens.ts +154 -0
  86. package/src/camera-format.ts +76 -0
  87. package/src/camera-motions.ts +615 -0
  88. package/src/character-fx.ts +274 -0
  89. package/src/color-look.ts +103 -0
  90. package/src/composition-effects.ts +67 -0
  91. package/src/entity-prompts.ts +231 -0
  92. package/src/era.ts +292 -0
  93. package/src/exposure-settings.ts +142 -0
  94. package/src/factory-presets/generate-image.ts +1644 -0
  95. package/src/factory-presets/generate-video.ts +1116 -0
  96. package/src/factory-presets/index.ts +46 -0
  97. package/src/factory-presets/lottie-overlay.ts +166 -0
  98. package/src/factory-presets/motion-graphics.ts +350 -0
  99. package/src/factory-presets/music.ts +734 -0
  100. package/src/factory-presets/sfx.ts +136 -0
  101. package/src/factory-presets/shared-image.ts +207 -0
  102. package/src/factory-presets/switchx.ts +65 -0
  103. package/src/factory-presets/text.ts +292 -0
  104. package/src/factory-presets/types.ts +51 -0
  105. package/src/factory-presets/video-edit.ts +136 -0
  106. package/src/factory-presets/voice.ts +172 -0
  107. package/src/factory-presets.ts +2 -0
  108. package/src/factory-snippets/catalog.ts +105 -0
  109. package/src/factory-snippets/index.ts +16 -0
  110. package/src/factory-snippets/types.ts +33 -0
  111. package/src/framing.ts +634 -0
  112. package/src/held-prop.ts +187 -0
  113. package/src/identity-lock.ts +213 -0
  114. package/src/index.ts +66 -0
  115. package/src/instrumentation.ts +337 -0
  116. package/src/lens.ts +59 -0
  117. package/src/lighting.ts +229 -0
  118. package/src/loop-subject.ts +276 -0
  119. package/src/materials.ts +184 -0
  120. package/src/mood.ts +186 -0
  121. package/src/music-genre.ts +662 -0
  122. package/src/music-mood.ts +137 -0
  123. package/src/object-asset-presets.ts +81 -0
  124. package/src/parameter-prompt-hint.ts +281 -0
  125. package/src/person.ts +1368 -0
  126. package/src/photo-genre.ts +151 -0
  127. package/src/photographer.ts +612 -0
  128. package/src/picker-analyzer-registry.ts +374 -0
  129. package/src/picker-catalogs.ts +858 -0
  130. package/src/pose.ts +246 -0
  131. package/src/post-process-effects.ts +94 -0
  132. package/src/prompt-builder-structured-fields.ts +116 -0
  133. package/src/prompt-builder.ts +2964 -0
  134. package/src/prompt-templates.ts +50 -0
  135. package/src/prompt-wizard-categories.ts +334 -0
  136. package/src/provider-prompt-doctrine.ts +85 -0
  137. package/src/render-quality.ts +89 -0
  138. package/src/resolve-prompt.ts +120 -0
  139. package/src/seedance-2-inputs.ts +100 -0
  140. package/src/setting.ts +130 -0
  141. package/src/sound-aggregator.ts +241 -0
  142. package/src/style-presets.ts +162 -0
  143. package/src/style.ts +99 -0
  144. package/src/styling.ts +585 -0
  145. package/src/temporal.ts +151 -0
  146. package/src/transitions.ts +333 -0
  147. package/src/video-reference-resolver.ts +823 -0
  148. package/src/voice-character.ts +237 -0
  149. package/src/voice-delivery.ts +142 -0
  150. package/src/wardrobe.ts +179 -0
package/src/styling.ts ADDED
@@ -0,0 +1,585 @@
1
+ /**
2
+ * Canonical catalog of Styling / beauty + wardrobe + accessories choices.
3
+ *
4
+ * Multi-dimension parameter node like Person and Framing:
5
+ *
6
+ * Beauty / Hair / Accessories
7
+ * 1. makeup — Natural, glamour, smoky, goth, bold lips, editorial, dewy…
8
+ * 2. hair-cut — Pixie, bob, buzz cut, pompadour, dreadlocks, braids (45 entries)
9
+ * 3. hair-treatment — Babylights, balayage, ombré, highlights…
10
+ * 4. hair-state — Wet, messy, windswept, voluminous, sleek, frizzy,
11
+ * tousled, flowing… Hair motion / condition. Distinct
12
+ * from cut (shape) and treatment (color).
13
+ * 5. eyewear — Sunglasses (aviators / cat-eye / round), fashion glasses…
14
+ * 6. headwear — Hats (beanie, cap, fedora…), headbands, hoods, crowns
15
+ * 7. jewelry — Subtle, statement, gold, silver, layered, pearl
16
+ * 8. nails — Polished, red, dark, long acrylic, French tips
17
+ * 9. face-paint — Subtle, dramatic, costume, tribal markings
18
+ *
19
+ * Wardrobe (head-to-toe garments)
20
+ * 10. outfit — Single-pick complete look (school uniform, business
21
+ * suit, evening gown, scrubs, bikini, lingerie, kimono…).
22
+ * Intended as an override that semantically supersedes
23
+ * the per-piece selections; users are responsible for
24
+ * not stacking conflicting pieces.
25
+ * 11. top — Upper-body garment (t-shirt, hoodie, sweater, blouse,
26
+ * crop top, bikini top, sports bra…)
27
+ * 12. bottom — Lower-body garment (jeans, chinos, skirt, shorts,
28
+ * leggings, sweatpants…)
29
+ * 13. outerwear — Layered-over outer garment (leather jacket, blazer,
30
+ * trench, puffer, cardigan, kimono robe…)
31
+ * 14. legwear — Stockings / tights / socks worn between bottom and
32
+ * footwear (sheer / opaque tights, fishnets, thigh-highs…)
33
+ * 15. footwear — Shoes (sneakers, heels, boots, loafers, sandals…)
34
+ *
35
+ * Modifiers
36
+ * 16. fabric — Clothing fabric (silk, leather, denim, velvet…) phrased
37
+ * as "wearing X". Overlaps vocabulary with the universal
38
+ * Material node in the Object category, but Fabric is
39
+ * clothing-specific and scoped to the Subject workflow.
40
+ * 17. wardrobe-state — How the clothes are worn (oversized, fitted, cropped,
41
+ * sheer, wet, ripped, off-shoulder, tucked-in, layered,
42
+ * unbuttoned…). Composes with any garment selection.
43
+ *
44
+ * Each dimension is mutually exclusive within itself; all are optional.
45
+ * Applies to BOTH image and video consumers. Includes pre/post free-text
46
+ * fields for specifics the catalog can't express.
47
+ */
48
+
49
+ export type StylingDimension =
50
+ | "makeup"
51
+ | "eyewear"
52
+ | "headwear"
53
+ | "hair-cut"
54
+ | "hair-treatment"
55
+ | "hair-state"
56
+ | "jewelry"
57
+ | "nails"
58
+ | "face-paint"
59
+ | "outfit"
60
+ | "top"
61
+ | "bottom"
62
+ | "outerwear"
63
+ | "legwear"
64
+ | "footwear"
65
+ | "fabric"
66
+ | "wardrobe-state"
67
+
68
+ export interface Styling {
69
+ readonly id: string
70
+ readonly label: string
71
+ readonly dimension: StylingDimension
72
+ readonly description: string
73
+ readonly promptHint: string
74
+ }
75
+
76
+ export const STYLINGS: ReadonlyArray<Styling> = [
77
+ // -------------------- Makeup --------------------
78
+ { id: "makeup-natural", label: "Natural", dimension: "makeup", description: "Subtle, no-makeup makeup", promptHint: "with natural, subtle no-makeup makeup" },
79
+ { id: "makeup-glamour", label: "Glamour", dimension: "makeup", description: "Full polished glam look", promptHint: "with full glamour makeup, polished and editorial" },
80
+ { id: "makeup-smoky", label: "Smoky Eye", dimension: "makeup", description: "Dark dramatic eye makeup", promptHint: "with smoky eye makeup, dark and dramatic" },
81
+ { id: "makeup-bold-lips", label: "Bold Lips", dimension: "makeup", description: "Strong red or dark lipstick", promptHint: "with bold lips, a strong red or dark lipstick as the focal point" },
82
+ { id: "makeup-editorial", label: "Editorial", dimension: "makeup", description: "Avant-garde fashion makeup", promptHint: "with avant-garde editorial makeup, artistic and unconventional" },
83
+ { id: "makeup-goth", label: "Goth", dimension: "makeup", description: "Dark goth aesthetic", promptHint: "with goth makeup — pale skin, black eyeliner, dark lips" },
84
+ { id: "makeup-dewy", label: "Dewy Glow", dimension: "makeup", description: "Glowing fresh-skin focus", promptHint: "with dewy makeup, glowing fresh skin and minimal coverage" },
85
+
86
+ // -------------------- Eyewear --------------------
87
+ { id: "eyewear-sunglasses", label: "Sunglasses", dimension: "eyewear", description: "Generic dark sunglasses", promptHint: "wearing sunglasses" },
88
+ { id: "eyewear-aviators", label: "Aviators", dimension: "eyewear", description: "Classic aviator shades", promptHint: "wearing classic aviator sunglasses with a metal frame" },
89
+ { id: "eyewear-cat-eye", label: "Cat-Eye", dimension: "eyewear", description: "Vintage cat-eye frames", promptHint: "wearing cat-eye glasses with vintage upswept frames" },
90
+ { id: "eyewear-round", label: "Round / John Lennon", dimension: "eyewear", description: "Round wire-frame glasses", promptHint: "wearing round wire-frame glasses, John Lennon style" },
91
+ { id: "eyewear-fashion", label: "Fashion Glasses", dimension: "eyewear", description: "Bold designer frames", promptHint: "wearing bold fashion glasses with designer frames" },
92
+ { id: "eyewear-sport", label: "Sport Goggles", dimension: "eyewear", description: "Wraparound sport eyewear", promptHint: "wearing wraparound sport sunglasses" },
93
+
94
+ // -------------------- Headwear --------------------
95
+ { id: "headwear-beanie", label: "Beanie", dimension: "headwear", description: "Knit beanie hat", promptHint: "wearing a knit beanie" },
96
+ { id: "headwear-baseball-cap", label: "Baseball Cap", dimension: "headwear", description: "Curved-brim cap", promptHint: "wearing a baseball cap" },
97
+ { id: "headwear-fedora", label: "Fedora", dimension: "headwear", description: "Brimmed fedora", promptHint: "wearing a fedora hat" },
98
+ { id: "headwear-sun-hat", label: "Sun Hat", dimension: "headwear", description: "Wide-brimmed sun hat", promptHint: "wearing a wide-brimmed sun hat" },
99
+ { id: "headwear-headband", label: "Headband", dimension: "headwear", description: "Hair headband", promptHint: "wearing a headband" },
100
+ { id: "headwear-bandana", label: "Bandana", dimension: "headwear", description: "Bandana tied around head", promptHint: "wearing a bandana tied around the head" },
101
+ { id: "headwear-hood", label: "Hood", dimension: "headwear", description: "Hooded sweatshirt up", promptHint: "with a hood pulled up over the head" },
102
+ { id: "headwear-crown", label: "Crown", dimension: "headwear", description: "Royal or decorative crown", promptHint: "wearing a crown atop the head" },
103
+ { id: "headwear-helmet", label: "Helmet", dimension: "headwear", description: "Protective helmet", promptHint: "wearing a helmet" },
104
+ { id: "headwear-veil", label: "Veil", dimension: "headwear", description: "Veil draped over face/hair", promptHint: "wearing a veil draped over the head" },
105
+ { id: "headwear-bucket-hat", label: "Bucket Hat", dimension: "headwear", description: "Soft-brimmed casual bucket hat", promptHint: "wearing a soft-brimmed casual bucket hat" },
106
+ { id: "headwear-beret", label: "Beret", dimension: "headwear", description: "Soft round French beret", promptHint: "wearing a soft round French beret tilted to one side" },
107
+ { id: "headwear-turban", label: "Turban", dimension: "headwear", description: "Wrapped head turban, cultural / fashion", promptHint: "wearing a wrapped head turban with neatly folded layers" },
108
+ { id: "headwear-fascinator", label: "Fascinator", dimension: "headwear", description: "Small decorative headpiece, royal-wedding style", promptHint: "wearing a small decorative fascinator with feathers and netting, royal-wedding style" },
109
+ { id: "headwear-bowler", label: "Bowler Hat", dimension: "headwear", description: "Round-crown derby/bowler hat", promptHint: "wearing a round-crown bowler hat with a curled brim" },
110
+ { id: "headwear-cowboy-hat", label: "Cowboy Hat", dimension: "headwear", description: "Wide-brim Western cowboy hat", promptHint: "wearing a wide-brim Western cowboy hat with a creased crown" },
111
+
112
+ // -------------------- Hair Cut (the styled cut/shape) --------------------
113
+ // Natural texture + length live in Person.hair-base. This is what the
114
+ // stylist did with it. 45 entries — the picker uses a modal browser.
115
+ // ---- Short cuts ----
116
+ { id: "cut-pixie", label: "Pixie", dimension: "hair-cut", description: "Short, cropped pixie cut", promptHint: "styled in a short pixie cut" },
117
+ { id: "cut-buzz-cut", label: "Buzz Cut", dimension: "hair-cut", description: "Very short buzz cut", promptHint: "buzzed short" },
118
+ { id: "cut-crew-cut", label: "Crew Cut", dimension: "hair-cut", description: "Short tapered classic crew cut", promptHint: "styled in a short tapered crew cut" },
119
+ { id: "cut-shaved", label: "Shaved", dimension: "hair-cut", description: "Fully shaved", promptHint: "shaved bald" },
120
+ { id: "cut-undercut", label: "Undercut", dimension: "hair-cut", description: "Short sides, longer top", promptHint: "with an undercut — short sides and longer hair on top" },
121
+ { id: "cut-faux-hawk", label: "Faux Hawk", dimension: "hair-cut", description: "Center strip raised, sides faded", promptHint: "styled in a faux hawk with a raised center strip and faded sides" },
122
+ { id: "cut-mohawk", label: "Mohawk", dimension: "hair-cut", description: "Shaved sides, tall center strip", promptHint: "styled in a mohawk with shaved sides and a tall center strip" },
123
+ { id: "cut-pompadour", label: "Pompadour", dimension: "hair-cut", description: "Swept up and back, volume in front", promptHint: "styled in a pompadour with hair swept up and back from the forehead" },
124
+ { id: "cut-short", label: "Short", dimension: "hair-cut", description: "Generic short cut", promptHint: "cut short" },
125
+ { id: "cut-short-curly", label: "Short Curly Cut", dimension: "hair-cut", description: "Short layered curly shape", promptHint: "cut short with curls left out" },
126
+
127
+ // ---- Bob family ----
128
+ { id: "cut-micro-bob", label: "Micro Bob", dimension: "hair-cut", description: "Very short ear-length bob", promptHint: "styled in a very short ear-length bob cut" },
129
+ { id: "cut-french-bob", label: "French Bob", dimension: "hair-cut", description: "Jaw-length blunt bob, often with bangs", promptHint: "styled in a jaw-length blunt French bob with soft bangs" },
130
+ { id: "cut-bob", label: "Bob", dimension: "hair-cut", description: "Chin-length bob cut", promptHint: "styled in a chin-length bob cut" },
131
+ { id: "cut-lob", label: "Lob", dimension: "hair-cut", description: "Long bob, collarbone-length", promptHint: "styled in a long bob falling to the collarbone" },
132
+
133
+ // ---- Layered / shag family ----
134
+ { id: "cut-mullet", label: "Mullet", dimension: "hair-cut", description: "Short on top and sides, long in back", promptHint: "styled in a mullet with short top and long back" },
135
+ { id: "cut-wolf-cut", label: "Wolf Cut", dimension: "hair-cut", description: "Shaggy layered mullet with fringe", promptHint: "styled in a wolf cut with shaggy choppy layers and a wispy fringe" },
136
+
137
+ // ---- Bangs / fringe ----
138
+ { id: "cut-bangs", label: "Blunt Bangs", dimension: "hair-cut", description: "Straight bangs across forehead", promptHint: "with blunt bangs across the forehead" },
139
+ { id: "cut-curtain-bangs", label: "Curtain Bangs", dimension: "hair-cut", description: "Center-parted face-framing bangs", promptHint: "with center-parted curtain bangs framing the face" },
140
+ { id: "cut-wispy-bangs", label: "Wispy Bangs", dimension: "hair-cut", description: "Thin, piecey, airy fringe", promptHint: "with thin wispy piecey bangs" },
141
+ { id: "cut-side-swept", label: "Side-Swept", dimension: "hair-cut", description: "Falls across face over one eye", promptHint: "side-swept across the face with strands falling over one eye" },
142
+
143
+ // ---- Pulled back / updos ----
144
+ { id: "cut-slicked-back", label: "Slicked Back", dimension: "hair-cut", description: "Pulled straight back, polished", promptHint: "slicked straight back with a polished finish" },
145
+ { id: "cut-bardot-tendrils", label: "Bardot Tendrils", dimension: "hair-cut", description: "Pulled back with face-framing strands", promptHint: "pulled back with thin face-framing tendrils falling loose at the temples" },
146
+ { id: "cut-ponytail", label: "Ponytail (Low)", dimension: "hair-cut", description: "Low pulled-back ponytail", promptHint: "in a low pulled-back ponytail" },
147
+ { id: "cut-high-ponytail", label: "High Ponytail", dimension: "hair-cut", description: "Ponytail tied high on the crown", promptHint: "in a high ponytail tied at the crown" },
148
+ { id: "cut-half-up", label: "Half-Up Half-Down", dimension: "hair-cut", description: "Top pulled back, rest flows down", promptHint: "in a half-up half-down style, top pulled back with the rest flowing down" },
149
+ { id: "cut-bun", label: "Bun", dimension: "hair-cut", description: "Classic low or mid bun", promptHint: "in a bun" },
150
+ { id: "cut-top-knot", label: "Top Knot", dimension: "hair-cut", description: "Bun tied high on the crown", promptHint: "in a top knot on the crown" },
151
+ { id: "cut-space-buns", label: "Space Buns", dimension: "hair-cut", description: "Two symmetric buns either side", promptHint: "in two symmetric space buns" },
152
+
153
+ // ---- Braids ----
154
+ { id: "cut-braids", label: "Braids", dimension: "hair-cut", description: "Multiple loose woven braids", promptHint: "styled in multiple loose braids" },
155
+ { id: "cut-single-braid", label: "Single Braid", dimension: "hair-cut", description: "One long braid down the back", promptHint: "in a single long braid down the back" },
156
+ { id: "cut-two-braids", label: "Two Braids", dimension: "hair-cut", description: "Pigtail braids either side", promptHint: "in two pigtail braids" },
157
+ { id: "cut-french-braid", label: "French Braid", dimension: "hair-cut", description: "Woven flat against the scalp", promptHint: "in a French braid woven flat against the scalp" },
158
+ { id: "cut-dutch-braid", label: "Dutch Braid", dimension: "hair-cut", description: "Inverted raised French braid", promptHint: "in a raised Dutch braid" },
159
+ { id: "cut-fishtail-braid", label: "Fishtail Braid", dimension: "hair-cut", description: "Fine two-strand weave", promptHint: "in a fishtail braid" },
160
+ { id: "cut-box-braids", label: "Box Braids", dimension: "hair-cut", description: "Individual sectioned braids", promptHint: "in sectioned box braids" },
161
+ { id: "cut-crown-braid", label: "Crown Braid", dimension: "hair-cut", description: "Braid wrapped around the head", promptHint: "in a crown braid wrapped around the head" },
162
+ { id: "cut-cornrows", label: "Cornrows", dimension: "hair-cut", description: "Braided cornrow pattern", promptHint: "in tight cornrows" },
163
+
164
+ // ---- Locs ----
165
+ { id: "cut-dreadlocks", label: "Dreadlocks", dimension: "hair-cut", description: "Matted rope-like locs", promptHint: "in dreadlocks" },
166
+ { id: "cut-sisterlocks", label: "Sisterlocks", dimension: "hair-cut", description: "Thin, neatly sectioned micro-locs", promptHint: "in thin neat sisterlocks" },
167
+
168
+ // -------------------- Hair State (motion / condition — distinct from cut shape and treatment color) --------------------
169
+ { id: "hair-wet", label: "Wet", dimension: "hair-state", description: "Soaked, water-clinging hair", promptHint: "with hair soaked and wet, strands clinging together and dripping water" },
170
+ { id: "hair-damp", label: "Damp", dimension: "hair-state", description: "Just-washed damp hair", promptHint: "with hair freshly damp, slightly weighted and softly clumped" },
171
+ { id: "hair-messy", label: "Messy", dimension: "hair-state", description: "Disheveled, unkempt", promptHint: "with hair messy and disheveled, unkempt strands going every direction" },
172
+ { id: "hair-tousled", label: "Tousled", dimension: "hair-state", description: "Lightly mussed, lived-in", promptHint: "with hair softly tousled and lived-in, casual undone movement" },
173
+ { id: "hair-bedhead", label: "Bedhead", dimension: "hair-state", description: "Just-woken-up flattened side", promptHint: "with bedhead — hair flattened on one side, fluffed on the other, like just woken up" },
174
+ { id: "hair-windswept", label: "Windswept", dimension: "hair-state", description: "Wind-blown, hair in motion", promptHint: "with hair caught mid-motion in wind, strands streaming sideways across and away from the face" },
175
+ { id: "hair-voluminous", label: "Voluminous", dimension: "hair-state", description: "Big, blown-out volume", promptHint: "with hair full of volume, blown out and bouncy with body and lift at the roots" },
176
+ { id: "hair-sleek", label: "Sleek", dimension: "hair-state", description: "Glassy smooth straight", promptHint: "with hair sleek and glass-smooth, every strand pressed flat with a polished sheen" },
177
+ { id: "hair-frizzy", label: "Frizzy", dimension: "hair-state", description: "Halo of frizz", promptHint: "with hair frizzy, fine flyaway strands forming a soft halo around the head" },
178
+ { id: "hair-strands-on-face", label: "Strands on Face", dimension: "hair-state", description: "Loose strands across face", promptHint: "with loose hair strands falling across the face, partially covering one eye" },
179
+ { id: "hair-tucked-behind-ear", label: "Tucked Behind Ear", dimension: "hair-state", description: "Pushed behind one ear", promptHint: "with hair pushed back and tucked behind one ear, exposing the side of the face" },
180
+ { id: "hair-flowing", label: "Flowing", dimension: "hair-state", description: "Long flowing motion", promptHint: "with hair flowing freely, strands cascading and rippling with subtle movement" },
181
+
182
+ // -------------------- Hair Treatment (salon coloring techniques) --------------------
183
+ { id: "treatment-babylights", label: "Babylights", dimension: "hair-treatment", description: "Ultra-fine, delicate highlights", promptHint: "with babylights — ultra-fine, delicate highlights that mimic natural sun-kissed hair" },
184
+ { id: "treatment-balayage", label: "Balayage", dimension: "hair-treatment", description: "Hand-painted highlights", promptHint: "with balayage — hand-painted highlights with a soft, sun-kissed gradient" },
185
+ { id: "treatment-ombre", label: "Ombré", dimension: "hair-treatment", description: "Gradient dark roots to light ends", promptHint: "with ombré — a smooth gradient from dark roots to lighter ends" },
186
+ { id: "treatment-sombre", label: "Sombré", dimension: "hair-treatment", description: "Subtle soft ombré", promptHint: "with sombré — a subtle, soft ombré gradient" },
187
+ { id: "treatment-highlights", label: "Highlights", dimension: "hair-treatment", description: "Classic foil highlights", promptHint: "with highlights — lighter streaks throughout the hair" },
188
+ { id: "treatment-lowlights", label: "Lowlights", dimension: "hair-treatment", description: "Darker shade streaks", promptHint: "with lowlights — darker streaks woven through for dimension" },
189
+ { id: "treatment-rooted", label: "Rooted", dimension: "hair-treatment", description: "Visible root regrowth look", promptHint: "with a rooted look — visible darker roots blending into lighter lengths" },
190
+
191
+ // -------------------- Jewelry --------------------
192
+ { id: "jewelry-subtle", label: "Subtle", dimension: "jewelry", description: "Minimal, delicate jewelry", promptHint: "wearing subtle, minimal jewelry" },
193
+ { id: "jewelry-statement", label: "Statement", dimension: "jewelry", description: "Bold statement piece", promptHint: "wearing a bold statement jewelry piece" },
194
+ { id: "jewelry-gold", label: "Gold", dimension: "jewelry", description: "Gold necklace + earrings", promptHint: "wearing gold jewelry — a necklace and earrings" },
195
+ { id: "jewelry-silver", label: "Silver", dimension: "jewelry", description: "Silver necklace + earrings", promptHint: "wearing silver jewelry — a necklace and earrings" },
196
+ { id: "jewelry-layered", label: "Layered", dimension: "jewelry", description: "Layered necklaces / chains", promptHint: "wearing layered necklaces of varying lengths" },
197
+ { id: "jewelry-pearl", label: "Pearl", dimension: "jewelry", description: "Pearl necklace / earrings", promptHint: "wearing a pearl necklace and pearl earrings" },
198
+ { id: "jewelry-chunky", label: "Chunky", dimension: "jewelry", description: "Chunky chains and rings", promptHint: "wearing chunky chains and oversized rings" },
199
+ { id: "jewelry-smart-watch", label: "Smart Watch", dimension: "jewelry", description: "Modern smart watch on wrist", promptHint: "wearing a modern smart watch on the wrist with a sleek digital face and silicone band" },
200
+ { id: "jewelry-choker-leather", label: "Leather Choker", dimension: "jewelry", description: "Black leather choker close to throat", promptHint: "wearing a black leather choker fitted close around the throat" },
201
+ { id: "jewelry-choker-velvet", label: "Velvet Choker", dimension: "jewelry", description: "Velvet ribbon choker, dressy and vintage", promptHint: "wearing a velvet ribbon choker around the throat, a dressy vintage touch with a small pendant at the front" },
202
+ { id: "jewelry-choker-chain", label: "Chain Choker", dimension: "jewelry", description: "Thin metal-chain choker", promptHint: "wearing a thin metal-chain choker tight around the throat" },
203
+ { id: "jewelry-stud-earrings", label: "Stud Earrings", dimension: "jewelry", description: "Small simple studs", promptHint: "wearing small simple stud earrings" },
204
+ { id: "jewelry-hoop-earrings", label: "Hoop Earrings", dimension: "jewelry", description: "Gold or silver hoops", promptHint: "wearing gold or silver hoop earrings" },
205
+ { id: "jewelry-ear-cuff", label: "Ear Cuff", dimension: "jewelry", description: "Sculptural cuff climbing the cartilage", promptHint: "wearing a sculptural ear cuff climbing the cartilage of one ear" },
206
+ { id: "jewelry-septum-ring", label: "Septum Ring", dimension: "jewelry", description: "Septum nose ring", promptHint: "wearing a septum nose ring through the center of the nose" },
207
+ { id: "jewelry-body-chain", label: "Body Chain", dimension: "jewelry", description: "Thin metallic chain across torso", promptHint: "wearing a thin metallic body chain draped across the torso" },
208
+
209
+ // -------------------- Nails --------------------
210
+ { id: "nails-polished", label: "Polished", dimension: "nails", description: "Clear or nude polished nails", promptHint: "with polished nude nails" },
211
+ { id: "nails-red", label: "Red", dimension: "nails", description: "Bright red nail polish", promptHint: "with bright red nail polish" },
212
+ { id: "nails-dark", label: "Dark", dimension: "nails", description: "Dark / black nails", promptHint: "with dark black nail polish" },
213
+ { id: "nails-long-acrylic", label: "Long Acrylic", dimension: "nails", description: "Long acrylic nails", promptHint: "with long acrylic nails" },
214
+ { id: "nails-french", label: "French Tips", dimension: "nails", description: "Classic French manicure", promptHint: "with classic French tip manicure" },
215
+
216
+ // -------------------- Face Paint --------------------
217
+ { id: "face-paint-subtle", label: "Subtle Body Paint", dimension: "face-paint", description: "Subtle body / face paint accents", promptHint: "with subtle body paint accents on the skin" },
218
+ { id: "face-paint-dramatic", label: "Dramatic Face Paint", dimension: "face-paint", description: "Bold artistic face paint", promptHint: "with dramatic, artistic face paint covering portions of the face" },
219
+ { id: "face-paint-costume", label: "Costume Paint", dimension: "face-paint", description: "Cosplay / theatrical paint", promptHint: "with theatrical costume face paint" },
220
+ { id: "face-paint-tribal", label: "Tribal Markings", dimension: "face-paint", description: "Tribal-inspired face markings", promptHint: "with tribal-inspired face markings" },
221
+ { id: "face-paint-warpaint", label: "War Paint", dimension: "face-paint", description: "Warrior war paint streaks", promptHint: "with warrior war paint streaked across the face" },
222
+
223
+ // -------------------- Fabric (clothing material) --------------------
224
+ // Clothing-specific fabrics, phrased as "wearing X". Overlaps in vocabulary
225
+ // with the universal Material node in the Object category, but Material uses
226
+ // "made of X" grammar (works on any object/surface/body). Fabric reads
227
+ // natively when the subject is already assumed to be wearing something.
228
+ { id: "fabric-silk", label: "Silk", dimension: "fabric", description: "Smooth glossy silk garments", promptHint: "wearing smooth glossy silk with a subtle sheen and fluid drape" },
229
+ { id: "fabric-cotton", label: "Cotton", dimension: "fabric", description: "Soft matte cotton", promptHint: "wearing soft matte cotton with a natural woven texture" },
230
+ { id: "fabric-denim", label: "Denim", dimension: "fabric", description: "Heavy indigo denim", promptHint: "wearing heavy indigo denim with visible diagonal weave and worn edges" },
231
+ { id: "fabric-leather", label: "Leather", dimension: "fabric", description: "Rich supple leather", promptHint: "wearing rich supple leather with a soft satin sheen and natural grain" },
232
+ { id: "fabric-velvet", label: "Velvet", dimension: "fabric", description: "Plush velvet", promptHint: "wearing plush velvet with a deep soft nap and rich saturated color" },
233
+ { id: "fabric-satin", label: "Satin", dimension: "fabric", description: "Glossy satin", promptHint: "wearing glossy satin with a lustrous mirror-like surface and fluid folds" },
234
+ { id: "fabric-lace", label: "Lace", dimension: "fabric", description: "Delicate patterned lace", promptHint: "wearing delicate patterned lace with intricate floral openwork" },
235
+ { id: "fabric-wool", label: "Wool", dimension: "fabric", description: "Warm woven wool", promptHint: "wearing warm woven wool with a soft matte surface and visible fibers" },
236
+ { id: "fabric-linen", label: "Linen", dimension: "fabric", description: "Natural textured linen", promptHint: "wearing natural linen with a loose open weave, slight slubs and an airy drape" },
237
+ { id: "fabric-tweed", label: "Tweed", dimension: "fabric", description: "Rustic woven tweed", promptHint: "wearing rustic tweed with a flecked multi-color woven texture and a heritage feel" },
238
+ { id: "fabric-cashmere", label: "Cashmere", dimension: "fabric", description: "Luxurious soft cashmere", promptHint: "wearing luxurious cashmere with an ultra-soft matte texture" },
239
+ { id: "fabric-chiffon", label: "Chiffon", dimension: "fabric", description: "Sheer flowing chiffon", promptHint: "wearing sheer chiffon with a lightweight floating drape and soft translucent layers" },
240
+ { id: "fabric-fur", label: "Fur", dimension: "fabric", description: "Thick plush fur", promptHint: "wearing thick plush fur with long dense strands and natural variation" },
241
+ { id: "fabric-sequins", label: "Sequins", dimension: "fabric", description: "Sparkling sequin fabric", promptHint: "wearing sparkling sequined fabric catching light with countless tiny reflective facets" },
242
+ { id: "fabric-latex", label: "Latex", dimension: "fabric", description: "Glossy latex", promptHint: "wearing glossy latex with a high-shine liquid look clinging to the body" },
243
+
244
+ // -------------------- Outfit (single-pick complete look — overrides individual pieces) --------------------
245
+ { id: "outfit-school-uniform", label: "School Uniform", dimension: "outfit", description: "Classic school uniform set", promptHint: "dressed in a classic school uniform — collared blouse, pleated skirt and knee-high socks" },
246
+ { id: "outfit-business-suit", label: "Business Suit", dimension: "outfit", description: "Tailored two-piece business suit", promptHint: "dressed in a sharp tailored two-piece business suit with a crisp shirt underneath" },
247
+ { id: "outfit-tuxedo", label: "Tuxedo", dimension: "outfit", description: "Black-tie tuxedo", promptHint: "dressed in a black tuxedo with satin lapels and a bow tie" },
248
+ { id: "outfit-evening-gown", label: "Evening Gown", dimension: "outfit", description: "Floor-length formal gown", promptHint: "dressed in a floor-length evening gown with a fitted bodice and a flowing skirt" },
249
+ { id: "outfit-wedding-dress", label: "Wedding Dress", dimension: "outfit", description: "White wedding gown", promptHint: "dressed in a white wedding gown with intricate lace detailing and a sweeping train" },
250
+ { id: "outfit-cocktail-dress", label: "Cocktail Dress", dimension: "outfit", description: "Knee-length cocktail dress", promptHint: "dressed in a sleek knee-length cocktail dress" },
251
+ { id: "outfit-lab-coat", label: "Lab Coat", dimension: "outfit", description: "White medical lab coat", promptHint: "wearing a crisp white lab coat layered over the rest of the clothing" },
252
+ { id: "outfit-scrubs", label: "Medical Scrubs", dimension: "outfit", description: "Solid-color medical scrubs", promptHint: "dressed in solid-color medical scrubs — loose-fit top and matching drawstring pants" },
253
+ { id: "outfit-military", label: "Military Fatigues", dimension: "outfit", description: "Olive-drab military fatigues", promptHint: "dressed in olive-drab military fatigues with utility pockets and a sturdy belt" },
254
+ { id: "outfit-lifeguard", label: "Lifeguard Outfit", dimension: "outfit", description: "Red lifeguard top and shorts", promptHint: "dressed in a bright red lifeguard outfit — a fitted top and matching shorts" },
255
+ { id: "outfit-athleisure", label: "Athleisure Set", dimension: "outfit", description: "Matching athleisure top and bottom", promptHint: "dressed in a matching athleisure set — a fitted top and leggings in the same tone" },
256
+ { id: "outfit-tracksuit", label: "Tracksuit", dimension: "outfit", description: "Two-piece zip-front tracksuit", promptHint: "dressed in a two-piece tracksuit — a zip-front jacket and matching joggers" },
257
+ { id: "outfit-bikini", label: "Bikini", dimension: "outfit", description: "Two-piece swimsuit", promptHint: "in a two-piece bikini" },
258
+ { id: "outfit-one-piece-swim", label: "One-Piece Swimsuit", dimension: "outfit", description: "Fitted one-piece swimsuit", promptHint: "in a fitted one-piece swimsuit" },
259
+ { id: "outfit-lingerie", label: "Lingerie Set", dimension: "outfit", description: "Matching lingerie set", promptHint: "in a matching lingerie set" },
260
+ { id: "outfit-pajamas", label: "Pajamas", dimension: "outfit", description: "Soft cotton pajama set", promptHint: "in a soft cotton pajama set — a button-up top and matching pants" },
261
+ { id: "outfit-bathrobe", label: "Bathrobe", dimension: "outfit", description: "Plush terrycloth robe", promptHint: "wrapped in a plush terrycloth bathrobe tied at the waist" },
262
+ { id: "outfit-kimono", label: "Kimono", dimension: "outfit", description: "Traditional Japanese kimono", promptHint: "dressed in a traditional Japanese kimono with an obi sash" },
263
+ { id: "outfit-ballerina", label: "Ballerina", dimension: "outfit", description: "Classical ballerina costume", promptHint: "dressed in a classical ballerina costume — fitted leotard and tulle tutu" },
264
+ { id: "outfit-flapper", label: "1920s Flapper", dimension: "outfit", description: "Beaded flapper dress", promptHint: "dressed in a 1920s flapper dress — beaded fringe and a low-drop hem" },
265
+ { id: "outfit-goth", label: "Goth", dimension: "outfit", description: "Full dark goth: black lace, leather, dark makeup, chains", promptHint: "wearing a full goth outfit — black lace and leather layered together, chains and silver hardware, with dark dramatic makeup" },
266
+ { id: "outfit-emo", label: "Emo", dimension: "outfit", description: "Early-2000s emo: skinny jeans, band tee, dyed hair, eyeliner", promptHint: "wearing an early-2000s emo outfit — skinny black jeans and a band tee, with dyed side-swept hair and heavy eyeliner" },
267
+ { id: "outfit-streetwear", label: "Streetwear", dimension: "outfit", description: "Modern streetwear: hoodie, baggy pants, sneakers, bucket hat", promptHint: "wearing a modern streetwear outfit — an oversized hoodie, baggy pants, chunky sneakers, and a bucket hat" },
268
+ { id: "outfit-cyberpunk", label: "Cyberpunk", dimension: "outfit", description: "Neon-lit cyberpunk: tech wear, LED accents, mesh layers", promptHint: "wearing a cyberpunk outfit — neon-lit techwear with LED accents, mesh layers, and a futuristic urban silhouette" },
269
+ { id: "outfit-cottagecore", label: "Cottagecore", dimension: "outfit", description: "Pastoral cottage aesthetic: prairie dress, apron, basket", promptHint: "wearing a cottagecore outfit — a long pastoral prairie dress with an apron and a woven basket on the arm" },
270
+ { id: "outfit-dark-academia", label: "Dark Academia", dimension: "outfit", description: "Oxford-tweed scholar: blazer, vest, oxford shoes, books", promptHint: "wearing a dark academia outfit — a tweed blazer over a knit vest, oxford shoes, with books tucked under the arm" },
271
+ { id: "outfit-anime-cosplay", label: "Anime Cosplay", dimension: "outfit", description: "Costume modeled on a recognizable anime character archetype", promptHint: "wearing an anime cosplay costume modeled on a recognizable anime character archetype, with stylized details and bold colors" },
272
+ { id: "outfit-nurse", label: "Nurse", dimension: "outfit", description: "Medical scrubs, stethoscope, lanyard ID", promptHint: "dressed as a nurse — fitted medical scrubs with a stethoscope around the neck and a lanyard ID badge" },
273
+ { id: "outfit-pirate", label: "Pirate", dimension: "outfit", description: "Pirate costume: tricorn hat, sash, frilly shirt, boots", promptHint: "wearing a pirate costume — a tricorn hat, a frilly shirt with a sash at the waist, and tall leather boots" },
274
+ { id: "outfit-fairy", label: "Fairy", dimension: "outfit", description: "Fantasy fairy: gauzy wings, flower crown, ethereal dress", promptHint: "wearing a fantasy fairy costume — gauzy translucent wings, a flower crown, and an ethereal flowing dress" },
275
+ { id: "outfit-mermaid", label: "Mermaid", dimension: "outfit", description: "Fantasy mermaid: scaled tail/skirt, shell top, flowing hair", promptHint: "wearing a fantasy mermaid costume — a scaled tail or fitted scaled skirt, a shell top, and long flowing hair" },
276
+
277
+ // -------------------- Top (upper-body garment) --------------------
278
+ { id: "top-tshirt", label: "T-Shirt", dimension: "top", description: "Plain crewneck t-shirt", promptHint: "wearing a fitted plain crewneck t-shirt with short sleeves" },
279
+ { id: "top-tank", label: "Tank Top", dimension: "top", description: "Scoop-neck tank top", promptHint: "wearing a fitted scoop-neck tank top with thin shoulder straps" },
280
+ { id: "top-crop-top", label: "Crop Top", dimension: "top", description: "Cropped above the midriff", promptHint: "wearing a cropped top that ends above the midriff" },
281
+ { id: "top-hoodie", label: "Hoodie", dimension: "top", description: "Pullover hoodie", promptHint: "wearing a relaxed pullover hoodie with a kangaroo pocket" },
282
+ { id: "top-sweater", label: "Sweater", dimension: "top", description: "Knit pullover sweater", promptHint: "wearing a soft knit pullover sweater with a relaxed fit" },
283
+ { id: "top-turtleneck", label: "Turtleneck", dimension: "top", description: "High-neck turtleneck", promptHint: "wearing a fitted turtleneck sweater with a high rolled neckline" },
284
+ { id: "top-blouse", label: "Blouse", dimension: "top", description: "Flowing dressy blouse", promptHint: "wearing a flowing blouse with a soft drape and a tied neckline" },
285
+ { id: "top-button-down", label: "Button-Down", dimension: "top", description: "Tailored button-down shirt", promptHint: "wearing a tailored button-down shirt with a sharp pointed collar" },
286
+ { id: "top-polo", label: "Polo Shirt", dimension: "top", description: "Short-sleeve polo", promptHint: "wearing a fitted polo shirt with a small ribbed collar and short sleeves" },
287
+ { id: "top-tube-top", label: "Tube Top", dimension: "top", description: "Strapless tube top", promptHint: "wearing a strapless tube top fitted across the chest" },
288
+ { id: "top-camisole", label: "Camisole", dimension: "top", description: "Thin satin cami", promptHint: "wearing a thin satin camisole with delicate spaghetti straps" },
289
+ { id: "top-corset", label: "Corset", dimension: "top", description: "Structured corset top", promptHint: "wearing a structured corset top with boning and visible lacing" },
290
+ { id: "top-bra-top", label: "Bra Top", dimension: "top", description: "Bra-style top showing midriff", promptHint: "wearing a fitted bra-style top with the midriff exposed" },
291
+ { id: "top-sports-bra", label: "Sports Bra", dimension: "top", description: "Athletic sports bra", promptHint: "wearing a structured sports bra with athletic strapping" },
292
+ { id: "top-bikini-top", label: "Bikini Top", dimension: "top", description: "Triangle bikini top", promptHint: "wearing a triangle bikini top tied behind the neck and back" },
293
+ { id: "top-bodysuit", label: "Bodysuit", dimension: "top", description: "Fitted one-piece torso garment", promptHint: "wearing a fitted bodysuit, a one-piece torso garment snapped at the inseam" },
294
+ { id: "top-leotard", label: "Leotard", dimension: "top", description: "Dance-style fitted top with sleeves", promptHint: "wearing a dance-style leotard, a fitted one-piece top with sleeves" },
295
+ { id: "top-mesh-top", label: "Mesh Top", dimension: "top", description: "Sheer mesh fabric top", promptHint: "wearing a sheer mesh top, the open-weave fabric letting skin show through" },
296
+ { id: "top-sheer-top", label: "Sheer Top", dimension: "top", description: "Translucent fabric top", promptHint: "wearing a sheer translucent top with a soft drape, hinting at the silhouette underneath" },
297
+ { id: "top-bandeau", label: "Bandeau", dimension: "top", description: "Strapless tube top", promptHint: "wearing a strapless bandeau top wrapped across the chest" },
298
+
299
+ // -------------------- Bottom (lower-body garment) --------------------
300
+ { id: "bottom-jeans", label: "Jeans", dimension: "bottom", description: "Classic blue jeans", promptHint: "in classic five-pocket blue jeans with a straight leg cut" },
301
+ { id: "bottom-skinny-jeans", label: "Skinny Jeans", dimension: "bottom", description: "Skinny-cut jeans", promptHint: "in skinny-cut jeans hugging the legs from hip to ankle" },
302
+ { id: "bottom-wide-leg-jeans", label: "Wide-Leg Jeans", dimension: "bottom", description: "Wide-leg loose jeans", promptHint: "in wide-leg jeans with a loose relaxed silhouette flaring slightly at the hem" },
303
+ { id: "bottom-mom-jeans", label: "Mom Jeans", dimension: "bottom", description: "High-waist mom jeans", promptHint: "in high-waisted mom jeans with a relaxed straight-leg fit" },
304
+ { id: "bottom-low-rise-jeans", label: "Low-Rise Jeans", dimension: "bottom", description: "Low-rise jeans", promptHint: "in low-rise jeans sitting well below the natural waist" },
305
+ { id: "bottom-chinos", label: "Chinos", dimension: "bottom", description: "Tailored chino pants", promptHint: "in tailored chinos with a clean smooth weave and a slim straight leg" },
306
+ { id: "bottom-trousers", label: "Dress Trousers", dimension: "bottom", description: "Pressed dress trousers", promptHint: "in pressed dress trousers with a clean break at the ankle" },
307
+ { id: "bottom-cargo", label: "Cargo Pants", dimension: "bottom", description: "Cargo pants with side pockets", promptHint: "in loose cargo pants with utility side pockets and a relaxed leg" },
308
+ { id: "bottom-leggings", label: "Leggings", dimension: "bottom", description: "Fitted leggings", promptHint: "in fitted stretch leggings hugging the legs" },
309
+ { id: "bottom-sweatpants", label: "Sweatpants", dimension: "bottom", description: "Relaxed sweatpants", promptHint: "in relaxed jogger-cut sweatpants gathered at the ankle" },
310
+ { id: "bottom-shorts", label: "Shorts", dimension: "bottom", description: "Mid-thigh shorts", promptHint: "in casual mid-thigh shorts" },
311
+ { id: "bottom-denim-shorts", label: "Denim Shorts", dimension: "bottom", description: "Cut-off denim shorts", promptHint: "in cuffed denim cut-off shorts" },
312
+ { id: "bottom-mini-skirt", label: "Mini Skirt", dimension: "bottom", description: "Above-the-knee mini skirt", promptHint: "in a short mini skirt cut well above the knee" },
313
+ { id: "bottom-pleated-skirt", label: "Pleated Skirt", dimension: "bottom", description: "Pleated mid-thigh skirt", promptHint: "in a pleated mid-thigh skirt with sharp folds" },
314
+ { id: "bottom-midi-skirt", label: "Midi Skirt", dimension: "bottom", description: "Calf-length midi skirt", promptHint: "in a calf-length midi skirt with a flowing hem" },
315
+ { id: "bottom-maxi-skirt", label: "Maxi Skirt", dimension: "bottom", description: "Floor-length maxi skirt", promptHint: "in a floor-length maxi skirt with a fluid drape" },
316
+ { id: "bottom-overalls", label: "Overalls", dimension: "bottom", description: "Denim overalls / dungarees", promptHint: "in denim overalls with a bib front, shoulder straps, and metal buckles" },
317
+ { id: "bottom-culottes", label: "Culottes", dimension: "bottom", description: "Wide-leg cropped trousers, mid-calf", promptHint: "in wide-leg culottes cropped at mid-calf with a flowing silhouette" },
318
+ { id: "bottom-palazzo-pants", label: "Palazzo Pants", dimension: "bottom", description: "Flowing wide-leg pants", promptHint: "in flowing palazzo pants with a wide-leg silhouette and fluid drape" },
319
+ { id: "bottom-harem-pants", label: "Harem Pants", dimension: "bottom", description: "Drop-crotch loose pants", promptHint: "in drop-crotch harem pants, loose through the leg and gathered at the ankle" },
320
+ { id: "bottom-bike-shorts", label: "Bike Shorts", dimension: "bottom", description: "Fitted lycra mid-thigh shorts", promptHint: "in fitted lycra bike shorts ending mid-thigh" },
321
+
322
+ // -------------------- Outerwear (layered-over outer garment) --------------------
323
+ { id: "outerwear-leather-jacket", label: "Leather Jacket", dimension: "outerwear", description: "Slim-fit leather jacket", promptHint: "wearing a slim-fit black leather jacket with a fitted collar and zip front" },
324
+ { id: "outerwear-denim-jacket", label: "Denim Jacket", dimension: "outerwear", description: "Classic denim jacket", promptHint: "wearing a classic blue denim jacket with chest pockets and metal buttons" },
325
+ { id: "outerwear-bomber", label: "Bomber Jacket", dimension: "outerwear", description: "Satin bomber jacket", promptHint: "wearing a satin bomber jacket with ribbed cuffs and hem" },
326
+ { id: "outerwear-blazer", label: "Blazer", dimension: "outerwear", description: "Tailored blazer", promptHint: "wearing a tailored single-breasted blazer with notched lapels" },
327
+ { id: "outerwear-trench", label: "Trench Coat", dimension: "outerwear", description: "Belted trench coat", promptHint: "wearing a belted beige trench coat falling to the knees" },
328
+ { id: "outerwear-overcoat", label: "Wool Overcoat", dimension: "outerwear", description: "Long wool overcoat", promptHint: "wearing a long wool overcoat with broad notched lapels" },
329
+ { id: "outerwear-puffer", label: "Puffer Jacket", dimension: "outerwear", description: "Quilted puffer jacket", promptHint: "wearing a quilted puffer jacket with horizontal baffles and a stand-up collar" },
330
+ { id: "outerwear-parka", label: "Parka", dimension: "outerwear", description: "Hooded fur-trim parka", promptHint: "wearing a hooded fur-trim parka with a heavy quilted lining" },
331
+ { id: "outerwear-cardigan", label: "Cardigan", dimension: "outerwear", description: "Open-front knit cardigan", promptHint: "wearing an open-front knit cardigan with a relaxed drape" },
332
+ { id: "outerwear-vest", label: "Vest", dimension: "outerwear", description: "Tailored vest", promptHint: "wearing an unbuttoned tailored vest layered over the shirt" },
333
+ { id: "outerwear-kimono-robe", label: "Kimono Robe", dimension: "outerwear", description: "Flowing kimono robe", promptHint: "wearing a flowing silk kimono robe tied with a sash" },
334
+ { id: "outerwear-varsity", label: "Varsity Jacket", dimension: "outerwear", description: "Letterman varsity jacket", promptHint: "wearing a classic letterman varsity jacket with leather sleeves and a chenille patch" },
335
+ { id: "outerwear-fur-coat", label: "Fur Coat", dimension: "outerwear", description: "Plush fur coat", promptHint: "wearing a plush fur coat with a deep textured pile" },
336
+
337
+ // -------------------- Legwear (between bottom and footwear) --------------------
338
+ { id: "legwear-bare", label: "Bare Legs", dimension: "legwear", description: "Bare legs, no hosiery", promptHint: "with bare legs, no hosiery" },
339
+ { id: "legwear-sheer-tights", label: "Sheer Tights", dimension: "legwear", description: "Sheer nude pantyhose", promptHint: "with sheer nude pantyhose" },
340
+ { id: "legwear-opaque-tights", label: "Opaque Tights", dimension: "legwear", description: "Solid opaque tights", promptHint: "with opaque black tights covering the legs" },
341
+ { id: "legwear-fishnets", label: "Fishnets", dimension: "legwear", description: "Diamond-mesh fishnets", promptHint: "with fishnet stockings, the skin showing through the diamond mesh" },
342
+ { id: "legwear-thigh-highs", label: "Thigh-High Stockings", dimension: "legwear", description: "Thigh-high stockings", promptHint: "with thigh-high stockings stopping mid-thigh" },
343
+ { id: "legwear-lace-top-stockings", label: "Lace-Top Stockings", dimension: "legwear", description: "Lace-banded thigh-highs", promptHint: "with lace-topped thigh-high stockings cinched mid-thigh" },
344
+ { id: "legwear-knee-highs", label: "Knee-High Socks", dimension: "legwear", description: "Knee-high socks", promptHint: "with knee-high socks pulled up the calf" },
345
+ { id: "legwear-crew-socks", label: "Crew Socks", dimension: "legwear", description: "Mid-calf crew socks", promptHint: "with simple crew socks visible above the shoes" },
346
+ { id: "legwear-ankle-socks", label: "Ankle Socks", dimension: "legwear", description: "Low-cut ankle socks", promptHint: "with low-cut ankle socks barely showing above the shoes" },
347
+ { id: "legwear-leg-warmers", label: "Leg Warmers", dimension: "legwear", description: "Knit leg warmers", promptHint: "with bunched knit leg warmers stacked over the calves" },
348
+
349
+ // -------------------- Footwear (shoes) --------------------
350
+ { id: "footwear-sneakers", label: "Sneakers", dimension: "footwear", description: "Low-top sneakers", promptHint: "in clean white low-top sneakers" },
351
+ { id: "footwear-high-tops", label: "High-Top Sneakers", dimension: "footwear", description: "High-top canvas sneakers", promptHint: "in high-top canvas sneakers" },
352
+ { id: "footwear-running-shoes", label: "Running Shoes", dimension: "footwear", description: "Athletic running shoes", promptHint: "in technical running shoes with a chunky cushioned sole" },
353
+ { id: "footwear-stilettos", label: "Stiletto Heels", dimension: "footwear", description: "Pointed stiletto heels", promptHint: "in pointed-toe stiletto heels" },
354
+ { id: "footwear-block-heels", label: "Block Heels", dimension: "footwear", description: "Chunky block-heel pumps", promptHint: "in chunky block-heel pumps" },
355
+ { id: "footwear-platforms", label: "Platform Shoes", dimension: "footwear", description: "Tall platform soles", promptHint: "in platform shoes with thick chunky soles" },
356
+ { id: "footwear-ankle-boots", label: "Ankle Boots", dimension: "footwear", description: "Fitted ankle boots", promptHint: "in fitted black ankle boots" },
357
+ { id: "footwear-knee-boots", label: "Knee-High Boots", dimension: "footwear", description: "Tall knee-high boots", promptHint: "in tall knee-high leather boots" },
358
+ { id: "footwear-thigh-high-boots", label: "Thigh-High Boots", dimension: "footwear", description: "Thigh-high boots", promptHint: "in over-the-knee thigh-high leather boots" },
359
+ { id: "footwear-combat-boots", label: "Combat Boots", dimension: "footwear", description: "Laced combat boots", promptHint: "in laced black combat boots with a chunky lugged sole" },
360
+ { id: "footwear-chelsea-boots", label: "Chelsea Boots", dimension: "footwear", description: "Slip-on Chelsea boots", promptHint: "in clean Chelsea boots with elastic side panels" },
361
+ { id: "footwear-cowboy-boots", label: "Cowboy Boots", dimension: "footwear", description: "Pointed-toe cowboy boots", promptHint: "in pointed-toe cowboy boots with a stacked heel and decorative stitching" },
362
+ { id: "footwear-loafers", label: "Loafers", dimension: "footwear", description: "Polished penny loafers", promptHint: "in polished leather penny loafers" },
363
+ { id: "footwear-oxfords", label: "Oxfords", dimension: "footwear", description: "Laced leather oxfords", promptHint: "in laced leather oxford shoes with a polished finish" },
364
+ { id: "footwear-sandals", label: "Sandals", dimension: "footwear", description: "Flat strappy sandals", promptHint: "in flat strappy sandals" },
365
+ { id: "footwear-mules", label: "Mules", dimension: "footwear", description: "Backless slip-on mules", promptHint: "in slip-on backless mules" },
366
+ { id: "footwear-flip-flops", label: "Flip-Flops", dimension: "footwear", description: "Casual rubber flip-flops", promptHint: "in casual rubber flip-flops" },
367
+ { id: "footwear-ballet-flats", label: "Ballet Flats", dimension: "footwear", description: "Slip-on ballet flats", promptHint: "in slip-on ballet flats with a soft rounded toe" },
368
+ { id: "footwear-barefoot", label: "Barefoot", dimension: "footwear", description: "No shoes — barefoot", promptHint: "barefoot, no shoes" },
369
+ { id: "footwear-crocs", label: "Crocs", dimension: "footwear", description: "Colorful resin clogs, casual and divisive", promptHint: "in colorful resin Crocs clogs with the signature perforated upper" },
370
+ { id: "footwear-birkenstocks", label: "Birkenstocks", dimension: "footwear", description: "Cork-footbed sandals", promptHint: "in cork-footbed Birkenstock sandals with twin leather straps" },
371
+ { id: "footwear-doc-martens", label: "Doc Martens", dimension: "footwear", description: "Chunky leather combat boots", promptHint: "in chunky leather Doc Martens boots with yellow welt stitching and an air-cushioned sole" },
372
+ { id: "footwear-converse", label: "Converse", dimension: "footwear", description: "Canvas high-top sneakers, classic Chuck Taylor", promptHint: "in classic Converse Chuck Taylor canvas high-top sneakers with a rubber toe cap" },
373
+ { id: "footwear-vans", label: "Vans", dimension: "footwear", description: "Slip-on or low-top skater sneakers", promptHint: "in classic Vans skater sneakers with the signature waffle sole" },
374
+ { id: "footwear-espadrilles", label: "Espadrilles", dimension: "footwear", description: "Woven jute-sole canvas summer shoe", promptHint: "in woven jute-sole espadrilles with a canvas upper, a casual summer shoe" },
375
+
376
+ // -------------------- Wardrobe State (modifier — composes with any garment) --------------------
377
+ { id: "state-oversized", label: "Oversized", dimension: "wardrobe-state", description: "Loose, oversized fit", promptHint: "the clothing loose and oversized, draping freely well past the body" },
378
+ { id: "state-fitted", label: "Fitted", dimension: "wardrobe-state", description: "Form-fitting silhouette", promptHint: "the clothing fitted and form-conscious, hugging the contours of the body" },
379
+ { id: "state-cropped", label: "Cropped", dimension: "wardrobe-state", description: "Top cropped at midriff", promptHint: "the top cropped above the midriff with the stomach visible" },
380
+ { id: "state-sheer", label: "Sheer", dimension: "wardrobe-state", description: "Translucent fabric", promptHint: "the fabric translucent and sheer, hinting at the silhouette underneath" },
381
+ { id: "state-wet", label: "Wet", dimension: "wardrobe-state", description: "Soaked, water-clinging", promptHint: "the clothing soaked and wet, the fabric clinging to the body and dripping water" },
382
+ { id: "state-ripped", label: "Ripped", dimension: "wardrobe-state", description: "Torn and frayed", promptHint: "the fabric torn and ripped at the seams, with frayed edges" },
383
+ { id: "state-distressed", label: "Distressed", dimension: "wardrobe-state", description: "Worn, faded, weathered", promptHint: "the clothing distressed and weathered, with faded color and worn-down edges" },
384
+ { id: "state-vintage", label: "Vintage", dimension: "wardrobe-state", description: "Worn, retro character", promptHint: "the clothing carrying vintage character — softened color, broken-in fit, retro silhouette" },
385
+ { id: "state-tucked-in", label: "Tucked In", dimension: "wardrobe-state", description: "Top tucked into bottom", promptHint: "the top neatly tucked into the bottom" },
386
+ { id: "state-half-tucked", label: "Half-Tucked", dimension: "wardrobe-state", description: "Front-tucked, back loose", promptHint: "the top half-tucked — front neatly tucked in, back hanging loose" },
387
+ { id: "state-off-shoulder", label: "Off-Shoulder", dimension: "wardrobe-state", description: "Slipped off one shoulder", promptHint: "the top slipped off one shoulder, baring the skin and collarbone" },
388
+ { id: "state-unbuttoned", label: "Unbuttoned", dimension: "wardrobe-state", description: "Open / unbuttoned", promptHint: "the outerwear hanging open and unbuttoned, falling loose at the sides" },
389
+ { id: "state-rolled-sleeves", label: "Rolled Sleeves", dimension: "wardrobe-state", description: "Sleeves rolled up forearm", promptHint: "the sleeves rolled up to the forearm" },
390
+ { id: "state-layered", label: "Layered", dimension: "wardrobe-state", description: "Multiple stacked layers", promptHint: "the outfit composed of multiple stacked layers, each piece visible at the edges" },
391
+ ] as const
392
+
393
+ export const STYLING_DIMENSION_ORDER: ReadonlyArray<StylingDimension> = [
394
+ // Beauty / hair / accessories
395
+ "makeup",
396
+ "hair-cut",
397
+ "hair-treatment",
398
+ "hair-state",
399
+ "eyewear",
400
+ "headwear",
401
+ "jewelry",
402
+ "nails",
403
+ "face-paint",
404
+ // Wardrobe (head-to-toe). Outfit comes first as a "complete look" override
405
+ // semantically supersedes individual pieces.
406
+ "outfit",
407
+ "top",
408
+ "bottom",
409
+ "outerwear",
410
+ "legwear",
411
+ "footwear",
412
+ // Modifiers — fabric and state apply to whatever garment(s) above.
413
+ "fabric",
414
+ "wardrobe-state",
415
+ ]
416
+
417
+ export const STYLING_DIMENSION_LABELS: Readonly<Record<StylingDimension, string>> = {
418
+ makeup: "Makeup",
419
+ eyewear: "Eyewear",
420
+ headwear: "Headwear",
421
+ "hair-cut": "Hair Cut / Style",
422
+ "hair-treatment": "Hair Treatment",
423
+ "hair-state": "Hair State",
424
+ jewelry: "Jewelry",
425
+ nails: "Nails",
426
+ "face-paint": "Face Paint",
427
+ outfit: "Outfit",
428
+ top: "Top",
429
+ bottom: "Bottom",
430
+ outerwear: "Outerwear",
431
+ legwear: "Legwear",
432
+ footwear: "Footwear",
433
+ fabric: "Fabric",
434
+ "wardrobe-state": "Wardrobe State",
435
+ }
436
+
437
+ export const STYLING_FIELD_BY_DIMENSION: Record<
438
+ StylingDimension,
439
+ | "makeup"
440
+ | "eyewear"
441
+ | "headwear"
442
+ | "hairCut"
443
+ | "hairTreatment"
444
+ | "hairState"
445
+ | "jewelry"
446
+ | "nails"
447
+ | "facePaint"
448
+ | "outfit"
449
+ | "top"
450
+ | "bottom"
451
+ | "outerwear"
452
+ | "legwear"
453
+ | "footwear"
454
+ | "fabric"
455
+ | "wardrobeState"
456
+ > = {
457
+ makeup: "makeup",
458
+ eyewear: "eyewear",
459
+ headwear: "headwear",
460
+ "hair-cut": "hairCut",
461
+ "hair-treatment": "hairTreatment",
462
+ "hair-state": "hairState",
463
+ jewelry: "jewelry",
464
+ nails: "nails",
465
+ "face-paint": "facePaint",
466
+ outfit: "outfit",
467
+ top: "top",
468
+ bottom: "bottom",
469
+ outerwear: "outerwear",
470
+ legwear: "legwear",
471
+ footwear: "footwear",
472
+ fabric: "fabric",
473
+ "wardrobe-state": "wardrobeState",
474
+ }
475
+
476
+ /** Per-dimension multi-select cap — single source of truth for the picker UI,
477
+ * the image-analyzer tool schema, and the Zod validator. jewelry: 3
478
+ * (necklace + earrings + rings), wardrobe-state: 3 (oversized + wet + ripped),
479
+ * hair-state: 2 (wet + windswept). All others single-select (absent → 1). */
480
+ export const MAX_SELECTED_BY_STYLING_DIMENSION: Partial<Record<StylingDimension, number>> = {
481
+ jewelry: 3,
482
+ "wardrobe-state": 3,
483
+ "hair-state": 2,
484
+ }
485
+
486
+ /** Selection limit for a styling dimension (1 when not multi-select). */
487
+ export function getStylingDimensionLimit(dimension: StylingDimension): number {
488
+ return MAX_SELECTED_BY_STYLING_DIMENSION[dimension] ?? 1
489
+ }
490
+
491
+ export interface StylingValue {
492
+ makeup?: string
493
+ eyewear?: string
494
+ headwear?: string
495
+ /** Hair cut / styling choice — bob, wolf cut, braids, ponytail, etc.
496
+ * Pairs with Person.hair-base (texture + length). */
497
+ hairCut?: string
498
+ hairTreatment?: string
499
+ /** Hair state / motion / condition — wet, messy, windswept, voluminous,
500
+ * sleek, frizzy, tousled, flowing… Distinct from cut (shape) and
501
+ * treatment (color processing). Single id or up to 2 (e.g.
502
+ * ["wet", "windswept"], ["messy", "voluminous"]). */
503
+ hairState?: string | ReadonlyArray<string>
504
+ /** Jewelry. Single id or up to 3 ids for stacked jewelry
505
+ * (e.g. necklace + earrings + rings). */
506
+ jewelry?: string | ReadonlyArray<string>
507
+ nails?: string
508
+ facePaint?: string
509
+ /** Single-pick complete outfit archetype (school uniform, business suit,
510
+ * evening gown, scrubs, bikini, lingerie, kimono…). Intended as an override
511
+ * that semantically supersedes the per-piece selections. */
512
+ outfit?: string
513
+ /** Upper-body garment (t-shirt, sweater, blouse, sports bra, bikini top…). */
514
+ top?: string
515
+ /** Lower-body garment (jeans, chinos, skirt, shorts, leggings…). */
516
+ bottom?: string
517
+ /** Layered-over outer garment (jacket, blazer, coat, cardigan…). */
518
+ outerwear?: string
519
+ /** Legwear worn between bottom and footwear (tights, fishnets, stockings, socks…). */
520
+ legwear?: string
521
+ /** Shoes (sneakers, heels, boots, loafers, sandals…). */
522
+ footwear?: string
523
+ /** Clothing fabric / material — silk, leather, denim, etc. Phrased as
524
+ * "wearing X"; overlaps in vocabulary with the universal Material node
525
+ * in the Object category. */
526
+ fabric?: string
527
+ /** How the clothes are worn — oversized, fitted, cropped, sheer, wet,
528
+ * ripped, off-shoulder, tucked-in, layered, unbuttoned… Composes with
529
+ * any garment selection. Single id or up to 3 ids for stacked
530
+ * modifiers (e.g. ["oversized", "wet", "ripped"]). */
531
+ wardrobeState?: string | ReadonlyArray<string>
532
+ preText?: string
533
+ postText?: string
534
+ }
535
+
536
+ const stylingById = new Map<string, Styling>(STYLINGS.map((s) => [s.id, s]))
537
+
538
+ export function getStyling(id: string | undefined | null): Styling | undefined {
539
+ if (!id) return undefined
540
+ return stylingById.get(id)
541
+ }
542
+
543
+ export function getStylingLabel(id: string | undefined | null, fallback?: string): string {
544
+ const s = getStyling(id)
545
+ if (s) return s.label
546
+ if (fallback !== undefined) return fallback
547
+ return (id ?? "").replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())
548
+ }
549
+
550
+ export function getStylingPromptHint(id: string | undefined | null): string {
551
+ return getStyling(id)?.promptHint ?? ""
552
+ }
553
+
554
+ export const STYLING_IDS: ReadonlyArray<string> = STYLINGS.map((s) => s.id)
555
+
556
+ export function buildStylingHints(
557
+ data: Record<string, unknown> & StylingValue,
558
+ ): string[] {
559
+ const hints: string[] = []
560
+
561
+ const pre = typeof data.preText === "string" ? data.preText.trim() : ""
562
+ if (pre) hints.push(pre)
563
+
564
+ for (const dimension of STYLING_DIMENSION_ORDER) {
565
+ const field = STYLING_FIELD_BY_DIMENSION[dimension]
566
+ const raw = data[field]
567
+ // jewelry / wardrobe-state / hair-state are multi-pick (string | string[]);
568
+ // emit each id's hint independently and let the comma-join compose.
569
+ if (typeof raw === "string" && raw.length > 0) {
570
+ const hint = getStylingPromptHint(raw)
571
+ if (hint) hints.push(hint)
572
+ } else if (Array.isArray(raw)) {
573
+ for (const item of raw) {
574
+ if (typeof item !== "string" || item.length === 0) continue
575
+ const hint = getStylingPromptHint(item)
576
+ if (hint) hints.push(hint)
577
+ }
578
+ }
579
+ }
580
+
581
+ const post = typeof data.postText === "string" ? data.postText.trim() : ""
582
+ if (post) hints.push(post)
583
+
584
+ return hints
585
+ }