Skip to content

feat(themes): add 686 Princess Connect story portrait themes - #20

Merged
Swan416ya merged 25 commits into
miaoledor:mainfrom
Swan416ya:add-theme-priconne
Oct 19, 2026
Merged

Swan416ya merged 25 commits into
miaoledor:mainfrom
Swan416ya:add-theme-priconne

Conversation

@Swan416ya

@Swan416ya Swan416ya commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

This adds the Princess Connect story portrait collection as composable static themes: every retained story model ships as its own theme or inside the theme of the character it belongs to, so a card never shuffles between unrelated characters.

The final catalog contains:

  • 686 Princess Connect themes: 522 named character themes and 164 themes that carry only a story nameplate as a search alias
  • 1,114 retained source outfits, of which 720 are consolidated into 292 merged themes
  • 35,180 deduplicated layers and 262,542 combinations
  • 7,647 reconstruction references with a maximum channel error of 8/255
  • about 383.1 MiB of layered WebP assets
  • 1,203 themes in the full project catalog

Themes are named per story model, not per ID prefix: the leading four digits of a model ID identify a story batch, and one batch can contain several unrelated characters, mascots or props, so grouping by them made a single theme render a different character each time. Each portrait now takes the nameplate printed for that exact model in the story scripts (Puck, Subaru and Petelgeuse from the Re:Zero collaboration, Ogato, Rage Rage, Daigo, Nebia, Masaki, Minerva beta, Zane, Pukichi, Skull Dad, Mora, Gami). This also corrects pcr-191411, which the ID prefix had labelled Kokkoro but whose story nameplate is Goushin. Titles are romanized (kokkoro, 11, jun ( kurisumasu ), 11) because several localized names were wrong; the localized names stay search aliases.

Portraits that show the same character merge into one theme when the tens digit of their story suffix matches: config.json keeps one mutually exclusive set per portrait, so a render picks a portrait first and an expression inside it. Variants add up instead of multiplying, and different tens digits (another skin of the same character) stay separate. Story-only batches follow the same rule: their four-digit ids are story-local NPC slots, so one tens digit can hold several unrelated NPCs, and the merged theme picks one of them per render.

Five portraits are deleted outright: their art is a fragment of a body, sits outside its frame, or would drag a mixed group into a merge. The 106 portraits whose suffix tens digit is 4 are deleted too: they are the evening rendering of the same pose and outfit (darker, tinted violet, usually without the weapon), so they only duplicated the portrait shipped next to them.

One character's real-world portrait is also the same artwork in every costume batch — the story happens inside a VR game, so a costume only changes the in-game avatar — and generic story NPCs are reused across batches. Those repeats are not always byte-identical (the same art is re-exported on another canvas, or reappears as one of the mutually exclusive sets inside a merged theme), so the check renders every portrait, aligns it by its opaque bounding box, scales it to a common height and compares the alpha mask and luma within a strict tolerance. One portrait per group now ships - a whole theme when that was all it held, a single set otherwise - and the 270 dropped portraits keep their titles as search aliases of the theme that keeps the artwork.

Screenshots from the running counter:

Searching the gallery for kyaru: one theme per costume-shared portrait

Descriptive nameplates stay search aliases while the title falls back to the story batch

Preview panel with the selected theme and its character

Merged themes pick one portrait first: two renders of kokkoro, kyaru and karin

A wide portrait fading out at the card and preview edges

The importer removes 128 non-portrait bundles, 102 unrevealed-character silhouette models, 162 low-variant themes, 217 models that were already excluded, 5 unusable portraits, 106 dusk duplicates and 270 repeated portraits (760 excluded ids in total), and the exclusion lists are persisted and enforced by the exhaustive asset test, which also requires every shipped Princess Connect theme to keep at least ten variants, every merged theme to match the checked-in merge plan and every deduplicated portrait to be gone.

The PR also includes multilingual search aliases, thumbnails, provenance snapshots, reproducible import and merge scripts, and validation reports.

Validation:

  • go test -vet=all -count=1 -p 1 ./...
  • go run ./cmd/check-theme
  • pnpm --dir web generate
  • node scripts/validate-theme-meta.js

