Improve camera and pose variation for card prompts

This commit is contained in:
2026-06-18 00:12:00 +09:00
parent 42bc05cce7
commit d52fad552a
4 changed files with 5100 additions and 5013 deletions

View File

@@ -63,7 +63,7 @@ function damageSpec(stage) {
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",
"front three-quarter or low-angle front view for clear character identity",
},
{
label: "light-damage",
@@ -89,7 +89,7 @@ function damageSpec(stage) {
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",
"three-quarter front or low/high mixed angle, enough to show both face and first armor damage",
},
{
label: "medium-damage",
@@ -115,7 +115,7 @@ function damageSpec(stage) {
baseLayerDamage:
"medium damage must not leave support layers, suit liners, lower wraps, or other 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 replacement coverage or teen-safe re-covering 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",
"side view, strong three-quarter, or low-angle side frame to keep shoulder and abdomen damage visible",
},
{
label: "heavy-damage",
@@ -141,7 +141,7 @@ function damageSpec(stage) {
baseLayerDamage:
"heavy damage must visibly affect support underlayers and coverage panels too: support pieces, suit liners, lower wraps, and coverage 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 replacement coverage; 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",
"dramatic low-angle side, rear three-quarter, or over-the-shoulder angle while keeping face partially visible",
},
{
label: "defeated",
@@ -167,12 +167,97 @@ function damageSpec(stage) {
baseLayerDamage:
"defeated damage must make support underlayers and coverage panels look battle-wrecked too: support pieces, suit liners, lower wraps, and coverage panels should be torn at edges, dirtied, deformed, strap-broken, soot-marked, and partly overlapped by shattered armor fragments. Keep only battered opaque remnants where coverage is required; never leave pristine replacement coverage",
camera:
"rear three-quarter, side-back, or low side view; show back/shoulder/cloak damage while keeping enough face profile to read pain",
"rear three-quarter, side-back, or high/low side view; show back/shoulder/cloak damage while keeping enough face profile to read pain",
},
];
return specs[stage];
}
const CAMERA_VARIANTS = {
normal: [
"front three-quarter composition, clean face visibility, full body centered",
"low-angle front composition from knee-height, upward energy on the stance and hips",
"high-angle three-quarter look-down view, knees and torso readable while still showing face",
"soft side-front camera, weight shifted into the lead foot",
],
light: [
"three-quarter front shot with slight side angle, enough to show first damage marks",
"low side angle showing bent knee, shoulder hit, and first torn fabric edge",
"high-angle diagonal from above, showing torso recoil and waist/arm damage",
"dynamic side-front camera with a small shoulder turn",
],
medium: [
"strong side view, body twisted from force so shoulder, torso, and abdomen damage are obvious",
"low-stance three-quarter side view that reveals back-side torso damage",
"high-angle side view with visible hip turn and split seams",
"rearward three-quarter action angle while keeping enough face profile",
],
heavy: [
"dramatic low side view, torn shoulder and torso damage visible under impact",
"rear three-quarter side-back angle from slightly below, showing opened back and waist zones",
"over-the-shoulder angle with bent lower body and exposed damaged limbs",
"high-angle rear-three-quarter frame to reveal damaged back, cloak, and hip areas",
],
defeated: [
"rear three-quarter, side-back, or very low side view; show damaged back/shoulder/cloak with readable face profile",
"high side angle while collapsing onto a knee, exposing abdomen and hip-line destruction",
"low angle side-back shot with fallen armor pieces and defeated body posture",
"overhead-to-side hybrid angle showing broken stance, torn outfit remnants, and pain posture",
],
};
const POSE_VARIANTS = {
normal: [
"combat-ready neutral launch stance with even weight and a controlled torso twist",
"alert guard pose with one hand forward, weapon ready at half-step",
"forward-bent readiness pose, shoulders aligned for immediate counterattack",
],
light: [
"reaction pose after first impact, one shoulder dropping and feet rebalancing",
"counter-step pose with hip pivot and hand reposition around weapon",
"upper-body twist and short recoil, keeping face and weapon in view",
],
medium: [
"strained mid-combat pose with bent knee, waist coil, and heavy shoulder impact",
"arm-blocking, torso-rotating hit reaction showing exposed flank",
"charging recovery pose while the damaged arm pushes and the hips shift backward",
],
heavy: [
"collapsed combat pose, torso over one leg and shoulders catching recoil",
"weapon-gripped recovery pose with broken stance and side body collapse",
"wounded counterpose, upper body twisted, one shoulder dropped low from impact",
],
defeated: [
"kneeling collapse with one hand low and one hand gripping broken gear",
"half-fallen arched-back pose showing loss of balance and pain",
"seated back-leaning defeat pose with heavy breathing and exposed impact line",
],
};
function charSeed(text) {
let hash = 2166136261;
for (let i = 0; i < text.length; i += 1) {
hash ^= text.charCodeAt(i);
hash = Math.imul(hash, 16777619);
}
return hash >>> 0;
}
function pickDeterministic(list, seed, salt = 0) {
const value = (seed + salt * 2654435761) >>> 0;
return list[value % list.length];
}
function pickCameraForStage(spec, character, stage) {
const list = CAMERA_VARIANTS[spec.label] ?? CAMERA_VARIANTS.normal;
return pickDeterministic(list, charSeed(`${character.id}-${character.scene}`), stage * 17 + list.length);
}
function pickPoseModifier(spec, character, stage) {
const list = POSE_VARIANTS[spec.label] ?? POSE_VARIANTS.normal;
return pickDeterministic(list, charSeed(`${character.pose}-${character.weapon}`), stage * 19 + 11);
}
function promptFor(character, stage) {
const spec = damageSpec(stage);
const elementName = {
@@ -188,6 +273,8 @@ function promptFor(character, stage) {
"weapon-impact damage readability: destruction should look caused by readable combat impacts, not vines, webs, thread nets, or lace-like shredding. Prefer a few large directional cuts, diagonal slash paths, sheared armor plates, split seams following the weapon angle, missing costume panels, broken buckles, crushed plate zones, and big hanging cloth sections. Avoid dozens of tiny parallel rips, uniformly shredded edges across the whole outfit, wire tangles, vine-shaped cuts, spiderweb cracks, glittering filaments, and random micro-tears. A blade hit should create one or two coherent slash directions across nearby cloth, straps, and armor edges; a blunt hit should bend or crush plates around one impact zone; an energy hit should burn away broad panels.";
const broadDamageGate =
"broad-damage gate: if the damaged outfit mostly reads as many fine cracks, tiny scratches, lace frays, thorny threads, or vine-like tendrils, the card fails even when the character is exposed. Each major damaged zone should include at least one large missing panel, wide split seam, snapped fastener, sheared plate, or heavy hanging remnant that can be understood at card size.";
const camera = pickCameraForStage(spec, character, stage);
const poseModifier = pickPoseModifier(spec, character, stage);
return [
"Use case: stylized-concept",
"Asset type: high-resolution individual trading card illustration",
@@ -198,9 +285,9 @@ function promptFor(character, stage) {
`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}.`,
`Personality and pose: ${character.personality}; ${character.pose}; ${spec.poseNote}; ${poseModifier}.`,
`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.`,
`Camera/view variation: ${camera}. Across a character's five damage stages, avoid repeating the same straight-front pose; include front, side, rear, low-angle, and high-angle 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.`,