@nodaro/shared 1.4.2

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 (665) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +32 -0
  3. package/dist/index.cjs +12506 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +12269 -0
  6. package/dist/index.d.ts +12269 -0
  7. package/dist/index.js +11831 -0
  8. package/dist/index.js.map +1 -0
  9. package/package.json +54 -0
  10. package/src/__tests__/__snapshots__/prompt-builder-segments.test.ts.snap +65 -0
  11. package/src/__tests__/ai-avatar-pricing.test.ts +321 -0
  12. package/src/__tests__/apply-video-negative-prompt.test.ts +76 -0
  13. package/src/__tests__/attach-columns.test.ts +28 -0
  14. package/src/__tests__/audio-crossfade-curves.test.ts +33 -0
  15. package/src/__tests__/build-model-menu.test.ts +58 -0
  16. package/src/__tests__/character-aspect-defaults.test.ts +142 -0
  17. package/src/__tests__/character-mention-slug.test.ts +199 -0
  18. package/src/__tests__/character-reference-photo-kinds.test.ts +32 -0
  19. package/src/__tests__/character-usage-mode.test.ts +147 -0
  20. package/src/__tests__/character-variant-assets.test.ts +142 -0
  21. package/src/__tests__/character-voice.test.ts +130 -0
  22. package/src/__tests__/cinematic-avatar-pricing.test.ts +119 -0
  23. package/src/__tests__/combine-transitions.test.ts +137 -0
  24. package/src/__tests__/component-types.test.ts +87 -0
  25. package/src/__tests__/condition-variables.test.ts +98 -0
  26. package/src/__tests__/credit-identifiers.test.ts +811 -0
  27. package/src/__tests__/default-video-provider.test.ts +63 -0
  28. package/src/__tests__/entity-image-handle.test.ts +43 -0
  29. package/src/__tests__/entity-variants.test.ts +33 -0
  30. package/src/__tests__/fal-lip-sync-sets.test.ts +31 -0
  31. package/src/__tests__/featured-entities.test.ts +33 -0
  32. package/src/__tests__/film-pricing.test.ts +64 -0
  33. package/src/__tests__/filter-condition.test.ts +285 -0
  34. package/src/__tests__/freecut-protocol.test.ts +35 -0
  35. package/src/__tests__/generate-text-items.test.ts +19 -0
  36. package/src/__tests__/generated-results.test.ts +50 -0
  37. package/src/__tests__/graph-utils.test.ts +618 -0
  38. package/src/__tests__/group-aggregation.test.ts +83 -0
  39. package/src/__tests__/i18n-locale-completeness.test.ts +156 -0
  40. package/src/__tests__/image-critic-node.test.ts +86 -0
  41. package/src/__tests__/image-mask-mode.test.ts +16 -0
  42. package/src/__tests__/image-ref-limit.test.ts +78 -0
  43. package/src/__tests__/inpaint-region.test.ts +24 -0
  44. package/src/__tests__/input-field-map-parity.test.ts +30 -0
  45. package/src/__tests__/json-evaluator.test.ts +289 -0
  46. package/src/__tests__/json-path.test.ts +64 -0
  47. package/src/__tests__/lip-sync-pricing.test.ts +142 -0
  48. package/src/__tests__/list-merge.test.ts +96 -0
  49. package/src/__tests__/list-sort.test.ts +134 -0
  50. package/src/__tests__/llm-models.test.ts +445 -0
  51. package/src/__tests__/location-mention-slug.test.ts +246 -0
  52. package/src/__tests__/locations-coverage-critic-schema.test.ts +92 -0
  53. package/src/__tests__/loop-delimiter.test.ts +39 -0
  54. package/src/__tests__/lottie-slots.test.ts +245 -0
  55. package/src/__tests__/model-catalog-flux2-resolutions.test.ts +21 -0
  56. package/src/__tests__/model-constants-location.test.ts +20 -0
  57. package/src/__tests__/model-constants.test.ts +122 -0
  58. package/src/__tests__/model-tree.test.ts +86 -0
  59. package/src/__tests__/no-internal-imports.test.ts +25 -0
  60. package/src/__tests__/node-default-mappings.test.ts +175 -0
  61. package/src/__tests__/node-mappable-fields.test.ts +7 -0
  62. package/src/__tests__/node-preset-export.test.ts +46 -0
  63. package/src/__tests__/node-preset-extract.test.ts +166 -0
  64. package/src/__tests__/node-refs-canonical.test.ts +54 -0
  65. package/src/__tests__/node-refs-combine.test.ts +54 -0
  66. package/src/__tests__/node-refs.test.ts +187 -0
  67. package/src/__tests__/node-runtime-keys.test.ts +99 -0
  68. package/src/__tests__/object-aspect-defaults.test.ts +59 -0
  69. package/src/__tests__/parameter-node-value.test.ts +137 -0
  70. package/src/__tests__/pinterest-url.test.ts +35 -0
  71. package/src/__tests__/pipeline-chat.test.ts +110 -0
  72. package/src/__tests__/pipeline-validation.test.ts +98 -0
  73. package/src/__tests__/presentation-utils.test.ts +1137 -0
  74. package/src/__tests__/producer-types.test.ts +47 -0
  75. package/src/__tests__/prompt-length-limits.test.ts +156 -0
  76. package/src/__tests__/provider-directive-defaults.test.ts +46 -0
  77. package/src/__tests__/reduce-strategy-registry.test.ts +43 -0
  78. package/src/__tests__/reference-board-templates.test.ts +33 -0
  79. package/src/__tests__/reference-roles.test.ts +36 -0
  80. package/src/__tests__/resolve-field-mappings.test.ts +110 -0
  81. package/src/__tests__/resolve-pipeline-model.test.ts +76 -0
  82. package/src/__tests__/scene-node-types.test.ts +80 -0
  83. package/src/__tests__/scraper-actors.test.ts +67 -0
  84. package/src/__tests__/seedance-2-catalog.test.ts +18 -0
  85. package/src/__tests__/seedance-2-credit-id.test.ts +23 -0
  86. package/src/__tests__/seedance-aspects.test.ts +52 -0
  87. package/src/__tests__/selector.test.ts +1151 -0
  88. package/src/__tests__/settled-with-limit.test.ts +214 -0
  89. package/src/__tests__/social-media-specs.test.ts +129 -0
  90. package/src/__tests__/sub-workflow-validation.test.ts +88 -0
  91. package/src/__tests__/switchx-pricing.test.ts +28 -0
  92. package/src/__tests__/to-connected-references.test.ts +153 -0
  93. package/src/__tests__/utilities.test.ts +541 -0
  94. package/src/__tests__/video-analysis-pricing.test.ts +58 -0
  95. package/src/__tests__/video-analysis.test.ts +63 -0
  96. package/src/__tests__/video-audio-capability.test.ts +204 -0
  97. package/src/__tests__/video-gen-providers.test.ts +28 -0
  98. package/src/__tests__/video-mode-aliases.test.ts +150 -0
  99. package/src/__tests__/video-ref-limits.test.ts +72 -0
  100. package/src/__tests__/video-utils.test.ts +303 -0
  101. package/src/__tests__/voice-changer-models.test.ts +33 -0
  102. package/src/__tests__/workflow-export-strip.test.ts +46 -0
  103. package/src/ai-avatar-pricing.ts +213 -0
  104. package/src/ancestor-refs.ts +48 -0
  105. package/src/animals.ts +231 -0
  106. package/src/audio-crossfade-curves.ts +73 -0
  107. package/src/audio-fx-presets.ts +64 -0
  108. package/src/avatar-payload-validators.ts +214 -0
  109. package/src/caption-styles.ts +31 -0
  110. package/src/character-aspect-defaults.ts +102 -0
  111. package/src/character-facets.ts +37 -0
  112. package/src/character-mention-slug.ts +166 -0
  113. package/src/character-usage-mode.ts +109 -0
  114. package/src/character-variant-assets.ts +121 -0
  115. package/src/character-voice.ts +151 -0
  116. package/src/cinematic-avatar-pricing.ts +111 -0
  117. package/src/clone-utils.ts +46 -0
  118. package/src/combine-transitions.ts +482 -0
  119. package/src/community.ts +112 -0
  120. package/src/component-types.ts +127 -0
  121. package/src/condition-variables.ts +65 -0
  122. package/src/credit-estimators/index.ts +15 -0
  123. package/src/credit-estimators/video-utils.ts +165 -0
  124. package/src/credit-identifiers.ts +304 -0
  125. package/src/entity-approval-types.ts +31 -0
  126. package/src/entity-aspect-defaults.ts +82 -0
  127. package/src/entity-asset-types.ts +296 -0
  128. package/src/entity-image-handle.ts +36 -0
  129. package/src/extra-refs.ts +139 -0
  130. package/src/featured-entities.ts +136 -0
  131. package/src/film-pricing.ts +117 -0
  132. package/src/filter-condition.ts +250 -0
  133. package/src/flux2-pricing.ts +18 -0
  134. package/src/freecut-protocol.ts +52 -0
  135. package/src/furniture.ts +167 -0
  136. package/src/generate-text-items.ts +15 -0
  137. package/src/generated-results.ts +63 -0
  138. package/src/group-aggregation.ts +75 -0
  139. package/src/hint-graph-types.ts +18 -0
  140. package/src/i18n/action-fx.ar.ts +89 -0
  141. package/src/i18n/action-fx.de.ts +89 -0
  142. package/src/i18n/action-fx.es.ts +89 -0
  143. package/src/i18n/action-fx.fr.ts +89 -0
  144. package/src/i18n/action-fx.he.ts +89 -0
  145. package/src/i18n/action-fx.hi.ts +89 -0
  146. package/src/i18n/action-fx.ja.ts +89 -0
  147. package/src/i18n/action-fx.ko.ts +89 -0
  148. package/src/i18n/action-fx.pt-BR.ts +89 -0
  149. package/src/i18n/action-fx.ru.ts +89 -0
  150. package/src/i18n/action-fx.zh-CN.ts +89 -0
  151. package/src/i18n/aesthetic.ar.ts +170 -0
  152. package/src/i18n/aesthetic.de.ts +48 -0
  153. package/src/i18n/aesthetic.es.ts +169 -0
  154. package/src/i18n/aesthetic.fr.ts +52 -0
  155. package/src/i18n/aesthetic.he.ts +169 -0
  156. package/src/i18n/aesthetic.hi.ts +55 -0
  157. package/src/i18n/aesthetic.ja.ts +165 -0
  158. package/src/i18n/aesthetic.ko.ts +169 -0
  159. package/src/i18n/aesthetic.pt-BR.ts +148 -0
  160. package/src/i18n/aesthetic.ru.ts +155 -0
  161. package/src/i18n/aesthetic.zh-CN.ts +172 -0
  162. package/src/i18n/animals.ar.ts +145 -0
  163. package/src/i18n/animals.de.ts +144 -0
  164. package/src/i18n/animals.es.ts +158 -0
  165. package/src/i18n/animals.fr.ts +144 -0
  166. package/src/i18n/animals.he.ts +155 -0
  167. package/src/i18n/animals.hi.ts +157 -0
  168. package/src/i18n/animals.ja.ts +159 -0
  169. package/src/i18n/animals.ko.ts +159 -0
  170. package/src/i18n/animals.pt-BR.ts +157 -0
  171. package/src/i18n/animals.ru.ts +155 -0
  172. package/src/i18n/animals.zh-CN.ts +155 -0
  173. package/src/i18n/atmosphere.ar.ts +49 -0
  174. package/src/i18n/atmosphere.de.ts +47 -0
  175. package/src/i18n/atmosphere.es.ts +50 -0
  176. package/src/i18n/atmosphere.fr.ts +47 -0
  177. package/src/i18n/atmosphere.he.ts +47 -0
  178. package/src/i18n/atmosphere.hi.ts +49 -0
  179. package/src/i18n/atmosphere.ja.ts +49 -0
  180. package/src/i18n/atmosphere.ko.ts +49 -0
  181. package/src/i18n/atmosphere.pt-BR.ts +49 -0
  182. package/src/i18n/atmosphere.ru.ts +47 -0
  183. package/src/i18n/atmosphere.zh-CN.ts +152 -0
  184. package/src/i18n/backdrop.ar.ts +53 -0
  185. package/src/i18n/backdrop.de.ts +46 -0
  186. package/src/i18n/backdrop.es.ts +54 -0
  187. package/src/i18n/backdrop.fr.ts +52 -0
  188. package/src/i18n/backdrop.he.ts +51 -0
  189. package/src/i18n/backdrop.hi.ts +59 -0
  190. package/src/i18n/backdrop.ja.ts +61 -0
  191. package/src/i18n/backdrop.ko.ts +59 -0
  192. package/src/i18n/backdrop.pt-BR.ts +59 -0
  193. package/src/i18n/backdrop.ru.ts +57 -0
  194. package/src/i18n/backdrop.zh-CN.ts +57 -0
  195. package/src/i18n/camera-format.ar.ts +40 -0
  196. package/src/i18n/camera-format.de.ts +37 -0
  197. package/src/i18n/camera-format.es.ts +41 -0
  198. package/src/i18n/camera-format.fr.ts +37 -0
  199. package/src/i18n/camera-format.he.ts +37 -0
  200. package/src/i18n/camera-format.hi.ts +42 -0
  201. package/src/i18n/camera-format.ja.ts +37 -0
  202. package/src/i18n/camera-format.ko.ts +37 -0
  203. package/src/i18n/camera-format.pt-BR.ts +46 -0
  204. package/src/i18n/camera-format.ru.ts +42 -0
  205. package/src/i18n/camera-format.zh-CN.ts +42 -0
  206. package/src/i18n/camera-motions.ar.ts +86 -0
  207. package/src/i18n/camera-motions.de.ts +74 -0
  208. package/src/i18n/camera-motions.es.ts +86 -0
  209. package/src/i18n/camera-motions.fr.ts +86 -0
  210. package/src/i18n/camera-motions.he.ts +86 -0
  211. package/src/i18n/camera-motions.hi.ts +99 -0
  212. package/src/i18n/camera-motions.ja.ts +99 -0
  213. package/src/i18n/camera-motions.ko.ts +99 -0
  214. package/src/i18n/camera-motions.pt-BR.ts +99 -0
  215. package/src/i18n/camera-motions.ru.ts +99 -0
  216. package/src/i18n/camera-motions.zh-CN.ts +99 -0
  217. package/src/i18n/character-fx.ar.ts +72 -0
  218. package/src/i18n/character-fx.de.ts +72 -0
  219. package/src/i18n/character-fx.es.ts +72 -0
  220. package/src/i18n/character-fx.fr.ts +72 -0
  221. package/src/i18n/character-fx.he.ts +72 -0
  222. package/src/i18n/character-fx.hi.ts +72 -0
  223. package/src/i18n/character-fx.ja.ts +72 -0
  224. package/src/i18n/character-fx.ko.ts +72 -0
  225. package/src/i18n/character-fx.pt-BR.ts +72 -0
  226. package/src/i18n/character-fx.ru.ts +72 -0
  227. package/src/i18n/character-fx.zh-CN.ts +72 -0
  228. package/src/i18n/color-look.ar.ts +50 -0
  229. package/src/i18n/color-look.de.ts +47 -0
  230. package/src/i18n/color-look.es.ts +50 -0
  231. package/src/i18n/color-look.fr.ts +50 -0
  232. package/src/i18n/color-look.he.ts +49 -0
  233. package/src/i18n/color-look.hi.ts +52 -0
  234. package/src/i18n/color-look.ja.ts +54 -0
  235. package/src/i18n/color-look.ko.ts +54 -0
  236. package/src/i18n/color-look.pt-BR.ts +54 -0
  237. package/src/i18n/color-look.ru.ts +52 -0
  238. package/src/i18n/color-look.zh-CN.ts +53 -0
  239. package/src/i18n/composition-effects.ar.ts +26 -0
  240. package/src/i18n/composition-effects.de.ts +25 -0
  241. package/src/i18n/composition-effects.es.ts +27 -0
  242. package/src/i18n/composition-effects.fr.ts +25 -0
  243. package/src/i18n/composition-effects.he.ts +25 -0
  244. package/src/i18n/composition-effects.hi.ts +27 -0
  245. package/src/i18n/composition-effects.ja.ts +27 -0
  246. package/src/i18n/composition-effects.ko.ts +27 -0
  247. package/src/i18n/composition-effects.pt-BR.ts +25 -0
  248. package/src/i18n/composition-effects.ru.ts +82 -0
  249. package/src/i18n/composition-effects.zh-CN.ts +25 -0
  250. package/src/i18n/era.ar.ts +37 -0
  251. package/src/i18n/era.de.ts +34 -0
  252. package/src/i18n/era.es.ts +37 -0
  253. package/src/i18n/era.fr.ts +37 -0
  254. package/src/i18n/era.he.ts +36 -0
  255. package/src/i18n/era.hi.ts +39 -0
  256. package/src/i18n/era.ja.ts +41 -0
  257. package/src/i18n/era.ko.ts +39 -0
  258. package/src/i18n/era.pt-BR.ts +41 -0
  259. package/src/i18n/era.ru.ts +121 -0
  260. package/src/i18n/era.zh-CN.ts +39 -0
  261. package/src/i18n/exposure-settings.ar.ts +28 -0
  262. package/src/i18n/exposure-settings.de.ts +26 -0
  263. package/src/i18n/exposure-settings.es.ts +28 -0
  264. package/src/i18n/exposure-settings.fr.ts +29 -0
  265. package/src/i18n/exposure-settings.he.ts +28 -0
  266. package/src/i18n/exposure-settings.hi.ts +31 -0
  267. package/src/i18n/exposure-settings.ja.ts +31 -0
  268. package/src/i18n/exposure-settings.ko.ts +31 -0
  269. package/src/i18n/exposure-settings.pt-BR.ts +31 -0
  270. package/src/i18n/exposure-settings.ru.ts +31 -0
  271. package/src/i18n/exposure-settings.zh-CN.ts +31 -0
  272. package/src/i18n/framing.ar.ts +78 -0
  273. package/src/i18n/framing.de.ts +73 -0
  274. package/src/i18n/framing.es.ts +78 -0
  275. package/src/i18n/framing.fr.ts +78 -0
  276. package/src/i18n/framing.he.ts +77 -0
  277. package/src/i18n/framing.hi.ts +82 -0
  278. package/src/i18n/framing.ja.ts +84 -0
  279. package/src/i18n/framing.ko.ts +82 -0
  280. package/src/i18n/framing.pt-BR.ts +84 -0
  281. package/src/i18n/framing.ru.ts +82 -0
  282. package/src/i18n/framing.zh-CN.ts +82 -0
  283. package/src/i18n/furniture.ar.ts +92 -0
  284. package/src/i18n/furniture.de.ts +93 -0
  285. package/src/i18n/furniture.es.ts +101 -0
  286. package/src/i18n/furniture.fr.ts +93 -0
  287. package/src/i18n/furniture.he.ts +101 -0
  288. package/src/i18n/furniture.hi.ts +101 -0
  289. package/src/i18n/furniture.ja.ts +101 -0
  290. package/src/i18n/furniture.ko.ts +101 -0
  291. package/src/i18n/furniture.pt-BR.ts +101 -0
  292. package/src/i18n/furniture.ru.ts +101 -0
  293. package/src/i18n/furniture.zh-CN.ts +101 -0
  294. package/src/i18n/held-prop.ar.ts +74 -0
  295. package/src/i18n/held-prop.de.ts +65 -0
  296. package/src/i18n/held-prop.es.ts +83 -0
  297. package/src/i18n/held-prop.fr.ts +74 -0
  298. package/src/i18n/held-prop.he.ts +73 -0
  299. package/src/i18n/held-prop.hi.ts +82 -0
  300. package/src/i18n/held-prop.ja.ts +84 -0
  301. package/src/i18n/held-prop.ko.ts +84 -0
  302. package/src/i18n/held-prop.pt-BR.ts +84 -0
  303. package/src/i18n/held-prop.ru.ts +82 -0
  304. package/src/i18n/held-prop.zh-CN.ts +82 -0
  305. package/src/i18n/index.ts +208 -0
  306. package/src/i18n/instrumentation.ar.ts +195 -0
  307. package/src/i18n/instrumentation.de.ts +195 -0
  308. package/src/i18n/instrumentation.es.ts +195 -0
  309. package/src/i18n/instrumentation.fr.ts +195 -0
  310. package/src/i18n/instrumentation.he.ts +195 -0
  311. package/src/i18n/instrumentation.hi.ts +195 -0
  312. package/src/i18n/instrumentation.ja.ts +195 -0
  313. package/src/i18n/instrumentation.ko.ts +195 -0
  314. package/src/i18n/instrumentation.pt-BR.ts +195 -0
  315. package/src/i18n/instrumentation.ru.ts +195 -0
  316. package/src/i18n/instrumentation.zh-CN.ts +195 -0
  317. package/src/i18n/lens.ar.ts +24 -0
  318. package/src/i18n/lens.de.ts +24 -0
  319. package/src/i18n/lens.es.ts +24 -0
  320. package/src/i18n/lens.fr.ts +24 -0
  321. package/src/i18n/lens.he.ts +24 -0
  322. package/src/i18n/lens.hi.ts +24 -0
  323. package/src/i18n/lens.ja.ts +24 -0
  324. package/src/i18n/lens.ko.ts +24 -0
  325. package/src/i18n/lens.pt-BR.ts +24 -0
  326. package/src/i18n/lens.ru.ts +25 -0
  327. package/src/i18n/lens.zh-CN.ts +24 -0
  328. package/src/i18n/lighting.ar.ts +86 -0
  329. package/src/i18n/lighting.de.ts +84 -0
  330. package/src/i18n/lighting.es.ts +89 -0
  331. package/src/i18n/lighting.fr.ts +84 -0
  332. package/src/i18n/lighting.he.ts +88 -0
  333. package/src/i18n/lighting.hi.ts +90 -0
  334. package/src/i18n/lighting.ja.ts +90 -0
  335. package/src/i18n/lighting.ko.ts +90 -0
  336. package/src/i18n/lighting.pt-BR.ts +90 -0
  337. package/src/i18n/lighting.ru.ts +88 -0
  338. package/src/i18n/lighting.zh-CN.ts +92 -0
  339. package/src/i18n/loop-subject.ar.ts +39 -0
  340. package/src/i18n/loop-subject.de.ts +39 -0
  341. package/src/i18n/loop-subject.es.ts +39 -0
  342. package/src/i18n/loop-subject.fr.ts +39 -0
  343. package/src/i18n/loop-subject.he.ts +39 -0
  344. package/src/i18n/loop-subject.hi.ts +39 -0
  345. package/src/i18n/loop-subject.ja.ts +39 -0
  346. package/src/i18n/loop-subject.ko.ts +39 -0
  347. package/src/i18n/loop-subject.pt-BR.ts +39 -0
  348. package/src/i18n/loop-subject.ru.ts +39 -0
  349. package/src/i18n/loop-subject.zh-CN.ts +39 -0
  350. package/src/i18n/materials.ar.ts +80 -0
  351. package/src/i18n/materials.de.ts +80 -0
  352. package/src/i18n/materials.es.ts +87 -0
  353. package/src/i18n/materials.fr.ts +80 -0
  354. package/src/i18n/materials.he.ts +86 -0
  355. package/src/i18n/materials.hi.ts +86 -0
  356. package/src/i18n/materials.ja.ts +88 -0
  357. package/src/i18n/materials.ko.ts +88 -0
  358. package/src/i18n/materials.pt-BR.ts +88 -0
  359. package/src/i18n/materials.ru.ts +86 -0
  360. package/src/i18n/materials.zh-CN.ts +86 -0
  361. package/src/i18n/mood.ar.ts +61 -0
  362. package/src/i18n/mood.de.ts +61 -0
  363. package/src/i18n/mood.es.ts +66 -0
  364. package/src/i18n/mood.fr.ts +61 -0
  365. package/src/i18n/mood.he.ts +64 -0
  366. package/src/i18n/mood.hi.ts +66 -0
  367. package/src/i18n/mood.ja.ts +66 -0
  368. package/src/i18n/mood.ko.ts +66 -0
  369. package/src/i18n/mood.pt-BR.ts +64 -0
  370. package/src/i18n/mood.ru.ts +64 -0
  371. package/src/i18n/mood.zh-CN.ts +64 -0
  372. package/src/i18n/music-genre.ar.ts +302 -0
  373. package/src/i18n/music-genre.de.ts +302 -0
  374. package/src/i18n/music-genre.es.ts +302 -0
  375. package/src/i18n/music-genre.fr.ts +302 -0
  376. package/src/i18n/music-genre.he.ts +302 -0
  377. package/src/i18n/music-genre.hi.ts +302 -0
  378. package/src/i18n/music-genre.ja.ts +302 -0
  379. package/src/i18n/music-genre.ko.ts +302 -0
  380. package/src/i18n/music-genre.pt-BR.ts +302 -0
  381. package/src/i18n/music-genre.ru.ts +302 -0
  382. package/src/i18n/music-genre.zh-CN.ts +302 -0
  383. package/src/i18n/music-mood.ar.ts +75 -0
  384. package/src/i18n/music-mood.de.ts +75 -0
  385. package/src/i18n/music-mood.es.ts +75 -0
  386. package/src/i18n/music-mood.fr.ts +75 -0
  387. package/src/i18n/music-mood.he.ts +75 -0
  388. package/src/i18n/music-mood.hi.ts +75 -0
  389. package/src/i18n/music-mood.ja.ts +75 -0
  390. package/src/i18n/music-mood.ko.ts +75 -0
  391. package/src/i18n/music-mood.pt-BR.ts +75 -0
  392. package/src/i18n/music-mood.ru.ts +75 -0
  393. package/src/i18n/music-mood.zh-CN.ts +75 -0
  394. package/src/i18n/person.ar.ts +638 -0
  395. package/src/i18n/person.de.ts +629 -0
  396. package/src/i18n/person.es.ts +645 -0
  397. package/src/i18n/person.fr.ts +621 -0
  398. package/src/i18n/person.he.ts +656 -0
  399. package/src/i18n/person.hi.ts +654 -0
  400. package/src/i18n/person.ja.ts +662 -0
  401. package/src/i18n/person.ko.ts +662 -0
  402. package/src/i18n/person.pt-BR.ts +656 -0
  403. package/src/i18n/person.ru.ts +656 -0
  404. package/src/i18n/person.zh-CN.ts +656 -0
  405. package/src/i18n/photo-genre.ar.ts +58 -0
  406. package/src/i18n/photo-genre.de.ts +52 -0
  407. package/src/i18n/photo-genre.es.ts +64 -0
  408. package/src/i18n/photo-genre.fr.ts +58 -0
  409. package/src/i18n/photo-genre.he.ts +62 -0
  410. package/src/i18n/photo-genre.hi.ts +63 -0
  411. package/src/i18n/photo-genre.ja.ts +65 -0
  412. package/src/i18n/photo-genre.ko.ts +63 -0
  413. package/src/i18n/photo-genre.pt-BR.ts +65 -0
  414. package/src/i18n/photo-genre.ru.ts +63 -0
  415. package/src/i18n/photo-genre.zh-CN.ts +63 -0
  416. package/src/i18n/photographer.ar.ts +75 -0
  417. package/src/i18n/photographer.de.ts +74 -0
  418. package/src/i18n/photographer.es.ts +77 -0
  419. package/src/i18n/photographer.fr.ts +77 -0
  420. package/src/i18n/photographer.he.ts +78 -0
  421. package/src/i18n/photographer.hi.ts +80 -0
  422. package/src/i18n/photographer.ja.ts +84 -0
  423. package/src/i18n/photographer.ko.ts +84 -0
  424. package/src/i18n/photographer.pt-BR.ts +83 -0
  425. package/src/i18n/photographer.ru.ts +78 -0
  426. package/src/i18n/photographer.zh-CN.ts +78 -0
  427. package/src/i18n/pose.ar.ts +95 -0
  428. package/src/i18n/pose.de.ts +96 -0
  429. package/src/i18n/pose.es.ts +104 -0
  430. package/src/i18n/pose.fr.ts +96 -0
  431. package/src/i18n/pose.he.ts +104 -0
  432. package/src/i18n/pose.hi.ts +104 -0
  433. package/src/i18n/pose.ja.ts +104 -0
  434. package/src/i18n/pose.ko.ts +104 -0
  435. package/src/i18n/pose.pt-BR.ts +104 -0
  436. package/src/i18n/pose.ru.ts +104 -0
  437. package/src/i18n/pose.zh-CN.ts +104 -0
  438. package/src/i18n/post-process-effects.ar.ts +25 -0
  439. package/src/i18n/post-process-effects.de.ts +24 -0
  440. package/src/i18n/post-process-effects.es.ts +26 -0
  441. package/src/i18n/post-process-effects.fr.ts +24 -0
  442. package/src/i18n/post-process-effects.he.ts +24 -0
  443. package/src/i18n/post-process-effects.hi.ts +26 -0
  444. package/src/i18n/post-process-effects.ja.ts +26 -0
  445. package/src/i18n/post-process-effects.ko.ts +26 -0
  446. package/src/i18n/post-process-effects.pt-BR.ts +24 -0
  447. package/src/i18n/post-process-effects.ru.ts +24 -0
  448. package/src/i18n/post-process-effects.zh-CN.ts +24 -0
  449. package/src/i18n/render-quality.ar.ts +34 -0
  450. package/src/i18n/render-quality.de.ts +30 -0
  451. package/src/i18n/render-quality.es.ts +35 -0
  452. package/src/i18n/render-quality.fr.ts +34 -0
  453. package/src/i18n/render-quality.he.ts +33 -0
  454. package/src/i18n/render-quality.hi.ts +39 -0
  455. package/src/i18n/render-quality.ja.ts +39 -0
  456. package/src/i18n/render-quality.ko.ts +39 -0
  457. package/src/i18n/render-quality.pt-BR.ts +37 -0
  458. package/src/i18n/render-quality.ru.ts +37 -0
  459. package/src/i18n/render-quality.zh-CN.ts +37 -0
  460. package/src/i18n/seasons.ar.ts +10 -0
  461. package/src/i18n/seasons.de.ts +10 -0
  462. package/src/i18n/seasons.es.ts +10 -0
  463. package/src/i18n/seasons.fr.ts +10 -0
  464. package/src/i18n/seasons.he.ts +10 -0
  465. package/src/i18n/seasons.hi.ts +10 -0
  466. package/src/i18n/seasons.ja.ts +10 -0
  467. package/src/i18n/seasons.ko.ts +10 -0
  468. package/src/i18n/seasons.pt-BR.ts +10 -0
  469. package/src/i18n/seasons.ru.ts +10 -0
  470. package/src/i18n/seasons.zh-CN.ts +10 -0
  471. package/src/i18n/setting.ar.ts +73 -0
  472. package/src/i18n/setting.de.ts +73 -0
  473. package/src/i18n/setting.es.ts +77 -0
  474. package/src/i18n/setting.fr.ts +73 -0
  475. package/src/i18n/setting.he.ts +76 -0
  476. package/src/i18n/setting.hi.ts +76 -0
  477. package/src/i18n/setting.ja.ts +78 -0
  478. package/src/i18n/setting.ko.ts +76 -0
  479. package/src/i18n/setting.pt-BR.ts +78 -0
  480. package/src/i18n/setting.ru.ts +76 -0
  481. package/src/i18n/setting.zh-CN.ts +76 -0
  482. package/src/i18n/style.ar.ts +55 -0
  483. package/src/i18n/style.de.ts +54 -0
  484. package/src/i18n/style.es.ts +54 -0
  485. package/src/i18n/style.fr.ts +54 -0
  486. package/src/i18n/style.he.ts +54 -0
  487. package/src/i18n/style.hi.ts +54 -0
  488. package/src/i18n/style.ja.ts +54 -0
  489. package/src/i18n/style.ko.ts +54 -0
  490. package/src/i18n/style.pt-BR.ts +56 -0
  491. package/src/i18n/style.ru.ts +54 -0
  492. package/src/i18n/style.zh-CN.ts +54 -0
  493. package/src/i18n/styling.ar.ts +295 -0
  494. package/src/i18n/styling.de.ts +285 -0
  495. package/src/i18n/styling.es.ts +317 -0
  496. package/src/i18n/styling.fr.ts +285 -0
  497. package/src/i18n/styling.he.ts +307 -0
  498. package/src/i18n/styling.hi.ts +323 -0
  499. package/src/i18n/styling.ja.ts +317 -0
  500. package/src/i18n/styling.ko.ts +311 -0
  501. package/src/i18n/styling.pt-BR.ts +301 -0
  502. package/src/i18n/styling.ru.ts +301 -0
  503. package/src/i18n/styling.zh-CN.ts +307 -0
  504. package/src/i18n/temporal.ar.ts +31 -0
  505. package/src/i18n/temporal.de.ts +24 -0
  506. package/src/i18n/temporal.es.ts +27 -0
  507. package/src/i18n/temporal.fr.ts +28 -0
  508. package/src/i18n/temporal.he.ts +31 -0
  509. package/src/i18n/temporal.hi.ts +31 -0
  510. package/src/i18n/temporal.ja.ts +31 -0
  511. package/src/i18n/temporal.ko.ts +31 -0
  512. package/src/i18n/temporal.pt-BR.ts +31 -0
  513. package/src/i18n/temporal.ru.ts +31 -0
  514. package/src/i18n/temporal.zh-CN.ts +31 -0
  515. package/src/i18n/transitions.ar.ts +97 -0
  516. package/src/i18n/transitions.de.ts +97 -0
  517. package/src/i18n/transitions.es.ts +97 -0
  518. package/src/i18n/transitions.fr.ts +97 -0
  519. package/src/i18n/transitions.he.ts +97 -0
  520. package/src/i18n/transitions.hi.ts +97 -0
  521. package/src/i18n/transitions.ja.ts +97 -0
  522. package/src/i18n/transitions.ko.ts +97 -0
  523. package/src/i18n/transitions.pt-BR.ts +97 -0
  524. package/src/i18n/transitions.ru.ts +97 -0
  525. package/src/i18n/transitions.zh-CN.ts +97 -0
  526. package/src/i18n/types.ts +158 -0
  527. package/src/i18n/vehicles.ar.ts +137 -0
  528. package/src/i18n/vehicles.de.ts +125 -0
  529. package/src/i18n/vehicles.es.ts +138 -0
  530. package/src/i18n/vehicles.fr.ts +125 -0
  531. package/src/i18n/vehicles.he.ts +136 -0
  532. package/src/i18n/vehicles.hi.ts +138 -0
  533. package/src/i18n/vehicles.ja.ts +138 -0
  534. package/src/i18n/vehicles.ko.ts +138 -0
  535. package/src/i18n/vehicles.pt-BR.ts +136 -0
  536. package/src/i18n/vehicles.ru.ts +136 -0
  537. package/src/i18n/vehicles.zh-CN.ts +136 -0
  538. package/src/i18n/voice-character.ar.ts +126 -0
  539. package/src/i18n/voice-character.de.ts +126 -0
  540. package/src/i18n/voice-character.es.ts +126 -0
  541. package/src/i18n/voice-character.fr.ts +126 -0
  542. package/src/i18n/voice-character.he.ts +126 -0
  543. package/src/i18n/voice-character.hi.ts +126 -0
  544. package/src/i18n/voice-character.ja.ts +126 -0
  545. package/src/i18n/voice-character.ko.ts +126 -0
  546. package/src/i18n/voice-character.pt-BR.ts +126 -0
  547. package/src/i18n/voice-character.ru.ts +126 -0
  548. package/src/i18n/voice-character.zh-CN.ts +126 -0
  549. package/src/i18n/voice-delivery.ar.ts +77 -0
  550. package/src/i18n/voice-delivery.de.ts +77 -0
  551. package/src/i18n/voice-delivery.es.ts +77 -0
  552. package/src/i18n/voice-delivery.fr.ts +77 -0
  553. package/src/i18n/voice-delivery.he.ts +77 -0
  554. package/src/i18n/voice-delivery.hi.ts +77 -0
  555. package/src/i18n/voice-delivery.ja.ts +77 -0
  556. package/src/i18n/voice-delivery.ko.ts +77 -0
  557. package/src/i18n/voice-delivery.pt-BR.ts +77 -0
  558. package/src/i18n/voice-delivery.ru.ts +77 -0
  559. package/src/i18n/voice-delivery.zh-CN.ts +77 -0
  560. package/src/i18n/weapons.ar.ts +115 -0
  561. package/src/i18n/weapons.de.ts +114 -0
  562. package/src/i18n/weapons.es.ts +116 -0
  563. package/src/i18n/weapons.fr.ts +103 -0
  564. package/src/i18n/weapons.he.ts +114 -0
  565. package/src/i18n/weapons.hi.ts +116 -0
  566. package/src/i18n/weapons.ja.ts +116 -0
  567. package/src/i18n/weapons.ko.ts +116 -0
  568. package/src/i18n/weapons.pt-BR.ts +114 -0
  569. package/src/i18n/weapons.ru.ts +114 -0
  570. package/src/i18n/weapons.zh-CN.ts +114 -0
  571. package/src/image-critic-node.ts +61 -0
  572. package/src/image-critic-types.ts +40 -0
  573. package/src/index.ts +866 -0
  574. package/src/inject-upstream.ts +15 -0
  575. package/src/inpaint-region.ts +51 -0
  576. package/src/json-evaluator.ts +732 -0
  577. package/src/json-path.ts +52 -0
  578. package/src/lip-sync-pricing.ts +90 -0
  579. package/src/list-merge.ts +40 -0
  580. package/src/list-sort.ts +122 -0
  581. package/src/list-source-resolver.ts +50 -0
  582. package/src/llm-models.ts +245 -0
  583. package/src/location-mention-slug.ts +291 -0
  584. package/src/location-preset-catalog-map.ts +128 -0
  585. package/src/loop-delimiter.ts +73 -0
  586. package/src/lora-routing.ts +95 -0
  587. package/src/lottie-overlay-catalog.ts +175 -0
  588. package/src/lottie-slots.ts +309 -0
  589. package/src/model-catalog.ts +2386 -0
  590. package/src/model-constants.ts +1910 -0
  591. package/src/model-tree.ts +120 -0
  592. package/src/monetization.ts +15 -0
  593. package/src/multi-pick.ts +42 -0
  594. package/src/node-default-mappings.ts +262 -0
  595. package/src/node-mappable-fields.ts +70 -0
  596. package/src/node-preset-export.ts +56 -0
  597. package/src/node-preset-extract.ts +147 -0
  598. package/src/node-refs.ts +253 -0
  599. package/src/node-runtime-keys.ts +117 -0
  600. package/src/object-aspect-defaults.ts +72 -0
  601. package/src/object-picker-types.ts +22 -0
  602. package/src/parameter-node-value.ts +284 -0
  603. package/src/pinterest-url.ts +28 -0
  604. package/src/pipeline-chat.ts +72 -0
  605. package/src/pipeline-defaults.ts +318 -0
  606. package/src/pipeline-events.ts +162 -0
  607. package/src/pipeline-state-types.ts +196 -0
  608. package/src/pipeline-types.ts +647 -0
  609. package/src/pipeline-validation.ts +87 -0
  610. package/src/presentation-types.ts +23 -0
  611. package/src/presentation-utils.ts +397 -0
  612. package/src/producer-types.ts +188 -0
  613. package/src/progress-curve.ts +99 -0
  614. package/src/provider-directive-defaults.ts +69 -0
  615. package/src/reduce-strategy-registry.ts +121 -0
  616. package/src/reference-board-templates.ts +81 -0
  617. package/src/reference-roles.ts +153 -0
  618. package/src/reference-sheet/__tests__/board-to-column.test.ts +20 -0
  619. package/src/reference-sheet/__tests__/catalog.test.ts +50 -0
  620. package/src/reference-sheet/__tests__/cost.test.ts +38 -0
  621. package/src/reference-sheet/__tests__/no-drift.test.ts +28 -0
  622. package/src/reference-sheet/__tests__/panel-plan.test.ts +61 -0
  623. package/src/reference-sheet/__tests__/panel-prompts.test.ts +17 -0
  624. package/src/reference-sheet/__tests__/plan-generation.test.ts +72 -0
  625. package/src/reference-sheet/__tests__/presets.test.ts +54 -0
  626. package/src/reference-sheet/__tests__/types.test.ts +24 -0
  627. package/src/reference-sheet/catalog.ts +144 -0
  628. package/src/reference-sheet/cost.ts +37 -0
  629. package/src/reference-sheet/credit-id.ts +7 -0
  630. package/src/reference-sheet/index.ts +8 -0
  631. package/src/reference-sheet/panel-plan.ts +65 -0
  632. package/src/reference-sheet/panel-prompts.ts +14 -0
  633. package/src/reference-sheet/plan-generation.ts +79 -0
  634. package/src/reference-sheet/presets.ts +77 -0
  635. package/src/reference-sheet/types.ts +92 -0
  636. package/src/repeat-types.ts +97 -0
  637. package/src/resolve-field-mappings.ts +119 -0
  638. package/src/route-filter.ts +80 -0
  639. package/src/scene-helper-types.ts +249 -0
  640. package/src/scene-node-types.ts +281 -0
  641. package/src/scraper-actors.ts +57 -0
  642. package/src/scraper-output-schemas.ts +25 -0
  643. package/src/seasons.ts +45 -0
  644. package/src/selector.ts +864 -0
  645. package/src/settled-with-limit.ts +42 -0
  646. package/src/shot-element.ts +43 -0
  647. package/src/social-media-specs.ts +121 -0
  648. package/src/social-post.ts +24 -0
  649. package/src/sub-workflow-validation.ts +78 -0
  650. package/src/supported-fonts.ts +40 -0
  651. package/src/surround.ts +113 -0
  652. package/src/switchx-pricing.ts +33 -0
  653. package/src/text-separators.ts +59 -0
  654. package/src/to-connected-references.ts +77 -0
  655. package/src/types.ts +272 -0
  656. package/src/variant-job-id.ts +17 -0
  657. package/src/vehicles.ts +213 -0
  658. package/src/video-analysis-pricing.ts +74 -0
  659. package/src/video-analysis.ts +127 -0
  660. package/src/video-duration.ts +25 -0
  661. package/src/voice-changer-models.ts +36 -0
  662. package/src/voice-matcher-types.ts +37 -0
  663. package/src/voices.ts +92 -0
  664. package/src/weapons.ts +190 -0
  665. package/src/workflow-export.ts +153 -0
