Online co-op browser remake of Arknights' Stronghold Protocol: Alliance (client-simulated combat, official waves/bonds/items/strategies, 3D board, facing wheel, operator loadout, official emotes, deployment scripts).
40 KiB
07 — Art and audio assets: sources, feasibility and the final plan
Scope: every art and audio asset the fan remake of 卫戍协议:盟约 (act2autochess) needs, with URL patterns that have been checked, measured hit rates, file sizes and fallbacks.
Machine-readable companion: docs/research/07-assets.json. It maps every id to resolved URLs and byte sizes: 138 operators, 20 tokens, 200 enemies, 23 bonds, 59 shop items, 40 bands, the UI sprite groups and the audio banks.
All 4,451 unique URLs in that JSON were HEAD-checked on 2026-09-27 and returned 200.
Probe artifacts are in the scratchpad at …/scratchpad/gd/extra/assets/:
- Git-tree listings:
y_*.txt,fx_spine.txt,am_enemies.txt,aa2_*.txt,aa2v_*.txt. - Id lists:
charids.txt,enemyids.txt,tokenids.txt,trapids.txt. - Spine sample:
spine_sample/. - Browser render proof:
spine_test.png, produced fromspine_test.html. - Generator script:
gen_assets_json.py.
0. TL;DR: the final plan
| Class | Source (primary) | Pattern | Hit rate (pool) | Typical file | Fallback |
|---|---|---|---|---|---|
| a) Avatar (square) | yuanyan3060/ArknightsGameResource avatar/ |
{charId}.png, E2: {charId}_2.png |
138/138; E2 122/138 | 180×180 PNG, ~58 KB | E2 missing → base {charId}.png (the 16 misses are the 预备干员/Sharp/Pith/… char_60x/61x ids that have no E2 art) |
| b) Half-body portrait | same repo portrait/ |
{charId}_1.png, E2 _2.png |
138/138; E2 122/138 | 180×360 PNG, ~117 KB | _1 |
| b') Full art (detail panel only) | same repo skin/ |
{charId}_1b.png, E2 _2b.png |
138/138; E2 122/138 | 681×1317, ~0.8 MB (E2 ~3.2 MB) | portrait _1; lazy-load only |
| c) Skill icon | same repo skill/ |
skill_icon_{skill.iconId ?? skillId}.png (percent-encode [ ]) |
317/317 (all skills of pool operators; 144 are default skills) | 128×128, ~19 KB | arts/ui/[uc]charcommon/skills/empty_skill.png |
| d) Profession / sub-profession | ArknightsAssets/ArknightsAssets2 @cn assets/dyn/arts/… |
profession_hub/icon_{prof}.png, ui/subprofessionicon/sub_{subProfessionId}_icon.png |
8/8, 58/58 | ~12 KB / ~2 KB | battlecard icon_profession_*.png |
| e) Enemy icon | yuanyan enemy/ |
{enemyId}.png |
200/200 | ~158×158, ~44 KB | none needed |
| f) Bond icons: the real autochess ones | AA2 ui/autochess/[uc]autochesscommon/arts/bondicon/ |
{iconId.toLowerCase()}.png, e.g. icon_yanship.png |
23/23 | ~110×98 white glyph, ~4 KB | arts/camplogo/logo_{nation}.png (see §4) |
| g) Item / trap icons: the real autochess ones | AA2 …/arts/shopitemicon/ |
{trapId}.png |
59/59 (56 EQUIP + 3 MAGIC) | ~137×157, ~19 KB | none needed |
| g') Band (strategy) icons | AA2 …/arts/bandicon/ |
icon_{bandId minus "band_"}.png |
40/40 | 180×180, ~69 KB | — |
| h) Map tiles | none usable: the game map is a 3D Unity scene | — | — | — | Draw tiles procedurally (§7). Use real autochess backdrops for the lobby and prep screens. |
| i) UI: rarity, elite, chess-level, shop, HUD | AA2 ui/autochess/… (537 PNGs) + arts/rarity_hub, elite_hub |
see JSON autochessUi, arts |
100% | 0.3–250 KB | CSS-drawn panels (Unity 9-slice borders are not in the dump) |
| j) Fonts | Google Fonts + self-hosted Bender / Novecento | §8 | — | — | system CJK |
| k) BGM + SFX: the real game audio | AA2 @voice branch assets/dyn/audio/sound_beta_2/… |
mapped by audio_data.json banks |
BGM 3/3; per-operator SFX 138/138; enemies 185/200; autochess UI SFX 47 banks | mp3; BGM ~2 MB, SFX 5–60 KB | WebAudio-synthesized blips (§6.4) |
| l) Battle Spine (in-battle chibi) | operators: fexli/ArknightsResource spine/; enemies: isHarryh/Ark-Models models_enemies/ |
spine/{id}/{id}/{Front|Back}/{id}.{skel,atlas,png}; enemies via models_data.json assetList |
ops Front 138/138, Back 135/138; enemies 198/200 | median op front+back ≈ 690 KB; enemy ≈ 134 KB | missing Back → mirrored Front; missing enemy → static icon sprite (§5.6) |
| Spine runtime | PixiJS 7.4.2 + pixi-spine 4.0.6 (UMD from jsDelivr) | — | render checked in headless Chrome | 456 KB + 362 KB | — |
Size budget, all classes, only what the pool needs
| Size | |
|---|---|
| Raw | ≈ 200 MB (≈ 700 MB if full art is included, so leave full art out of the bundle) |
| After build-time optimization | ≈ 65–75 MB: WebP for images, gzip/brotli for skel |
| Initial page load (lazy-loading Spine per board) | < 6 MB |
1. Id inventory (from act2autochess)
| Set | Count | Notes |
|---|---|---|
Operators (charShopChessDatas[*].charId ∪ backupCharId) |
138 unique charIds over 133 chess | 74 PRESET, 55 NORMAL, 4 DIY. DIY chess have charId=null, so the operator is chosen at runtime and uses the chosen operator's assets. Chess levels 1–6: 20/19/21/26/25/22. |
Most chess are evolvePhase=PHASE_2 |
94 PHASE_2 (+ 39 PHASE_1) non-golden; every golden chess is PHASE_2 | → Prefer E2 avatar/portrait (_2) and fall back to _1. |
| Tokens/summons referenced by pool operators | 20 | displayTokenDict and overrideTokenKey. Bond summon "炎佑" (Yan 6/9) has no token id in the data, see §5.6. |
| Enemies | 200 | Union of enemyInfoDict, specialEnemyInfoDict, bossInfoDict-linked ids and level files. All 200 are in enemy_handbook_table. |
| Bonds | 23 | bondInfoDict[*].iconId: icon_yanShip … icon_suntShip |
| Shop items | 59 | trapShopChessDatas[*].trapId = trap_10xx_acarmNNN and friends |
| Bands (strategies) | 40 | bandDataListDict keys band_* |
| Sub-professions in pool | 58 | e.g. fastshot, protector, ritualist, primprotector, counsellor, hunter… |
| Nations in pool | 18 + None | bolivar, columbia, egir, higashi, iberia, kazimierz, kjerag, laterano, leithanien, lungmen, rhodes, rim, sami, sargon, siracusa, ursus, victoria, yan |
Newest operators in the pool, all verified present in every class: char_4211_snhunt 雪猎, char_4207_branch 折桠, char_4196_reckpr 录武官, char_4194_rmixer 信仰搅拌机, char_4193_lemuen 蕾缪安, char_4191_tippi 蒂比, char_1047_halo2 溯光星源, char_1046_sbell2 圣聆初雪, char_1045_svash2 凛御银灰, and the activity-only char_616_pithst 盟约·辅助干员 and char_617_sharp2 领主·Sharp.
2. Sources evaluated
| Repo | Branch | Updated | What it has | Verdict |
|---|---|---|---|---|
yuanyan3060/ArknightsGameResource |
main |
2026-09-24 | avatar (incl. token_*, non-autochess trap_*), portrait, skin (full art b), skill, enemy, item, item_rarity_img, map (not autochess) |
Primary for 2D portraits and icons. AGPL-3.0 applies to its code; the art is © Hypergryph. |
ArknightsAssets/ArknightsAssets2 |
cn (art), voice (all audio) |
2026-09-23 | Full ArknightsStudio dump: assets/dyn/ui/autochess/** (real autochess UI), activity/[uc]act2autochess/**, arts/** (camplogo, profession, rarity, elite, subprofession, loading illustrations), battle/[pack]common/**, and all audio under @voice |
Primary for autochess-specific icons, UI and ALL audio. Battle spine here is incomplete: atlas/skel without PNGs. |
fexli/ArknightsResource |
main |
2026-09-20 | spine/{charId}/{charId}/{Front,Back}/ battle models + base (build_*) models + skins; camplogo, charpor, skills… |
Primary for operator battle Spine |
isHarryh/Ark-Models |
main |
2026-08-02 | models_enemies/ enemy battle Spine (PC build, PMA forced), models/ base (基建) chibis only, models_illust/ dynamic illustrations; models_data.json index |
Primary for enemy battle Spine. Its operator models are base chibis, not battle chibis. |
Aceship/Arknight-Images |
main |
2024-05 (stale) | avatars etc. | Hit rate 89/138. It lacks every 2024+ operator. Not recommended. |
PRTS media.prts.wiki/{md5[0]}/{md5[0:2]}/{文件名} |
— | live | e.g. 头像_德克萨斯.png returns 200 |
Last-resort fallback only: Chinese-name keyed, and hotlinking is discouraged. torappu.prts.wiki timed out from this host. |
web.hycdn.cn (official CDN) |
— | — | guessed avatar path → 404 | not usable |
TimWangZi/The-font-of-Arknights |
master |
— | Bender, Novecento Wide, 思源宋体 | font source (§8) |
CDN behaviour, all checked
raw.githubusercontent.comreturnsaccess-control-allow-origin: *withcache-control: max-age=300.cdn.jsdelivr.net/gh/<repo>@<branch>/…works with CORS*and a 7-day cache for yuanyan, fexli, Ark-Models and AA2@cn.- jsDelivr returns 404 for the AA2
@voicebranch. Use raw for audio. - Do not hotlink at runtime (GitHub rate limits, availability, and it is impolite). Mirror at build time (§9).
Path gotchas
[uc]→%5Buc%5Dand[pack]→%5Bpack%5D.- Skill icons such as
skill_icon_skcom_atk_up[1].pngneed%5B1%5D. curl's globbing also breaks on unencoded brackets. - Skin ids contain
#→%23. Skins are not needed. - Bond
iconIdis camelCase in data (icon_yanShip) but lower-case on disk (icon_yanship.png). - Band icon =
icon_+ bandId minusband_. - Liskarm's default battle model lives at
spine/char_107_liskam/char_107_liskarm/…, a dump-side typo. char_1012_skadi2has a singleSpine/folder instead ofFront/andBack/.- Enemy spine filenames can differ from the folder name:
1043_zomsbr/enemy_1043_zomsabr.*,1169_duphlx/enemy_1169_duphx.*. Always usemodels_data.json → data[key].assetList.07-assets.jsonalready resolves this.
3. 2D portraits and icons (classes a–e, i)
a) Avatars
- URL:
https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/avatar/{charId}.png- E2 variant:
{charId}_2.png. - Mirror:
https://cdn.jsdelivr.net/gh/yuanyan3060/ArknightsGameResource@main/avatar/….
- E2 variant:
- Checked by curling all 138 charIds (xargs -P16): 138/138 200. E2 variant: 122/138.
- The 16 without E2 are
char_600_cpione, 601_cguard, 602_cdfend, 603_csnipe, 604_ccast, 605_cmedic, 606_csuppo, 607_cspec, 608_acpion, 609_acguad, 610_acfend, 611_acnipe, 612_accast, 613_acmedc, 614_acsupo, 615_acspec. They have no E2 art in-game, so use the base image. - Size 180×180 RGBA, avg 58 KB (8.4 MB for the set, preferring E2). WebP q88 comes to about 15 KB each.
- Tokens:
avatar/{tokenId}.pnghits 15/20.- Missing:
token_10012_rosmon_shield,token_10039_ulpia_block,token_10040_siege2_vlion,token_10057_svash2_eagle,token_10058_sbell2_icetgt. - Fallback: owner operator avatar with a small "召唤物" badge, or the battlecard
icon_profession_token.png.
- Missing:
b) Portraits
…/portrait/{charId}_1.png(E2_2.png), 180×360 半身像 (the squad-card crop used on shop cards). 138/138; E2 122/138. Avg 117 KB, about 31 KB as WebP q88.- Full art
…/skin/{charId}_1b.pngis 681×1317, avg 787 KB; E2_2baverages 3.2 MB. Use it only in the operator detail modal, lazy-loaded. Keep it out of the bundle; fetch on demand from jsDelivr.
c) Skill icons
…/skill/skill_icon_{iconId}.png, whereiconId = skill_table[skillId].iconId ?? skillId. 317/317 (every skill of every pool operator, after percent-encoding brackets). 128×128, avg 19 KB.- The shop only shows the chess's default skill (
defaultSkillIndex), which is 144 distinct icons (≈ 2.7 MB raw).
d) Profession and sub-profession
https://raw.githubusercontent.com/ArknightsAssets/ArknightsAssets2/cn/assets/dyn/arts/profession_hub/icon_{caster|medic|pioneer|sniper|special|support|tank|warrior}.png- Large white variant:
profession_large_hub/icon_profession_{p}_large_white.png. - Small battle-card variant:
arts/ui/[uc]battlecommon/ui_battle_new/battlecard/icon_profession_{p}.png, which also includes…_token.png.
- Large white variant:
- Sub-profession:
…/arts/ui/subprofessionicon/sub_{subProfessionId}_icon.png. 58/58, ~2 KB white glyphs.
e) Enemies
…yuanyan…/enemy/{enemyId}.png, 200/200, avg 44 KB.- The boss HP-bar portrait style exists as
arts/ui/[uc]battlecommon/ui_battle_new/enemybossinfo/…for only a few bosses. Use the enemy icon insidesprite_enemy_boss_avatar_bg.png.
i) Rarity, elite and misc UI (all 200)
- Rarity stars:
arts/rarity_hub/rarity_{0..5}.png, plusrarity_yellow_{i},rarity_black_{i}andrarity_left_{i}.- Autochess-specific:
ui/autochess/[uc]autochessouter/arts/charraritysprite/rarity_{0..5}.png.
- Autochess-specific:
- Elite icons:
arts/elite_hub/elite_{0..3}.png,_large,_card.- Autochess
eliteIconIdvalues (shopCharChessInfoData[*].eliteIconId) map to…/[uc]autochessouter/arts/charelitesprite/{char_elite_base_1|char_elite_base_2|char_elite_gold_2}.png. Also available:char_elite_detail_*.
- Autochess
- Chess tier (等阶 1–6):
…/chesslevelsprite/chess_level_icon_{0..6}.png,chess_level_detail_{0..6}.png.- Shop card:
…/autochess_shop_card_item/img_chess_level_{1..6}.png,frame_lv{1..3}.png,bg_common.png,ice_matte.png(frozen),icon_ice.png.
- Shop card:
- Shop level (调度中心):
…/shoplevelsprite/shop_level_icon_{1..6}.png,shop_level_tag_{1..6}.png(150×595 vertical banners). Tag bg colours in data:#434343, #626654, #445760, #615B74, #6C5E41, #5d341e. - Garrison (特质) type icons:
…/garrisontypeicon/{icon_battle|icon_bond|icon_gold|icon_support}.png, pluss_small versions. These matchgarrisonDataDict[*].eventTypeIcon. - Mode icons
mode_{normal|hard|abyss|funny|training}_icon.png. Buff iconsicon_{boss_debuff|enemy_debuff|player_buff|stage_buff|team_buff}.png, matchingeffectDecoIconId. - Title icons
comment_icon_{1..6}.png(playerTitlepicId). Trophiestrophy_level{1..5}_icon.png. Enemy-type icons{fly|times|dot|element|invisible|reflection|special}_icon.png, matchingenemyInfoDictkeys. - Bond board pips:
…/[uc]autochessbattle/arts/bondboardicon/{n}_{k}.png(1_0 … 4_4). - HUD:
…/hud/autochess_hud_panel/*.png(55 files:icon_hp,icon_battle,icon_boss,icon_coop,icon_rest,hp_bar,bg_*…). - Shop:
…/shop/autochess_shop/*.png(refresh_icon,frozen_icon,upgrade_max,bg_money,cost_free…). - Equip slot:
…/act2autochess_equip_slot_panel/*.png. Round banner:…/dialog/round_start_dialog/*.png. - Loading illustrations (1920-class, ~0.9 MB each):
arts/loadingillusts/loading_ac_{core|normal|hard|abyss|funny|prototype|train|training}.png.modeDataDict.loadingPicIdvalues such asloading_AC_core→ lower-case the id.
- Lobby / backdrop art:
activity/[uc]act2autochess/prefabs/act2autochess_activity_stage/{entry_bkg_01,entry_bkg_02,bkg_01,bkg_02,bg_mountains_tiled,season_logo,img_coin}.png.- Mode select:
ui/autochess/[uc]autochessouter/modechoice/auto_chess_mode_choice_state/{normal,hard,abyss,funny}_rhodes_island.png. - Battle ready:
…/battleready/auto_chess_battle_ready_state/{bg_mountain1,bg_mountain2,bg_terrain,rhodes}.png.
- Battle common sprites:
battle/[pack]common/sprites/{sprite_shadow,sprite_direction_arrow,sprite_direction_ring,sprite_box_shadow}.pngand…/projectiles/projectile_arrow.png.- Battle UI:
arts/ui/[uc]battlecommon/ui_battle_new/{btn_speed_1x,btn_speed_2x,btn_pause,slider_hp_back,slider_hp_fill,sprite_skill_ready…}.png.
- Battle UI:
- Caveat: Unity sprite 9-slice borders are not in the dump. Use the art for icons, badges and backdrops, and draw frames and panels in CSS or canvas.
4. Bond icons (f): the real ones are available
https://raw.githubusercontent.com/ArknightsAssets/ArknightsAssets2/cn/assets/dyn/ui/autochess/%5Buc%5Dautochesscommon/arts/bondicon/{iconId lowercased}.png
All 23 are verified: white glyphs on transparent, so tint via CSS filter or canvas globalCompositeOperation='source-in'. Nation fallbacks come from arts/camplogo/logo_{id}.png (44 logos, 20–110 KB). The non-nation fallbacks below are [ASSUMED] suggestions.
| bondId | Name | Real icon file | Bytes | Fallback |
|---|---|---|---|---|
| yanShip | 炎 | icon_yanship.png |
5466 | camplogo/logo_yan.png |
| sargonShip | 萨尔贡 | icon_sargonship.png |
2845 | camplogo/logo_sargon.png |
| victoriaShip | 维多利亚 | icon_victoriaship.png |
4267 | camplogo/logo_victoria.png |
| kjeragShip | 谢拉格 | icon_kjeragship.png |
5255 | camplogo/logo_kjerag.png |
| lateranoShip | 拉特兰 | icon_lateranoship.png |
4725 | camplogo/logo_laterano.png |
| egirShip | 阿戈尔 | icon_egirship.png |
4715 | camplogo/logo_egir.png |
| siracusaShip | 叙拉古 | icon_siracusaship.png |
6956 | camplogo/logo_siracusa.png |
| kazimierzShip | 卡西米尔 | icon_kazimierzship.png |
4288 | camplogo/logo_kazimierz.png |
| preciShip | 精准 | icon_preciship.png |
4872 | sub_fastshot_icon |
| swiftShip | 迅捷 | icon_swiftship.png |
3675 | icon_profession_pioneer |
| skillfulShip | 灵巧 | icon_skillfulship.png |
4166 | sub_executor_icon |
| arcaneShip | 奥术 | icon_arcaneship.png |
4114 | icon_profession_caster |
| steadShip | 坚守 | icon_steadship.png |
2702 | icon_profession_tank |
| deputShip | 助力 | icon_deputship.png |
3726 | icon_profession_support |
| visiShip | 远见 | icon_visiship.png |
3451 | garrisontypeicon/icon_gold |
| miraShip | 奇迹 | icon_miraship.png |
4945 | garrisontypeicon/icon_gold (tinted) |
| investShip | 投资人 | icon_investship.png |
2058 | garrisontypeicon/icon_gold |
| raidShip | 突袭 | icon_raidship.png |
2982 | sub_executor_icon |
| indomShip | 不屈 | icon_indomship.png |
3439 | sub_unyield_icon |
| maniShip | 调和 | icon_maniship.png |
3124 | garrisontypeicon/icon_bond |
| emptyShip | 协防干员 | icon_emptyship.png |
2762 | battlecard icon_profession_token |
| soloShip | 独行 | icon_soloship.png |
2169 | sub_lord_icon |
| suntShip | 绝技 | icon_suntship.png |
3366 | elite_hub/elite_2.png |
Band / strategy icons (g'): …/[uc]autochesscommon/arts/bandicon/icon_{bldsk|amiya|duyaoy|sarkazb|orchid|justin|ermengard|lmlee|kirara|pepe|harold|sciurus|paganini|clementia|emperor|mberry|humus|quintus|yu|doberm|cathy|malkie|qalaisa|chen|damaztic|pith|dusk|cannot|ducklord|lisa|vodfox|ioleta|jesica|mlyss|makiri|fang|mlynar|chiave|narant|amedic}.png. All 40/40 are 180×180 "STRATEGY" cards, ~69 KB each.
5. Items / traps (g)
…/[uc]autochesscommon/arts/shopitemicon/{trapId}.png, 59/59, ~137×157 on a transparent background, avg 19 KB, e.g. trap_1041_acarm041 维式重锤.
- The 3 non-shop special traps are effect ids with no icons:
trap_copy_front_char,trap_create_self_choice,trap_disney_special. Use the icon of the item that grants them. - Rarity backgrounds for item frames: yuanyan
item_rarity_img/sprite_item_r{1..6}.png. - Level-placed traps (
trap_1104_aclasert,trap_1105_accrate,trap_1112_acblzd,trap_098_mire,trap_013_blower,trap_042_tidectrl) have no autochess icon. Draw them as tile overlays.
5b. Battle Spine (l): the real in-battle animated chibis
5.1 Sources and verification
- Operators (fexli):
https://raw.githubusercontent.com/fexli/ArknightsResource/main/spine/{charId}/{charId}/{Front|Back}/{charId}.{skel|atlas|png}- jsDelivr:
https://cdn.jsdelivr.net/gh/fexli/ArknightsResource@main/spine/…. - Front 138/138. Back 135/138: missing for
char_4134_cetsyr魔王,char_291_aglina安洁莉娜 andchar_1012_skadi2浊心斯卡蒂. Skadi2 has one model in aSpine/folder. These are supporters that are often shown only from the front. - One texture page per model.
- jsDelivr:
- Enemies (Ark-Models):
https://raw.githubusercontent.com/isHarryh/Ark-Models/main/models_enemies/{enemyId minus "enemy_"}/{assetList[.skel|.atlas|.png]}. 198/200.- Missing:
enemy_1305_mhslim(_2). AA2 has its atlas and skel but not its PNG.
- Missing:
- Sample downloaded:
char_102_texasFront and Back plusenemy_1007_slime→…/scratchpad/gd/extra/assets/spine_sample/.- Texas Front: skel 187,826 B, atlas 4,903 B, png 65,126 B (512×512).
- Texas Back: 73,065 / 3,346 / 47,290 B (256×256).
- Slime: 16,567 / 552 / 11,659 B (128×128).
- Skel header: read with a varint-string parser, and again with the pixi-spine 3.8
SkeletonBinaryin Node. Every sampled file reports version3.8.99: 11 operators and 5 enemies. - Browser proof: headless Chrome rendered Texas Front (Attack_Loop), Texas Back, 雪猎 Front and enemy “自在” (
enemy_1517_xi, boss) with PixiJS 7.4.2 and pixi-spine 4.0.6 loaded directly from jsDelivr, with no errors. Screenshot:…/scratchpad/gd/extra/assets/spine_test.png.
5.2 Sizes
| Set | Raw | Optimized (skel+atlas gzip ≈ 24%, PNG → lossless WebP ≈ 50%) |
|---|---|---|
| Operators Front (138) | skel 44.3 + png 20.6 + atlas 1.2 = 66 MB | — |
| Operators Back (135) | skel 24.6 + png 16.7 + atlas 0.8 = 42 MB | — |
| Operators total | 108 MB; median op 690 KB; max char_427_vigil 3.1 MB |
≈ 36 MB |
| Enemies (198) | skel 14.9 + png 11.1 + atlas 0.5 = 26.6 MB; avg 134 KB | ≈ 9 MB |
Gzip measurements: texas skel 188 KB → 46 KB; snhunt 659 KB → 122 KB; ghost2 933 KB → 184 KB. A texas 512² PNG goes from 65 KB to 31 KB as lossless WebP. Estimate for 133 ops + 60 enemies on one server: about 110 MB raw, about 38 MB served. A client only downloads the models on its board or in its shop, typically 10–25 models = 5–15 MB.
5.3 Runtime: use pixi-spine, not official spine-ts 3.8
- CDN:
https://cdn.jsdelivr.net/npm/pixi.js@7.4.2/dist/pixi.min.js(456 KB)https://cdn.jsdelivr.net/npm/pixi-spine@4.0.6/dist/pixi-spine.js(362 KB, UMD →PIXI.spine, auto-detects 3.7/3.8/4.0/4.1)- Or
@pixi-spine/all-3.8@4.0.6/dist/pixi-spine-3.8.js(148 KB) for a 3.8-only build. - npm:
pixi.js@7,pixi-spine@4.0.6. pixi-spine 4 needs PixiJS 7, not 8.
- Load with
PIXI.Assets.load(url.skel). The.atlasand.pngmust sit next to it with the same basename. Thennew PIXI.spine.Spine(res.spineData)andspine.state.setAnimation(0, name, loop). - Why not official spine-ts 3.8 (
cdn.jsdelivr.net/gh/EsotericSoftware/spine-runtimes@3.8/spine-ts/build/spine-webgl.js, reachable):- Its atlas parser only treats
rotate: true|90as rotated. Arknights atlases userotate: 270(seen in ghost2 and ulpia), so those regions render wrong. - The fexli atlases omit the
size:line. pixi-spine falls back to the real texture size; spine-ts 3.8 divides by page width 0.
- Its atlas parser only treats
- Atlas quirks to normalize at build time:
- Insert
size: W,Hafter the page name, read from the PNG. - If PNGs are converted to WebP, rename the page line.
- Insert
- Alpha:
- fexli operator textures are straight alpha: a 512² texas texture has 193 pixels with RGB > A, up to 108 over. Load them normally.
- Ark-Models enemy textures are premultiplied (README: "强制启用 PMA"; slime has 1 violation of ≤2). Add a
pma: truepage line to those atlases (pixi-spine honours it and setsALPHA_MODES.PMA), or setbaseTexture.alphaMode = PIXI.ALPHA_MODES.PMA. Otherwise edges come out dark.
- Licensing note: pixi-spine is MIT, but it embeds Spine Runtime code under the Spine Runtimes License, which technically expects a Spine Editor licence. This is commonly tolerated for non-commercial fan tools, and should be noted in the credits.
5.4 Animation names (parsed; the naming varies, so build a resolver)
| Unit | Animations |
|---|---|
| char_103_angel (F) | Attack, Default, Die, Idle, Start |
| char_102_texas (F) | Attack_Start/Loop/End, Default, Die, Idle, Skill, Start. Back model has no Die, no Skill. |
| char_172_svrash (F) | Attack, Combat, Combat_Down, Default, Die, Idle, Skill, Start |
| char_350_surtr (F) | Attack, Die, Idle, Skill_2, Skill_2_Down, Skill_3_Begin/Idle/Loop, Start |
| char_2015_dusk (F) | Attack, Die, Idle, Skill2_Begin/Loop/End, Skill3_Attack, Start. No underscore after "Skill". |
| char_4211_snhunt (F) | Attack_Begin/Loop/End, Attack_Down_, Reload_, Skill_1, Skill_2_Begin/Loop/End, Skill_Down_*, Die, Idle, Start. Events: BeastOnAttack, OnAttack, OnStart. |
| char_1023_ghost2 (F) | Attack, Attack_Down, Die, Die_B, Idle, Idle_B, Skill_1, Skill_3_*, Start, Start_B… |
| char_4134_cetsyr (F) | no Attack; Skill_{1,2,3}_Begin/Loop/End, Idle, Die, Stun, Stun_Begin, Start |
| char_1012_skadi2 (Spine) | no Attack; Skill_{n}_Begin/Loop, Idle, Die, Stun, Start |
| char_600_cpione, char_616_pithst | Attack, Default, Die, Idle, Start |
| enemy_1007_slime | Attack, Default, Die, Idle, Move_Begin/Loop/End |
| enemy_1000_gopro_2 | … + Run_Begin/Loop/End |
| enemy_1502_crowns | Appear, Attack, Die, Disappear, Idle, Move |
| enemy_1517_xi (boss) | Attack_01, Attack_02, Die, Idle, Move, Revive_01, Skill_01, Skill_01_02, Skill_02_Begin/Loop/End. Events: OnAttack, OnPlayAudio. |
| enemy_9009_acfort | Attack, Die, Idle, Move, Skill_1_Begin/Loop/End, Skill_2 |
Resolver. Precompute it at build time by parsing every skel in Node with @pixi-spine/runtime-3.8; see spinetest/parse.cjs in the scratchpad. Emit anims.json, then resolve each role in order:
idle:Idle→Default.deploy:Start(fall back toIdle).attack:Attack;- else
Attack_Start|Attack_Begin→Attack_Loop→Attack_End; - else
Combat; - else (pure supporter)
Skill_1_Loop, or justIdlewith a flash. - Prefer non-
_Downvariants. Use_Downwhen the target is below the unit on screen.
skill, for the chess's default skill index n (1-based):Skill_{n}_Begin→Skill_{n}_Loop(while active) →Skill_{n}_End;- else
Skill{n}_Begin/Loop/End; - else
Skill_{n}; - else
Skill; - else fall back to
attack. - During a skill,
Skill_{n}_Idlereplacesidlewhen present.
die:Die(if the Back model lacks it, swap to the Front model for the death animation), else fade out over 0.5 s.move(enemies):Move_Begin→Move_Loop→Move_End; elseMove; elseRun_Loop.stun:Stun_Begin→Stun, else freeze the current track attimeScale = 0.- Hit timing: apply damage and spawn projectiles on the Spine event
OnAttack(operators and enemies). If no event fires, use 50% of the attack animation. Scale the attack animation'stimeScaletoanimDuration / attackIntervalso it matches the simulated attack speed.
5.5 Direction and scale
- Operators:
- Front model when facing right or down.
- Front mirrored (
scale.x = -1) when facing left. - Back model when facing up; if there is no Back model, use Front.
- Enemies: single model; flip x by the sign of horizontal velocity. The model faces right by default. [ASSUMED from standard Arknights behaviour; verify by eye]
- Scale [ASSUMED]: skeleton height is ~360–450 units for a standard chibi. Start with
scale = tilePx / 300so a chibi stands about 1.2 tiles tall, and tune by eye. Anchor at the feet (Spine origin 0,0 is at the feet). - Put
battle/[pack]common/sprites/sprite_shadow.pngunder each unit.
5.6 Gaps and fallbacks
- Tokens/summons: fexli has the default battle Spine for only 1/20 tokens (
token_10000_silent_healrb); the rest exist only as skin variants (e.g.…vodfox_doll_witch_2). AA2 has their atlas and skel but no PNGs.- Options, in order of preference:
- Use the first skin-variant Spine, listed in
tokens[*].battleSpineSkinVariantsOnlyin the JSON. It looks slightly off-model, but it animates. - Draw the token avatar (15/20) as a circular sprite with a bob tween.
- Draw a procedural glyph.
- Use the first skin-variant Spine, listed in
- Options, in order of preference:
- "炎佑" (Yan-bond summon), [ASSUMED]: no token id is in the data. Render it with the
token_10015_dusk_drgnskin-variant Spine tinted orange-red, or with the Yan bond glyph plus fire particles. - enemy_1305_mhslim: reuse
enemy_1007_slimeSpine with a hue shift, or fall back to the icon sprite. - General policy: if any Spine load fails, render the square avatar or enemy icon in a rarity-coloured diamond with a tween (idle bob, lunge on attack, flash on hit). The game must never block on Spine.
6. Audio (k): the real audio is available in AA2 @voice
Base: https://raw.githubusercontent.com/ArknightsAssets/ArknightsAssets2/voice/assets/dyn/audio/sound_beta_2/ (CORS *; jsDelivr 404s on this branch). The mapping comes from excel/audio_data.json, downloaded to …/extra/assets/audio_data.json. For an asset like Audio/Sound_Beta_2/CustomSE/act1autochess/act1autochess_b_ui_roundstart, strip the prefix, lower-case it and append .mp3.
6.1 BGM (verified)
| Level bgmEvent / context | Files | Size |
|---|---|---|
act2autochess m01–m04 use bgmEvent=act1autochess_shop → bank battle.ON_GAME_READY.act1autochess_shop |
music/act1autochess/m_bat_act1autochess_loop.mp3 |
2.0 MB |
Lobby: sys.ON_ACTIVITY_LOADED.act1autochess |
music/act1autochess/m_sys_act1autochess_intro.mp3, then loop m_sys_act1autochess_loop.mp3 |
1.1 + 1.1 MB |
h07_05 levels use bgmEvent=rglk1phantomcastle |
music/rogue_1/m_bat_rglk1phantomcastle_intro.mp3 + _loop.mp3 |
1.0 + 1.5 MB |
Play the intro, then crossfade to a looping AudioBufferSourceNode (crossfade: 1.0 s in the bank).
6.2 Autochess UI and battle SFX (47 banks, all resolved, in 07-assets.json → audio.autochessSfxBanks)
Key bank names, which make good event names for our code:
- Shop:
ui.ON_ACT1AUTOCHESS_SHOP_UPGRADE,…SHOP_LOCK,…GETMONEY. - Equipment and bonds:
battle.ON_ACT1AUTOCHESS_EQUIP_DONE,…CHAR_BONUS(3-merge upgrade),…EQUIP_BONUS,…ADD_BOND(buffup). - Round flow:
ui.…ROUNDSTART,…BATTLESTART,…BATTLESTART_BOSS,…REST,…YOURTURN,…YOURTURN_CIRCLE,…COUNTDOWN. - Boss rounds:
…BOSSROUND_{TEAM,SINGLE,SECRET},…KILLBOSS{,_ALL,_NORMAL},…DEFENCE_{START,UNITE}. - End of battle and settlement:
…BATTLEOVER_{REDUCE,NOREDUCE,NORMAL},…SETTLEMENT_{SUCCEED,FAIL,TEAM,BOSSSIGN}. - Matchmaking and lobby:
…MATCH_{SUCCEED,FAIL,CANCEL},…PLAYER_{JOINROOM,READY},…STRATEGY,…LOAD,…START,…GOFIRST,…DISCONNECT,…BROADCASTHINT,…ENTER_DANGER. - Other:
battle.ON_CUSTOM_TRIGGER.autochess_kill_gain_coin,battle.ON_ACT1AUTOCHESS_MAGIC_PLACE_BATTLE. - Files are under
customse/act1autochess/*.mp3(46 files, 5–75 KB). Generic sounds:battle/b_char/b_char_set.mp3(deploy),battle/b_enemy/b_enemy_dead_{n,h}.mp3,battle/b_ui/b_ui_{win,lose}.mp3,general/g_ui/g_ui_btn_{h,u}.mp3,g_ui_confirm_h.mp3.
6.3 Per-unit combat SFX (exact, from the data)
Banks are keyed by unit id:
battle.ON_ABILITY_START.{charId}.attack(swing or fire)battle.ON_ABILITY_HIT.{charId}.attack(impact)battle.ON_UNIT_BORN.{id},battle.ON_UNIT_DEAD.{id}battle.ON_SKILL_START.{skillId}(skill activation)
Coverage: 138/138 operators and 185/200 enemies have at least one bank; the remaining 15 enemies use a generic e_atk/e_imp sound. 07-assets.json lists the resolved URLs per unit (operators[*].sfx, operators[*].skills[*].sfx, enemies[*].sfx).
The pool's needed set is 691 mp3 = 8.7 MB:
player/p_atk,p_imp,p_skill: 452 files, 6.8 MBenemy/e_*: 223 files, 2.6 MBbattle/: 0.9 MBcustomse/: 1.3 MB
Pitch-randomize using the bank's minPitch/maxPitch (typically 0.8–1.2). Respect maxSoundAllowed, which caps concurrent instances per bank at 1–2 (popOldest). This matters in a 20-unit fight.
6.4 Optional and fallback audio
- Voice (optional, off by default):
voice_cn/{charId}/cn_{NNN}.mp3, about 30 lines and ~1 MB per operator.- Useful lines, by the standard charword ids [ASSUMED mapping, confirm with
charword_table.json]:cn_021/cn_022选中干员,cn_023/cn_024部署,cn_025–cn_028作战中. - Japanese voice is under
voice/.
- Useful lines, by the standard charword ids [ASSUMED mapping, confirm with
- WebAudio synthesis fallback, used if the fetch fails or the user mutes "game audio":
- UI click: 1.2 kHz square, 30 ms, exponential decay.
- Coin: two sines, 1.5→2.2 kHz, 80 ms.
- Hit: white-noise burst through a band-pass (1–3 kHz), 60 ms.
- Deploy: low 110 Hz sine thump plus a noise click.
- BGM fallback: silence or an ambient pad. Do not try to imitate the OST.
- Monster Siren (official streaming,
monster-siren.hypergryph.com/api/songs) returns JSON but no CORS headers, so the browser cannot use it directly. Not recommended.
7. Map tiles and battle background (h)
- The game data has no 2D map texture. Autochess maps are 19×21 tile grids rendered as a 3D Unity scene.
- The AA2 root PNGs
assets/tile_floor.png,tile_road.pngand similar are 64×64 editor debug placeholders (green, wood planks). Do not use them. - yuanyan
map/previews do not include autochess stages.
- The AA2 root PNGs
- act2autochess level tile keys:
tile_road,tile_floor,tile_wall,tile_forbidden,tile_fence_bound,tile_start,tile_end,tile_telin,tile_telout,tile_achand(autochess bench/hand area),tile_mire(m02),tile_smog(m03),tile_deepsea(m04).heightTypeis LOWLAND or HIGHLAND;buildableTypeis ALL, MELEE, RANGED or NONE.
- Procedural tile renderer, in the Arknights look [ASSUMED palette, tune by eye]:
- Oblique top-down view; each tile is an inset square with a 1 px lighter top edge and a darker bottom bevel.
- LOWLAND road
#3b4048with subtle 45° noise. Deployable lowland gets a faint blue-grey outline#6f8aa3at 40% when a melee chess is dragged. - HIGHLAND (
tile_wall) is a raised block: top#6b7280, side face#3a3f4710 px tall, with a white 1 px top rim. tile_forbidden:#22262cwith a diagonal hatch.tile_fence_bound: dark plus a yellow-black edge stripe.tile_start(enemy spawn): red#d0453bpulsing frame with an arrow glyph.tile_end(protection point): blue#2d7fd6with a house glyph.tile_telin/telout: purple ring.tile_mire: murky green overlay.tile_smog: animated grey fog alpha.tile_deepsea: teal wave overlay.tile_achand: bench slots with a dashed outline.- Attack-range preview:
arts/ui/[uc]battlecommon/ui_battle_new/attack_range_attack.pngandattack_range_stand.png, or draw orange#ff9c33squares at 35% alpha.
- Backdrop: a dark gradient
#15171b → #262a31, withbg_mountains_tiled.png(act2 entry, 112 KB) parallaxed at 20% opacity. Lobby:entry_bkg_01.png(0.99 MB) andseason_logo.png.
8. Fonts (j)
| Use | Font | Source | Size |
|---|---|---|---|
| Chinese UI and body | Noto Sans SC 400/500/700/900 (思源黑体) | Google Fonts, fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700;900&display=swap (200); npm @fontsource/noto-sans-sc@5 |
sliced unicode-range, ~50–100 KB per used slice |
| Chinese titles (formal, serif as in-game) | Noto Serif SC 600/900 (思源宋体) | Google Fonts (200) | same |
| Numbers, HUD, costs, timers (in-game Bender) | Bender (Jovanny Lemonad, free incl. commercial) | https://raw.githubusercontent.com/TimWangZi/The-font-of-Arknights/master/font/Bender/BENDER.OTF (200, 52 KB); also Light and Thin. Convert to woff2 and self-host. |
52 KB |
| English headers (in-game Novecento Wide) | Novecento Sans Wide Normal | same repo, font/Novecento-Wide-Normal-2.otf (200, 45 KB); self-host |
45 KB |
| Google-only fallbacks for Bender / Novecento | Rajdhani 600/700; Saira Condensed 500/700; Barlow Condensed; Teko; Oswald; Chakra Petch | Google Fonts, all 200 | — |
Recommended CSS stacks:
- Numerals and English UI:
font-family: Bender, Rajdhani, 'Noto Sans SC', sans-serif. - Headlines:
'Novecento Wide', 'Saira Condensed', 'Noto Sans SC'.
Avoid redistributing Georgia and Times New Roman (Microsoft fonts) from that repo. The 11 MB 思源宋体 OTFs are unnecessary because Google Fonts serves them subset.
9. Build and delivery plan (recommended)
- Keep assets out of git. Add
client/public/assets/to.gitignore. - Write
scripts/fetch-assets.mjs. It readsdocs/research/07-assets.jsonand downloads, with concurrency of about 16, retry ×3 and a jsDelivr mirror when raw fails:assets/char/avatar/{charId}.webp, choosing E2 if present, else base.assets/char/portrait/{charId}.webp.assets/skill/{iconId}.webp.assets/enemy/icon/{enemyId}.webp.assets/ui/…,assets/bond/{bondId}.png,assets/item/{trapId}.webp,assets/band/{bandId}.webp.assets/spine/op/{charId}/{front|back}/{charId}.{skel,atlas,webp}andassets/spine/enemy/{enemyId}/….assets/audio/{bgm|sfx}/…mp3.- Full art is not downloaded; fetch it lazily from jsDelivr at runtime.
- Post-process:
- Icons and portraits → WebP q88. Spine textures → lossless WebP, then rewrite the atlas page line.
- Inject
size:into fexli atlases andpma: trueinto Ark-Models atlases. - Normalize every filename to lowercase ASCII.
- Precompute
anims.json(animation list + resolver result per model) andsfx.json(per unit: attack start and hit URLs, skill start, die). - Serve
.skeland.atlaswith gzip or brotli via Nodecompression.
- Runtime loading:
- Preload UI, icons, avatars and portraits: about 6 MB.
- Load Spine on demand when a chess enters the shop, bench or board, or when an enemy wave is announced. Cache with
PIXI.Assetsand an LRU of about 60 models. - Show the avatar-sprite fallback until the Spine loads.
- Budgets after optimization:
Asset group Size Avatars ~2 MB Portraits ~4 MB Default-skill icons ~0.8 MB Enemy icons ~2 MB Bonds, items, bands, UI subset ~4 MB Loading illustrations ~2 MB Op Spine ~36 MB Enemy Spine ~9 MB Audio (BGM + SFX) ~15 MB Total on the server ≈ 75 MB Per client (typical session) ≈ 20–30 MB
10. Licensing note
- All images, Spine models and audio are © Hypergryph (上海鹰角网络); overseas publisher Yostar.
- Every mirror repo states this: fexli "All files … copyrighted by Hypergryph … solely for educational and research purposes", and Ark-Models "不得用于商业用途".
- No official permissive fan-game policy was found. Hypergryph and Yostar do enforce copyright.
- Therefore:
- Non-commercial only; no ads, donations or paywall.
- Show a credits screen: "Arknights © Hypergryph / Yostar. This is an unofficial fan project; all game assets belong to their owners."
- Keep it private or small-group, and remove on request.
- Do not redistribute bulk asset archives; fetch at deploy time.
- Also credit the asset dumpers and tooling: yuanyan3060, fexli/ArkResourceAutoUpdateBot, isHarryh/ArkUnpacker, ArknightsAssets/ArknightsStudio, Kengxxiao/ArknightsGameData, pixi-spine (MIT) and the Spine Runtimes License.
- Fonts: Noto (SIL OFL); Bender (free by author); Novecento Sans (free licence by Synthview).
11. Open questions and [ASSUMED] items
- Token spines: only 1 of 20 defaults is available (§5.6). Approve the skin-variant or avatar fallback.
- 炎佑 summon visual [ASSUMED]: the data has no dedicated model.
- Tile palette and 3D look [ASSUMED]: procedural. Tune against in-game screenshots (PRTS map pages or bwiki screenshots of 卫戍协议).
- Spine scale
tilePx/300and enemy default facing [ASSUMED]: verify visually during build. - PMA for Ark-Models enemy textures: add
pma: true, then check visually for dark halos. The test render looked acceptable even without it. - Voice line index mapping (
cn_021–cn_028) [ASSUMED]: confirm againstcharword_table.jsonif voices get enabled. - The Unity 9-slice metadata for UI panels is not in the dump, so panels are drawn in CSS. Only icons and backdrops use the real sprites.
Addendum (critic)
Written 2026-09-27 by the completeness critic.
- Spot check. 40 URLs were sampled at random from the 4,469 unique URLs in
07-assets.json: avatars, enemy skel, audio on@voice, and others. Each got acurl -Ion 2026-09-27. Result: 40/40 returned200. The URL patterns in §0 hold. - UI reference captured for the designer. It is not to be shipped: it is official art and layout.
- The official gameplay-intro long image, 800×13685, sliced into
scratchpad/gd/extra/critic/intro_00..09.jpg. - 11 in-game screenshots (
*.jpgin the same folder): prep with shop at R1/R2/R3, briefing, strategy draft, the three 机变 families, 联防, Final Assault, and the banned-operator dropdown. - They confirm these layout facts:
- bottom shop bar: LEVEL card | operator cards | item card | funds card;
- freeze and refresh buttons above the bar;
- "剩余可放置角色" label;
- 3×2 机变 grid;
- bond strip with layer numbers under the discs;
‹ 自己 ›/‹ 全景 ›view switcher.
- The official gameplay-intro long image, 800×13685, sliced into
- Icons that are also needed:
- Disabled-bond badge: the person-✕ glyph on greyed bond discs.
- "层数叠加已禁用" state of the bond strip.
- Price-0 reward card.
- Candidates are in the AA2
ui/autochess/…groups already listed in §3 i). If none match, draw them in CSS or SVG.