Export the portrait selection from two recorded manifests as lossless WebP
layers with independent body, eye and mouth selection. Preserve source
draw order, special expressions, story poses and body-only NPCs. Exclude
documented UI panels and prop/effect models. Add searchable
localized gallery metadata, thumbnails, source records and an offline
exporter with per-expression reconstruction checks.

新增公主连结 1976 个剧情立绘静态主题,支持眼嘴独立组合,补齐分类、搜索、
缩略图、素材来源记录、导出工具和回拼预览。
Convert the theme directory file URL with fileURLToPath so metadata
validation inspects actual files on Windows instead of reporting zero
checked files for drive-letter paths and paths containing spaces.

修复 Windows 元数据校验路径,确保实际检查主题文件而非误报零文件通过。
…sembly

Match exported portraits to the recorded source selection and validate
category membership, candidate dimensions and
placement. Assemble through the production lazy catalog and verify SVG
structure, part selection and variation across multiple selections,
without fixing the number of themes in the test.

为公主连结主题添加真实素材集成测试,覆盖图层坐标、加载、生产合成路径
和多种组合下的 SVG 输出,避免将主题数量写死在测试中。
@miaoledor

Copy link
Copy Markdown
Owner

Portrait preview是怎么生成的,我希望每一个主题列表都有相应的preview可以吗

Add mutually exclusive character sets so one outfit is selected before its compatible body and expression parts, keeping variant counts additive. Consolidate unnamed NPC models, remove unrevealed-character silhouettes and duplicate outfits, and sort named characters before NPC themes.

将无名 NPC 的多套服装归并为互斥套装主题,先选服装再选对应表情,变化数按套装相加;删除未登场阴影与重复资源,并将有名角色排在 NPC 之前。
@Swan416ya Swan416ya changed the title feat(themes): add 1,976 static Princess Connect story portraits feat(themes): add 1,540 Princess Connect story portrait themes Oct 18, 2026
Use two deterministic assembly seeds per Princess Connect theme and parse one representative SVG. This still exercises every asset, mutually exclusive outfit, and alternative branch while avoiding redundant large data-URI parsing under the race detector.

每个公主连结主题使用两个确定性种子并只解析一份代表性 SVG,在保留全素材、互斥服装和差分分支覆盖的同时,避免竞态检测下重复解析大型数据 URI 导致超时。
Remove every Princess Connect theme whose final variant count is one, including named characters and merged NPCs. Persist the exclusion list, clean orphaned thumbnails, and enforce the rule in exhaustive asset validation.

删除所有最终变化数为一的公主连结主题,包括具名角色与合并后的 NPC;保存明确排除清单、清理孤立缩略图,并在全量素材测试中强制校验该规则。
@Swan416ya Swan416ya changed the title feat(themes): add 1,540 Princess Connect story portrait themes feat(themes): add 1,406 Princess Connect story portrait themes Oct 18, 2026
Label the Princess Connect story portraits that were consolidated as unnamed
themes before their names were frozen. Subaru (Re:Zero collaboration), the
protagonist, and Ameth keep their consolidated themes and now carry the
character name, romanisation, and search aliases instead of a Story placeholder;
the explicit stem list lives in scripts/priconne-consolidated-named.json.
Replace the romanised placeholder that stood in for Kaiser Insight's Chinese
name with 霸瞳皇帝, record the deliberately unnamed stems (mascot portraits and
a portrait set that matches no known Sheffy design) in the documentation, and
keep every source outfit ID searchable through the catalogue aliases.

给冻结姓名之前按编号合并的剧情立绘补上角色名:Re:Zero 联动的菜月昴、游戏主人
公、爱梅斯沿用原合并主题并改用角色名与搜索别名,反派改用中文名「霸瞳皇帝」,
只有立绘可逐个核对时才按编号前四位命名,吉祥物立绘与造型对不上的主题保持无名。
Record the third consolidated story portrait set whose leading model ID has a
master-data name but whose individual portraits cannot be matched to that
character, so all three deliberately unnamed sets are documented together.

补充说明第三个「编号有主数据库名字、但立绘无法与该角色对上」的合并主题,把三
个刻意保持无名的主题写全。
@Swan416ya