@@ -0,0 +1,102 @@
1
+ // ─────────────────────────────────────────────────────────────────────────────
2
+ // Character aspect-ratio defaults
3
+ // ─────────────────────────────────────────────────────────────────────────────
4
+ //
5
+ // Characters are vertical subjects — the historical 16:9 default produced wide,
6
+ // crop-unfriendly portraits. The per-asset-type table below picks the ratio
7
+ // that fits each asset's natural framing:
8
+ //
9
+ // - Portrait / canonical head shot → 3:4
10
+ // - Expressions (head-and-shoulders) → 1:1
11
+ // - Poses (full-body) → 9:16
12
+ // - Head angles → 3:4
13
+ // - Body angles (full-body) → 9:16
14
+ // - Lighting variations (full-body context) → 3:4
15
+ // - Motions (vertical clip, full-body i2v) → 9:16
16
+ //
17
+ // Resolution precedence (low → high):
18
+ // 1. Per-asset-type default (this table)
19
+ // 2. Character node's `defaultAssetAspectRatio` (user override on the canvas
20
+ // node — flows in as `characterNodeAspectRatio` in the request body)
21
+ // 3. Explicit `aspectRatio` on the API request (caller wins)
22
+ //
23
+ // The character node's `defaultAssetAspectRatio` toggle (1:1 / 3:4 / 16:9 /
24
+ // 9:16) drives BOTH the canvas thumbnail crop AND this override slot.
25
+ // ─────────────────────────────────────────────────────────────────────────────
26
+
27
+ export const CHARACTER_ASPECT_OPTIONS = ["1:1", "3:4", "16:9", "9:16"] as const
28
+ export type CharacterAspectRatio = (typeof CHARACTER_ASPECT_OPTIONS)[number]
29
+
30
+ /**
31
+ * The asset categories with distinct natural framing. Aliases:
32
+ * - `angles` is the legacy single-surface key (now head-and-shoulders by
33
+ * default). Use `headAngles` for clarity in new code.
34
+ * - `bodyAngles` is the new full-body column added in migration 118.
35
+ */
36
+ export type CharacterAssetTypeForAspect =
37
+ | "portrait"
38
+ | "expressions"
39
+ | "poses"
40
+ | "angles"
41
+ | "headAngles"
42
+ | "bodyAngles"
43
+ | "lighting"
44
+ | "motions"
45
+
46
+ export const CHARACTER_ASPECT_DEFAULTS: Record<
47
+ CharacterAssetTypeForAspect,
48
+ CharacterAspectRatio
49
+ > = {
50
+ portrait: "3:4",
51
+ // Legacy `angles` was head angles — keep its default aligned with `headAngles`.
52
+ angles: "3:4",
53
+ headAngles: "3:4",
54
+ // Full-body framings:
55
+ poses: "9:16",
56
+ bodyAngles: "9:16",
57
+ motions: "9:16",
58
+ // Expressions are head-and-shoulders — square framing matches the existing
59
+ // expression card grid and avoids cutting off forehead/chin.
60
+ expressions: "1:1",
61
+ // Lighting variations are framed like portraits (3:4) — they're full-body in
62
+ // the prompt but the user usually wants to see the lighting on the face.
63
+ lighting: "3:4",
64
+ }
65
+
66
+ export function isCharacterAspectRatio(s: string): s is CharacterAspectRatio {
67
+ return (CHARACTER_ASPECT_OPTIONS as readonly string[]).includes(s)
68
+ }
69
+
70
+ export interface ResolveCharacterAspectOptions {
71
+ /** Explicit `aspectRatio` on the request body — highest precedence. */
72
+ readonly explicit?: string | null
73
+ /**
74
+ * The character node's `defaultAssetAspectRatio` — set per-canvas-node via
75
+ * the 4-pill toggle on the character node. Flows through the API as
76
+ * `characterNodeAspectRatio`.
77
+ */
78
+ readonly nodeOverride?: string | null
79
+ /** What's being generated. Drives the default when nothing else is set. */
80
+ readonly assetType: CharacterAssetTypeForAspect
81
+ }
82
+
83
+ /**
84
+ * Resolve the final aspect ratio for a character generation request.
85
+ *
86
+ * Precedence: explicit > node override > per-asset-type default. The two
87
+ * "soft" inputs are tolerated as raw strings and only honored when they
88
+ * parse to a value in `CHARACTER_ASPECT_OPTIONS` — anything else falls
89
+ * through to the next layer (so a stale enum value doesn't poison the
90
+ * generation).
91
+ */
92
+ export function resolveCharacterAspectRatio(
93
+ opts: ResolveCharacterAspectOptions,
94
+ ): CharacterAspectRatio {
95
+ if (opts.explicit && isCharacterAspectRatio(opts.explicit)) {
96
+ return opts.explicit
97
+ }
98
+ if (opts.nodeOverride && isCharacterAspectRatio(opts.nodeOverride)) {
99
+ return opts.nodeOverride
100
+ }
101
+ return CHARACTER_ASPECT_DEFAULTS[opts.assetType]
102
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Facets of a source character/asset that can be selectively injected into a
3
+ * consumer character via the Character node's Assets handle (element/asset
4
+ * injection, P2). Single source of truth for the frontend facet chip options
5
+ * AND the backend facet-extraction instructions.
6
+ *
7
+ * `full` injects the whole source description verbatim (no LLM call needed).
8
+ * Every other facet is LLM-extracted on demand from the source's
9
+ * `canonicalDescription` via `POST /v1/character/extract-facet`.
10
+ */
11
+ export interface CharacterFacet {
12
+ /** Stable id stored on the connection (`assetInjections[].facet`). */
13
+ readonly id: string
14
+ /** Human label shown in the facet chip. */
15
+ readonly label: string
16
+ /** What the extractor should pull from the source description. Phrased to
17
+ * complete "Extract {instruction} …". Unused for `full`. */
18
+ readonly instruction: string
19
+ }
20
+
21
+ export const CHARACTER_FACETS: readonly CharacterFacet[] = [
22
+ { id: "full", label: "Full likeness", instruction: "the complete physical likeness and appearance" },
23
+ { id: "hair", label: "Hair", instruction: "ONLY the hair — style, length, colour, and texture" },
24
+ { id: "skin-tone", label: "Skin tone", instruction: "ONLY the skin tone / complexion" },
25
+ { id: "face", label: "Face", instruction: "ONLY the facial features — face shape, eyes, nose, mouth, eyebrows, and any distinguishing marks" },
26
+ { id: "style", label: "Style", instruction: "ONLY the overall visual style, aesthetic, and vibe — not specific garments" },
27
+ { id: "outfit", label: "Outfit", instruction: "ONLY the clothing, outfit, and wardrobe" },
28
+ { id: "personality", label: "Personality", instruction: "ONLY the personality, demeanour, and characteristic expression" },
29
+ ] as const
30
+
31
+ export const DEFAULT_CHARACTER_FACET = "full"
32
+
33
+ export const CHARACTER_FACET_IDS: ReadonlySet<string> = new Set(CHARACTER_FACETS.map((f) => f.id))
34
+
35
+ export function getCharacterFacet(id: string): CharacterFacet | undefined {
36
+ return CHARACTER_FACETS.find((f) => f.id === id)
37
+ }
@@ -0,0 +1,166 @@
1
+ import { isUsageMode, type UsageMode } from "./character-usage-mode.js"
2
+
3
+ /**
4
+ * Slugify a name (character or variant) for use in @-mention tokens.
5
+ * Lowercase, strip non-alphanumeric, collapse runs of dashes.
6
+ */
7
+ export function characterMentionSlug(name: string): string {
8
+ return name
9
+ .toLowerCase()
10
+ .replace(/[^a-z0-9]+/g, "-")
11
+ .replace(/-+/g, "-")
12
+ .replace(/^-|-$/g, "")
13
+ }
14
+
15
+ export interface CharacterMentionTokenInfo {
16
+ readonly token: string
17
+ readonly characterSlug: string
18
+ /**
19
+ * 1-based positional index assigned at insertion time by the autocomplete.
20
+ * Lets the user wire a literal-text mention (`@kira:1`) to a final-prompt
21
+ * identity directive (`Image 1 (person) — match exactly…`) so the order in
22
+ * the typed prompt matches the order in the assembled directive block.
23
+ */
24
+ readonly imageIndex: number
25
+ readonly variantSlug: string | null
26
+ /**
27
+ * Optional per-mention usage-mode override (e.g. `:face`, `:style`). When
28
+ * `null`, the assembled directive falls back to the source character node's
29
+ * `defaultUsageMode`, then to the global `"identical"` default. Always one
30
+ * of the entries in `USAGE_MODES` when non-null — the parser rejects any
31
+ * other 4-part token.
32
+ */
33
+ readonly usageMode: UsageMode | null
34
+ /**
35
+ * Additive per-mention identity-lock sentinel (Unified Reference Roles,
36
+ * Task 4 + F4). Tri-state: `true` (trailing `~lock`, force lock ON) |
37
+ * `false` (trailing `~nolock`, force lock OFF — suppresses a ref-level
38
+ * `identityLock.enabled = true`) | ABSENT/undefined (neither sentinel —
39
+ * inherit the ref/source default; byte-identical to the pre-Task-4 shape).
40
+ * Only ACTED UPON by the HYBRID resolvers; the LEGACY resolvers ignore it
41
+ * entirely, so both `~lock` and `~nolock` are inert on the legacy path.
42
+ */
43
+ readonly lock?: boolean
44
+ readonly offset: number
45
+ }
46
+
47
+ /**
48
+ * Parse a single `@<character>:<index>(:<variant>)?(:<usageMode>)?` token.
49
+ *
50
+ * Supported shapes (each segment after `:` may contain internal dashes, so
51
+ * `@young-kira:1:soft-smile` parses unambiguously as character + index +
52
+ * variant):
53
+ *
54
+ * - `@kira:1` → canonical, default mode
55
+ * - `@kira:1:smile` → variant smile, default mode
56
+ * - `@kira:1:face` → canonical, mode "face" (mode is detected by
57
+ * checking the 3rd segment against `USAGE_MODES`)
58
+ * - `@kira:1:smile:face` → variant smile, mode "face"
59
+ * - `@kira:1:smile:bogus` → null (4-part rejected when last segment is not
60
+ * a valid usage mode — keeps the format strict)
61
+ *
62
+ * Format change: as of the index-in-slug update, the index segment is required.
63
+ * Bare `@kira` is not a mention; the autocomplete always inserts at least
64
+ * `@kira:N`.
65
+ *
66
+ * `knownCharacterSlugs` is no longer needed for parsing (the structure is
67
+ * unambiguous given the closed `USAGE_MODES` enum) — it remains accepted for
68
+ * API compatibility but ignored here. `findCharacterMentionTokens` still uses
69
+ * it to filter unknown characters.
70
+ */
71
+ export function parseCharacterMentionToken(
72
+ text: string,
73
+ _knownCharacterSlugs?: readonly string[],
74
+ ): { characterSlug: string; imageIndex: number; variantSlug: string | null; usageMode: UsageMode | null; lock?: boolean } | null {
75
+ if (!text.startsWith("@")) return null
76
+ let rest = text.slice(1)
77
+ if (rest.length === 0 || !/^[a-z]/.test(rest)) return null
78
+
79
+ // Additive `~lock` / `~nolock` sentinels (Unified Reference Roles, Task 4 +
80
+ // F4). Strip a trailing `~nolock` (force lock OFF) or `~lock` (force lock ON)
81
+ // BEFORE splitting on ":" so the segment grammar below is byte-identical to
82
+ // pre-Task-4 (a `~` can never appear inside a segment — the shapes are
83
+ // `[a-z][a-z0-9-]*`). Check `~nolock` FIRST: `"x~nolock".endsWith("~lock")` is
84
+ // false (last 5 chars "olock"), but the explicit ordering keeps intent clear.
85
+ // A token with NEITHER sentinel is untouched here and gains NO `lock` key
86
+ // (byte-identical). The parsed tri-state `lock` (true/false/undefined) is only
87
+ // honored by the HYBRID resolvers — undefined inherits the ref default, true
88
+ // forces the lock on, false forces it off.
89
+ let lockField: { lock?: boolean } = {}
90
+ if (rest.endsWith("~nolock")) {
91
+ rest = rest.slice(0, -"~nolock".length)
92
+ lockField = { lock: false }
93
+ } else if (rest.endsWith("~lock")) {
94
+ rest = rest.slice(0, -"~lock".length)
95
+ lockField = { lock: true }
96
+ }
97
+
98
+ // Format: <character>:<index>(:<variant|mode>)?(:<mode>)?.
99
+ // Splitting on ":" requires 2–4 parts (no bare @character anymore).
100
+ const parts = rest.split(":")
101
+ if (parts.length < 2 || parts.length > 4) return null
102
+
103
+ const [characterSlug, indexStr, third, fourth] = parts
104
+ if (!/^[a-z][a-z0-9-]*$/.test(characterSlug)) return null
105
+ if (!/^\d+$/.test(indexStr)) return null
106
+ const imageIndex = parseInt(indexStr, 10)
107
+ if (!Number.isInteger(imageIndex) || imageIndex < 1) return null
108
+
109
+ // 2-part: kira:1 — canonical, default mode.
110
+ if (parts.length === 2) {
111
+ return { characterSlug, imageIndex, variantSlug: null, usageMode: null, ...lockField }
112
+ }
113
+
114
+ // 3-part: kira:1:X — X is either a usage-mode keyword or a variant slug.
115
+ // The closed `USAGE_MODES` enum + the variant-slug shape constraint
116
+ // (`[a-z][a-z0-9-]*`) makes this unambiguous. A keyword like "face" wins
117
+ // the mode interpretation; anything else is treated as a variant slug.
118
+ if (parts.length === 3) {
119
+ if (!/^[a-z][a-z0-9-]*$/.test(third)) return null
120
+ if (isUsageMode(third)) {
121
+ return { characterSlug, imageIndex, variantSlug: null, usageMode: third, ...lockField }
122
+ }
123
+ return { characterSlug, imageIndex, variantSlug: third, usageMode: null, ...lockField }
124
+ }
125
+
126
+ // 4-part: kira:1:smile:mode — variant + mode override. Both segments must
127
+ // satisfy their respective shape; an unknown mode kills the token entirely
128
+ // (callers fall back to literal text, matching unknown-character behavior).
129
+ if (parts.length === 4) {
130
+ if (!/^[a-z][a-z0-9-]*$/.test(third)) return null
131
+ if (!isUsageMode(fourth)) return null
132
+ return { characterSlug, imageIndex, variantSlug: third, usageMode: fourth, ...lockField }
133
+ }
134
+
135
+ return null
136
+ }
137
+
138
+ /** Find all @-mentions in a prompt that match a known character slug. */
139
+ export function findCharacterMentionTokens(
140
+ prompt: string,
141
+ knownCharacterSlugs: readonly string[],
142
+ ): CharacterMentionTokenInfo[] {
143
+ const tokens: CharacterMentionTokenInfo[] = []
144
+ // `@<character>:<index>(:<variant|mode>)?(:<mode>)?` preceded by
145
+ // non-alphanumeric (or start of string) to prevent email-like matches.
146
+ // The `\d+` index segment is required — see `parseCharacterMentionToken`
147
+ // for the rationale. The two optional trailing `:<slug>` groups absorb
148
+ // either `:<variant>`, `:<mode>`, or `:<variant>:<mode>`; the parser
149
+ // disambiguates which segment is which based on `USAGE_MODES`. The optional
150
+ // trailing `(?:~(?:no)?lock)?` absorbs the additive Task-4/F4 identity-lock
151
+ // sentinel (`~lock` force-on OR `~nolock` force-off) INTO the token (so it is
152
+ // spliced out at resolve time); it is optional, so a lock-less token matches
153
+ // byte-identically to before. The `(?![a-z0-9-])` word boundary keeps
154
+ // `~locked` / `~nolockx` literal.
155
+ const regex = /(?:^|[^a-zA-Z0-9])(@[a-z][a-z0-9-]*:\d+(?::[a-z][a-z0-9-]*)?(?::[a-z][a-z0-9-]*)?(?:~(?:no)?lock(?![a-z0-9-]))?)/g
156
+ const knownSet = new Set(knownCharacterSlugs)
157
+ for (const match of prompt.matchAll(regex)) {
158
+ const token = match[1]
159
+ const offset = (match.index ?? 0) + (match[0].length - token.length)
160
+ const parsed = parseCharacterMentionToken(token)
161
+ if (parsed && knownSet.has(parsed.characterSlug)) {
162
+ tokens.push({ token, ...parsed, offset })
163
+ }
164
+ }
165
+ return tokens
166
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Character-mention usage modes — describe HOW the AI should consume a
3
+ * referenced character image. The mode shapes the per-image directive in the
4
+ * assembled prompt (see `usageModeDirective`) so the same character reference
5
+ * can act as a full likeness replacement, a face-only crop, a style donor,
6
+ * etc., without needing different upstream images.
7
+ *
8
+ * The mode source-of-truth lives in two places:
9
+ *
10
+ * 1. **Character node default** — `CharacterNodeData.defaultUsageMode`.
11
+ * Set via the small dropdown in the character node's title row.
12
+ * Propagates into every `ConnectedReference` derived from that node.
13
+ *
14
+ * 2. **Per-mention override** — optional 4th segment in the slug,
15
+ * e.g. `@kira:1:smile:face` overrides the character's default for that
16
+ * specific mention. Parsed by `parseCharacterMentionToken` in
17
+ * `character-mention-slug.ts`.
18
+ *
19
+ * Mode resolution at prompt-build time (in `resolveCharacterMentions`):
20
+ * token.usageMode ?? ref.defaultUsageMode ?? "identical"
21
+ */
22
+
23
+ export const USAGE_MODES = [
24
+ "identical",
25
+ "face",
26
+ "face-pose",
27
+ "pose",
28
+ "emotion",
29
+ "style",
30
+ "name",
31
+ "none",
32
+ ] as const
33
+
34
+ export type UsageMode = (typeof USAGE_MODES)[number]
35
+
36
+ /** Default mode when neither the slug nor the character node specifies one. */
37
+ export const DEFAULT_USAGE_MODE: UsageMode = "identical"
38
+
39
+ /** Type guard — narrows an arbitrary string to `UsageMode` when valid. */
40
+ export function isUsageMode(s: string): s is UsageMode {
41
+ return (USAGE_MODES as readonly string[]).includes(s)
42
+ }
43
+
44
+ /**
45
+ * Return the natural-language directive appended to a per-image bullet for the
46
+ * given mode. The text is intentionally explicit so the model knows exactly
47
+ * which aspects of the reference to take and which to derive from the rest of
48
+ * the prompt.
49
+ *
50
+ * `name` and `none` are minimal-intervention modes that return `null` — the
51
+ * caller emits NO trailing directive for them. `name` still includes the
52
+ * character name in the labeled subject (`Image A (shira)`); `none` suppresses
53
+ * the name as well (bare `Image A`) and excludes the character entirely from
54
+ * the top-level "Use these characters:" header when ALL of its mentions are
55
+ * `none`. Use these when the user wants the visual reference to speak for
56
+ * itself without textual bias.
57
+ *
58
+ * Calling sites: `resolveCharacterMentions` (shared/prompt-builder.ts) and the
59
+ * per-character canonical fallback (also in prompt-builder.ts), plus the video
60
+ * mention resolvers on frontend (execute-node.ts) and backend (payload-builder.ts)
61
+ * which mirror the same directive shape.
62
+ */
63
+ export function usageModeDirective(mode: UsageMode): string | null {
64
+ switch (mode) {
65
+ case "identical":
66
+ return "The subject must remain exactly the same person — preserve 100% facial identity, bone structure, skin tone, proportions, and all unique features. Do not alter eyes, nose, mouth, or facial shape. Maintain natural skin texture, including pores and imperfections."
67
+ case "face":
68
+ return "Take ONLY the facial features and expression — preserve 100% facial identity, bone structure, skin tone, and all unique features. Do not alter eyes, nose, mouth, or facial shape. Maintain natural skin texture, including pores and imperfections. Adopt clothing, hair styling, and posture from the rest of the prompt."
69
+ case "face-pose":
70
+ return "Take the facial features AND body pose — preserve 100% facial identity, bone structure, skin tone, and all unique features. Do not alter eyes, nose, mouth, or facial shape. Maintain natural skin texture. Adopt clothing and styling from the rest of the prompt."
71
+ case "pose":
72
+ return "Take only the body pose and posture — do not copy facial identity, features, or skin. Adopt face, clothing, hair, and all other details from the rest of the prompt."
73
+ case "emotion":
74
+ return "Take only the emotional expression — preserve 100% facial identity and all unique features unchanged. Adopt face shape, clothing, body, and pose from the rest of the prompt; transfer only the emotional cue."
75
+ case "style":
76
+ return "Take only the visual style and tone (lighting, color grade, atmosphere). Do not copy the subject's identity, clothing, or pose."
77
+ case "name":
78
+ case "none":
79
+ return null
80
+ }
81
+ }
82
+
83
+ /** Human-readable label for the dropdown / badge UI. */
84
+ export function usageModeLabel(mode: UsageMode): string {
85
+ switch (mode) {
86
+ case "identical": return "Identical"
87
+ case "face": return "Face only"
88
+ case "face-pose": return "Face + Pose"
89
+ case "pose": return "Pose only"
90
+ case "emotion": return "Emotion only"
91
+ case "style": return "Style only"
92
+ case "name": return "Name only"
93
+ case "none": return "None"
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Whether the labeled subject for this mode should include the character name
99
+ * in parens (e.g. `Image A (shira)`) or stay bare (`Image A`). Only `none`
100
+ * returns false — every other mode (including `name`) keeps the name so the
101
+ * model can correlate the bullet with a named entity in the rest of the
102
+ * prompt. Used by `resolveCharacterMentions` to decide the subject form AND to
103
+ * filter the top-level "Use these characters:" header (a character whose
104
+ * mentions are ALL `none` is invisible textually — only the image is
105
+ * attached).
106
+ */
107
+ export function usageModeIncludesName(mode: UsageMode): boolean {
108
+ return mode !== "none"
109
+ }
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Single source of truth for a character's `{name, url}[]` variant-asset buckets
3
+ * — the image/video variants that are expandable into connected references and
4
+ * therefore selectable in the reference picker AND `@`-mentionable in prompts.
5
+ *
6
+ * Historically the expansion list was hardcoded (6 copies across frontend
7
+ * `connected-references.ts` / `connected-refs-builder.ts` / `execute-node.ts` and
8
+ * backend `payload-builder.ts`), so when wardrobe (`outfitVariations`) and detail
9
+ * close-ups (`detailCloseups`) were added — same `{name,url}[]` shape, written by
10
+ * studio.nodaro.ai — they were silently dropped from the picker and `@` list.
11
+ * Drive every expansion site off this constant so a new bucket can't drift again.
12
+ *
13
+ * NOT included (different shapes, handled elsewhere):
14
+ * - `sheets` (`ReferenceSheet[]` — composited multi-panel boards)
15
+ * - `referenceVideosByVariant` (`Record<variant, url[]>` — per-emotion video refs)
16
+ */
17
+ export const CHARACTER_VARIANT_ASSET_BUCKETS = [
18
+ "expressions",
19
+ "poses",
20
+ "motions",
21
+ "angles",
22
+ "bodyAngles",
23
+ "lightingVariations",
24
+ "outfitVariations",
25
+ "detailCloseups",
26
+ ] as const
27
+
28
+ export type CharacterVariantAssetBucket = (typeof CHARACTER_VARIANT_ASSET_BUCKETS)[number]
29
+
30
+ export interface CharacterVariantAssetItem {
31
+ readonly name: string
32
+ readonly url: string
33
+ readonly description?: string
34
+ }
35
+
36
+ /**
37
+ * Build the `{ bucket: items[] }` map for every variant-asset bucket from a
38
+ * character node's data. Missing / non-array buckets coerce to `[]`. One helper
39
+ * for all six expansion sites so the bucket set is defined exactly once.
40
+ */
41
+ export function characterVariantAssetArrays(
42
+ data: Record<string, unknown> | null | undefined,
43
+ ): Record<CharacterVariantAssetBucket, readonly CharacterVariantAssetItem[]> {
44
+ const out = {} as Record<CharacterVariantAssetBucket, readonly CharacterVariantAssetItem[]>
45
+ for (const bucket of CHARACTER_VARIANT_ASSET_BUCKETS) {
46
+ const value = data?.[bucket]
47
+ out[bucket] = Array.isArray(value) ? (value as readonly CharacterVariantAssetItem[]) : []
48
+ }
49
+ return out
50
+ }
51
+
52
+ /**
53
+ * Map a character's composite reference `sheets` (ReferenceSheet[] — a different
54
+ * shape, with a composite board `url` + `type`/`skin`) into mentionable
55
+ * `{name,url}` items so they too can be picked / `@`-mentioned. Each sheet → one
56
+ * item named `"<type> <skin>"` (e.g. "turnaround studio"). Drops url-less sheets.
57
+ */
58
+ export function characterSheetRefItems(sheets: unknown): CharacterVariantAssetItem[] {
59
+ if (!Array.isArray(sheets)) return []
60
+ return sheets.flatMap((s) => {
61
+ const sheet = s as { url?: unknown; type?: unknown; skin?: unknown }
62
+ if (!sheet || typeof sheet.url !== "string" || !sheet.url) return []
63
+ const type = typeof sheet.type === "string" && sheet.type ? sheet.type : "sheet"
64
+ const skin = typeof sheet.skin === "string" && sheet.skin ? ` ${sheet.skin}` : ""
65
+ return [{ name: `${type}${skin}`, url: sheet.url }]
66
+ })
67
+ }
68
+
69
+ /** Legacy `selected_asset_by_variant` keys that hold boards born before the
70
+ * `boards` column existed (studio.nodaro.ai's reserved namespace). */
71
+ const BOARD_SHIM_KEY = "studioBoard"
72
+ const BOARD_SHIM_PREFIX = "studioBoard:"
73
+
74
+ /**
75
+ * Resolve a character's named reference boards from BOTH the `boards` column AND
76
+ * the LEGACY `selected_asset_by_variant` shim (`studioBoard` / `studioBoard:<name>`)
77
+ * — mirroring studio.nodaro.ai's read (entity-boards.ts), which merges both since
78
+ * pre-column boards still live in the shim. Column wins on duplicate name; the
79
+ * unnamed legacy board is named "board". Drops url-less entries.
80
+ */
81
+ export function characterBoardItems(
82
+ data: Record<string, unknown> | null | undefined,
83
+ ): CharacterVariantAssetItem[] {
84
+ const column: CharacterVariantAssetItem[] = Array.isArray(data?.boards)
85
+ ? (data!.boards as unknown[]).flatMap((b) => {
86
+ const board = b as { name?: unknown; url?: unknown }
87
+ if (!board || typeof board.url !== "string" || !board.url) return []
88
+ return [{ name: typeof board.name === "string" && board.name ? board.name : "board", url: board.url }]
89
+ })
90
+ : []
91
+
92
+ const map = (data?.selectedAssetByVariant ?? {}) as Record<string, unknown>
93
+ const shim: CharacterVariantAssetItem[] = []
94
+ const legacy = map[BOARD_SHIM_KEY]
95
+ if (typeof legacy === "string" && legacy) shim.push({ name: "board", url: legacy })
96
+ for (const [k, v] of Object.entries(map)) {
97
+ if (k.startsWith(BOARD_SHIM_PREFIX) && typeof v === "string" && v) {
98
+ shim.push({ name: k.slice(BOARD_SHIM_PREFIX.length) || "board", url: v })
99
+ }
100
+ }
101
+
102
+ const haveNames = new Set(column.map((b) => b.name.toLowerCase()))
103
+ return [...column, ...shim.filter((b) => !haveNames.has(b.name.toLowerCase()))]
104
+ }
105
+
106
+ /**
107
+ * The COMPLETE set of mentionable character asset arrays: the `{name,url}[]`
108
+ * variant buckets + derived `sheets` and `boards` buckets. This is what the
109
+ * connected-reference / `@`-mention expansion sites iterate, so every
110
+ * studio-produced asset (variants, composite sheets, AND boards — incl. legacy
111
+ * shim boards) surfaces in the reference picker and `@` list.
112
+ */
113
+ export function characterMentionableAssetArrays(
114
+ data: Record<string, unknown> | null | undefined,
115
+ ): Record<string, readonly CharacterVariantAssetItem[]> {
116
+ return {
117
+ ...characterVariantAssetArrays(data),
118
+ sheets: characterSheetRefItems(data?.sheets),
119
+ boards: characterBoardItems(data),
120
+ }
121
+ }