背景
画风是生成质量的主要变量之一,同一段提示词换一种画风,模型表现的差异远大于换措辞。当前产品把画风表达为一段自由文本,这段文本同时承担了两件本质不同的职责,而真正能约束风格的那条链路建好了却没有入口。
问题
一、自由文本同时决定了两件事,其中一件是二值管线开关。
_load_constraints(orchestrator/executor.py:97)从自由文本做子串匹配:
is_pixel = "pixel" in style .lower () or "像素" in style
stylize = "pixel" if is_pixel else "none"
Stylize 不是「画得像什么」,而是「生成帧要不要按母版的原生像素块大小降采样、并把颜色吸附回母版色板」(postprocess/pixelate.py)。写「复古 8bit」「点阵风」「low-res sprite」都推不出 pixel,像素角色于是走 LANCZOS 重采样,硬边被糊成灰边并引入色板外颜色。猜错是静默的 ——帧数、时长、成色全部正常,没有一道会红。
二、风格参考图后端全链路已通,前端零入口。
sprite_sample_url 从 Project 模型、API 出入参、到 ProjectConstraints、再到 _produce_image 的图生图分支全部就绪。但前端只有 DTO 字段映射,没有任何页面能设置它。这条已建成的链路当前不可达。
三、Quick Start 从不设置画风。
createAutoPrepareProject(frontend/src/pages/quick-start/service.ts:814)建项目时只传 name、perspective、directionalMovement、spriteSize。走 Quick Start 建的项目 game_style 恒为 null,而它是当前主推入口。
四、画布上画风只读。
workflow-editor-view.tsx:61 把 project.gameStyle ?? '未设置画风' 放进左下角约束条。用户看得到「未设置画风」,但没有入口能改。
竞品怎么做
像素密度
画风
体型
参考图
PixelLab
size: int,默认 48
detail / shading / outline 三条正交枚举
proportions:default / chibi / cartoon / stylized / realistic_male / realistic_female / heroic
Bitforge 支持
Retro Diffusion
width / height 任意
约 15 个具名预设下拉
—
支持,且可传强制调色板
评论中贴的友商
16 / 24 / 32 / 48 / 64px
简约 / 中等 / 精致
Q版 / 等身
—
三条可借鉴的:
PixelLab 把体型比例(chibi / realistic)单独成轴 ,不混进画风。真实与否首先是身高头身比,其次才是渲染方式。
PixelLab 的 detail / shading / outline 相互正交 ,不压成一维。
三家都支持参考图,RD 还支持强制调色板 —— 我们实测三个生图模型色数全部顶到 256,没有一个做限色。
友商那份清单的问题(也是评论里指出「会有点乱」的原因):它把像素密度、资产类型、体型比例 三件事塞进同一个清单,于是 32px 出现了 5 次(简约像素角色、简约Q版角色、简约等身角色、简约像素道具、简约像素武器)。
一条不采纳的 :三家都用具体像素数字,我们不该跟。它们是专用像素模型,size=48 就真出 48px;我们用通用模型,实测提示词要 32px 时实际逻辑高中位 97、范围 51181,要 64px 时中位 171、范围 93275。两档拉得开,但绝对值接不住 ——给用户一个我们兑现不了的数字是承诺不履约。所以用档位不用数字。
实测
像素与否自动判定这条已被推翻(2026-08-21 复测),本提案不再依赖它。
原先写的是「detect_pixel_size(母版) >= 2 判对 17/17,非像素图全部恰好为 1」。那一轮只用了 5 张非像素样本,且脚本未归档。拿画风分档现成的 36 张非像素图重跑:32/36 被判成像素画 (pixel_size 读到 2~7),判据不成立。
改用尺寸无关的四个候选量,在人工标注的生产母版上重测(24 张真实母版,人工标注 21 张是像素画、3 张不是):
候选量
像素画(n=21,256px)
厚涂缩到 256(n=36)
是否分开
唯一色数
中位 6591
中位 6299
重叠
邻像素相同率
中位 0.079
中位 0.392
重叠且方向相反
前 8 色覆盖
中位 0.589
中位 0.914
重叠
软边占比
中位 0.760
中位 0.927
重叠
四个全部重叠。 根因不是指标没选好:生产母版是 1~2 px 像素块的高密度像素画 ,几何上与同尺寸的精细插画没有可分的结构差异——「邻像素相同率」上非像素样本(0.90、0.56)反而高于像素画。
一个必须记下的仪器教训:两组样本若尺寸不同,几乎任何量都会「完全分开」,分开的是尺寸不是画风。第一次复测时非像素组全是 1024px、像素组全是 256px,读出三个「完全分开」的假信号;把非像素组缩到 256 后全部重叠。
结论:自动判定做不出来,但本提案也不需要它。 受控档位的意义正是让用户选,选了就知道是不是像素,不必再猜。自动判定原本只为存量兼容,而存量的实际规模见下。
画风不影响抠图难度。 三种非像素画风(卡通 / 手绘 / 厚涂写实)× 三个生图模型 × 每格 4 张,共 36 张:
净抠穿面积
gemini-2.5-flash-image
0.05%
gemini-3.0-pro-image-preview
0.01%
gemini-3.1-flash-image-preview
0.01%
按画风分组同样全部 ≤0.15%。没有任何一格出现真正的抠穿。
这里要说明读数口径:一开始用的是「主体内孔洞占比」,读出卡通 8.12% / 手绘 23.69% / 厚涂 1.45%,看似差异巨大。逐张看图后发现它测的是构图 不是抠图——高值全部来自半透明披风、叉腿站姿的腿间空隙、纸张底纹,这些本来就该透明。改用「净抠穿面积」(孔洞处像素离底色比主体第 25 百分位还远的比例 × 孔洞面积)后,差异消失。另外单模型与两模型并集对比,并集只补 0.0~2.9 个百分点,说明剩下的孔洞不是漏检。
所以画风分档不能拿管线找依据 —— 卡通、手绘、写实在管线里走同一条路(stylize=none),抠图难度也没有实质差异。它们该分开的唯一理由是用户能看出区别 :卡通有粗描线平涂、手绘有笔触与纸纹、厚涂无描线渐变,三者一眼可辨。一个想要卡通描线的用户拿到厚涂写实,就是没被满足。
方案
画风预设(单选,默认「自动」)
├ 自动 ← 由母版量出像素与否,不问用户
├ 低像素 / 中像素 / 高像素 ← stylize = pixel
├ 卡通 ┐
├ 手绘 ├ stylize = none
└ 写实 ┘
体型(独立轴,不与画风混) 等身 / Q版
画风补充描述(自由文本) 温馨 / 中世纪 / 日系…不做枚举
项目参考图(图) 复用已有的 sprite_sample_url,补前端入口
四条设计判据:
「自动」当默认 。用户建项目时未必想清楚,而母版一旦生成,像素与否是客观事实;它也覆盖用户上传母版的场景。用户显式选择时以用户为准——有一种情况自动会判错:用户想要像素资产却传了一张非像素母版,那时他要的是「把它像素化」。
像素给档位不给数字 ,理由见上。档位只影响生成母版时的提示词,不进后处理参数——master_pixel_spec 会从母版自己量。
体型单独成轴 ,跟 PixelLab 一致。混进画风会让「写实」既表示渲染方式又表示身材比例。
题材气质不做枚举 。温馨、中世纪、日系这类只影响提示词文字,不触发任何管线分支,做成枚举等于把无限的描述空间硬塞进几个格子。受控枚举只给用户需要明确表达、且我们能兑现的区分。
不包含
不做每种画风的提示词调优,不判断哪个模型更擅长哪种画风——那属于 proposal: 建立生图与视频模型的选型判据与实验规程 #465 。
不改动生成链路的默认模型。
动作生成接入风格参考图不在本 Issue:executor.py:331 注释写明「视频 i2v 没有独立的 style reference 字段」,需要先确认 i2v 侧有没有可用入口。
需要对齐
像素三档与卡通/手绘/写实是否放在同一个下拉 ,还是先选「像素/非像素」再选细分。前者选项共 7 个,后者多一次点击。
体型轴放不放进本期 。 已定:本期不放。 体型轴需要自己一套母版与标定(等身与 Q 版的头身比直接改变 align_bottom_center 的 fill_h 定标口径),放进来会把画风这条拖成大件。它是新字段、Project 目前没有对应位置,另开 issue 排后期。
参考图与画风文字冲突时听谁的。 已定:检出冲突时在 UI 上问用户,不在后端择一。
择一的两种做法各有静默失败:参考图赢会让「传一张写实图、想转成像素风」这个正当用法失效;文字赢则参考图的约束被悄悄丢掉,而它恰恰是唯一能锁住身份的输入。
判定「冲突」不需要自动判画风 (本提案已实测该判定做不出来)。判据是两个显式输入同时存在且不同源:用户上传了参考图,且画风预设不是「自动」。此时问一次以哪个为准,答案落到项目上,不每次生成都问。
存量项目的自由文本如何迁移。 已有答案,不需要讨论。 查生产库:133 个项目里只有 9 个 填了 game_style,取值只有两种(像素风格 ×7、像素风 ×2),且全部命中现有的像素子串匹配;staging 23 个里 4 个,取值只有 像素风格。不需要兼容读法,一次映射 13 行数据即可 ,空值走默认档。
反过来这个数说明了更要紧的事:92% 的项目根本没填画风 ,这个自由文本字段几乎没人用。
新增:这条提案要解决的问题比原先写的更严重
stylize 由 game_style 的子串匹配决定(executor.py:98:is_pixel = "pixel" in style.lower() or "像素" in style),空值即 stylize="none",出口不做像素化。
把两个数放一起:人工标注的 24 张真实生产母版里 21 张是像素画,而它们所属项目的 game_style 全部为空 —— 100% 会被跳过像素化。
实测后果(同一帧,只差出口那一步):母版 5982 色、边缘是硬的;交付帧 9278 色、边缘糊成渐变;对同一帧按母版色板补做像素化后回到 48 色、边缘重新变硬。用户看到的「母版没问题但最终 GIF 很糊」就是这条。
所以受控档位不只是「选项更清楚」,它是让像素画项目真的走像素化管线 的前提。
验收
Quick Start 能设置画风,所建项目的 game_style 不再恒为 null。
画布左下角的画风可编辑,不再是只读展示。
Stylize 由显式档位或自动判定决定,不再对自由文本做子串匹配。
项目参考图在前端可设置,且母版生成确实走了图生图分支。
有一条测试锁住「选了像素档的项目,序列帧走 NEAREST 且颜色吸附回母版色板」。
背景
画风是生成质量的主要变量之一,同一段提示词换一种画风,模型表现的差异远大于换措辞。当前产品把画风表达为一段自由文本,这段文本同时承担了两件本质不同的职责,而真正能约束风格的那条链路建好了却没有入口。
问题
一、自由文本同时决定了两件事,其中一件是二值管线开关。
_load_constraints(orchestrator/executor.py:97)从自由文本做子串匹配:Stylize不是「画得像什么」,而是「生成帧要不要按母版的原生像素块大小降采样、并把颜色吸附回母版色板」(postprocess/pixelate.py)。写「复古 8bit」「点阵风」「low-res sprite」都推不出 pixel,像素角色于是走 LANCZOS 重采样,硬边被糊成灰边并引入色板外颜色。猜错是静默的——帧数、时长、成色全部正常,没有一道会红。二、风格参考图后端全链路已通,前端零入口。
sprite_sample_url从Project模型、API 出入参、到ProjectConstraints、再到_produce_image的图生图分支全部就绪。但前端只有 DTO 字段映射,没有任何页面能设置它。这条已建成的链路当前不可达。三、Quick Start 从不设置画风。
createAutoPrepareProject(frontend/src/pages/quick-start/service.ts:814)建项目时只传 name、perspective、directionalMovement、spriteSize。走 Quick Start 建的项目game_style恒为 null,而它是当前主推入口。四、画布上画风只读。
workflow-editor-view.tsx:61把project.gameStyle ?? '未设置画风'放进左下角约束条。用户看得到「未设置画风」,但没有入口能改。竞品怎么做
size: int,默认 48detail/shading/outline三条正交枚举proportions:default / chibi / cartoon / stylized / realistic_male / realistic_female / heroic三条可借鉴的:
detail/shading/outline相互正交,不压成一维。友商那份清单的问题(也是评论里指出「会有点乱」的原因):它把像素密度、资产类型、体型比例三件事塞进同一个清单,于是 32px 出现了 5 次(简约像素角色、简约Q版角色、简约等身角色、简约像素道具、简约像素武器)。
一条不采纳的:三家都用具体像素数字,我们不该跟。它们是专用像素模型,
size=48就真出 48px;我们用通用模型,实测提示词要 32px 时实际逻辑高中位 97、范围 51181,要 64px 时中位 171、范围 93275。两档拉得开,但绝对值接不住——给用户一个我们兑现不了的数字是承诺不履约。所以用档位不用数字。实测
像素与否自动判定这条已被推翻(2026-08-21 复测),本提案不再依赖它。
原先写的是「
detect_pixel_size(母版) >= 2判对 17/17,非像素图全部恰好为 1」。那一轮只用了 5 张非像素样本,且脚本未归档。拿画风分档现成的 36 张非像素图重跑:32/36 被判成像素画(pixel_size读到 2~7),判据不成立。改用尺寸无关的四个候选量,在人工标注的生产母版上重测(24 张真实母版,人工标注 21 张是像素画、3 张不是):
四个全部重叠。 根因不是指标没选好:生产母版是 1~2 px 像素块的高密度像素画,几何上与同尺寸的精细插画没有可分的结构差异——「邻像素相同率」上非像素样本(0.90、0.56)反而高于像素画。
一个必须记下的仪器教训:两组样本若尺寸不同,几乎任何量都会「完全分开」,分开的是尺寸不是画风。第一次复测时非像素组全是 1024px、像素组全是 256px,读出三个「完全分开」的假信号;把非像素组缩到 256 后全部重叠。
结论:自动判定做不出来,但本提案也不需要它。 受控档位的意义正是让用户选,选了就知道是不是像素,不必再猜。自动判定原本只为存量兼容,而存量的实际规模见下。
画风不影响抠图难度。 三种非像素画风(卡通 / 手绘 / 厚涂写实)× 三个生图模型 × 每格 4 张,共 36 张:
按画风分组同样全部 ≤0.15%。没有任何一格出现真正的抠穿。
这里要说明读数口径:一开始用的是「主体内孔洞占比」,读出卡通 8.12% / 手绘 23.69% / 厚涂 1.45%,看似差异巨大。逐张看图后发现它测的是构图不是抠图——高值全部来自半透明披风、叉腿站姿的腿间空隙、纸张底纹,这些本来就该透明。改用「净抠穿面积」(孔洞处像素离底色比主体第 25 百分位还远的比例 × 孔洞面积)后,差异消失。另外单模型与两模型并集对比,并集只补 0.0~2.9 个百分点,说明剩下的孔洞不是漏检。
所以画风分档不能拿管线找依据 —— 卡通、手绘、写实在管线里走同一条路(
stylize=none),抠图难度也没有实质差异。它们该分开的唯一理由是用户能看出区别:卡通有粗描线平涂、手绘有笔触与纸纹、厚涂无描线渐变,三者一眼可辨。一个想要卡通描线的用户拿到厚涂写实,就是没被满足。方案
四条设计判据:
master_pixel_spec会从母版自己量。不包含
executor.py:331注释写明「视频 i2v 没有独立的 style reference 字段」,需要先确认 i2v 侧有没有可用入口。需要对齐
像素三档与卡通/手绘/写实是否放在同一个下拉,还是先选「像素/非像素」再选细分。前者选项共 7 个,后者多一次点击。
体型轴放不放进本期。已定:本期不放。 体型轴需要自己一套母版与标定(等身与 Q 版的头身比直接改变align_bottom_center的fill_h定标口径),放进来会把画风这条拖成大件。它是新字段、Project目前没有对应位置,另开 issue 排后期。参考图与画风文字冲突时听谁的。已定:检出冲突时在 UI 上问用户,不在后端择一。择一的两种做法各有静默失败:参考图赢会让「传一张写实图、想转成像素风」这个正当用法失效;文字赢则参考图的约束被悄悄丢掉,而它恰恰是唯一能锁住身份的输入。
判定「冲突」不需要自动判画风(本提案已实测该判定做不出来)。判据是两个显式输入同时存在且不同源:用户上传了参考图,且画风预设不是「自动」。此时问一次以哪个为准,答案落到项目上,不每次生成都问。
存量项目的自由文本如何迁移。已有答案,不需要讨论。 查生产库:133 个项目里只有 9 个填了game_style,取值只有两种(像素风格×7、像素风×2),且全部命中现有的像素子串匹配;staging 23 个里 4 个,取值只有像素风格。不需要兼容读法,一次映射 13 行数据即可,空值走默认档。反过来这个数说明了更要紧的事:92% 的项目根本没填画风,这个自由文本字段几乎没人用。
新增:这条提案要解决的问题比原先写的更严重
stylize由game_style的子串匹配决定(executor.py:98:is_pixel = "pixel" in style.lower() or "像素" in style),空值即stylize="none",出口不做像素化。把两个数放一起:人工标注的 24 张真实生产母版里 21 张是像素画,而它们所属项目的
game_style全部为空 —— 100% 会被跳过像素化。实测后果(同一帧,只差出口那一步):母版 5982 色、边缘是硬的;交付帧 9278 色、边缘糊成渐变;对同一帧按母版色板补做像素化后回到 48 色、边缘重新变硬。用户看到的「母版没问题但最终 GIF 很糊」就是这条。
所以受控档位不只是「选项更清楚」,它是让像素画项目真的走像素化管线的前提。
验收
game_style不再恒为 null。Stylize由显式档位或自动判定决定,不再对自由文本做子串匹配。