Copy link
Copy Markdown
Collaborator Author

Portrait preview是怎么生成的,我希望每一个主题列表都有相应的preview可以吗

其实是截图丢进去的

Resolve the consolidated story portrait names from the game's story command
listings instead of the leading digits of a model ID: each speaker nameplate is
paired with the character ID carried by the nearest preceding type/visible/jump/
in_* command and only kept when it repeats across story files. This names the
Re:Zero collaboration cast (Puck, Subaru, Petelgeuse), Ogato, Rage Rage, Daigo,
Nebia, Masaki, Minerva beta and Zane, keeps descriptive nameplates such as 男孩
or 村长 as search aliases instead of titles, and corrects pcr-191411, which the
ID prefix had labelled Kokkoro but whose story nameplate is Goushin.

从游戏剧情脚本的命令清单解析名牌与立绘编号,而不是按编号前四位猜名字:补上
Re:Zero 联动的帕克/菜月昴/培提尔其乌斯、尾狗刀、拉基拉基、大吾、涅比亚、真崎、
米奈瓦β、ゼーン 等,把「男孩/村长」这类描述性名牌放进搜索别名,并修正
pcr-191411 按前缀错标成的可可萝。
Follow-up on the story-text naming pass. The 1914 stem mixes two designs: its
191411 portrait carries the Goushin nameplate, while 191412 and 191413 appear
nowhere in the story text and must not inherit that name, so a per-model
overrides table (scripts/priconne-model-names.json) now decides such portraits
individually. Their theme metadata no longer claims Kokkoro either, the
redundant Goushin alias is dropped, and the documentation records the story
file count, the nameplate provenance and the medium confidence of the
protagonist's name.

剧情文本补名的后续修正:1914 这个 stem 混了两种造型,191411 有「ゴウシン」名牌,
而 191412/191413 在剧情文本里没有名牌,不应继承该名字;新增逐立绘的
priconne-model-names.json 覆盖表处理这种情况,同时修正这三个主题的 meta.json、
去掉多余的 Goushin 别名,并把剧情文件数、名牌来源与主人公名字的置信度写进文档。
Add web screenshots of the running counter: searching the gallery by a story
nameplate such as 尾狗刀, the preview panel showing the character behind a
consolidated theme, and the rendered counters for the Re:Zero and arc-villain
portraits. Also record in the guide that the served frontend is the embedded
`assets/dist` copy of `web/dist`.

补上计数器网页的截图:按剧情名牌搜索主题库、合并主题的预览与角色信息、以及
Re:Zero 与剧情反派等命名主题的计数图;并在文档里说明服务端前端来自
`web/dist` 拷贝进 `assets/dist` 的嵌入产物。
The consolidated pcr-npc-<stem> themes grouped portraits by the leading four
digits of a model ID, which is a story batch rather than a character, so a
single theme could shuffle between unrelated characters on every render. Split
every consolidated theme back into one theme per six-digit story model, take
each title from that model's own story nameplate, raise the variant floor to ten
so nearly static themes are dropped, and record every deliberately unshipped
model in scripts/priconne-excluded-themes.json.

剧情立绘改为一个模型一个主题:此前按编号前四位合并,而前四位是剧情批次不是角色,
同一个主题每次渲染可能在无关角色之间跳换;现在逐立绘取名牌,变化数低于 10 的
主题全部删除,未发布的编号记入 priconne-excluded-themes.json。
Very wide portraits kept their intrinsic width next to the preview panel's
height cap, so they ran past the panel edges. Centre them in the frame, clip the
frame and fade the left and right edges with a horizontal mask, which leaves
narrower portraits untouched because their own edges never reach the mask. The
rendered counter SVG itself is unchanged, so embedded counters still show the
complete image.

特别宽的立绘在预览里会横向溢出面板:现在框内居中、裁掉框外部分并把左右两侧做成
渐隐,比框窄的立绘不受影响;`/@demo` 输出的计数图仍是完整图片。
Story nameplates that are not names (男孩子, 女老师, 男人, サンタクロース,
恶霸地方官, ???) no longer title a Princess Connect theme. Those themes
fall back to `Story <batch>, <suffix>` and keep the nameplate as a search
alias, which is what the documented convention already required. The same
applies to pcr-191412 and pcr-191413: they only inherited the stem name
Goushin, while the story scripts never print a nameplate for either model.

