@nodaro/prompts 1.35.0 → 1.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,18 @@
1
1
  import type { FactoryPreset } from "./types.js"
2
2
 
3
+ // ── UGC & Creator: shared sentences, kept word for word ─────────────────
4
+ const UGC_TAIL = "Keep it subtitle-free, do not generate a watermark."
5
+ const UGC_PAUSE = "A short natural pause before the first word and after the last."
6
+ const ugcSpeech = (line: string): string =>
7
+ `The person says, in a natural American accent, lively and conversational, quicker on connecting words and slower on numbers: "{line || ${line}}"`
8
+ /** Seedance 2.5, vertical, 8 s, 720p with audio — pinned, so every surface renders and bills the same clip. */
9
+ const UGC_VIDEO = { provider: "seedance-2-5", aspectRatio: "9:16", duration: 8, resolution: "720p", generateAudio: true } as const
10
+ /** The same clip at 5 s, for a one-line answer or a quick reaction that 8 s would leave mostly silent. */
11
+ const UGC_SHORT_VIDEO = { ...UGC_VIDEO, duration: 5 } as const
12
+ const ugcPrompt = (...parts: string[]): string => [...parts, UGC_TAIL].join(" ")
13
+ const TALKING_AT_HOME =
14
+ "{image:1:person} talks straight to the viewer at eye level at home, face and shoulders close, the framing a little crooked, deep focus, plain colour, a faint natural sway;"
15
+
3
16
  export const GENERATE_VIDEO_PRESETS: readonly FactoryPreset[] = [
4
17
  // ── Camera Moves (composable cinematography fragments) ───────────────────
5
18
  {
@@ -1135,4 +1148,62 @@ export const GENERATE_VIDEO_PRESETS: readonly FactoryPreset[] = [
1135
1148
  "Keep everything else in the clip unchanged: the same people, motion, framing and timing. Keep it subtitle-free, do not generate a watermark.",
1136
1149
  },
1137
1150
  },
1151
+
1152
+ // ── UGC & Creator (everyday talking-to-camera clips) ──────────────────────
1153
+ {
1154
+ id: "generate-video/ugc-talking-head",
1155
+ name: "UGC Talking Head",
1156
+ description: "Talks to the viewer at home — type the line to be spoken; write numbers as words.",
1157
+ group: "UGC & Creator",
1158
+ data: { ...UGC_VIDEO, prompt: ugcPrompt(`${TALKING_AT_HOME} hands move naturally while talking and hold nothing.`, ugcSpeech("I cut my weekly reporting from three hours to twenty minutes."), UGC_PAUSE) },
1159
+ },
1160
+ {
1161
+ id: "generate-video/ugc-product-closer",
1162
+ name: "UGC Product Closer",
1163
+ description: "Holds your product up while talking — wire a face photo and a product photo; type the line, numbers as words.",
1164
+ group: "UGC & Creator",
1165
+ data: { ...UGC_VIDEO, prompt: ugcPrompt(`${TALKING_AT_HOME} hands move naturally while talking and hold nothing until the first word.`, "As they say the first word, one hand lifts {image:2:product} into view and holds it up beside their face, its front turned to the viewer, while they talk; the other hand keeps moving naturally.", ugcSpeech("Honestly, this is the one I keep coming back to."), UGC_PAUSE, "After the last word, they lower the product with a small smile.") },
1166
+ },
1167
+ {
1168
+ id: "generate-video/handheld-unboxing",
1169
+ name: "Handheld Unboxing",
1170
+ description: "Opens a box with their own hands and reveals your product — wire a face photo and a product photo.",
1171
+ group: "UGC & Creator",
1172
+ data: { ...UGC_VIDEO, prompt: ugcPrompt(
1173
+ "Close on a table at home, seen the whole time through the eyes of {image:1:person} as they look down at it.",
1174
+ "From the first moment their own two hands are on the lid of a plain box, both forearms coming up from the bottom of the frame.",
1175
+ "One adult's left and right hand, no one else's; only their hands and forearms are seen.",
1176
+ "They open the box at once and lift out {image:2:product} with both hands, clear of the box by the middle of the clip.",
1177
+ "Until the end they hold it up in front of them, the whole of it in frame, tilting it slowly in the light with the same side toward them.",
1178
+ "Daylight, deep focus from their hands to the background, plain colour, the framing a little crooked, a faint natural sway.",
1179
+ ) },
1180
+ },
1181
+ {
1182
+ id: "generate-video/get-ready-with-me",
1183
+ name: "Get Ready With Me",
1184
+ description: "Gets ready at a mirror while chatting — type the line, numbers as words.",
1185
+ group: "UGC & Creator",
1186
+ data: { ...UGC_VIDEO, prompt: ugcPrompt("{image:1:person} at a bathroom mirror applies a little makeup while chatting to the viewer, everyday light, deep focus, plain colour.", ugcSpeech("Two minutes and I'm ready to go."), UGC_PAUSE) },
1187
+ },
1188
+ {
1189
+ id: "generate-video/street-qa",
1190
+ name: "Street-Style Q&A",
1191
+ description: "A staged street-interview look — cast it yourself; type a short answer, numbers as words.",
1192
+ group: "UGC & Creator",
1193
+ data: { ...UGC_SHORT_VIDEO, prompt: ugcPrompt("A staged street-interview look: {image:1:person} stands on a sidewalk answering an interviewer who stays out of frame, beside the viewer; only the interviewer's hand is seen, holding a plain microphone out toward them from a lower corner of the frame, passers-by soft in the background.", "Their eyes stay on the interviewer the whole time, off to the side the microphone comes from.", "The answer starts at once, with no wait before the first word.", ugcSpeech("I'd say about twenty minutes a day, tops."), "After the last word, a small laugh and a shrug, eyes still on the interviewer.") },
1194
+ },
1195
+ {
1196
+ id: "generate-video/reaction-shot",
1197
+ name: "Reaction Shot",
1198
+ description: "A quick reaction to something out of frame.",
1199
+ group: "UGC & Creator",
1200
+ data: { ...UGC_SHORT_VIDEO, prompt: ugcPrompt("{image:1:person} sits on a couch at home, a cushion and a lamp behind them, looking off to one side at something just out of frame; at eye level, the framing a little crooked, deep focus, plain colour, a faint natural sway.", "Almost at once, what they see catches them by surprise: their eyes go wide, a hand flies to their mouth and they break into a laugh, their shoulders shaking.", "Still laughing, they glance briefly at the viewer, then look back off to the side, shaking their head.", "A short exclamation at most.") },
1201
+ },
1202
+ {
1203
+ id: "generate-video/acts-on-phone",
1204
+ name: "Acts on Phone, Screen Hidden",
1205
+ description: "Taps a phone whose screen faces away — type the line, numbers as words.",
1206
+ group: "UGC & Creator",
1207
+ data: { ...UGC_VIDEO, prompt: ugcPrompt(`${TALKING_AT_HOME} hands move naturally while talking and hold nothing until the last seconds.`, ugcSpeech("That's the whole setup, and it took me five minutes."), UGC_PAUSE, "In the last seconds the person picks up a phone and looks down into its screen while typing on it for a moment, then looks back up at the viewer; the screen faces away from the camera.") },
1208
+ },
1138
1209
  ]
