export type QwenSpriteActionTemplateId = | 'idle' | 'run' | 'attack_slash' | 'hurt' | 'die'; export type QwenSpriteActionTemplate = { id: QwenSpriteActionTemplateId; label: string; loop: boolean; defaultFps: number; bodyTravel: string; weaponRule: string; sequenceLines: [string, string, string, string]; ending: string; }; export const QWEN_SPRITE_ACTION_TEMPLATES: QwenSpriteActionTemplate[] = [ { id: 'idle', label: '待机循环', loop: true, defaultFps: 8, bodyTravel: '原地', weaponRule: '武器始终在主手,位置稳定', sequenceLines: [ '1-4 帧:稳定站姿,轻微呼吸起伏', '5-8 帧:胸腔与肩膀轻微抬起,衣摆极轻微变化', '9-12 帧:呼气回落,重心恢复', '13-16 帧:逐渐回到与首帧接近的站姿', ], ending: '第 16 帧自然衔接第 1 帧', }, { id: 'run', label: '奔跑循环', loop: true, defaultFps: 12, bodyTravel: '小幅前移但角色中心基本固定', weaponRule: '武器始终在主手,不换手', sequenceLines: [ '1-4 帧:右腿前摆,左腿后蹬,身体略前倾', '5-8 帧:双腿交叉经过身体下方,手臂反向摆动', '9-12 帧:左腿前摆,右腿后蹬,继续前倾', '13-16 帧:完成另一半跑步循环并回到可接第 1 帧的状态', ], ending: '第 16 帧能无缝接回第 1 帧', }, { id: 'attack_slash', label: '横斩攻击', loop: false, defaultFps: 12, bodyTravel: '中幅前探', weaponRule: '右手持武器,始终右手,不换手', sequenceLines: [ '1-4 帧:轻微收身蓄力,武器向后收', '5-8 帧:重心前压,挥击开始', '9-12 帧:斩击达到最大幅度,动作力量最强', '13-16 帧:顺势收招,回到可接下一动作的稳定姿态', ], ending: '第 16 帧停在收招后稳定姿态', }, { id: 'hurt', label: '受击后仰', loop: false, defaultFps: 10, bodyTravel: '原地或极小后仰', weaponRule: '武器不要脱手,不要换手', sequenceLines: [ '1-4 帧:突然受击,头肩后仰', '5-8 帧:身体失衡最明显', '9-12 帧:手臂和武器随惯性摆动', '13-16 帧:逐渐恢复到勉强站稳的姿态', ], ending: '第 16 帧能接回 idle 或下一个动作', }, { id: 'die', label: '倒地死亡', loop: false, defaultFps: 8, bodyTravel: '明显倒地位移', weaponRule: '武器不可瞬间消失', sequenceLines: [ '1-4 帧:受创失衡,重心被打断', '5-8 帧:身体明显下坠或后仰', '9-12 帧:倒地过程完成,动作幅度最大', '13-16 帧:停在清晰的终止姿态', ], ending: '第 16 帧停在死亡结束姿态,不需要循环', }, ]; const CHIBI_STYLE_TEXT = 'Q版大头身动作角色,头身比固定控制在 2 到 2.5 头身,头部占比明显更大,肩宽和骨盆都更收紧,躯干与四肢短而紧凑,接近经典横版像素动作角色的身体比例,不要写实长身比例。'; const PIXEL_STYLE_TEXT = '像素风画风,整体是像素游戏角色设计方向,深色粗轮廓配合清晰大色块,侧脸五官简化,发型、服装、配饰优先形成醒目剪影,身体始终朝右,适合横版动作 sprite 资产。'; export function getActionTemplateById(id: QwenSpriteActionTemplateId) { return ( QWEN_SPRITE_ACTION_TEMPLATES.find((template) => template.id === id) ?? QWEN_SPRITE_ACTION_TEMPLATES[0] ); } export function buildMasterPrompt(characterBrief: string) { return [ '单人,2D 横版游戏角色标准设定图,主体完整可见,底部轮廓完整,身体比例稳定,轮廓清楚,适合后续制作 sprite sheet 动画。', `视角要求:角色采用横版动作素材常用的右向斜侧身站姿,身体整体朝右,但保留少量正面信息,能读到面部轮廓与胸肩结构,不是完全 90 度纯右视图,也不是正面立绘。`, `主体要求:画面中只保留单个角色主体,不要额外人物、动物、召唤物、载具或陪体。`, `画面要求:1:1 正方形画布,画面中心构图,角色主体完整置于画面中央,不要裁切主体顶部和底部,不要镜头透视,不要特写。背景固定为纯绿色绿幕,只作为抠像底色,不出现建筑、室内布景、风景、地面道具、漂浮物、烟雾叙事元素或其他角色以外的场景内容。`, `风格要求:Q版大头身动作角色,清爽可爱,头身比固定控制在 2 到 2.5 头身,头部占比明显更大,肩宽和骨盆都更收紧,躯干与四肢短而紧凑。深色粗轮廓配合清晰大色块,侧脸五官简化,发型、服装、配饰优先形成醒目剪影,适合横版动作 sprite 资产。高可读性游戏角色设定图,形体清晰,服装层次明确,便于后续连续动作生成。`, '请先拆解设定中的“身份词、主题词、身体结构词”。如果文字设定没有明确要求非人身体结构,默认优先使用参考图对应的人类或类人动作角色骨架,保持清楚的头、躯干、手臂和双腿轮廓,只有当文字设定明确要求非人结构时,才改为对应非人身体。', '主题词默认只作用在角色自身的服装剪裁、材质、纹样、饰品、发光细节上,不要把主题词自动扩写成背景建筑、自然场景、漂浮装饰或额外环境物件。', '视觉优先级应当是:身体结构词第一,身份词第二,主题词第三。没有明确身体结构词时,默认用人形拟人化表现,再把主题词转译成服装和装饰。', characterBrief.trim(), ] .filter(Boolean) .join('\n'); } export function buildVideoActionPrompt(options: { actionTemplate: QwenSpriteActionTemplate; actionDetailText: string; useChromaKey: boolean; characterBrief: string; }) { return [ `单人全身角色动作视频,动作主题是 ${options.actionTemplate.label}。`, `角色固定为图1同一角色,保持右向斜侧身动作视角,镜头稳定,轮廓清晰,不要退化成完全 90 度纯右视图。`, `视角要求:角色采用横版动作素材常用的右向斜侧身站姿,身体整体朝右,但保留少量正面信息,能读到面部轮廓与胸肩结构,不是完全 90 度纯右视图,也不是正面立绘。`, `主体要求:画面中只保留单个角色主体,不要额外人物、动物、召唤物、载具或陪体。`, `画面要求:1:1 正方形画布,画面中心构图,角色主体完整置于画面中央,不要裁切主体顶部和底部,不要镜头透视,不要特写。背景固定为纯绿色绿幕,只作为抠像底色,不出现建筑、室内布景、风景、地面道具、漂浮物、烟雾叙事元素或其他角色以外的场景内容。`, `风格要求:${CHIBI_STYLE_TEXT} ${PIXEL_STYLE_TEXT} 清爽可爱,高可读性游戏角色设定图,偏像素动画前置设计稿,形体清晰,服装层次明确,道具/权杖/武器如有则存在关系合理,便于后续连续动作生成。`, `动作结构:${options.actionTemplate.sequenceLines.join(';')}。结尾要求:${options.actionTemplate.ending}。`, options.useChromaKey ? '背景为纯绿色绿幕,无其他人物和场景元素,方便后期抽帧与抠像。' : '背景简洁纯净,无复杂场景。', `动作补充细节:${options.actionDetailText.trim() || '保持动作清晰、节奏明确、适合后续抽帧为 sprite sheet。'}`, `角色设定:${options.characterBrief.trim()}`, '目标是后续抽帧为横版动作游戏精灵表,因此不要镜头切换,不要景别变化,不要角色漂移。', ].join(' '); }