Regenerated web/app/data/priconne-themes.json and assets/themes.json, now
1,186 named and 309 nameplate-only themes.

剧情脚本里描述性的称呼(男孩子、女老师、男人、サンタクロース、恶霸地方官、
???)不再当作主题标题,标题回到 `Story <批次号>, <后缀>`,名牌仍保留为
搜索别名。191412/191413 只继承了批次名 ゴウシン,剧情文本里没有它们的名牌,
同样回到无名。重新生成目录后为 1,186 个有名主题 + 309 个仅带别名主题。
The horizontal fade for very wide portraits was applied to .thumb-box and
.preview-stage, so the frame background and its rounded corners faded out
together with the image. The gradient now sits on .preview-image and
.theme-card img: the frames stay flat, the loading skeleton keeps its full
width, wide portraits still fade at both edges, and portraits narrower
than the frame are untouched.

宽立绘左右渐隐的遮罩原来加在卡片框与预览框这两个容器上,框自身的底色和圆角
也跟着被渐隐。现在改为加在 .preview-image 与 .theme-card img 上:框保持平整、
骨架背景不受影响,宽立绘仍然两侧渐隐,比框窄的立绘完全不受影响。
Documented the exclusion list split (162 low-variant plus 217 already
excluded equals 379), corrected the named/nameplate-only split to
1,186/309, spelled out the descriptive-nameplate rule with pcr-191412,
pcr-191413 and pcr-100012 as examples, dropped the unproven claim that the
217 models are pixel-identical to shipped portraits, and replaced the
screenshots with ones from the current build, adding the alias-title case
and the card/preview framing comparison.

更新公主连结主题文档:说明排除清单的构成(162 条变化数低于下限 + 217 条此前
已排除 = 379)、命名口径修正为 1,186 个有名主题 + 309 个仅带别名主题、把描述性
名牌与 191412/191413/100012 写进规则、删掉“与保留立绘像素完全相同”这一没有
证据的表述,并用当前构建重新截图(新增描述性命牌搜索示例与宽立绘卡片/预览框
对比图)。
@Swan416ya Swan416ya changed the title feat(themes): add 1,406 Princess Connect story portrait themes feat(themes): add 1,495 Princess Connect story portrait themes Oct 19, 2026
Princess Connect portraits that carry the same character name and the same tens
digit of the story suffix now ship as one theme whose config keeps one mutually
exclusive set per portrait, so a render picks a portrait first and an expression
inside it: variants add up instead of multiplying, and a card can no longer
shuffle between unrelated characters. Story-only batches merge only where a
portrait-by-portrait visual audit confirmed one character; the 13 batches whose
tens digit mixes unrelated NPCs stay one theme per portrait. Five portraits whose
art is a body fragment, sits outside its frame, or would drag a mixed group into a
merge are deleted.

Titles are romanized and stop using the localized names, several of which were
wrong; the localized names stay search aliases. 1,490 outfits become 1,026 themes,
of which 298 merge 762 portraits.

公主连结的立绘改为按「同名角色 + 后缀十位数相同」合并:合并主题在 config 里为
每套立绘保留一个互斥 set,渲染时先抽立绘再挑表情,变化数相加,卡片不会在角色
之间乱跳。无名批次只有逐个立绘目视确认是同一角色才合并,13 个同十位数混着不同
NPC 的批次保持逐立绘;另有 5 个画面残缺、出框或会污染分组的立绘直接删除。标题
统一改用罗马音(部分中文译名有误),中文仍作为搜索别名。1,490 套立绘整理为
1,026 个主题,其中 298 个主题合并了 762 套立绘。
@miaoledor

Copy link
Copy Markdown
Owner

Portrait preview是怎么生成的,我希望每一个主题列表都有相应的preview可以吗

其实是截图丢进去的

手动吗,我以为你的pr message全是ai自动提交的

