Improve camera and pose diversity for card prompts
This commit is contained in:
@@ -65,7 +65,7 @@ function damageSpec(stage) {
|
||||
camera:
|
||||
"low-angle side-front or three-quarter side-forward view for clear character identity without flat frontal dominance",
|
||||
cameraConstraint:
|
||||
"camera choice should include side/rear/low/high rotations across the deck so not every card uses direct frontal framing.",
|
||||
"camera choice should include side/rear/low/high rotations across the deck; do not use direct frontal framing.",
|
||||
},
|
||||
{
|
||||
label: "light-damage",
|
||||
@@ -93,7 +93,7 @@ function damageSpec(stage) {
|
||||
camera:
|
||||
"low/high/side mixed angles, enough to show both face and first armor damage without repeated frontal read",
|
||||
cameraConstraint:
|
||||
"avoid pure straight-on front framing when possible; prioritize side, rear, low-angle, or high-angle with frontal only if readability is essential.",
|
||||
"avoid pure straight-on front framing; prioritize side, rear, low-angle, or high-angle and do not use frontal composition when possible.",
|
||||
},
|
||||
{
|
||||
label: "medium-damage",
|
||||
@@ -121,7 +121,7 @@ function damageSpec(stage) {
|
||||
camera:
|
||||
"side view, strong three-quarter, or low-angle side frame to keep shoulder and abdomen damage visible",
|
||||
cameraConstraint:
|
||||
"must not be primarily straight front. Keep side/rear/low/high angles dominant; frontal only when continuity breaks otherwise.",
|
||||
"must not be primarily straight front. Keep side/rear/low/high angles dominant; frontal composition is disallowed.",
|
||||
},
|
||||
{
|
||||
label: "heavy-damage",
|
||||
@@ -149,7 +149,7 @@ function damageSpec(stage) {
|
||||
camera:
|
||||
"dramatic low-angle side/rear combination, high-angle recoil moments, or over-the-shoulder brutality while keeping face partially visible",
|
||||
cameraConstraint:
|
||||
"intentionally use low-angle or side/rear framing for brutality; limit frontal composition unless needed for continuity.",
|
||||
"intentionally use low-angle or side/rear framing for brutality; frontal composition is not acceptable.",
|
||||
},
|
||||
{
|
||||
label: "defeated",
|
||||
@@ -177,18 +177,18 @@ function damageSpec(stage) {
|
||||
camera:
|
||||
"rear three-quarter, side-back, or high/low side view; show back/shoulder/cloak damage while keeping enough face profile to read pain",
|
||||
cameraConstraint:
|
||||
"avoid direct front as much as possible. Use side/rear, low, or high framing to show defeat collapse and exposed damage zones.",
|
||||
"avoid direct front. Use side/rear, low, or high framing to show defeat collapse and exposed damage zones.",
|
||||
},
|
||||
];
|
||||
return specs[stage];
|
||||
}
|
||||
|
||||
const CAMERA_ORIENTATION_PLAN = {
|
||||
normal: ["low", "side", "high", "low", "rear", "high", "side", "low", "rear", "high"],
|
||||
"light-damage": ["low", "high", "side", "rear", "high", "low", "side", "rear", "high", "low", "side"],
|
||||
"medium-damage": ["side", "low", "high", "rear", "side", "high", "low", "rear", "high", "side", "low", "rear"],
|
||||
"heavy-damage": ["low", "rear", "high", "side", "high", "low", "rear", "low", "high", "side", "rear", "high"],
|
||||
defeated: ["rear", "low", "high", "side", "high", "rear", "low", "side", "high", "low", "rear", "side"],
|
||||
normal: ["low", "high", "side", "rear", "low", "high", "side", "rear", "high", "low", "side", "rear"],
|
||||
"light-damage": ["low", "high", "side", "rear", "low", "high", "side", "rear", "low", "high", "side", "rear"],
|
||||
"medium-damage": ["side", "low", "high", "rear", "side", "high", "low", "rear", "side", "high", "low", "rear", "high"],
|
||||
"heavy-damage": ["low", "rear", "high", "side", "high", "low", "rear", "high", "low", "side", "rear", "high", "low"],
|
||||
defeated: ["rear", "low", "high", "side", "high", "rear", "low", "high", "side", "rear", "low", "high", "side"],
|
||||
};
|
||||
|
||||
const CAMERA_VARIANTS = {
|
||||
@@ -228,7 +228,7 @@ const CAMERA_VARIANTS = {
|
||||
high: [
|
||||
"high-angle diagonal from above, revealing shoulder and torso recoil details",
|
||||
"high side-angle read of first armor loss and leaning recovery",
|
||||
"high front shoulder line view with hands reacting to first strike",
|
||||
"high side-angle shoulder line with hands reacting to first strike",
|
||||
],
|
||||
rear: [
|
||||
"rearward quarter-angle from behind the shoulder with face still readable",
|
||||
@@ -306,15 +306,23 @@ const CAMERA_VARIANTS = {
|
||||
|
||||
const CAMERA_ORIENTATION_RULES = {
|
||||
normal:
|
||||
"Use only side/rear/low/high framing. Frontal-on faces are disallowed unless identity continuity absolutely requires it. Across one character's 5 stages, enforce at least one low-angle and one high-angle shot.",
|
||||
"Use only side/rear/low/high framing. No frontal-on composition is allowed. Across one character's 5 stages, enforce at least one low-angle and one high-angle shot.",
|
||||
"light-damage":
|
||||
"Prioritize low-angle, rear, side, and high-angle framing. Frontal reads are disallowed unless strict identity continuity would otherwise fail.",
|
||||
"Prioritize low-angle, rear, side, and high-angle framing. Frontal reads are disallowed. Keep angle continuity varied.",
|
||||
"medium-damage":
|
||||
"Use energetic side/rear/low/high framing; force low-angle and high-angle alternation so adjacent stages do not share the same vertical framing.",
|
||||
"Use energetic side/rear/low/high framing and force low-angle/high-angle alternation so adjacent stages do not share the same vertical framing.",
|
||||
"heavy-damage":
|
||||
"Prioritize low-angle, side, high-angle, and rear framing to emphasize impact chaos; high/low angles should dominate this stage.",
|
||||
defeated:
|
||||
"Prioritize side/rear/back/low/high framing for collapse and pain continuity; frontal composition only if face continuity cannot be preserved.",
|
||||
"Prioritize side/rear/back/low/high framing for collapse and pain continuity; avoid frontal composition even when convenient.",
|
||||
};
|
||||
|
||||
const STAGE_POSE_FAMILY_PREFERENCE = {
|
||||
normal: ["impact", "defensive", "forward-motion", "ground-recovery", "airborne"],
|
||||
"light-damage": ["defensive", "impact", "ground-recovery", "airborne"],
|
||||
"medium-damage": ["defensive", "ground-recovery", "impact", "airborne"],
|
||||
"heavy-damage": ["ground-recovery", "defensive", "impact", "airborne"],
|
||||
defeated: ["ground-recovery", "defensive", "impact", "ground-recovery"],
|
||||
};
|
||||
|
||||
const POSE_ORIENTATION_VARIANTS = {
|
||||
@@ -620,8 +628,8 @@ function pickCameraForStage(spec, character, stage) {
|
||||
}
|
||||
const historyKey = character.id;
|
||||
const history = cameraHistoryByCharacter.get(historyKey) ?? [];
|
||||
const needLow = stage >= 3 && !history.includes("low");
|
||||
const needHigh = stage >= 4 && !history.includes("high");
|
||||
const needLow = stage >= 2 && !history.includes("low");
|
||||
const needHigh = stage >= 1 && !history.includes("high");
|
||||
if (needLow) {
|
||||
const lowIndex = firstIndexForOrientation(orientationPlan, "low");
|
||||
if (lowIndex !== -1) {
|
||||
@@ -634,7 +642,40 @@ function pickCameraForStage(spec, character, stage) {
|
||||
resolvedIndex = (resolvedIndex + normalizeToDirectionDistance(orientationPlan.length, resolvedIndex, highIndex)) % orientationPlan.length;
|
||||
}
|
||||
}
|
||||
if (history.length > 0) {
|
||||
let forced = false;
|
||||
if (stage === 1) {
|
||||
const stageSeed = charSeed(`${character.id}-${character.scene}-${character.weapon}`);
|
||||
const forcedOrientation = stageSeed % 2 === 0 ? "high" : "low";
|
||||
const forcedOrientationIndex = firstIndexForOrientation(orientationPlan, forcedOrientation);
|
||||
if (forcedOrientationIndex !== -1) {
|
||||
resolvedIndex = forcedOrientationIndex;
|
||||
forced = true;
|
||||
}
|
||||
}
|
||||
if (stage === 2) {
|
||||
if (!history.includes("low")) {
|
||||
const forcedLowIndex = firstIndexForOrientation(orientationPlan, "low");
|
||||
if (forcedLowIndex !== -1) {
|
||||
resolvedIndex = forcedLowIndex;
|
||||
forced = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stage === 3 && !history.includes("high")) {
|
||||
const forcedHighIndex = firstIndexForOrientation(orientationPlan, "high");
|
||||
if (forcedHighIndex !== -1) {
|
||||
resolvedIndex = forcedHighIndex;
|
||||
forced = true;
|
||||
}
|
||||
}
|
||||
if (stage === 4 && !history.includes("low")) {
|
||||
const forcedLowIndex = firstIndexForOrientation(orientationPlan, "low");
|
||||
if (forcedLowIndex !== -1) {
|
||||
resolvedIndex = forcedLowIndex;
|
||||
forced = true;
|
||||
}
|
||||
}
|
||||
if (history.length > 0 && (!forced || orientationPlan[resolvedIndex] === history[history.length - 1])) {
|
||||
resolvedIndex = nextDifferentIndex(orientationPlan, resolvedIndex, history[history.length - 1]);
|
||||
}
|
||||
|
||||
@@ -679,10 +720,22 @@ function pickPoseModifier(spec, character, stage, orientation) {
|
||||
POSE_ORIENTATION_VARIANTS.normal?.[normalizedOrientation] ??
|
||||
[];
|
||||
const posePool = orientationBonus.concat(list);
|
||||
const preferredFamilies = STAGE_POSE_FAMILY_PREFERENCE[spec.label] ??
|
||||
STAGE_POSE_FAMILY_PREFERENCE.normal;
|
||||
const familyHistory = poseFamilyHistoryByCharacter.get(character.id) ?? [];
|
||||
const avoidedFamilies = new Set(familyHistory.slice(-2));
|
||||
const avoidedFamilies = new Set(familyHistory.slice(-3));
|
||||
const preferredPool = posePool.filter(
|
||||
(pose) =>
|
||||
preferredFamilies.includes(poseFamily(pose)) &&
|
||||
!avoidedFamilies.has(poseFamily(pose)),
|
||||
);
|
||||
const familyFilteredPool = posePool.filter((pose) => !avoidedFamilies.has(poseFamily(pose)));
|
||||
const finalPool = familyFilteredPool.length > 0 ? familyFilteredPool : posePool;
|
||||
const finalPool =
|
||||
preferredPool.length > 0
|
||||
? preferredPool
|
||||
: familyFilteredPool.length > 0
|
||||
? familyFilteredPool
|
||||
: posePool;
|
||||
|
||||
const poolSeed = charSeed(`${character.id}-${character.pose}-${character.weapon}-${normalizedOrientation}`);
|
||||
const index = (poolSeed + stage * 19) % finalPool.length;
|
||||
@@ -729,7 +782,7 @@ function promptFor(character, stage) {
|
||||
"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 angleControl =
|
||||
"Angle strictness: this render must use side/rear/low/high framing first; direct frontal composition is disallowed unless the model absolutely cannot preserve face identity.";
|
||||
"Angle strictness: this render must not use frontal/front-facing composition. Use side/rear/low/high only, and explicitly rotate camera family between stages.";
|
||||
const angleConstraint =
|
||||
"Do not output front-facing framing for default action shots. Use side/rear/low/high angles as primary composition, and rotate the view family between shots so the same character does not repeat the exact same camera axis.";
|
||||
const poseDiversityConstraint =
|
||||
@@ -751,7 +804,7 @@ function promptFor(character, stage) {
|
||||
angleControl,
|
||||
angleConstraint,
|
||||
poseDiversityConstraint,
|
||||
"Across the character's five damage stages, rotate between side, rear, low-angle, and high-angle views as the primary framing, and only use frontal composition when the identity cannot be preserved.",
|
||||
"Across the character's five damage stages, rotate between side, rear, low-angle, and high-angle views as the primary framing. Frontal composition is disallowed, and at least one low-angle and one high-angle shot must appear.",
|
||||
`Camera constraint: ${CAMERA_ORIENTATION_RULES[spec.label] ?? CAMERA_ORIENTATION_RULES.normal}`,
|
||||
`Adult visual appeal: ${character.appealFocus}; ${adultAppeal}.`,
|
||||
`Scene/backdrop: ${character.scene}; ${elementName} elemental atmosphere; no other characters.`,
|
||||
|
||||
Reference in New Issue
Block a user