@@ -1,3 +1,4 @@
1
+ import { T2I_TO_I2I_VARIANT } from "@nodaro/shared"
1
2
  import type { FactoryPreset } from "./types.js"
2
3
  import { stylizedSubjectFor, editsFor } from "./shared-image.js"
3
4
  import { GENERATE_IMAGE_PRESETS } from "./generate-image.js"
@@ -14,6 +15,19 @@ import { LOTTIE_OVERLAY_PRESETS } from "./lottie-overlay.js"
14
15
  export type { FactoryPreset, FactoryPresetGroup } from "./types.js"
15
16
  export { groupFactoryPresets } from "./types.js"
16
17
 
18
+ /**
19
+ * A shared preset as Modify Image takes it. Modify Image always works from a source photo, so its
20
+ * provider list names a model's image-to-image id where the model has a separate one
21
+ * (`seedream-5-pro` → `seedream-5-pro-i2i`). The shared catalogs may carry the text-to-image id
22
+ * Generate Image takes — its route switches to that same image-to-image model once a photo is
23
+ * connected. Providers with no separate image-to-image id are left as they are.
24
+ */
25
+ function forModifyImage(p: FactoryPreset): FactoryPreset {
26
+ const provider = p.data.provider
27
+ const imageToImage = typeof provider === "string" ? T2I_TO_I2I_VARIANT[provider] : undefined
28
+ return imageToImage ? { ...p, data: { ...p.data, provider: imageToImage } } : p
29
+ }
30
+
17
31
  /** System/factory presets shipped with the app. Assembled here in the original
18
32
  * single-file key order; each value lives in its per-domain module. */