Spelled out how same-name same-tens portraits merge through mutually exclusive
sets, which story-only batches stay one theme per portrait and why, the corrected
counts (1,490 outfits, 1,026 themes, 298 merged themes, 47,088 layers, 352,411
combinations, 498.4 MiB, 384 excluded), and that titles are romanized while
localized names stay search aliases. Screenshots come from the current build and
now show romanized titles plus two renders of the same merged theme.

文档写清同名同十位立绘如何通过互斥 sets 合并、哪些无名批次保持逐立绘及原因,
并更新计数(1,490 套立绘 / 1,026 个主题 / 298 个合并主题 / 47,088 分层 /
352,411 组合 / 498.4 MiB / 384 条排除),说明标题统一用罗马音、中文只作搜索
别名;截图换成当前构建,含罗马音标题与同一合并主题的两次渲染。
@Swan416ya Swan416ya changed the title feat(themes): add 1,495 Princess Connect story portrait themes feat(themes): add 1,026 Princess Connect story portrait themes Oct 19, 2026
Titles moved to romanized names, so a localized name only reached the aliases
through the curated alias table and 479 named themes stopped matching the Chinese
name printed for their story batch. The catalog now adds the localized name of
every portrait inside a theme to its aliases, so Chinese input still finds merged
themes such as the `jiita, 11` group that also covers 环奈.

标题改成罗马音后,中文名只能靠人工别名表进入搜索,479 个有名主题因此搜不到自己
批次的中文名。现在把主题内每套立绘所属批次的中文名一并写进 aliases,用中文仍然
能搜到合并主题(例如 `jiita, 11` 这一组同时覆盖「环奈」)。
The gallery listed Princess Connect themes by model id, so one character's skins
were scattered across the list. Named themes now sort by their romanized character
name (which keeps every skin of a character adjacent) and unnamed themes keep
sorting by story batch at the end of the group; the checked-in catalog uses the
same order.

主题库原来按编号排,同一角色的皮肤散落在列表各处。现在有名主题按罗马音角色名
排序(同一角色的各套皮肤挨在一起),无名主题仍按剧情批次排在分组末尾,随仓库
提交的 catalog 也换成同样顺序。
Suffix tens digit 4 marks the evening rendering of a portrait: the same pose and
outfit, darker and tinted violet, and usually without the weapon or prop. 106 of
those shipped as themes of their own next to the daytime portrait they duplicate,
so they are dropped and recorded as excluded; a suffix digit listed in
`dusk_tens` does that without listing every model id. 1,026 themes become 921 and
1,490 outfits become 1,384.

后缀十位数为 4 的立绘是同一姿势、同一套服装的暮色差分(整体偏暗偏紫,通常还少了
武器/道具),其中 106 个原本各占一个主题,与它们重复的白天版本并存,现在整批删除
并记入排除清单;`dusk_tens` 里写一个十位数就能整批处理,不必逐个列编号。主题数从
1,026 降到 921,立绘从 1,490 降到 1,384。
@Swan416ya Swan416ya changed the title feat(themes): add 1,026 Princess Connect story portrait themes feat(themes): add 921 Princess Connect story portrait themes Oct 19, 2026
The story happens inside a VR game, so one character's real-world portrait (the
`31` skin) is the same artwork in every costume batch: only the in-game avatar
changes with the costume. 52 groups of themes were therefore byte-for-byte
identical apart from the costume in the title, so one theme per group now ships
and the other 69 portraits are dropped and recorded as excluded. The survivor is
picked deterministically (named before unnamed, a character name without a costume
before a costume entry, then the smallest model id) and every dropped title stays
searchable through the aliases of the theme that keeps the artwork. 921 themes
become 852.

剧情发生在 VR 游戏里,所以同一角色的现实立绘(后缀 31)在各个皮肤批次里是同一张
图(皮肤只改游戏内形象)。共发现 52 组只有标题里皮肤不同的逐字节重复主题,现在每
组只保留一个,另外 69 套立绘删除并记入排除清单;保留者按固定规则挑选(有名优先、
不带皮肤括号的名字优先、再按编号最小),被删主题的标题仍作为保留主题的搜索别名。
主题数从 921 降到 852。
The alphabetical order by romanized name was only meant to make the duplicated
real-world portraits easy to scan while deduplicating them; with that done, the
gallery goes back to the model-id order it had before.

