Harden prompt rotation for low/high and pose diversity
This commit is contained in:
@@ -380,76 +380,76 @@ const CAMERA_VIEW_ANGLE_HINTS = {
|
||||
const CAMERA_STAGE_REQUIREMENTS = {
|
||||
normal: {
|
||||
0: ["low", "side", "high"],
|
||||
1: ["high", "side", "rear"],
|
||||
2: ["low", "high"],
|
||||
3: ["rear", "low", "high"],
|
||||
1: ["high", "rear", "low"],
|
||||
2: ["rear", "side", "low"],
|
||||
3: ["side", "high", "rear"],
|
||||
4: ["high", "rear", "low"],
|
||||
},
|
||||
"light-damage": {
|
||||
0: ["low"],
|
||||
0: ["low", "high"],
|
||||
1: ["high", "side"],
|
||||
2: ["low", "side", "high"],
|
||||
3: ["rear", "low"],
|
||||
2: ["low", "rear", "high"],
|
||||
3: ["rear", "low", "side"],
|
||||
4: ["high", "rear", "side"],
|
||||
},
|
||||
"medium-damage": {
|
||||
0: ["low", "high", "side"],
|
||||
1: ["low", "high"],
|
||||
2: ["high", "side", "rear"],
|
||||
3: ["rear", "low", "high"],
|
||||
0: ["low", "high", "rear"],
|
||||
1: ["high", "side", "rear"],
|
||||
2: ["rear", "side", "low"],
|
||||
3: ["low", "high", "rear"],
|
||||
4: ["high", "side", "low"],
|
||||
},
|
||||
"heavy-damage": {
|
||||
0: ["low", "high"],
|
||||
1: ["high", "low", "rear"],
|
||||
2: ["rear", "low", "high"],
|
||||
0: ["low", "high", "side"],
|
||||
1: ["high", "rear"],
|
||||
2: ["low", "rear", "high"],
|
||||
3: ["rear", "low", "high"],
|
||||
4: ["high", "rear", "side"],
|
||||
4: ["high", "side", "low"],
|
||||
},
|
||||
defeated: {
|
||||
0: ["rear", "low", "high"],
|
||||
1: ["low", "high", "side"],
|
||||
2: ["high", "rear", "side"],
|
||||
3: ["side", "rear", "low"],
|
||||
4: ["side", "high", "low"],
|
||||
1: ["low", "high", "rear"],
|
||||
2: ["high", "rear", "low"],
|
||||
3: ["rear", "side", "low"],
|
||||
4: ["high", "rear", "side"],
|
||||
},
|
||||
};
|
||||
|
||||
const POSE_STAGE_LOCK_HINT = {
|
||||
normal: {
|
||||
0: "pose lock A: defensive or impact",
|
||||
1: "pose lock B: defensive + movement",
|
||||
2: "pose lock C: impact + defensive",
|
||||
3: "pose lock D: ground-recovery + impact",
|
||||
4: "pose lock E: airborne + impact",
|
||||
0: "pose lock A: defensive",
|
||||
1: "pose lock B: impact",
|
||||
2: "pose lock C: forward-motion",
|
||||
3: "pose lock D: ground-recovery",
|
||||
4: "pose lock E: airborne",
|
||||
},
|
||||
"light-damage": {
|
||||
0: "pose lock A: defensive",
|
||||
1: "pose lock B: impact + defensive",
|
||||
2: "pose lock C: airborne + impact",
|
||||
3: "pose lock D: ground-recovery + forward motion",
|
||||
4: "pose lock E: defensive + forward motion",
|
||||
1: "pose lock B: impact",
|
||||
2: "pose lock C: airborne",
|
||||
3: "pose lock D: ground-recovery",
|
||||
4: "pose lock E: forward-motion",
|
||||
},
|
||||
"medium-damage": {
|
||||
0: "pose lock A: defensive + recovery",
|
||||
1: "pose lock B: impact + airborne",
|
||||
2: "pose lock C: impact + recovery",
|
||||
3: "pose lock D: ground-recovery",
|
||||
4: "pose lock E: airborne + impact",
|
||||
0: "pose lock A: ground-recovery",
|
||||
1: "pose lock B: defensive",
|
||||
2: "pose lock C: impact",
|
||||
3: "pose lock D: airborne",
|
||||
4: "pose lock E: forward-motion",
|
||||
},
|
||||
"heavy-damage": {
|
||||
0: "pose lock A: defensive + recovery",
|
||||
1: "pose lock B: impact + recovery",
|
||||
2: "pose lock C: recovery + airborne",
|
||||
3: "pose lock D: defensive + forward",
|
||||
4: "pose lock E: airborne + defensive",
|
||||
0: "pose lock A: defensive",
|
||||
1: "pose lock B: impact",
|
||||
2: "pose lock C: ground-recovery",
|
||||
3: "pose lock D: defensive",
|
||||
4: "pose lock E: airborne",
|
||||
},
|
||||
defeated: {
|
||||
0: "pose lock A: ground-recovery",
|
||||
1: "pose lock B: defensive",
|
||||
2: "pose lock C: recovery + impact",
|
||||
3: "pose lock D: forward + ground-recovery",
|
||||
4: "pose lock E: collapsed + defensive",
|
||||
2: "pose lock C: impact",
|
||||
3: "pose lock D: forward-motion",
|
||||
4: "pose lock E: ground-recovery",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -498,39 +498,39 @@ const STAGE_POSE_FAMILY_PREFERENCE = {
|
||||
|
||||
const STAGE_POSE_FAMILY_REQUIREMENTS = {
|
||||
normal: [
|
||||
["defensive", "impact"],
|
||||
["ground-recovery", "defensive"],
|
||||
["forward-motion", "impact", "ground-recovery"],
|
||||
["ground-recovery", "impact", "airborne"],
|
||||
["airborne", "defensive", "forward-motion"],
|
||||
"defensive",
|
||||
"impact",
|
||||
"forward-motion",
|
||||
"ground-recovery",
|
||||
"airborne",
|
||||
],
|
||||
"light-damage": [
|
||||
["defensive", "ground-recovery"],
|
||||
["impact", "defensive"],
|
||||
["airborne", "impact"],
|
||||
["ground-recovery", "forward-motion", "airborne"],
|
||||
["defensive", "forward-motion", "impact"],
|
||||
"defensive",
|
||||
"impact",
|
||||
"airborne",
|
||||
"ground-recovery",
|
||||
"forward-motion",
|
||||
],
|
||||
"medium-damage": [
|
||||
["ground-recovery", "defensive"],
|
||||
["defensive", "impact", "airborne"],
|
||||
["impact", "ground-recovery"],
|
||||
["airborne", "defensive", "ground-recovery"],
|
||||
["ground-recovery", "forward-motion", "airborne"],
|
||||
"ground-recovery",
|
||||
"defensive",
|
||||
"impact",
|
||||
"airborne",
|
||||
"forward-motion",
|
||||
],
|
||||
"heavy-damage": [
|
||||
["ground-recovery", "defensive"],
|
||||
["defensive", "impact"],
|
||||
["impact", "ground-recovery", "airborne"],
|
||||
["ground-recovery", "defensive", "forward-motion"],
|
||||
["airborne", "ground-recovery", "defensive"],
|
||||
"ground-recovery",
|
||||
"defensive",
|
||||
"impact",
|
||||
"airborne",
|
||||
"forward-motion",
|
||||
],
|
||||
defeated: [
|
||||
["ground-recovery", "defensive"],
|
||||
["defensive", "ground-recovery", "impact"],
|
||||
["ground-recovery", "impact", "airborne"],
|
||||
["defensive", "forward-motion", "ground-recovery"],
|
||||
["ground-recovery", "defensive", "airborne"],
|
||||
"ground-recovery",
|
||||
"defensive",
|
||||
"impact",
|
||||
"forward-motion",
|
||||
"airborne",
|
||||
],
|
||||
};
|
||||
|
||||
@@ -820,6 +820,22 @@ function pickDiverseOption(list, seed, stage, step) {
|
||||
return list[index];
|
||||
}
|
||||
|
||||
function sanitizePerspectiveText(value) {
|
||||
if (!value) {
|
||||
return value;
|
||||
}
|
||||
return value
|
||||
.replace(/face\s*-\s*on/gi, "angled")
|
||||
.replace(/frontal/gi, "off-angle")
|
||||
.replace(/front\s*-?\s*on/gi, "non-frontal")
|
||||
.replace(/facing\s+the\s+camera/gi, "off-axis")
|
||||
.replace(/facing\s+camera/gi, "off-axis")
|
||||
.replace(/정면|직면/gi, "측면")
|
||||
.replace(/정면을?\s?바라/gi, "옆으로 돌아")
|
||||
.replace(/직시/gi, "비스듬히 보는")
|
||||
.trim();
|
||||
}
|
||||
|
||||
function firstIndexForOrientation(plan, wanted) {
|
||||
for (let i = 0; i < plan.length; i += 1) {
|
||||
if (normalizeOrientation(plan[i]) === wanted) {
|
||||
@@ -893,11 +909,10 @@ function pickCameraForStage(spec, character, stage) {
|
||||
? firstIndexForOrientation(orientationPlan, normalizedRequiredOrientation)
|
||||
: -1;
|
||||
if (requiredIndex !== -1) {
|
||||
const requestedOrientation = orientationPlan[requiredIndex];
|
||||
if (
|
||||
requiredPool &&
|
||||
requiredPool.length === 1 &&
|
||||
history.length > 0 &&
|
||||
orientationPlan[requiredIndex] === history[history.length - 1]
|
||||
requestedOrientation === history[history.length - 1]
|
||||
) {
|
||||
resolvedIndex = nextDifferentIndex(
|
||||
orientationPlan,
|
||||
@@ -1080,6 +1095,8 @@ function promptFor(character, stage) {
|
||||
"Pose diversity is mandatory: rotate through guard, movement, recoil, evasive, grounded, and collapse actions across the five stages; do not repeat the same motion family in multiple consecutive shots.";
|
||||
const poseHardStop =
|
||||
"Hard stop: do not keep the exact same pose family or core action type in repeated stages; distribute at least three different families over five stages, with low-angle/high-angle poses represented in light or higher damage stages.";
|
||||
const shotDiversityLock =
|
||||
"Shot diversity lock: across five shots, include low-angle and high-angle framing at least once each; avoid running three consecutive side or rear-only frames.";
|
||||
const poseModifier = pickPoseModifier(spec, character, stage, camera.orientation);
|
||||
const poseAngleHint = cameraAngleHintForStage(camera.orientation, character, stage);
|
||||
const selectedCameraCandidate = cameraOptions.length > 0
|
||||
@@ -1095,6 +1112,8 @@ function promptFor(character, stage) {
|
||||
? `Stage ${stage + 1} allowed camera families: ${cameraOptions.join(", ")}.`
|
||||
: `Stage ${stage + 1} camera family lock: ${selectedCameraCandidate}.`;
|
||||
const poseLockHint = POSE_STAGE_LOCK_HINT[spec.label]?.[stage] ?? `pose lock ${stage + 1}`;
|
||||
const sanitizedPersonality = sanitizePerspectiveText(character.personality);
|
||||
const sanitizedPose = sanitizePerspectiveText(character.pose);
|
||||
return [
|
||||
"Use case: stylized-concept",
|
||||
"Asset type: high-resolution individual trading card illustration",
|
||||
@@ -1105,7 +1124,7 @@ 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}; ${poseModifier}.`,
|
||||
`Personality and pose: ${sanitizedPersonality}; ${sanitizedPose}; ${spec.poseNote}; ${poseModifier}.`,
|
||||
`Facial expression: ${spec.expression}.`,
|
||||
`Camera/view variation: ${camera.orientation} angle. ${poseAngleHint}. ${elevationHintByOrientation}. Composition directive: ${camera.phrase}.`,
|
||||
requiredCameraLock,
|
||||
@@ -1118,6 +1137,7 @@ function promptFor(character, stage) {
|
||||
cameraAntiRepeatConstraint,
|
||||
poseDiversityConstraint,
|
||||
poseHardStop,
|
||||
shotDiversityLock,
|
||||
antiRepeatPoseConstraint,
|
||||
"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}`,
|
||||
|
||||
Reference in New Issue
Block a user