/** * The illustration / animation STYLE REGISTER. * * One typed, selectable set of visual base looks, consumed by BOTH * `multi-shot-prompt.ts` (the `Style:` line) and `filmmaking-prompts.ts` * (the character-sheet prompt, the storyboard-grid descriptors, the Seedance * FORMAT tone). A style carries all three facets rather than one string, * because a look that is only applied to the clip drifts away from the sheet * that locked the character's identity. * * This is a LEAF module on purpose: it imports nothing from the repo. * `cinema-profile.ts` <-> `filmmaking-prompts.ts` is already a live import * cycle, so housing the register inside either consumer would deepen it. * * TWO INVARIANTS, both load-bearing: * * 1. EVERY EMITTED FIELD IS PROMPT TEXT ONLY. `videoStyleLine`, * `charSheetStyle`, `gridDescriptors` and `formatTone` are interpolated * verbatim into provider submissions. Operator-facing commentary, caveats * and picker copy live in `docNote`, which is never emitted. * * 2. NO FRANCHISE, STUDIO, OR LIVING-ARTIST NAMES in an emitted field. * `sanitizePrompt` (seedance-content-filter.ts) strips them on the * Seedance/Dreamina submit path, so a style whose distinctiveness rests on * a name silently loses that style on a content-violation retry — the * hardest class of failure to diagnose after the fact. Describe looks by * visual property: line, texture, shading model, edge treatment, palette. * `style-register-filter.test.ts` enforces this by running the real filter * over every literal below; it also records the pre-existing legacy * violations in an allowlist rather than hiding them. * * The first ten entries are FROZEN. Their strings were lifted byte-identically * from the maps this register replaces (`GENRE_STYLE_LINES` in * multi-shot-prompt.ts, `GENRE_STYLES` in filmmaking-prompts.ts) so existing * projects render exactly as they did before. Several of them violate * invariant 2 — that is a pre-existing bug, recorded in the test allowlist and * in each `docNote`, and fixing it is a separate deliberate change. */ export type StyleFamily = | 'painterly' | 'cel' | 'ink' | 'print' | 'graphic' | 'material' | 'rendered-3d' | 'photoreal'; export interface VisualStyle { id: string; label: string; family: StyleFamily; /** * EMITTED — the multi-shot `Style:` line. Omitted means "inherit the active * preset's own styleLine"; `live-action` relies on this, so the property * must be ABSENT rather than an empty string (`?? ` would not catch `''`). */ videoStyleLine?: string; /** EMITTED — the character-sheet image prompt STYLE clause. */ charSheetStyle: string; /** EMITTED — the storyboard-grid panel descriptors. */ gridDescriptors: string; /** EMITTED — the Seedance FORMAT tone. */ formatTone: string; annotationThirdLine: 'MOOD' | 'VOICE' | 'STYLE'; /** * Whether `captureRealismBlock`'s photoreal anti-plastic clauses suit this * look. False for drawn and painted registers; TRUE for the physically * photographed material looks (clay, paper cutout), which really are shot. */ realism: boolean; /** Animation-on-twos (12fps stepping) suits this look. */ onTwos: boolean; /** An id from cinematography.ts LIGHTING. */ lightingId?: string; /** An id from cinematography.ts GRADE. */ gradeId?: string; /** * This style cannot carry facial identity on a character sheet. Lock identity * with a normal sheet FIRST, then apply this register to the video only. */ sheetDivergesFromVideo?: boolean; /** NEVER EMITTED. Operator-facing notes, caveats, picker copy. */ docNote: string; } const STYLES: readonly VisualStyle[] = [ { id: 'live-action', label: 'Live action (photoreal)', family: 'photoreal', charSheetStyle: 'photorealistic, life-like live action shot on a DSLR camera with 35mm film and muted color tones, do not make it look like a 3D render', gridDescriptors: 'live-action, photorealistic, lifelike, 35mm film grain', formatTone: 'cinematic grounded realism', annotationThirdLine: 'MOOD', realism: true, onTwos: false, lightingId: 'golden-hour', gradeId: 'desaturated-earth', docNote: "THE COMPAT KEYSTONE. videoStyleLine is \"\" — live-action has no entry in GENRE_STYLE_LINES today, so resolveStyleLine('live-action') must fall through to CINEMATIC_15S_PRESET.styleLine. CRITICAL: the resolver must be a TRUTHINESS check, not `??` — proved empirically this session by running the real compiled modules: `'' ?? fallback` returns `''`, `'' ? '' : fallback` returns the fallback, and resolveStyleLine('live-action') against today's shipping code returns the Nolan line. Use `const line = STYLE_BY_ID.get(genre.toLowerCase())?.videoStyleLine; return line ? line : CINEMATIC_15S_PRESET.styleLine;`. All four legacy facets diffed byte-for-byte against filmmaking-prompts.ts:448-453: 0 mismatches. Two pre-existing defects live in this string and are carried verbatim per the brief: DSLR dies to the ALL-CAPS BRAND_PATTERN on a level-1 retry (re-verified against the real sanitizer this session — output loses 'DSLR'), and this exact sheet is shared verbatim by music-video and action whose style lines demand saturated palettes — see preExistingBugs. realism/lightingId/gradeId below are DECLARED INTENT for a phase-2 cinema-profile migration, not current behaviour.", }, { id: 'pixar', label: 'Stylized 3D (legacy id)', family: 'rendered-3d', videoStyleLine: 'Stylized 3D render, soft global illumination, expressive proportions, warm inviting palette.', charSheetStyle: 'stylized 3D character sheet, rounded appealing forms with gently exaggerated proportions, smooth soft-edged shading, warm bounced global illumination, no photoreal rendering', gridDescriptors: 'stylized 3D render, rounded appealing forms, gently exaggerated proportions, soft-edged shading, warm bounced global illumination', formatTone: 'stylized 3D animation', annotationThirdLine: 'MOOD', realism: false, onTwos: false, lightingId: 'neutral-studio', gradeId: 'warm-nostalgia', docNote: "The id is a studio name and cannot be renamed: GENRE_ALIASES maps '3d' and 'animation' onto it, and filmmaking-prompts.test.ts:260 / cinematography.test.ts:106 bind to it. So the ID stays and the STRINGS moved instead. charSheetStyle and gridDescriptors used to say 'modern Pixar features' and 'Pixar-style'; CELEBRITY_IP_PATTERNS deleted the word on a level-1 retry, leaving the vague 'modern features' and a dangling 'stylized 3D -style render'. Note the severity was overstated in an earlier pass: the sheet never degraded to nothing, it kept four real descriptors and lost only the feature-animation anchor. Both facets now describe the look by property (rounded appealing forms, gently exaggerated proportions, soft-edged shading, warm bounced global illumination), verified against the real compiled filter: sanitizePrompt(f,1) === f and preValidatePrompt(f).length === 0, and still distinct from cel-shaded-3d (ink outline), low-poly (facets) and voxel (cubes). videoStyleLine and formatTone were already clean and are untouched." }, { id: 'anime', label: 'Anime (cel over painted backgrounds)', family: 'cel', videoStyleLine: '2D anime cel-shading, clean line work, painterly backgrounds, vivid saturated palette.', charSheetStyle: '2D anime cel-shading, clean line work, painterly backgrounds, no 3D render', gridDescriptors: '2D anime cel-shading, clean line work, painterly backgrounds', formatTone: '2D anime', annotationThirdLine: 'MOOD', realism: false, onTwos: true, lightingId: 'hard-dawn', docNote: "FROZEN — cannot be sharpened. The distinctness critique proposed appending 'hard-edged cel shadow blocks, flat saturated palette' to disambiguate it from painterly-2d and manga-cel, but constraint 1 forbids changing legacy emitted strings, so the two NEW neighbours moved instead: painterly-2d owns translucent-warm-color shadows plus a muted natural palette (opposing anime's cel-shading and vivid saturation), manga-cel owns hard aliased ink plus gray screentone plus a near-monochrome palette. The three-way ambiguity is resolved on the new side only. Its sheet/grid strings are substring-asserted at filmmaking-prompts.test.ts:170,173,213,214 (/2D anime cel-shading/) — extending them would be legal for those four tests but is still forbidden here. gradeId left undefined: no GRADE id expresses flat saturated (see remainingRisks). realism:false is declared intent; today it inherits true from hardDefault().", }, { id: 'noir', label: 'Noir', family: 'photoreal', videoStyleLine: 'High-contrast black and white, harsh chiaroscuro, deep shadow, 35mm grain.', charSheetStyle: 'high-contrast black and white film, harsh chiaroscuro lighting, 35mm grain', gridDescriptors: 'high-contrast black and white, harsh chiaroscuro, 35mm grain', formatTone: 'high-contrast noir', annotationThirdLine: 'MOOD', realism: true, onTwos: false, lightingId: 'chiaroscuro', gradeId: 'noir-bw', docNote: "Cleanest of the legacy ten — zero filter hits across all four prose facets, re-verified this session against the real compiled sanitizer (sanitizePrompt(f,1) === f and preValidatePrompt(f) === [] on all three GENRE_STYLES facets and the style line). Distinct from silhouette-shadow-puppet (which is a flat black figure against a fully COLORED detailed background) and from graphite-sketch (pencil tooth, no photographic capture). GENRE_DEFAULTS noir uses keyLightId night-fire; chiaroscuro is the better declared pairing and both ids exist in cinematography.ts LIGHTING. All facets diffed: 0 mismatches.", }, { id: 'influencer', label: 'Influencer / vlog', family: 'photoreal', videoStyleLine: 'Bright clean social-first look, soft flattering key, natural skin, crisp and current.', charSheetStyle: 'natural daylight, iPhone selfie-camera aesthetic, soft skin tones, no cinematic grade', gridDescriptors: 'natural daylight, iPhone selfie-camera aesthetic, soft skin tones', formatTone: 'handheld vlog realism', annotationThirdLine: 'VOICE', realism: true, onTwos: false, lightingId: 'neutral-studio', docNote: "The only id with a live cinema-profile override today (GENRE_PROFILE_DEFAULTS, cinema-profile.ts:61, captureRegister 'phone'). annotationThirdLine VOICE is test-locked at filmmaking-prompts.test.ts:261 via the 'vlog' alias — re-confirmed this session by calling the real resolveGenreStyle('vlog'). VERIFIED HAZARD: both charSheetStyle AND gridDescriptors contain 'selfie', which matches portraitTerms in preValidatePrompt and raises a MEDIUM 'Photo-realistic portrait reference detected' warning on every seedance-direct and dreamina-useapi submit — re-run this session against the real preValidatePrompt, which returned MEDIUM:selfie on BOTH strings — and gridDescriptors reaches three prompt sites in filmmaking-prompts.ts (STYLE: at :846, the grid Style: at :1058, CAMERA CAPTURE: at :1447), so it is not sheet-only. (An earlier note cited :1490; that is an unrelated comment line.) Carried verbatim per the brief. REFUTED HAZARD: 'iPhone' does NOT match the CamelCase BRAND_PATTERN — that pattern needs an uppercase letter at a word boundary and iPhone starts lowercase. Re-run this session: sanitizePrompt of both strings returns them with only 'selfie' warned and nothing deleted. Do not 'fix' this string. All facets diffed: 0 mismatches.", }, { id: 'action', label: 'Action', family: 'photoreal', videoStyleLine: 'Punchy high-contrast teal-and-orange, kinetic handheld, crushed shadows, aggressive coverage.', charSheetStyle: 'photorealistic, life-like live action shot on a DSLR camera with 35mm film, punchy high-contrast teal-and-orange grade and crushed shadows, do not make it look like a 3D render', gridDescriptors: 'live-action, photorealistic, kinetic, 35mm film grain', formatTone: 'kinetic action realism', annotationThirdLine: 'STYLE', realism: true, onTwos: false, lightingId: 'hard-dawn', gradeId: 'teal-orange', docNote: "PRESENTATION: same as music-video — live-action plus {hard-dawn, teal-orange} and a 1.2/sec cut rate, already in GENRE_DEFAULTS. Show as a variant, not a peer. Shares live-action's exact sheet including 'muted color tones', which contradicts its own 'teal-and-orange' line; carried verbatim, reported in preExistingBugs. Its grid differs from live-action by one word (kinetic vs lifelike). One of only two ids with a non-MOOD annotation third line, and that is test-locked at filmmaking-prompts.test.ts:262 via the 'fight' alias — re-confirmed this session by calling the real resolveGenreStyle('fight'), which returns annotationThirdLine 'STYLE'. All facets diffed: 0 mismatches.", }, { id: 'music-video', label: 'Music video', family: 'photoreal', videoStyleLine: 'Saturated stage color, rhythmic lighting, performance energy. Bold contrast, expressive grade, beat-driven cutting.', charSheetStyle: 'photorealistic, life-like live action shot on a DSLR camera with 35mm film, saturated stage color and bold expressive contrast, do not make it look like a 3D render', gridDescriptors: 'live-action, photorealistic, lifelike, 35mm film grain', formatTone: 'cinematic music-video energy', annotationThirdLine: 'MOOD', realism: true, onTwos: false, lightingId: 'night-fire', gradeId: 'cyberpunk-neon', docNote: "PRESENTATION: this is live-action plus a grade and a cut rate, not a separate look. Its sheet and grid strings are byte-identical to live-action; only the style line and formatTone differ, and cinematography.ts already encodes the delta as GENRE_DEFAULTS music-video {paletteHue 280, saturationPct 85, keyLightId night-fire}. Show it in any picker as a variant of live-action, not a peer. Its sheet says 'muted color tones' while its line says 'Saturated stage color' — a real sheet-versus-clip contradiction, carried verbatim per the brief and reported in preExistingBugs. All facets diffed against source: 0 mismatches.", }, { id: 'cgi', label: 'Photoreal CGI render (legacy id)', family: 'rendered-3d', videoStyleLine: 'Photoreal CGI render, ray-traced global illumination, physically-based materials, crisp specular highlights, volumetric light.', charSheetStyle: 'photoreal CGI render with ray-traced global illumination and physically-based materials, crisp specular highlights and volumetric light — rendered, not live-action', gridDescriptors: 'photoreal CGI render, ray-traced global illumination, PBR materials, volumetric light', formatTone: 'photoreal CGI render', annotationThirdLine: 'MOOD', realism: true, onTwos: false, lightingId: 'neutral-studio', docNote: "LEGACY ID WITH A CONFIRMED SUBMIT BUG AND A LEGACY-ON-LEGACY COLLISION. Re-verified this session against the real compiled sanitizer: the ALL-CAPS BRAND_PATTERN deletes CGI from ALL FOUR facets — style line, charSheetStyle, gridDescriptors AND formatTone ('photoreal CGI render' -> 'photoreal render') — and additionally deletes PBR from the grid, so on a retry the style line becomes 'Photoreal render, ray-traced global illumination, physically-based materials, crisp specular highlights, volumetric light', which is a photoreal capture prompt, i.e. live-action. Pre-retry the two ARE distinguishable (clean synthetic render vs 35mm grain and muted tones); post-retry they converge. Because BOTH ids are frozen this collision cannot be resolved in this pass and no new id was added in that space. Its only separators are negations ('do not make it look like a 3D render' / 'rendered, not live-action'), the weakest form of image instruction. Family reassigned from the proposal's 'photoreal' to 'rendered-3d' so it sits next to cel-shaded-3d, which is its material opposite and must never be folded into it. charSheetStyle contains an EM-DASH before 'rendered' — diffed byte-for-byte against source this session, 0 mismatches; do not retype it as a hyphen.", }, { id: 'cartoon', label: 'Bold-ink cartoon', family: 'cel', videoStyleLine: 'Hand-drawn 2D cartoon, bold clean outlines, flat cel fills, bouncy exaggerated motion, saturated primary palette.', charSheetStyle: 'hand-drawn 2D cartoon with bold clean outlines and flat cel fills, exaggerated proportions, no 3D render', gridDescriptors: 'hand-drawn 2D cartoon, bold outlines, flat cel fills, saturated primaries', formatTone: '2D cartoon', annotationThirdLine: 'MOOD', realism: false, onTwos: true, lightingId: 'neutral-studio', docNote: "FROZEN. Heaviest outline in the register plus flat cel fills and saturated primaries. Every new cel entry is moved away from IT rather than the reverse, and each of the three now opposes it on both of the axes it owns — line weight and palette: rubber-hose-vintage takes a CONSISTENT thin two-to-three-pixel even line with a sepia and gold palette; manga-cel takes hard aliased ink with a near-monochrome gray-screentone palette plus long-held poses (opposing bouncy motion); ligne-claire takes a fine even-weight thin contour with a calm mid-tone palette (this pass — see its docNote and mergedOrDropped). Absorbs the harvested bold-ink-slapstick candidate (03-cartoon.md:436) outright — whose own source cues named two studios that NEITHER sanitizer catches, which is exactly why the register describes by property. gradeId undefined: no GRADE id expresses flat saturated primaries. All facets diffed: 0 mismatches.", }, { id: 'social', label: 'Social / phone-native', family: 'photoreal', videoStyleLine: 'Bright phone-native vertical look, punchy saturation, fast pattern-interrupt cutting, captiony hook energy.', charSheetStyle: 'natural daylight, iPhone selfie-camera aesthetic, soft skin tones, no cinematic grade', gridDescriptors: 'natural daylight, iPhone selfie-camera aesthetic, soft skin tones', formatTone: 'handheld vlog realism', annotationThirdLine: 'VOICE', realism: true, onTwos: false, lightingId: 'neutral-studio', docNote: "THE MIRROR OF live-action, and the second load-bearing asymmetry. social IS in GENRE_STYLE_LINES (so its videoStyleLine is real and must be carried) but is NOT in GENRE_STYLES — GENRE_ALIASES maps social to influencer and resolveGenreStyle resolves the alias BEFORE the registry lookup (filmmaking-prompts.ts:525), so resolveGenreStyle('social').genre stays 'influencer' exactly as today; re-confirmed this session by calling the real compiled resolveGenreStyle('social'), which returned genre 'influencer'. Its charSheetStyle, gridDescriptors, formatTone and annotationThirdLine below are therefore UNREACHABLE and are set to influencer's verbatim values so that if the alias were ever removed the behaviour would be identical to today's alias target rather than a silent change. The proposal put that explanation INSIDE charSheetStyle, which is interpolated verbatim into the character-sheet image prompt at filmmaking-prompts.ts:1023-1028 — that was blocker 1 and it is fixed by keeping all of it in this field. Carries the same verified 'selfie' portraitTerms hazard as influencer. All facets diffed: 0 mismatches.", }, { id: 'painterly-2d', label: 'Painterly 2D (soft line, painted shadow)', family: 'painterly', videoStyleLine: 'Hand-painted 2D animation, soft anti-aliased brush-drawn outlines about two to three pixels wide, shadows laid in as translucent warm color with no black or gray anywhere, backgrounds painted to the same full finish as the figures so nothing in the frame is left loose, muted natural palette, rounded flowing anatomy, and smooth arcing slow-in slow-out motion.', charSheetStyle: 'hand-painted 2D character sheet, soft anti-aliased brush-drawn outline two to three pixels wide, rounded flowing anatomy, large eyes with a bright specular catchlight, shadows painted as translucent warm color with no black or gray, muted natural palette, painted gradient backdrop, no 3D render', gridDescriptors: 'hand-painted 2D, soft anti-aliased brush line, translucent warm color shadows, fully finished painted backgrounds, muted natural palette', formatTone: 'hand-painted 2D animation', annotationThirdLine: 'MOOD', realism: false, onTwos: false, lightingId: 'golden-hour', gradeId: 'warm-nostalgia', docNote: "DETAIL DISTRIBUTION POLE 1 of 4: backgrounds carried at the SAME full finish as the figures, nothing left loose. That clause is the family invariant, stated in the emitted line where it can actually act — see `added` for the argument. Separators that hold against every neighbour: vs anime (frozen) translucent-warm-color shadows with no black or gray oppose cel-shading, and muted natural opposes vivid saturated; vs painterly-focal-falloff the background finish is the direct inverse; vs watercolor-wash it has an outline at all; vs oil-impasto it has no paint relief and no canvas weave; vs the newly-sharpened ligne-claire the substrate differs on both axes — a soft anti-aliased BRUSH line over translucent painted shadow modeling, against a fine even-weight ink contour over broad unmodulated flat fill with no shadow modeling at all — and they sit in different families. Facet coherence checked: the palette and eye-design cues appear on the sheet AND the line, fixing the one-facet-only defect the distinctness critique flagged. British spelling normalised to American throughout so an operator typing the American form is not silently dropped to the Nolan fallback. Zero apostrophes.", }, { id: 'watercolor-wash', label: 'Watercolor wash', family: 'painterly', videoStyleLine: 'Watercolor animation with no outlines at all, form defined by translucent overlapping washes, visible wet-on-wet color mixing, edges that feather and bleed slightly past the form, visible paper grain, detail dissolving evenly across the whole frame rather than held on one point, and motion that flows like wet paint.', charSheetStyle: 'watercolor character sheet, translucent overlapping washes with no outline anywhere, wet-on-wet blending, soft feathered edges bleeding past the form, visible paper grain, muted natural palette', gridDescriptors: 'watercolor wash, no outline, translucent layered color, feathered bleeding edges, paper grain', formatTone: 'watercolor animation', annotationThirdLine: 'MOOD', realism: false, onTwos: true, lightingId: 'overcast', gradeId: 'desaturated-earth', docNote: "DETAIL DISTRIBUTION POLE 2 of 4: detail dissolves EVENLY across the whole frame, nothing held on one point — the explicit opposite of painterly-focal-falloff and the reason a blanket 'bake falloff into every painterly entry' rule would have broken this look. Unmistakable against every other painterly entry because it has no line at all. ID SPELLING: normalised to American ('watercolor', not 'watercolour') to match the existing repo corpus — resolveStyleLine and resolveGenreStyle do exact lowercase key lookups with no normalisation (re-read in source this session), so the British form would silently fall through to the Nolan fallback. IDENTITY CAUTION: an outline-free wash holds a face far less tightly than a line style; budget an extra consistency-audit pass on recurring characters.", }, { id: 'oil-impasto', label: 'Oil impasto (thick paint relief)', family: 'painterly', videoStyleLine: 'Oil-painted animation with thick impasto brushstrokes holding physical relief that catches raking light, color mixed optically in visible open strokes rather than blended smooth, stroke direction following and wrapping the form it describes, light modeled as warm against cool instead of directional rays, canvas weave visible through the paint, every part of the frame carried at the same heavy paint density, and a shimmer from frame-to-frame repainting.', charSheetStyle: 'oil-painted character sheet, thick impasto brushstrokes with visible paint relief, stroke direction wrapping and following the form, color mixed optically in open strokes, warm against cool light modeling instead of black shadow, visible canvas weave, no outline', gridDescriptors: 'oil impasto, thick paint relief, stroke direction wrapping the form, optical color mixing, warm and cool light modeling, canvas weave', formatTone: 'oil-painted animation', annotationThirdLine: 'MOOD', realism: false, onTwos: true, lightingId: 'golden-hour', gradeId: 'warm-nostalgia', docNote: "MERGED ENTRY — absorbs the proposal's separate `painterly-3d`. DETAIL DISTRIBUTION POLE 3 of 4: every part of the frame carried at the SAME heavy paint density, which is what now separates it from painterly-focal-falloff. Two defects the distinctness critique found are fixed here: (1) the proposal's painterly-3d claimed 'forms turn in space' as its only separator from oil-impasto — a motion property that says nothing about a character sheet or a grid panel, and one a video model renders for either prompt under a camera move; the surviving half of it that IS visible on a still, 'stroke direction following and wrapping the form it describes', is folded into all three facets here. (2) painterly-3d's line paired 'impasto ridges' (thick opaque relief) with 'watercolour bleed and soft feathered edges' (thin transparent wash) — contradictory paint behaviours a model averages into mush, and the bleed clause also borrowed watercolor-wash's own separator. That clause is deleted, not merged.", }, { id: 'painterly-focal-falloff', label: 'Painterly falloff (sharp focal point, dissolved background)', family: 'painterly', videoStyleLine: 'Painterly concept-art animation with detail and rendering held only on the focal subject while everything behind it collapses into loose abstract thick strokes that suggest the setting rather than resolving it, a painterly falloff rather than a photographic blur, edges alternately lost and found, matte brush-textured surfaces with no gloss and no thick paint relief, angular sculptural facial planes, a desaturated earthy palette carrying one saturated accent, hard chiaroscuro with a cool rim separating the figure from a warm key, and atmospheric haze.', charSheetStyle: 'painterly concept-art character sheet, rendering held on the face and hands while forms further from the focal point are left as unresolved loose strokes, matte brush-textured skin with no gloss, lost and found edges, angular sculptural facial planes, pushed stylized proportions, desaturated earthy palette with one saturated accent, hard chiaroscuro with a cool rim light against a warm key, plain unresolved backdrop', gridDescriptors: 'painterly concept art, detail held on the focal subject only, background collapsed into loose abstract strokes, lost and found edges, matte brush texture, desaturated earthy palette with one saturated accent, hard chiaroscuro with cool rim light', formatTone: 'painterly concept-art animation', annotationThirdLine: 'MOOD', realism: false, onTwos: false, lightingId: 'chiaroscuro', gradeId: 'desaturated-earth', docNote: "NEW — THE DETAIL-DISTRIBUTION ENTRY, and DETAIL DISTRIBUTION POLE 4 of 4. Closes the single real coverage gap: no id in the proposal could render the source skill's own defining look, whose most load-bearing rule is that detail is held ONLY on the focal point while the background collapses into loose abstract brushstrokes. See `added` for why this is an entry rather than an orthogonal facet. FACET-COHERENCE NOTE: the sheet facet deliberately does NOT say 'background collapses' — a character sheet is a turnaround on a plain backdrop and has no background — so falloff is expressed there as rendering held on the face and hands with forms further out left unresolved. That is the same one-facet-only defect the distinctness critique raised, avoided in the entry added to fix it. PORTED HAZARDS EXCLUDED BY CONSTRUCTION: 'arcane', 'jinx' and 'jayce' are live CELEBRITY_IP tokens; the source names a living artist who is NOT in the regex and would therefore survive our scrubber and reach the provider; the source --no block literally contains 'anime cel shading', which would collide head-on with the frozen `anime` id string. None of that appears above. The source's Midjourney-only params (--stylize, --sref, --v 8.1) are excluded — they mean nothing to Seedance or Veo. Zero apostrophes ('a painterly falloff rather than a photographic blur', never the possessive form).", }, { id: 'manga-cel', label: 'Sharp-line manga cel (screentone)', family: 'cel', videoStyleLine: 'Sharp-line 2D cel animation with hard aliased ink outlines, shading built from solid hard-edged shadow blocks and gray screentone dot fields rather than gradients, a restrained near-monochrome palette carrying at most one muted accent hue, hair drawn as carved sections instead of individual strands, oversized eyes with stacked eyelash lines, flat plain backgrounds, radiating speed lines, and long-held dramatic poses.', charSheetStyle: '2D cel character sheet, sharp aliased black ink line, solid hard-edged shadow blocks and gray screentone dot shading with no gradients, restrained near-monochrome palette with at most one muted accent hue, hair drawn as carved sections not individual strands, large eyes with stacked eyelash lines, flat plain background, no 3D render', gridDescriptors: 'sharp-line 2D cel, hard aliased ink, solid shadow blocks, gray screentone dots, near-monochrome palette, sectioned hair, radiating speed lines', formatTone: 'sharp-line 2D cel', annotationThirdLine: 'MOOD', realism: false, onTwos: true, lightingId: 'hard-dawn', gradeId: 'mono-accent', docNote: "SHARPENED TO RESOLVE TWO COLLISIONS, both by moving THIS id because both counterparts are constrained. (1) vs inked-comic: the proposal parked the only separator in pairsWith.gradeId 'mono-accent', which the compat phase leaves unwired — distinctness that lives in an unwired field does not exist at ship, which was blocker 5. The palette separator is now inside all three emitted facets: manga-cel is a restrained near-monochrome palette with GRAY SCREENTONE dot fields; inked-comic is saturated primary red blue and yellow with FOUR-COLOR halftone. Those render visibly different frames. (2) vs the frozen `anime` and `cartoon`: hard ALIASED ink opposes anime's clean line, near-monochrome opposes both palettes, flat plain backgrounds oppose anime's painterly backgrounds, and long-held dramatic poses oppose cartoon's bouncy motion. vs the newly-sharpened ligne-claire: hard aliased heavy ink plus gray screentone dot fields, against a fine even-weight thin contour over unmodulated flat fill with no dot texture of any kind. The words manga and anime are safe; the titles are not — 'goku', 'naruto', 'luffy', 'jujutsu' and 'demon slayer' are live tokens and none appears above.", }, { id: 'rubber-hose-vintage', label: 'Vintage rubber-hose ink', family: 'cel', videoStyleLine: 'Vintage hand-inked animation with a consistent two to three pixel black outline of even weight, limbs that stretch and corkscrew with no anatomical logic, eyes drawn as two solid circles with dot pupils and no white sclera, geometric fan and chevron background patterns, a sepia and gold palette, and rhythmic musical motion at a choppy low frame cadence.', charSheetStyle: 'vintage hand-inked cartoon character sheet, consistent two to three pixel black outline of even weight, tube-shaped rubbery limbs, eyes as two solid circles with dot pupils and no white sclera, sepia and gold palette, geometric fan-patterned background', gridDescriptors: 'vintage rubber-hose ink, consistent thin even black outline, sepia and gold palette, geometric fan and chevron background, corkscrew limbs', formatTone: 'vintage inked cartoon', annotationThirdLine: 'MOOD', realism: false, onTwos: true, lightingId: 'neutral-studio', gradeId: 'warm-nostalgia', docNote: "Separates from the frozen `cartoon` on line weight (consistent thin two-to-three pixel even outline vs bold outline) and palette (sepia and gold vs saturated primaries), plus a construction tell nothing else has: eyes as two solid circles with dot pupils and no white sclera. Separates from the newly-sharpened ligne-claire, which now shares the thin-even-line axis, on FOUR independent properties held in all three of its own facets: sepia and gold against a calm mid-tone palette, tube-shaped rubbery corkscrewing limbs against organic freehand anatomy, eyes as solid circles with no sclera against ordinary drawn eyes, and geometric fan and chevron background patterns against ligne-claire's generous empty space. DROPPED 'four-fingered gloves' from the proposal's sheet — it passes both sanitizers cleanly but steers the model toward one studio's specific mascots, so the style stops returning a vintage-inked character and starts returning a particular figure. That is a distinctness defect as much as an IP one. 'rubber hose' is a technique term and safe; the emitted lines say 'geometric fan and chevron' rather than naming the period style, to stay clear of even period-adjacent branding.", }, { id: 'ligne-claire', label: 'Clear-line comic', family: 'cel', videoStyleLine: 'Clear-line comic animation drawn with a fine even-weight thin contour of consistent width on every form, organic freehand curves with no ruled edges and no geometric construction, no hatching and no shadow modeling anywhere, broad flat unmodulated fills in a calm mid-tone palette, foreground and background drawn at identical line priority so nothing is de-emphasized, generous empty space in the frame, and performance carried by small nuanced gestures and eye contact.', charSheetStyle: 'clear-line comic character sheet, fine even-weight thin contour of consistent width with organic freehand curves and no ruled edges, no hatching and no shadow modeling, broad flat unmodulated fills in a calm mid-tone palette, even line priority across every element, generous empty space, no 3D render', gridDescriptors: 'clear-line fine even-weight thin contour, organic freehand curves, no hatching, broad flat unmodulated fills, calm mid-tone palette, even line priority across foreground and background', formatTone: 'clear-line comic animation', annotationThirdLine: 'MOOD', realism: false, onTwos: false, lightingId: 'overcast', docNote: "SHARPENED TWICE. THE COLLISION THAT MATTERED IS THE FROZEN `cartoon`, AND IT IS NOW EXAMINED HEAD-ON. The previous revision only argued against flat-vector and never checked its nearest frozen neighbour: cartoon emits 'flat cel fills' and no shading either, so 'flat unmodulated color fills' and 'no hatching and no shadow modeling' separated nothing, and the old 'single uniform-weight hand-drawn contour' did not either, because a bold contour is uniform-weight. What was left was compositional (empty space, even line priority, small gestures), which image models apply weakly and which says nothing on a turnaround. cartoon owns exactly two rendering axes — BOLD outlines and a SATURATED PRIMARY palette — and this entry now opposes it on BOTH, in all three prose facets: a fine even-weight THIN contour of consistent width (thin against bold) and broad flat unmodulated fills in a CALM MID-TONE palette (calm mid-tone against saturated primaries). formatTone is deliberately left unchanged: it is a two-to-four-word tone slug across the whole register and the distinctness lens judges the two still surfaces separately from the clip surface, so the separation has to live — and now does live — in videoStyleLine, charSheetStyle and gridDescriptors. 'muted' was deliberately NOT used for the palette: it is painterly-2d's and watercolor-wash's word, and reaching for it would push this entry toward two existing entries on the exact axis being fixed; 'calm mid-tone' is unshared. SECOND SHARPENING, CARRIED FORWARD: 'organic freehand curves with no ruled edges and no geometric construction' in all three facets resolves the flat-vector collision from this side (line-present-and-organic against flat-vector's no-outline-and-ruler-straight). vs rubber-hose-vintage, which also has a thin even line: sepia and gold, tube limbs, eyes as solid circles with no white sclera and geometric fan and chevron grounds, against a calm mid-tone palette, organic anatomy and generous empty space. vs painterly-2d: a different family and a different substrate — a soft anti-aliased brush line over translucent warm painted shadow, against an even ink contour over unmodulated flat fill with no shadow modeling at all. NOTE its 'identical line priority' clause is the literal INVERSE of the detail-distribution rule, which is one of the two reasons detail distribution could not be an orthogonal facet — see `added`. gradeId left undefined: no GRADE id expresses clean flat mid-tone color. FILTER RE-VERIFIED FOR THE NEW STRINGS, MECHANICALLY: all four prose facets were run through the REAL compiled seedance-content-filter.js this session — sanitizePrompt(f,1) === f and preValidatePrompt(f).length === 0 on every one, zero ALL-CAPS tokens, zero CamelCase tokens, zero apostrophes, zero double quotes, ASCII only — plus six cross-seam composites (the Style: line at fp:1101, CAMERA CAPTURE at fp:1447, the storyboard header at fp:1098, the grid-variant 'Create a {duration} {tone} sequence' at fp:1423, SCENE & MOOD at fp:1470 and the Style & Mood seam at ms:367), all value-preserving.", }, { id: 'inked-comic', label: 'Inked comic print (halftone)', family: 'print', videoStyleLine: 'Inked comic-book animation with heavy black brush outlines of varying weight, four-color halftone dot separation visible in skin tones and shadow areas, a saturated primary red blue and yellow palette, radiating emphasis lines around impacts, and heroically exaggerated anatomy against more finely rendered faces.', charSheetStyle: 'inked comic-book character sheet, heavy black brush outline with weight variation, four-color halftone dot shading in skin and shadow, saturated primary red blue and yellow palette, exaggerated heroic anatomy, flat panel background', gridDescriptors: 'heavy black ink contour with weight variation, four-color halftone dots, saturated primary red blue and yellow, radiating emphasis lines', formatTone: 'inked comic-book animation', annotationThirdLine: 'MOOD', realism: false, onTwos: false, lightingId: 'hard-dawn', gradeId: 'teal-orange', docNote: "Palette and dot-model separator explicit in all three facets to break the manga-cel collision: FOUR-COLOR halftone dot separation plus a saturated primary red blue and yellow palette, against manga-cel's gray screentone and near-monochrome. Also separates from the new spot-ink-print, which has no black key line and only two or three flat inks with visible misregistration; and from the newly-sharpened ligne-claire, whose contour is fine and even-weight over untextured flat mid-tone fill, against this entry's heavy varying-weight black brush over four-color dot texture. WORST FRANCHISE EXPOSURE IN THE WHOLE HARVEST, on two independent axes, both defused: the source names a comics publisher and works its example as two named superheroes, and every one of those names is a live CELEBRITY_IP token deleted on retry; and the four-letter print-process acronym is all-caps and dies to BRAND_PATTERNS on the SAME retry, which is exactly why every facet says 'four-color halftone dot separation' instead. Use that phrasing wherever this style appears. annotationThirdLine set to MOOD, not the critique's suggested STYLE — STYLE is reserved for the one legacy id that is test-locked to it, and an arbitrary third value is the unpredictability the register removes.", }, { id: 'spot-ink-print', label: 'Spot-ink print (screenprint)', family: 'print', videoStyleLine: 'Limited spot-ink print animation using only two or three flat ink colors with no black key line, plates visibly misregistered by a few pixels so edges double and fringe, grainy mottled overprint where two inks cross, coarse paper texture showing through every fill, and no gradients anywhere.', charSheetStyle: 'limited spot-ink print character sheet, two or three flat ink colors only with no black key line, plates misregistered so edges double and fringe, grainy overprint where inks overlap, coarse paper texture showing through, no gradients', gridDescriptors: 'limited spot-ink print, two or three flat inks, misregistered doubled edges, grainy overprint, coarse paper texture', formatTone: 'spot-ink print animation', annotationThirdLine: 'MOOD', realism: false, onTwos: true, lightingId: 'overcast', docNote: "NEW — gives the print family a real second member. Before this, `family: 'print'` shipped with exactly one entry in an eight-family taxonomy. Collides with nothing registered: inked-comic is four-color halftone under a heavy black key line, flat-vector bans texture outright, graphite-sketch is monochrome pencil, and ligne-claire is a clean untextured flat fill under an even ink contour against this entry's no-key-line, misregistered, grainy overprinted paper. Directly relevant to this repo's live brand-explainer and mograph lanes. ID CHOICE: named for the property, not the process brand. `genreStyle.genre` is never interpolated into any prompt — the ONLY place the genre string is read is the `=== 'music-video'` comparison at filmmaking-prompts.ts:1455, re-read in source this session — so id spelling is a picker/UX call, not a submit-safety one; the brand-free name is chosen anyway so docs and CLI help stay clean. If an alias for the common trade name is ever wanted, check it against the free-text genres used in tests first (the `claymation` lesson). gradeId left UNDEFINED for the same reason as flat-vector: 'mono-accent' means near-monochrome with a single accent hue, which contradicts this entry's own 'two or three flat ink colors'.", }, { id: 'graphite-sketch', label: 'Graphite pencil', family: 'ink', videoStyleLine: 'Graphite pencil animation with visible graphite tooth on every stroke, shading built entirely from linear cross-hatching rather than gradients, no color fill anywhere, visible erasure ghosts left in, and a subtle frame-to-frame line boil.', charSheetStyle: 'graphite pencil character sheet on paper, visible graphite tooth on every stroke, cross-hatched shading with no gradients, no color fill anywhere, faint erasure marks left visible, plain paper background', gridDescriptors: 'graphite pencil, visible graphite tooth, linear cross-hatch shading, no color fill, erasure ghosts, line boil', formatTone: 'graphite pencil animation', annotationThirdLine: 'MOOD', realism: false, onTwos: true, lightingId: 'rembrandt-gray', docNote: "WIDENED AGAINST doodle-marker. The proposal gave both entries the same drawing gesture — 'lines that do not close at the corners' here and 'lines that overshoot their corners' there — plus visible corrections on both. The corner clause is removed from this entry and kept only on doodle-marker, at zero cost: this entry's real separators are graphite tooth, LINEAR cross-hatch shading, and no color fill anywhere, which directly contradicts doodle-marker's highlighter color swipes. One craft caveat baked into the emitted text: the bare word 'sketch' reads to a model as 'unfinished rough', so 'animation' and 'cross-hatched shading' must stay in to hold it as an intentional finished look. gradeId left UNDEFINED — 'mono-accent' would inject a single accent hue that a pure graphite drawing does not have, and 'noir-bw' would drag the word noir into a pencil style.", }, { id: 'doodle-marker', label: 'Doodle marker', family: 'ink', videoStyleLine: 'Rough hand-drawn doodle animation with wobbling variable-weight lines that overshoot their corners, color applied as loose highlighter-marker swipes that overrun the line work, in-frame comic marks such as speech bubbles motion ticks and star bursts, and visible sketch corrections left in.', charSheetStyle: 'rough marker and pen doodle character sheet, wobbling variable-weight line that overshoots corners, loose highlighter color swipes overrunning the outline, visible sketch corrections, plain white paper background', gridDescriptors: 'rough doodle line overshooting corners, highlighter marker color, in-frame comic marks, visible corrections', formatTone: 'hand-drawn doodle animation', annotationThirdLine: 'MOOD', realism: false, onTwos: true, lightingId: 'overcast', docNote: "Keeps the overshooting-corner gesture that graphite-sketch gave up, so the pair now separates on medium (colored highlighter plus in-frame comic marks vs monochrome pencil plus cross-hatch) AND on mark quality. One of the cleanest entries in the register — zero filter risk on every facet. gradeId undefined: no GRADE id expresses loose bright highlighter color.", }, { id: 'flat-vector', label: 'Flat vector', family: 'graphic', videoStyleLine: 'Flat vector motion design built from perfect geometric primitives with ruler-straight edges and true circles, no outline at all so forms are separated by color alone, solid fills with no gradients and no texture, a strict three to five color palette, and mechanical mathematically-eased motion with no organic follow-through.', charSheetStyle: 'flat vector character sheet, solid color fills with no gradients or texture, geometric construction from true circles and rectangles with ruler-straight edges, no outline at all so forms are separated by color alone, three to five color palette, flat plain background', gridDescriptors: 'flat vector, geometric primitives, no outline, solid flat fills, no gradient or texture, three to five color palette', formatTone: 'flat vector motion design', annotationThirdLine: 'MOOD', realism: false, onTwos: false, lightingId: 'overcast', docNote: "SHARPENED TWICE. (1) The proposal's 'uniform thin outlines or none at all' was an either/or baked into an emitted prompt — the operator could not predict whether they got outlines, which is precisely the unpredictability the register exists to remove. Committed to 'no outline at all so forms are separated by color alone'. (2) That same commitment plus 'ruler-straight edges and true circles' resolves the ligne-claire collision from this side, while ligne-claire moves from the other with 'organic freehand curves with no ruled edges'. Line-absent-and-ruled against line-present-and-organic is a two-axis separation and it survives this pass unchanged. The safest and most immediately useful entry, and the natural default for explainer and motion-graphics work. gradeId left UNDEFINED: 'mono-accent' means near-monochrome with a single accent hue and contradicts this entry's own 'three to five color palette'. NAMESPACE COLLISION — see remainingRisks: src/video/mograph/style-families.ts:81 already owns an id `flat-vector` whose summary is 'Bold flat-vector energy: thick strokes, hard shapes, sporty pace' (re-read in source this session), the opposite of this entry. Two registries, one id.", }, { id: 'digital-flat-gradient', label: 'Digital flat with gradients', family: 'graphic', videoStyleLine: 'Modern digital-flat animation with soft rounded character forms and large expressive features, very light or entirely absent ink lines, smooth digital color gradients everywhere and no halftone or screentone anywhere, highly saturated environment color, and layered parallax depth between foreground and background.', charSheetStyle: 'digital-flat character sheet, soft rounded forms with very light or no ink outline, smooth digital color gradients and no screentone, highly saturated palette, large expressive features, plain gradient background', gridDescriptors: 'digital flat color, minimal ink line, smooth gradients and no screentone, soft rounded forms with large expressive features, saturated environment, parallax depth layers', formatTone: 'digital-flat animation', annotationThirdLine: 'MOOD', realism: false, onTwos: false, lightingId: 'neutral-studio', docNote: "Explicitly NOT screentone — smooth digital gradients exactly where a manga register would put dot fields, which is what separates it from manga-cel; and gradients-everywhere directly contradicts flat-vector's no-gradients and ligne-claire's unmodulated flat fills. FACET COHERENCE FIXED: the proposal put 'large expressive features' only on the sheet; it is now on all three facets, per the rule that any character-design or palette property stated on one facet must be stated on all three or deliberately absent from all three. The source calls this look by a platform name that is arguably a brand as well as a medium word; it is not regexed today, but every emitted facet stays on properties and never uses it. gradeId undefined: no GRADE id expresses highly saturated flat digital color.", }, { id: 'neon-glow-line', label: 'Neon glow line art', family: 'graphic', videoStyleLine: 'Luminous line-art animation with glowing electric strokes carrying heavy bloom halos on a pure black ground, little or no interior fill so the line work carries the whole image, extreme contrast, and persistent motion trails that keep the stroke neon hue rather than turning white.', charSheetStyle: 'glowing line-art character sheet, luminous magenta and cyan strokes with a bloom halo on a pure black background, no interior fill, form described by line alone', gridDescriptors: 'neon glowing line art, pure black ground, bloom halo on strokes, no interior fill, extreme contrast', formatTone: 'luminous line-art animation', annotationThirdLine: 'MOOD', realism: false, onTwos: false, lightingId: 'neon-split', gradeId: 'cyberpunk-neon', sheetDivergesFromVideo: true, docNote: "SHEET DIVERGENCE — CARRIES `sheetDivergesFromVideo: true` IN THE SHIPPED INTERFACE. That boolean is re-added to the FINAL VisualStyle type this pass (see resolvedProblems); it has no field in the transport schema used to deliver this dataset, so it is recorded here and named in resolvedProblems as one of exactly three carriers (neon-glow-line, pixel-art, silhouette-shadow-puppet) that MUST be set to true in the shipped TypeScript. THE RECIPE, WHICH BELONGS HERE AND NOT IN AN EMITTED FIELD: a fill-free glowing line drawing cannot lock a face. When a character needs facial continuity, build a normal full-color line sheet to lock identity FIRST, then apply this register to the video line only. show-preflight should refuse a glow sheet as an identity anchor — see remainingRisks. BLOCKER FIXED IN THE PREVIOUS PASS AND STILL HOLDING: charSheetStyle is TRUNCATED at 'form described by line alone'; the proposal had welded two sentences of operator documentation onto the end of it, and charSheetStyle is interpolated verbatim into the character-sheet image prompt at filmmaking-prompts.ts:1023-1028, so that prose would have been submitted to a paid image model as if it were style description. Avoid the adjacent all-caps display-technology acronyms; both are deleted on retry.", }, { id: 'pixel-art', label: 'Pixel art', family: 'graphic', videoStyleLine: 'Pixel-art animation on a visible square pixel grid with hard edges and no anti-aliasing or blur anywhere, a strict eight to thirty-two color palette, flat sprite shading with no dimensional falloff, chunky readable silhouettes, tiled pixel backgrounds, and visibly stepped movement cycles.', charSheetStyle: 'pixel-art character sheet on a visible square pixel grid, hard aliased edges with no anti-aliasing, strict limited palette of roughly sixteen colors, flat sprite shading, chunky readable silhouette, flat single-color background', gridDescriptors: 'pixel art, square pixel grid, hard aliased edges, limited color palette, flat sprite shading, chunky silhouette, tiled background', formatTone: 'pixel-art animation', annotationThirdLine: 'MOOD', realism: false, onTwos: true, lightingId: 'neutral-studio', sheetDivergesFromVideo: true, docNote: "SHEET DIVERGENCE — CARRIES `sheetDivergesFromVideo: true` IN THE SHIPPED INTERFACE (second of the three carriers; the transport schema delivering this dataset has no field for the boolean, so it is recorded here and in resolvedProblems). THE RECIPE, WHICH BELONGS HERE: at this color depth a sheet cannot carry face detail, so lock identity on silhouette, palette and one distinct garment shape rather than on facial features; show-preflight should refuse a pixel sheet as an identity anchor. BLOCKER FIXED IN THE PREVIOUS PASS AND STILL HOLDING: charSheetStyle is TRUNCATED at 'flat single-color background', same defect and same emission site as neon-glow-line. SHARPENED against voxel: 'flat sprite shading with no dimensional falloff' makes this a flat 2D grid look, against voxel's dimensional cubes with hard right-angle CAST shadows. '8-bit' and '16-bit' are hardware-era terms and safe; the console-era characters the style implies are not — 'mario', 'luigi' and 'pikachu' are live tokens and none appears above. Numbers are spelled as words throughout the register partly because 'eleven' is itself a bare CELEBRITY_IP token. gradeId undefined: no GRADE id expresses a strict limited palette.", }, { id: 'silhouette-shadow-puppet', label: 'Silhouette / shadow puppet', family: 'graphic', videoStyleLine: 'Silhouette animation with every figure rendered as a pure solid black shape carrying no interior detail at all, action read entirely through pose gesture and outline, set against a richly detailed and fully colored background that carries all of the color and detail in the frame, strong backlighting, and extreme figure-to-ground contrast.', charSheetStyle: 'silhouette character sheet, the figure rendered as a pure solid black shape with no interior detail and no facial features, identity carried by outline alone across a turnaround of clear readable poses, strong backlight, plain bright backdrop', gridDescriptors: 'silhouette figures as solid black shapes, no interior detail, richly detailed fully colored background, strong backlight, extreme figure-to-ground contrast', formatTone: 'silhouette animation', annotationThirdLine: 'MOOD', realism: false, onTwos: false, lightingId: 'silhouette', sheetDivergesFromVideo: true, docNote: "SHEET DIVERGENCE — CARRIES `sheetDivergesFromVideo: true` IN THE SHIPPED INTERFACE (third and final carrier; recorded here and in resolvedProblems because the transport schema has no field for it). The sheet cannot carry facial identity — lock identity on outline and pose across a turnaround, or build a normal sheet first and apply this register to the video only. RESTORED in the previous pass: it was fully specified in the harvest and dropped SILENTLY, appearing neither in the proposal's styles nor anywhere in its droppedCandidates. It collides with nothing: vs neon-glow-line it is the exact inverse (solid black figure on a rich colored ground, against glowing colored strokes on pure black); vs the frozen `noir` it has a FULLY COLORED background against noir's monochrome photoreal capture. It also already has two consumers in this repo. (1) THE CONTENT-FILTER ESCAPE HATCH: filmmaking-prompts.ts:1062 already appends an ad-hoc backlit-silhouette clause for --no-faces, whose own comment says it 'keeps the sheet usable as a provider reference image despite real-person content filters' — re-read verbatim in source this session. Wiring --no-faces to SELECT this id would let one register drive both surfaces instead of an inline string. (2) The proposal's own type doc anticipated 'any future silhouette register'. DELIBERATE WORDING: the source says the background may be 'photorealistic'; the emitted lines say 'richly detailed and fully colored' instead, because a photoreal instruction fights the very filter-avoidance this entry exists to provide.", }, { id: 'stop-motion-clay', label: 'Clay stop-motion', family: 'material', videoStyleLine: 'Stop-motion puppet animation with physically modeled clay figures carrying fingerprints tool marks and visible mold seams in the surface, real dimensional film lighting with soft shadows and shallow focus, credible handheld camera parallax, matte plasticine surfaces with no gloss, and motion that steps frame to frame instead of interpolating smoothly.', charSheetStyle: 'stop-motion clay puppet character sheet, physically sculpted figure photographed under studio lighting, visible fingerprints tool marks and mold seams in the clay surface, matte plasticine finish, plain sweep backdrop', gridDescriptors: 'clay stop-motion puppet, visible fingerprints and seams, real dimensional lighting, stepped frame cadence, credible camera parallax', formatTone: 'clay stop-motion', annotationThirdLine: 'MOOD', realism: true, onTwos: true, lightingId: 'neutral-studio', gradeId: 'warm-nostalgia', docNote: "THE NOTABLE realism:true EXCEPTION, and the reason realism is not simply 'illustrated means false': the subject is a real physical object photographed under real light, so the anti-plastic captureRealismBlock clauses are exactly right here rather than actively wrong. CRITICAL NAMING CONSTRAINT: the id must NOT be `claymation`, and `claymation` must NOT become a GENRE_ALIASES entry — filmmaking-prompts.test.ts:264 asserts resolveGenreStyle('claymation') stays an UNKNOWN passthrough, and cinematography.test.ts:111 relies on genreDefaults('claymation') hitting the neutral fallback. Re-confirmed this session by calling the real compiled resolveGenreStyle('Claymation'), which returns genre 'Claymation' — original case, not the lowercased key — so the passthrough must return `genre.trim()`, never `key`. Registering that word turns two green tests red. Any future id or alias must be checked against the free-text genres used in tests, which this session enumerated as claymation, thriller, cinematic, totally-unknown and threads. British 'mould' normalised to 'mold'.", }, { id: 'paper-cutout', label: 'Layered paper cutout', family: 'material', videoStyleLine: 'Layered paper-cutout animation where every element is a separate flat paper sheet with visible creases fold lines and worn edges, hard-edged cast shadows between offset layers giving shallow physical depth, coarse paper grain, and motion produced by rotating and repositioning whole layers rather than deforming them.', charSheetStyle: 'paper-cutout character sheet, character built from flat colored paper sheets with visible creases and torn edges, hard-edged drop shadow between each offset layer, paper grain texture, plain neutral backing sheet', gridDescriptors: 'layered paper cutout, visible creases and fold lines, hard-edged layer shadows, paper grain, shallow stacked depth', formatTone: 'paper-cutout animation', annotationThirdLine: 'MOOD', realism: true, onTwos: true, lightingId: 'neutral-studio', gradeId: 'desaturated-earth', docNote: "Second realism:true illustrated entry, same reasoning as stop-motion-clay — physically photographed material. Separates from stop-motion-clay on construction (flat offset sheets with hard-edged shadows BETWEEN layers vs sculpted volume with fingerprints and seams) and on motion (whole-layer rotation and repositioning vs frame-by-frame deformation of a solid puppet). Zero filter risk.", }, { id: 'cel-shaded-3d', label: 'Cel-shaded 3D', family: 'rendered-3d', videoStyleLine: 'Cel-shaded 3D render with shading quantized into two or three flat color bands and hard-edged shadow boundaries that snap as the light angle changes, ink outlines on both the silhouette and the interior form lines, a limited flat palette with no gradient falloff, and full three-dimensional rotation and parallax under the flat surface.', charSheetStyle: 'cel-shaded 3D character sheet, bold ink outline on the silhouette and interior form lines, shading collapsed into two or three flat bands with hard shadow edges, limited flat color palette, no gradients, single strong directional key, turnaround on a plain backdrop', gridDescriptors: 'cel-shaded 3D, bold ink outlines on silhouette and form lines, two-tone flat shading, hard snapping shadow edges, limited palette, full 3D rotation', formatTone: 'cel-shaded 3D animation', annotationThirdLine: 'MOOD', realism: false, onTwos: false, lightingId: 'hard-dawn', gradeId: 'teal-orange', docNote: "True 3D parallax and rotation happening UNDERNEATH a flat 2D-looking surface. Materially OPPOSITE to the frozen `cgi` id (quantized flat bands and ink outlines vs ray-traced physically-based materials), so it must never be folded into it — which is why cgi's family is reassigned to rendered-3d here, so the two sit adjacent in any picker and the contrast is visible. Separates from the frozen `cartoon` on dimensionality: full three-dimensional rotation and parallax, plus ink outlines on INTERIOR form lines, neither of which a flat 2D cartoon has.", }, { id: 'low-poly', label: 'Low-poly faceted', family: 'rendered-3d', videoStyleLine: 'Low-poly render built from visible triangular facets each filled with a single flat color, hard creases at every edge, no texture detail anywhere, and light reading as per-facet tonal steps rather than smooth falloff.', charSheetStyle: 'low-poly character sheet, visible triangular facets, a single flat color per facet, hard edge creases, no texture maps, per-facet tonal stepping, plain backdrop', gridDescriptors: 'low-poly, visible triangular facets, flat per-facet color, hard creases, stepped per-facet shading', formatTone: 'low-poly 3D animation', annotationThirdLine: 'MOOD', realism: false, onTwos: false, lightingId: 'neutral-studio', gradeId: 'cool-isolation', docNote: "Distinct from voxel because the primitive is an arbitrary TRIANGLE, not a cube on a grid — and light reads as per-facet tonal steps rather than voxel's hard right-angle cast shadows. The harvested lit variant carried the all-caps physically-based-rendering acronym, which the ALL-CAPS BRAND_PATTERN deletes (the same mechanism verified this session on cgi's grid, where PBR is deleted outright); this entry says 'no texture detail anywhere' and, where the lit variant is wanted, the guidance is to phrase it as 'physically accurate materials' rather than the acronym.", }, { id: 'voxel', label: 'Voxel cube grid', family: 'rendered-3d', videoStyleLine: 'Voxel render with every form built from uniform cubes on a fixed grid, stair-stepped curves and diagonals, a single flat color per cube, hard right-angled cast shadows, and chunky blocky dimensional silhouettes.', charSheetStyle: 'voxel character sheet, body built entirely from uniform cubes on a fixed grid, stair-stepped curves, one flat color per cube, hard right-angle cast shadows, plain backdrop', gridDescriptors: 'voxel, uniform cube grid, stair-stepped edges, flat per-cube color, hard right-angle cast shadows', formatTone: 'voxel animation', annotationThirdLine: 'MOOD', realism: false, onTwos: false, lightingId: 'neutral-studio', docNote: "THIS ENTRY EARNS ITS PLACE ON SAFETY GROUNDS, not just coverage. The harvested source describes the look by naming a specific game, and that title is NOT in CELEBRITY_IP_PATTERNS and is not CamelCase, so BOTH sanitizers leave it untouched and our own retry path would forward a game title straight to the provider. It must be excluded BY CONSTRUCTION, because the retry path will not save you — a registered, property-only voxel line IS the fix. Generalises to the register's real scope limit: submit-safety here means 'the style word survives OUR level-1 sanitization', not 'the provider will accept it'. '8-bit' and 'retro-computer' are safe substitutes for the era. gradeId undefined: no GRADE id expresses flat per-cube color.", }, ]; export const VISUAL_STYLES: readonly VisualStyle[] = STYLES; export const STYLE_BY_ID: ReadonlyMap = new Map( STYLES.map((s) => [s.id, s]), ); export const STYLE_IDS: readonly string[] = STYLES.map((s) => s.id); /** Styles grouped for pickers and `--styles` listings. */ export function stylesByFamily(): ReadonlyMap { const out = new Map(); for (const s of STYLES) { const bucket = out.get(s.family); if (bucket) bucket.push(s); else out.set(s.family, [s]); } return out; }