19
33
  export const FACTORY_PRESETS: Readonly<Record<string, readonly FactoryPreset[]>> = {
@@ -22,7 +36,7 @@ export const FACTORY_PRESETS: Readonly<Record<string, readonly FactoryPreset[]>>
22
36
  // modify-image shares the Stylized Subject + Edits catalogs with generate-image
23
37
  // (single source of truth in STYLIZED_SUBJECT / IMAGE_EDITS). modify-image is
24
38
  // slated for deprecation in favor of generate-image — when removed, drop this key.
25
- "modify-image": [...stylizedSubjectFor("modify-image"), ...editsFor("modify-image")],
39
+ "modify-image": [...stylizedSubjectFor("modify-image"), ...editsFor("modify-image")].map(forModifyImage),
26
40
  "generate-video": GENERATE_VIDEO_PRESETS,
27
41
  "text-to-speech": TEXT_TO_SPEECH_PRESETS,
28
42
  "text-to-audio": TEXT_TO_AUDIO_PRESETS,
@@ -1,4 +1,5 @@
1
1
  import type { FactoryPreset } from "./types.js"
2
+ import { REALISM_FINISH, REALISM_PASS_INSTRUCTION } from "../realism-wording.js"
2
3
 
3
4
  /**
4
5
  * Selective-stylization presets shared by `modify-image` (transform an input photo) and
@@ -190,6 +191,47 @@ const IMAGE_EDITS: ReadonlyArray<{
190
191
  "altered photo, restyled or recolored scene, covered faces, filled color blocks, sticker or clipart look, cliché phrases, garbled or misspelled handwriting, cluttered composition, watermark, blurry",
191
192
  },
192
193
  },
194
+ {
195
+ slug: "add-skin-realism",
196
+ name: "Add Skin Realism",
197
+ description: "Brings back visible skin texture — same person, same photo.",
198
+ data: { provider: "nano-banana-2-1", aspectRatio: "auto", resolution: "2K", promptPrefix: REALISM_PASS_INSTRUCTION },
199
+ },
200
+ {
201
+ slug: "natural-photo-finish",
202
+ name: "Natural Photo Finish",
203
+ description: "Takes out a rendered-looking finish, keeps the photo.",
204
+ data: {
205
+ provider: "nano-banana-2-1",
206
+ aspectRatio: "auto",
207
+ resolution: "2K",
208
+ promptPrefix: `Keep this photo as it is and take out only what makes it look rendered: smoothed, waxy or airbrushed skin, a glow, over-sharpened edges, hair too perfect to be real. ${REALISM_FINISH} Otherwise the same people, framing, pose and background.`,
209
+ },
210
+ },
211
+ {
212
+ slug: "phone-camera-look",
213
+ name: "Phone Camera Look",
214
+ description: "Re-finishes a photo as an everyday snapshot.",
215
+ data: {
216
+ provider: "nano-banana-2-1",
217
+ aspectRatio: "auto",
218
+ resolution: "2K",
219
+ promptPrefix: `Re-finish this photo, changing nothing in it: ${REALISM_FINISH} Same people, framing, pose and background.`,
220
+ },
221
+ },
222
+ {
223
+ slug: "undo-beauty-filter",
224
+ name: "Undo Beauty Filter",
225
+ description: "Reverses smoothing and reshaping on a real photo.",
226
+ data: {
227
+ provider: "seedream-5-pro",
228
+ // "auto" keeps the photo's shape: this model lists no native "auto", so on either node the
229
+ // run takes its listed ratio nearest the connected photo.
230
+ aspectRatio: "auto",
231
+ quality: "high",
232
+ promptPrefix: "Undo the beauty filter on this photo: bring back the person's real skin texture, the natural shape of the face, jaw, nose and eyes, and the real colour of skin and lips. Change nothing else: the same person, expression, hair, clothing, framing and background.",
233
+ },
234
+ },
193
235
  ]
194
236
 
195
237
  /** Build the Edits presets for a node type (id = `<nodeType>/<slug>`). */
@@ -98,6 +98,27 @@ export const LLM_CHAT_PRESETS: readonly FactoryPreset[] = [
98
98
  temperature: 0.9,
99
99
  },
100
100
  },