按罗马音字母排序只是为了方便在去重时扫出重复的现实立绘;去重完成后,主题库恢复
原来按编号排序。
@Swan416ya Swan416ya changed the title feat(themes): add 921 Princess Connect story portrait themes feat(themes): add 852 Princess Connect story portrait themes Oct 19, 2026
@miaoledor miaoledor added the enhancement New feature or request label Oct 19, 2026
…ants

A character's real-world portrait reappears in every costume batch (the story runs
inside a VR game, so a costume only changes the in-game avatar) and generic story
NPCs are reused across batches, but those repeats are not always byte-identical: the
same art is re-exported on another canvas or reappears as one of the mutually
exclusive sets inside a merged theme. `dedupe-priconne-themes.py` now renders every
portrait, aligns it by its opaque bounding box, scales it to a common height and
compares the alpha mask and luma within 0.995 / 1.5, then keeps one portrait per
group (named before unnamed, a plain name before a costume, the richer expression set
before a poorer one, then the smallest id) and drops the rest - the whole theme when
that portrait was all it held, a single set otherwise, moving a theme to the id it
still holds when its representative set goes. Dropped titles stay search aliases.

The merge step also groups a portrait whose nameplate is the stem's Chinese name with
the stem's Japanese nameplates by the romanized stem name, so `pcr-107311` and
`pcr-107312` (ラジラジ / 拉基拉基) finally consolidate while a nameplate naming another
character in a mixed batch still keeps its own identity. 852 themes become 712.

角色的现实立绘会在每个皮肤批次里重复出现(剧情发生在 VR 游戏里,皮肤只改游戏内
形象),通用 NPC 立绘也会跨批次复用,但这些重复不一定是逐字节相同:同一张图常以
不同画布尺寸重新导出,或者成为某个合并主题里的一个互斥 set。去重脚本改为渲染每套
立绘、按不透明边界框对齐、缩放到同一高度后比较 alpha 掩膜与亮度(阈值 0.995 /
1.5),每组只留一套(有名优先、不带皮肤括号优先、表情多的一套优先、再按编号最小),
其余整主题或整 set 删除,代表 set 被删时主题改名为它仍持有的编号;被删标题仍作为
搜索别名。合并步骤同时把「名牌是该批次中文名」的立绘按批次罗马音与日文名牌归并,
`pcr-107311`/`pcr-107312`(ラジラジ / 拉基拉基)因此合并,而批次内指向另一个角色的
名牌仍保持独立。主题数从 852 降到 712。
@Swan416ya Swan416ya changed the title feat(themes): add 852 Princess Connect story portrait themes feat(themes): add 712 Princess Connect story portrait themes Oct 19, 2026
Story-only batches were kept one theme per portrait when a visual audit found that
one tens digit mixed unrelated NPCs. That exception is dropped: a batch and a tens
digit now decide the merge for NPCs as well, so `Story 0005` ships as one theme with
000511+000512 and `Story 0009` as one theme with 000911/000913/000914/000915/000917.
A merged NPC theme therefore picks one of those portraits per render, which is the
behaviour the project owner asked for; the batch list in
`scripts/priconne-merge-exceptions.json` stays as the place to exclude any group that
would look wrong. 712 themes become 686.

无名批次原先在「同一十位数混着不同 NPC」时保持逐立绘发布,现在这个例外取消:批次 + 十位
数同样决定 NPC 的合并,所以 `Story 0005` 合成一个主题(000511+000512)、`Story 0009`
合成一个主题(000911/000913/000914/000915/000917),合并后的 NPC 主题每次渲染在这些
立绘里抽一套——这是项目所有者要的行为;`priconne-merge-exceptions.json` 里的批次名单
仍保留,用来排除看起来不对的分组。主题数从 712 降到 686。
@Swan416ya Swan416ya changed the title feat(themes): add 712 Princess Connect story portrait themes feat(themes): add 686 Princess Connect story portrait themes Oct 19, 2026
@Swan416ya
Swan416ya merged commit 0fa438e into miaoledor:main Oct 19, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants