336 lines
28 KiB
JavaScript
336 lines
28 KiB
JavaScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import vm from "node:vm";
|
|
|
|
const root = process.cwd();
|
|
const mainPath = path.join(root, "main.js");
|
|
const cardsRoot = path.join(root, "assets", "cards");
|
|
const promptsDir = path.join(cardsRoot, "prompts");
|
|
|
|
function makeElement() {
|
|
return {
|
|
className: "",
|
|
dataset: {},
|
|
style: { setProperty() {} },
|
|
children: [],
|
|
textContent: "",
|
|
innerHTML: "",
|
|
addEventListener() {},
|
|
replaceChildren(...nodes) {
|
|
this.children = nodes;
|
|
},
|
|
prepend(node) {
|
|
this.children.unshift(node);
|
|
},
|
|
remove() {},
|
|
};
|
|
}
|
|
|
|
function buildDomStub() {
|
|
const nodes = new Map();
|
|
return {
|
|
querySelector(selector) {
|
|
if (!nodes.has(selector)) nodes.set(selector, makeElement());
|
|
if (selector === "#emptyCardTemplate") {
|
|
nodes.get(selector).content = { cloneNode: () => makeElement() };
|
|
}
|
|
return nodes.get(selector);
|
|
},
|
|
createElement: makeElement,
|
|
};
|
|
}
|
|
|
|
function damageSpec(stage) {
|
|
const specs = [
|
|
{
|
|
label: "normal",
|
|
visual: "intact armor and clothing, pristine battle-ready silhouette",
|
|
impactIntensity:
|
|
"no impact damage yet; the card should look fully prepared before combat",
|
|
exposure:
|
|
"no battle-damage exposure yet; mature silhouette is visible through intact adult outfit design",
|
|
poseNote: "confident ready stance",
|
|
expression:
|
|
"controlled confident expression, eyes focused, no distress",
|
|
missingArmor:
|
|
"no missing armor or clothing; all equipment is intact",
|
|
destructionFloor:
|
|
"0% armor/equipment destruction: the baseline card must be fully intact before combat",
|
|
damageCoverage:
|
|
"all outfit and armor zones are intact and clean; no damage distribution is needed at this stage",
|
|
protectedZoneDamage:
|
|
"no protected-zone damage yet; chest armor or bodice, hip armor, rear skirt or coat panels, and seat armor are intact before combat",
|
|
baseLayerDamage:
|
|
"no base-layer damage yet; support underlayers, bodysuit panels, and lower coverage panels are intact before combat",
|
|
camera:
|
|
"front or three-quarter front view for clear character identity",
|
|
},
|
|
{
|
|
label: "light-damage",
|
|
visual:
|
|
"light battle damage from a clear opening hit: scratched and lightly dented armor or modern gear, torn jacket or cloak edges, scuffed gloves, one shoulder strap loosened, cracked small accessory or visor edge, small visible exposure around collarbone, shoulder edge, forearm, waistline, or upper thigh",
|
|
impactIntensity:
|
|
"light damage must still look like a real strike landed: include visible scuffs, dents, loosened straps, and at least one broken small accessory, while keeping the character mostly combat-ready",
|
|
materialPacing:
|
|
"material-aware opening damage: cloth, ribbons, capes, thin bodysuit edges, and leather straps may tear or fray early; metal armor, hard sci-fi plates, helmets, and mechanical gear should mostly dent, scratch, crack at fasteners, or bend slightly instead of vanishing all at once",
|
|
exposure:
|
|
"low but noticeable battle-damage exposure: collarbone, shoulder edge, forearm, waistline, or upper thigh should be visible from damaged outer layers",
|
|
poseNote: "still composed but reacting to an opening exchange",
|
|
expression:
|
|
"annoyed grimace, narrowed eyes, clenched jaw, clearly frustrated by the first hit",
|
|
missingArmor:
|
|
"minor loss of outer accessories only: torn glove edge, loosened shoulder strap, scuffed boot armor",
|
|
destructionFloor:
|
|
"opening-hit destruction only: keep the character mostly combat-ready, but make the first visible armor/equipment failures clear enough to establish later cumulative damage",
|
|
damageCoverage:
|
|
"light damage should be distributed across at least three visible zones, such as a shoulder strap, sleeve or glove, waist edge, thigh guard, boot guard, visor, or small accessory, so no single isolated tear carries the whole stage",
|
|
protectedZoneDamage:
|
|
"light damage may include small scuffs, dents, or loosened fasteners on chest armor or bodice edges, hip armor, rear skirt or coat panels, or seat armor, while preserving opaque coverage and keeping the adult pinup combat context clear",
|
|
baseLayerDamage:
|
|
"light damage may scuff or loosen visible support underlayers, bodysuit edges, or lower coverage seams, but they mostly remain intact at this stage",
|
|
camera:
|
|
"three-quarter front view or slight side angle, enough to show both face and first armor damage",
|
|
},
|
|
{
|
|
label: "medium-damage",
|
|
visual:
|
|
"moderate battle damage from repeated heavy hits: cracked shoulder armor or protective gear, bent plates, torn outer sleeves, loosened or snapped belts, damaged protective plates, exposed forearms, bare shoulder, torn neckline or side seam, clearly exposed abdomen and side torso, exposed upper thigh and hip line through broken outer layers, adult pinup silhouette already unmistakable, and no clean replacement underlayer hiding the damage",
|
|
impactIntensity:
|
|
"medium damage must read stronger than cosmetic tearing: show bent metal, snapped straps, cracked guards, separated seams, bruising-free impact marks on gear, and a posture that clearly reacts to forceful combat impact",
|
|
materialPacing:
|
|
"material-aware medium damage: compared with the damage-0 baseline, cloth layers, capes, skirts, ribbons, straps, and soft leather should be rapidly shredded or partly missing; metal or rigid armor should survive longer but must show real failures such as bent plates, cracked joins, broken rivets, detached sections, crushed edges, and disabled mechanisms",
|
|
exposure:
|
|
"clear adult battle-damage exposure: bare shoulder, side torso, abdomen, upper thigh, hip line, back angle, and emphasized mature bust silhouette should be obvious together, not hidden by intact modest underlayers, clean underwear, shorts, leotards, swimsuits, or new coverage panels",
|
|
poseNote: "strained but still fighting with focus",
|
|
expression:
|
|
"painful frown, wet eyes, anger and disbelief, trying not to cry while staying in the fight; if hit in the abdomen, show a gasping open mouth and strained breathing",
|
|
missingArmor:
|
|
"visible loss around hands, forearms, one shoulder, boot guards, and side-abdomen armor; damage suggests repeated heavy impacts",
|
|
destructionFloor:
|
|
"minimum 50% visible armor/equipment destruction relative to damage-0: at least half of the original outfit, armor, straps, plates, weapons, and equipment must no longer look intact. Dirt, soot, scratches, thin crack lines, background debris, pose changes, and floating fragments do not count toward this 50% unless the original worn gear itself is visibly torn away, bent, detached, disabled, or hanging loose across the body",
|
|
damageCoverage:
|
|
"medium damage should visibly affect upper body, arms, abdomen or waist, hips or thighs, and at least one boot or leg guard; do not leave a major clothing or armor region looking untouched",
|
|
protectedZoneDamage:
|
|
"medium damage must not avoid the chest or rear-body gear: chest armor or bodice panels, side-bust armor edges, hip plates, rear waist plates, seat armor, back skirt panels, or coat tails should show cracks, torn seams, dents, missing outer trim, or broken straps, while opaque remnants cover intimate areas",
|
|
baseLayerDamage:
|
|
"medium damage must not leave bra-shaped support tops, base bodysuit panels, compression shorts, brief-like lower covers, or other intimate-coverage underlayers looking pristine; show scuffed fabric, torn edges, stretched seams, snapped trim, soot, dents in reinforced liners, and uneven deformation while opaque coverage remains. If the image reads like clean underwear, a fresh swimsuit, or a teen-safe bodysuit after the outer gear breaks, it fails",
|
|
camera:
|
|
"side view or strong three-quarter side view, body twisted from impact so shoulder and abdomen damage are visible",
|
|
},
|
|
{
|
|
label: "heavy-damage",
|
|
visual:
|
|
"heavy battle damage after a brutal exchange: broken and warped outer armor or modern gear, shredded mantle/jacket/stage outfit, fractured bracers, missing glove armor, crushed or split waist plates, damaged boots or bare foot/ankle on one side, high-exposure near-nude non-explicit battle pinup presentation with heavily exposed shoulders, back, abdomen/midriff, hips, upper thighs, side-bust or under-bust silhouette, and only battered opaque costume remnants through destroyed outer armor",
|
|
impactIntensity:
|
|
"heavy damage should look severe and unmistakable: armor plates bent out of shape, straps snapped, seams split open, bracers fractured, boots damaged, weapon accessories partly broken, and the character's balance visibly failing from repeated impacts",
|
|
materialPacing:
|
|
"material-aware heavy damage: soft materials should be mostly torn open or missing by now; leather should split, curl, and lose straps; metal armor should not simply disappear but should show multiple large plates cracked, warped, unlatched, hanging by broken fasteners, or fallen as readable chunks near the character",
|
|
exposure:
|
|
"push to high-exposure near-nude non-explicit battle-damage presentation: exposed shoulders, back, side-bust silhouette, under-bust edge, abdomen, hips, upper thighs, and tiny torn outfit remnants should make the impact feel severe and adult-only, with no clean bra, shorts, swimsuit, leotard, bodysuit, tights, magical mist, hair curtain, or pristine replacement fabric used to hide the damage",
|
|
poseNote: "wounded, guarded, barely keeping balance after a brutal exchange",
|
|
expression:
|
|
"tearful angry grimace, trembling lower lip, brows pinched, resentful eyes that show she hates losing; abdominal-hit reaction such as open mouth, gasping, hunched posture, and a small combat-pain saliva strand is allowed",
|
|
missingArmor:
|
|
"major loss around hands, feet, shoulders, abdomen, waist plates, and bracers; broken pieces scattered nearby",
|
|
destructionFloor:
|
|
"minimum 70% visible armor/equipment destruction relative to damage-0: most of the original protective outfit and carried equipment must be broken, missing, warped, unlatched, disabled, or hanging loose. Large intact bodysuit areas, pristine chest/hip panels, clean boots, or mostly complete armor silhouettes fail this stage even if there are many scratches, dirt marks, or background fragments",
|
|
damageCoverage:
|
|
"heavy damage must be full-body and balanced: headgear or visor, shoulders, chest armor or bodice, back or cloak, sleeves, gloves, abdomen, waist, hips, thighs, knees, boots, and weapon accessories should all show cracks, tears, missing outer plates, scuffs, or deformation; avoid leaving any major region pristine while another region is over-destroyed",
|
|
protectedZoneDamage:
|
|
"heavy damage must visibly affect chest and rear-body equipment too: dented or split chest armor, torn bodice seams, damaged under-bust straps, cracked side-bust armor edges, broken hip plates, torn rear skirt or coat panels, crushed seat armor, and snapped rear waist fasteners should be present as combat damage with adult high-exposure pinup appeal; never leave bust or rear/hip regions unusually pristine compared with the rest of the body",
|
|
baseLayerDamage:
|
|
"heavy damage must visibly affect support underlayers and coverage panels too: bra-shaped support pieces, bodysuit liners, compression shorts, hip wraps, brief-like lower covers, and modesty panels should be torn, scuffed, warped, soot-marked, strap-broken, or partially covered by broken armor remnants. In this stage they should read as battered opaque remnants, not clean lingerie, clean shorts, a swimsuit, or a modest replacement suit; they must still preserve non-explicit opaque coverage",
|
|
camera:
|
|
"dramatic side view, rear three-quarter view, or over-the-shoulder angle while keeping face partially visible",
|
|
},
|
|
{
|
|
label: "defeated",
|
|
visual:
|
|
"defeated state after overwhelming combat: kneeling, collapsed, or sitting back after battle, armor system barely holding together, broken armor pieces around them, torn outer garment layers, missing hand and foot armor, shattered shoulder or waist plates, maximum non-explicit high-exposure adult battle pinup presentation with bare shoulders, exposed back or side-back, exposed abdomen/midriff, hips, upper thighs, side-bust or under-bust silhouette, and only battered opaque remnants through destroyed outer armor",
|
|
impactIntensity:
|
|
"defeated damage should be the strongest non-gore stage: the outfit and armor should look comprehensively wrecked by combat, with collapsed straps, broken fasteners, crushed guards, missing outer plates, disabled weapon pieces, and a posture that clearly communicates she can no longer keep fighting",
|
|
materialPacing:
|
|
"material-aware defeated damage: cloth, capes, skirts, ribbons, and soft suit layers should remain only as battered opaque remnants; leather should be split and strap-broken; metal and mechanical armor should be comprehensively ruined through crushed sections, torn hinges, missing plates, disabled joints, broken weapons, and scattered large pieces rather than cosmetic scuffs",
|
|
exposure:
|
|
"maximum non-explicit high-exposure adult battle-damage presentation for the defeated card: broad exposed shoulder/back/side torso/abdomen/hip/thigh areas at once, dramatic tiny torn costume remnants, adult defeated pinup body language, and emphasized mature silhouette while staying framed as combat defeat rather than a sexual act; do not add clean underwear, hot pants, leotards, swimsuits, opaque tights, magical censorship mist, hair curtains, or pristine replacement panels",
|
|
poseNote: "battle-worn, emotionally overwhelmed, clearly defeated, no gore",
|
|
expression:
|
|
"frustrated tears, unfair-loss expression, clenched teeth or trembling open mouth, tear tracks, angry shame rather than calm dignity; defeated abdominal-hit pain reaction with open mouth, drool/saliva at the lip, and labored breathing is allowed when framed as combat pain",
|
|
missingArmor:
|
|
"the most intense equipment loss: shattered shoulder plates, missing bracers and glove armor, broken boot guards, torn waist and abdomen armor, scattered fragments",
|
|
destructionFloor:
|
|
"minimum 85% visible armor/equipment destruction relative to damage-0: the original armor, outfit, straps, weapons, and equipment system should be comprehensively wrecked, with only battered opaque remnants and broken supports still covering intimate areas. If more than a small minority of the original suit or armor reads as clean, continuous, or functional, the defeated card fails",
|
|
damageCoverage:
|
|
"defeated damage must read across the entire outfit and armor system: damaged headgear, shoulders, chest armor or bodice, back or cloak, sleeves, gloves, abdomen, waist, hips, thighs, knees, boots, and weapon accessories; every major zone should show battle damage while opaque remnants still cover intimate areas",
|
|
protectedZoneDamage:
|
|
"defeated damage must include the same destruction level on chest and rear-body gear as everywhere else: warped chest armor or torn bodice panels, broken under-bust support straps, damaged cleavage-edge armor without explicit anatomy focus, fractured hip plates, torn rear skirt or coat panels, crushed seat armor, and broken rear waist fasteners; these areas must not look selectively protected or repaired, while opaque remnants cover intimate areas",
|
|
baseLayerDamage:
|
|
"defeated damage must make support underlayers and intimate-coverage panels look battle-wrecked too: chest support pieces, bodysuit liners, compression shorts, hip wraps, brief-like lower covers, and modesty panels should be torn at edges, dirtied, deformed, strap-broken, soot-marked, and partly overlapped by shattered armor fragments. Keep only battered opaque remnants over intimate anatomy; never leave pristine underwear, clean shorts, a swimsuit-like layer, or newly repaired coverage",
|
|
camera:
|
|
"rear three-quarter, side-back, or low side view; show back/shoulder/cloak damage while keeping enough face profile to read pain",
|
|
},
|
|
];
|
|
return specs[stage];
|
|
}
|
|
|
|
function promptFor(character, stage) {
|
|
const spec = damageSpec(stage);
|
|
const elementName = {
|
|
water: "water/수",
|
|
metal: "metal/금",
|
|
earth: "earth/지",
|
|
fire: "fire/화",
|
|
wood: "wood/목",
|
|
}[character.affinity] ?? character.affinity;
|
|
const adultAppeal =
|
|
"adult female collectible-card appeal: emphasize large breasts through the armor, uniform, stage outfit, or gear silhouette; curvy mature body proportions; elegant sensual costume design; adult pinup body language is encouraged when framed as battle damage or defeat; high-damage cards should read adult-only, high-exposure, and not teen-safe";
|
|
return [
|
|
"Use case: stylized-concept",
|
|
"Asset type: high-resolution individual trading card illustration",
|
|
`Primary request: Create a unique full-card illustration for ${character.id} ${character.name}, damage stage ${stage} (${spec.label}).`,
|
|
`Subject: adult ${character.gender} ${character.race}, ${character.body}, ${character.title}, ${character.role}, weapon/equipment ${character.weapon}.`,
|
|
`World/era concept: ${character.world}; ${character.era}. This roster is not limited to medieval fantasy; characters can come from modern campuses, idol stages, cyberpunk streets, space colonies, sports arenas, mythic fashion worlds, or other time periods.`,
|
|
`Lighting/time/weather: ${character.lighting}. Do not default every battle to night; use daytime, afternoon, morning, cloudy, indoor, or night lighting only when this field calls for it.`,
|
|
`Signature costume/equipment: ${character.costume}.`,
|
|
`Unique appearance DNA: ${character.appearance.faceShape}; ${character.appearance.eyeStyle}; ${character.appearance.noseStyle}; ${character.appearance.lipStyle}; ${character.appearance.skinTone}; ${character.appearance.hairStyle}; ${character.appearance.bodyDetail}; ${character.appearance.bustShape}; ${character.appearance.presence}. Make this face and body clearly different from other cards.`,
|
|
`Identity lock across stages: preserve the exact same person in every damage stage--same race/species, ear shape, face structure, eye shape, nose, lips, skin tone, hair color, hair length, hairstyle, body proportions, bust shape, and mature presence. Damage may change clothing, armor, pose, expression, dirt, sweat, and injury reaction, but must never change a human into an elf, change ear shape, change hair color, change age, change ethnicity, or replace the character with a different-looking person.`,
|
|
`Personality and pose: ${character.personality}; ${character.pose}; ${spec.poseNote}.`,
|
|
`Facial expression: ${spec.expression}.`,
|
|
`Camera/view variation: ${spec.camera}. Across a character's five damage stages, avoid repeating the same straight-front pose; include front, side, and rear three-quarter views where appropriate.`,
|
|
`Adult visual appeal: ${character.appealFocus}; ${adultAppeal}.`,
|
|
`Scene/backdrop: ${character.scene}; ${elementName} elemental atmosphere; no other characters.`,
|
|
`Style/medium: ${character.style}, portrait card composition.`,
|
|
"Manager-preferred clean card style: prioritize the clear, calm readability of the C0007 baseline approach--large silhouette, clean focal areas, broad elemental or gravity shapes, crisp costume/equipment detail, and a background that supports the character instead of competing with her.",
|
|
"Strict visual noise control: do not fill the image with tiny sparkles, glitter dust, particle clouds, micro-shards, confetti debris, random luminous specks, hairline glowing filigree, spiderweb crack networks, or glittering wire/vine nets. Show damage through large readable torn panels, bent armor plates, broken equipment pieces, broad impact arcs, and a few bold elemental shapes; leave negative space around the face, torso, weapon, and main silhouette so the card reads cleanly at game size.",
|
|
"Composition/framing: full body or knees-up character centered, strong silhouette, vertical card art, cinematic but readable.",
|
|
`Damage state: ${spec.visual}.`,
|
|
`Impact intensity: ${spec.impactIntensity}. Make the damage feel forceful and physically convincing, not like mild fashion distressing.`,
|
|
`Material-aware damage pacing: ${spec.materialPacing ?? "no material damage yet; all materials remain intact before combat"}. Soft materials such as cloth, capes, ribbons, skirts, bodysuit edges, and leather straps should fail faster; hard materials such as metal armor, rigid sci-fi plates, helmets, drones, weapons, and mechanical joints should fail more slowly but must show dents, cracks, bent shapes, broken fasteners, detached plates, and disabled mechanisms as damage escalates.`,
|
|
"Baseline comparison gate: evaluate every damaged stage against this character's damage-0 outfit and equipment. From damage-2 onward, the worn costume/armor/equipment itself must be visibly destroyed by the required percentage; dirt, soot, scratches, thin crack lines, glow effects, pose changes, background rubble, and loose floating debris do not count unless the original worn gear is actually broken, torn away, detached, disabled, or hanging loose.",
|
|
`Armor/equipment destruction floor: ${spec.destructionFloor}. Treat this as a visual minimum for the stage, while keeping the image readable and non-gore.`,
|
|
`Damage coverage: ${spec.damageCoverage}. Damage must feel physically consistent across the whole outfit and armor system. Adult pinup posing, hip-forward stances, arched backs, twisted torsos, side-back views, exposed-leg kneeling, damaged-costume side-bust or under-bust silhouettes, and sensual defeated body language are strongly encouraged when they read as battle damage or defeat rather than a sex act.`,
|
|
`Protected-zone damage balance: ${spec.protectedZoneDamage}. Damage to chest, bust armor, hips, and rear-body outfit panels should read as natural combat destruction of equipment and clothing, never as selective preservation.`,
|
|
`Base-layer damage balance: ${spec.baseLayerDamage}. The inner coverage should stay non-explicit and opaque where needed, but it must share the same battle history as the rest of the outfit instead of looking untouched.`,
|
|
"Cumulative damage continuity: each later damage stage must preserve every visible tear, crack, missing armor plate, damaged accessory, and exposed non-intimate area established in earlier stages, then add new damage on top. Never repair, clean up, replace, or re-cover a previously damaged zone as the stage number increases.",
|
|
`Battle-damage exposure direction: ${spec.exposure}. The card should not look modest or fully covered after impact; exposure is part of the adult card-game reward and should be aggressively favored while remaining framed as combat damage, damaged costume, or defeat. From damage-3 onward, avoid teen-safe costume preservation: use broken armor pieces and torn opaque remnants instead of clean replacement underlayers. High-damage cards fail if they use clean bras, panties, hot pants, compression shorts, leotards, swimsuits, opaque tights, pristine bandages, magical censorship mist, hair curtains, or unbroken replacement panels to hide the body.`,
|
|
`Missing gear/clothing emphasis: ${spec.missingArmor}. Emphasize battle intensity through missing or damaged hand, foot, shoulder, abdomen, hip, and torso gear where appropriate, adapting the damage to this character's era and outfit.`,
|
|
`Continuity: keep this character's face, body type, race/species, ear shape, hair color/style, weapon/equipment, world/era, costume silhouette, color motif, and elemental identity consistent across all five damage stages. If any later stage looks like a different person, it is a failed card and must be regenerated.`,
|
|
"Constraints: all characters are adults; adult-oriented multi-world card art; sensual silhouette, adult pinup posing, high-exposure near-nude presentation, and body exposure are encouraged when framed as battle damage or defeat; pain expressions, tears, gasping, and small saliva/drool details must read as combat injury reactions; no intimate act; no penetration; no gore; no minors; no text; no logo; no watermark; no explicit anatomy focus.",
|
|
"Avoid: childlike appearance, underage cues, malformed hands, extra limbs, cropped head, UI elements.",
|
|
].join("\n");
|
|
}
|
|
|
|
const source = fs.readFileSync(mainPath, "utf8");
|
|
const context = {
|
|
document: buildDomStub(),
|
|
window: { setInterval() {}, clearInterval() {} },
|
|
fetch: async () => ({ ok: false }),
|
|
console,
|
|
};
|
|
const exportCode = `${source}
|
|
globalThis.__cardExport = {
|
|
damageStages: DAMAGE_ART_STAGES,
|
|
characters: CHARACTERS.map((character) => ({
|
|
id: character.id,
|
|
index: character.index,
|
|
name: character.name,
|
|
gender: character.gender,
|
|
race: character.race,
|
|
body: character.body,
|
|
affinity: character.affinity,
|
|
stars: character.stars,
|
|
title: character.title,
|
|
role: character.role,
|
|
weapon: character.weapon,
|
|
personality: character.personality,
|
|
pose: character.pose,
|
|
origin: character.origin,
|
|
world: character.world,
|
|
era: character.era,
|
|
scene: character.scene,
|
|
lighting: character.lighting,
|
|
costume: character.costume,
|
|
style: character.style,
|
|
damageProfile: character.damageProfile,
|
|
appealFocus: character.appealFocus,
|
|
appearance: character.appearance,
|
|
stats: character.stats
|
|
}))
|
|
};`;
|
|
|
|
vm.runInNewContext(exportCode, context);
|
|
|
|
const exported = context.__cardExport;
|
|
fs.mkdirSync(cardsRoot, { recursive: true });
|
|
fs.mkdirSync(promptsDir, { recursive: true });
|
|
|
|
const manifest = {
|
|
schemaVersion: 1,
|
|
artRoot: "assets/cards",
|
|
damageStages: Array.from({ length: exported.damageStages }, (_, stage) => ({
|
|
stage,
|
|
...damageSpec(stage),
|
|
})),
|
|
expectedImageCount: exported.characters.length * exported.damageStages,
|
|
imageSizeTarget: "portrait high resolution, 2048x3072 or better for final production",
|
|
safetyStyle: "adult-oriented multi-world pinup combat damage; emphasized mature silhouettes, adult pinup posing, high-exposure near-nude/body exposure encouraged as battle-damage or defeat presentation; no minors, intimate acts, penetration, gore, or explicit anatomy focus",
|
|
characters: exported.characters.map((character) => ({
|
|
...character,
|
|
art: Array.from({ length: exported.damageStages }, (_, stage) => ({
|
|
damageStage: stage,
|
|
path: `assets/cards/${character.id}/damage-${stage}.png`,
|
|
promptId: `${character.id}-D${stage}`,
|
|
status: "needed",
|
|
})),
|
|
})),
|
|
};
|
|
|
|
const promptLines = [];
|
|
for (const character of exported.characters) {
|
|
for (let stage = 0; stage < exported.damageStages; stage += 1) {
|
|
promptLines.push(
|
|
JSON.stringify({
|
|
promptId: `${character.id}-D${stage}`,
|
|
characterId: character.id,
|
|
damageStage: stage,
|
|
outputPath: `assets/cards/${character.id}/damage-${stage}.png`,
|
|
prompt: promptFor(character, stage),
|
|
}),
|
|
);
|
|
}
|
|
}
|
|
|
|
const availablePath = path.join(cardsRoot, "available-assets.json");
|
|
if (!fs.existsSync(availablePath)) {
|
|
fs.writeFileSync(
|
|
availablePath,
|
|
JSON.stringify(
|
|
{
|
|
schemaVersion: 1,
|
|
assets: [],
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
"utf8",
|
|
);
|
|
}
|
|
|
|
fs.writeFileSync(path.join(cardsRoot, "card-manifest.json"), JSON.stringify(manifest, null, 2), "utf8");
|
|
fs.writeFileSync(path.join(promptsDir, "card-image-prompts.jsonl"), `${promptLines.join("\n")}\n`, "utf8");
|
|
|
|
console.log(
|
|
JSON.stringify(
|
|
{
|
|
characters: exported.characters.length,
|
|
damageStages: exported.damageStages,
|
|
expectedImageCount: manifest.expectedImageCount,
|
|
manifest: "assets/cards/card-manifest.json",
|
|
prompts: "assets/cards/prompts/card-image-prompts.jsonl",
|
|
available: "assets/cards/available-assets.json",
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
);
|