101
+ {
102
+ id: "llm-chat/ugc-monologue-writer",
103
+ name: "UGC Monologue Writer",
104
+ description: "A talking-to-camera script as JSON: hook, beats, closer.",
105
+ group: "Writing & Marketing",
106
+ data: {
107
+ systemPrompt:
108
+ "You write the script of a short vertical video in which one person talks straight to the camera about a product, a site or an idea. Return it as JSON with three parts.\n\n" +
109
+ "hook — the first line: one short spoken clause of at most 8 words. It leads with the payload the viewer can check (a number, a price, a time saved, a before and after, a named result) and opens on the claim itself — no greeting, no filler, no introduction first.\n\n" +
110
+ "beats — one beat per point the video makes, in order. When the user lists screenshots, write one beat per screenshot, in the same order. The first beat names the product. Every beat is one short spoken sentence a person says in one easy breath; nothing is crammed in.\n\n" +
111
+ "closer — the last line. It ends on one simple physical action the speaker can do on camera.\n\n" +
112
+ "Leave room for a short pause at the start and the end of each clip. Sound said, not written: contractions, one connecting word, sentences of mixed length, and one live, imperfect moment such as a small self-correction or an aside. Carry emphasis with word choice and repetition, never with capitals or stage directions. Write only what is spoken: no speaker names, brackets, emoji or sound effects.\n\n" +
113
+ "Spell the brand exactly as the user gives it, every time. Write numbers as digits, except inside the brand's own name. Use only figures the user supplies. Write in the language the user writes in.\n\n" +
114
+ "When the script is in Hebrew: write spoken Israeli Hebrew, the way a person talks to their phone, not ad copy. Every first-person verb and adjective agrees with the speaker's gender, and never switches. Speak to the viewer in the plural (\"תנסו\"), so the viewer is not given a gender. Keep sentences short. Write numbers and prices as digits (\"3\", \"₪49\", \"20%\"). Keep the brand exactly as given, usually in Latin letters; when a Hebrew prefix joins it, use a hyphen (\"ב-Planwell\"). Leave out vowel points. The hook is at most 8 words, as in English, a word with a joined prefix counting as one word, and opens on the result, the number or the contrast — never on a greeting or a filler word.\n\n" +
115
+ "Return only this JSON, no code fences, no commentary:\n{\"hook\": \"…\", \"beats\": [\"…\", \"…\"], \"closer\": \"…\"}",
116
+ llmModel: "claude-opus-5.5",
117
+ reasoningEffort: "high",
118
+ temperature: 0.8,
119
+ maxTokens: 2048,
120
+ },
121
+ },
101
122
 
102
123
  // ── Utility ──────────────────────────────────────────────────────────────
103
124
  {
@@ -216,8 +237,10 @@ export const GENERATE_SCRIPT_PRESETS: readonly FactoryPreset[] = [
216
237
  sceneCount: 4,
217
238
  targetLength: 30,
218
239
  structure: "freeform",
240
+ llmModel: "claude-opus-5.5",
241
+ reasoningEffort: "high",
219
242
  styleGuide:
220
- "Selfie-style UGC testimonial for {product}. Structure: Hook (stop the scroll) → Show (the product in real use) → Proof (a concrete result or detail) → Opinion (a genuine personal take). A real person sharing a real opinion — first-person, natural, unpolished. Short spoken sentences for clean lip-sync; no salesy voiceover.",
243
+ "Selfie-style UGC testimonial for {product}. Open on the payload: the first spoken line is a short claim the viewer can check — a number, a price, a time saved, a before and after — never a greeting or an introduction. Then Show (the product in real use) → Proof (a concrete result or detail) → Opinion (a genuine personal take). Sound said, not written: contractions, sentences of mixed length, one small aside; carry emphasis with word choice, never capitals or stage directions. Spell the brand exactly as given and write numbers as digits. Use only figures the user supplies, in what is said and what is shown, and take the Proof from the topic. Short spoken sentences for clean lip-sync; no salesy voiceover.",
221
244
  },
222
245
  },
223
246
 
@@ -318,4 +341,15 @@ export const IMAGE_TO_TEXT_PRESETS: readonly FactoryPreset[] = [
318
341
  group: "Creative",
319
342
  data: { detailLevel: "detailed", customPrompt: "Describe this image as a detailed text-to-image generation prompt: subject, style, lighting, composition and lens. Return only the prompt." },
320
343
  },
344
+ {
345
+ id: "image-to-text/realism-audit",
346
+ name: "Realism Audit",
347
+ description: "Lists the signs an image was generated, with a count.",
348
+ group: "Creative",
349
+ data: {
350
+ detailLevel: "structured",
351
+ customPrompt:
352
+ "Check this image for signs that it was generated rather than photographed. Answer each question yes or no, with a few words why. 1. Is the skin smooth, waxy or airbrushed, with no visible pores? 2. Is the face unusually symmetrical, or are the teeth unnaturally even and white? 3. Are any hands or fingers malformed, merged or the wrong count? 4. Is any text, logo or sign garbled? 5. Is the background blurred far more than an everyday snapshot would be? 6. Are the catchlights in the eyes perfect rings, or identical in both eyes? 7. Is the hair uniformly perfect, with no flyaways? 8. Do edges look over-sharpened or haloed? 9. Is there a glow or bloom on the skin? 10. Do shadows or reflections disagree with the light? Finish with one line: \"Tells found: N of 10\".",
353
+ },
354
+ },
321
355
  ]
@@ -1,4 +1,5 @@
1
1
  import type { FactoryPreset } from "./types.js"
2
+ import { REALISM_FINISH } from "../realism-wording.js"
2
3
 
3
4
  export const VIDEO_TO_VIDEO_PRESETS: readonly FactoryPreset[] = [
4
5
  {
@@ -43,6 +44,21 @@ export const VIDEO_TO_VIDEO_PRESETS: readonly FactoryPreset[] = [
43
44
  group: "Restyle Looks",
44
45
  data: { provider: "wan", promptPrefix: "Restyle as a flowing watercolor animation with soft washes, bleeding edges, and visible paper texture. Keep the original motion and composition.", negativePrompt: "photorealistic, harsh edges, blurry, flickering" },
45
46
  },
47
+ {
48
+ id: "video-to-video/phone-footage-look",
49
+ name: "Phone Footage Look",
50
+ description: "Everyday handheld look for b-roll — it re-renders faces, so not for talking clips.",
51
+ group: "Restyle Looks",
52
+ data: {
53
+ provider: "wan-videoedit",
54
+ v2vResolution: "720p",
55
+ videoEditDuration: "0",
56
+ audioSetting: "origin",
57
+ promptExtend: false,
58
+ promptPrefix: `Keep everything in this clip as it is — the same people, objects, colours and light — and only make it look like everyday handheld digital video, left unedited. ${REALISM_FINISH} The edges of the frame keep the light they have in the clip, and each moment keeps the brightness it has in the clip, from the first frame to the last. Preserve the original motion, composition and timing.`,
59
+ negativePrompt: "cinematic grade, shallow depth of field, glow, skin smoothing, flickering, light leaks, flare, coloured bands at the edges of the frame, colour cast, shifted colours, oversaturated colours, vintage film look, overexposure, pulsing brightness, heavy grain",
60
+ },
61
+ },
46
62
  ]
47
63
 
48
64
  export const ADD_CAPTIONS_PRESETS: readonly FactoryPreset[] = [
package/src/index.ts CHANGED
@@ -90,6 +90,7 @@ export { stripAudioTags } from "./audio-tags.js"
90
90
  export * from "./node-prompt-fields.js"
91
91
  export * from "./factory-presets.js"
92
92
  export * from "./caption-treatments.js"
93
+ export * from "./realism-wording.js"
93
94
  export * from "./style-presets.js"
94
95
  export * from "./object-asset-presets.js"
95
96
  export * from "./factory-snippets/index.js"
@@ -89,6 +89,8 @@ export const NODE_PROMPT_FIELDS: Readonly<Record<string, PromptFieldSpec>> = {
89
89
  "cinematic-avatar": { prompt: "prompt", media: "video", inline: true },
90
90
  "video-sfx": { prompt: "prompt", negative: "negativePrompt", promptLabel: "Sound prompt", media: "audio", inline: true },
91
91
  "video-retake": { prompt: "prompt", promptLabel: "Retake prompt", media: "video", inline: true },
92
+ // Video Mask (SAM 3) — the subject to track, like Generate Mask's "what to mask".
93
+ "video-mask": { prompt: "prompt", promptLabel: "What to mask", media: "video", inline: true },
92
94
  // ── Audio / music ──
93
95
  "generate-music": { prompt: "prompt", media: "audio", inline: true },
94
96
  "suno-generate": { prompt: "prompt", media: "audio", inline: true },
@@ -252,7 +252,7 @@ export const PROVIDER_CAPABILITIES: Record<string, Record<string, string>> = {
252
252
  "seedance-2-fast": "Seedance 2.0 Fast — same multimodal + audio capabilities, cheaper and quicker",
253
253
  "seedance-2-mini": "Seedance 2.0 Mini — same multimodal + audio capabilities, budget tier, 480p/720p, 4-15s",
254
254
  "seedance-2-5": "Seedance 2.5 — up to 30s in ONE shot (no stitching), wider multimodal refs (30 images / 10 videos / 10 audio), native audio, 480p/720p/1080p",
255
- "minimax-h3": "MiniMax Hailuo 3 — premium multimodal refs (9 images / 3 videos / 3 audio), always-on audio, 2K or 768P, 4-15s per-second pricing",
255
+ "minimax-h3": "MiniMax H3 — premium multimodal refs (9 images / 3 videos / 3 audio), always-on audio, 2K or 768P, 4-15s per-second pricing",
256
256
  "wan": "Versatile, good for animations and transformations",
257
257
  "wan-turbo": "Faster Wan generation",
258
258
  "hailuo-standard": "Standard quality, cost-effective",
@@ -283,7 +283,7 @@ export const PROVIDER_CAPABILITIES: Record<string, Record<string, string>> = {
283
283
  "seedance-2-fast": "Seedance 2.0 Fast — same capabilities, cheaper and quicker",
284
284
  "seedance-2-mini": "Seedance 2.0 Mini — same capabilities, budget tier, 480p/720p",
285
285
  "seedance-2-5": "Seedance 2.5 — start/end frame + wide multimodal refs, native audio, up to 30s, 480p/720p/1080p",
286
- "minimax-h3": "MiniMax Hailuo 3 — first/last frame + multimodal refs, always-on audio, 2K or 768P, 4-15s",
286
+ "minimax-h3": "MiniMax H3 — first/last frame + multimodal refs, always-on audio, 2K or 768P, 4-15s",
287
287
  "hailuo-2.3-pro": "Premium Hailuo animation",
288
288
  "hailuo-2.3": "Standard Hailuo animation",
289
289
  "hailuo-standard": "Cost-effective animation",
@@ -23,7 +23,7 @@
23
23
  * - KIE API docs https://docs.kie.ai/market/kling/kling-3-0
24
24
  * - Live KIE-path dialogue probe 2026-07-16 (scripted lines spoken verbatim,
25
25
  * lip-synced, on both kling-2.6 and kling-3.0 with sound=true)
26
- * MiniMax Hailuo 3:
26
+ * MiniMax H3:
27
27
  * - KIE API docs https://docs.kie.ai/market/minimax-h3 (text-to-video /
28
28
  * image-to-video / reference-to-video — the API contract is the doctrine
29
29
  * source: limits, modes, aspect rules, pricing dimensions). No live probe
@@ -160,7 +160,7 @@ const KLING_AUDIO_DOCTRINE: ProviderPromptDoctrine = {
160
160
 
161
161
  const MINIMAX_H3_DOCTRINE: ProviderPromptDoctrine = {
162
162
  providers: ["minimax-h3"],
163
- heading: "MiniMax Hailuo 3 (minimax-h3)",
163
+ heading: "MiniMax H3 (minimax-h3)",
164
164
  tips: [
165
165
  "Natural-language prompts up to 7000 chars. Front-load what matters: subject → action → scene/environment → lighting → camera move → style. One camera movement per shot.",
166
166
  "Output 2K (default) or 768P (cheaper tier). Aspect: pure text-to-video needs a concrete ratio (21:9/16:9/4:3/1:1/3:4/9:16); reference runs default to adaptive (match the input).",
@@ -0,0 +1,39 @@
1
+ // packages/prompts/src/realism-wording.ts
2
+ /**
3
+ * Realism and viewpoint wording for everyday-photo prompts: skin and finish
4
+ * sentences, the identity-keeping realism instruction for an edit, and the eye-level
5
+ * viewpoint and empty-hands sentences, worded for any person.
6
+ */
7
+
8
+ /** Who a sentence is about: gendered ("she" / "her") or neutral ("the person" / "their"). */
9
+ export interface PersonWords {
10
+ readonly subject: string
11
+ readonly possessive: string
12
+ }
13
+
14
+ export const NEUTRAL_PERSON: PersonWords = { subject: "the person", possessive: "their" }
15
+
16
+ const cap = (s: string): string => (s.length === 0 ? s : `${s[0]!.toUpperCase()}${s.slice(1)}`)
17
+
18
+ export const REALISM_SKIN =
19
+ "Skin shows its real structure: visible pores that vary in size across the nose and cheeks, fine vellus hair catching the light, faint uneven pigmentation, a little redness around the nostrils, natural oil on the forehead."
20
+
21
+ export const REALISM_FINISH =
22
+ "The plain look of an everyday small-sensor snapshot: colour left as it was recorded, deep focus from the nearest shoulder to the background, a fine grain in the darker areas, bright areas that fade rather than clip."
23
+
24
+ export const REALISM_PASS_INSTRUCTION =
25
+ "Make this photo look like an unretouched everyday snapshot: skin that shows its pores, its " +
26
+ "fine hairs and the small changes in tone real skin has, colour left as it was recorded, everything " +
27
+ "sharp from the shoulders to the background, a little grain in the shadows. Take out anything that makes it " +
28
+ "look rendered — smoothed, waxy or airbrushed skin, a glow, over-sharpened edges — and add no text or icons. " +
29
+ "Otherwise it stays the same person in the same frame: the face and its proportions, hair, clothing, pose and " +
30
+ "background as they are."
31
+
32
+ /** The frame by its viewpoint only — never by a device. */
33
+ export function realismViewpoint(p: PersonWords): string {
34
+ return `${cap(p.subject)} is looking straight at the viewer from eye level, mid-sentence: ${p.possessive} face and shoulders close up, the framing loose and a little crooked, both arms relaxed and down out of the frame. The whole image is the photograph itself, edge to edge, with no text or icons anywhere.`
35
+ }
36
+
37
+ export function realismEmptyHands(p: PersonWords): string {
38
+ return `${cap(p.possessive)} hands are empty; ${p.subject} is holding nothing.`
39
+ }