🔔 Bladewake GDD
📄 Doc 31 · Art · VFX · Âm thanh

31 — VFX Bible (bản đầy đủ 1.0)

luật VFX khoá để agent dựng mọi hiệu ứng bằng pixelfx không cần hỏi: đọc được giữa bầy, phép chiếu 3/4, sở hữu màu, ngôn ngữ thời gian, hạng cỡ, ngân sách hiệu năng, khớp hitbox, nâng hạng tất định, mẫu VFX spec + 3 ví dụ, thư viện VFX_SHARED_*, checklist dựng.

Cập nhật: 2026-11-07
14
mục ##
9
mục ###
14
bảng
8611
từ

1Giới thiệu & bản đồ tài liệu

📌
Mục đích: luật VFX khoá để agent dựng mọi hiệu ứng bằng pixelfx không cần hỏi: đọc được giữa bầy, phép chiếu 3/4, sở hữu màu, ngôn ngữ thời gian, hạng cỡ, ngân sách hiệu năng, khớp hitbox, nâng hạng tất định, mẫu VFX spec + 3 ví dụ, thư viện VFX_SHARED_*, checklist dựng. Phụ thuộc: 00-Design-Bible.md + data/_bible.json (INV-01/02/03/08/09/10/13/14/18, §10.3–10.4, §11 VFX_<ownerId>_<slug>) · 30-Art-Direction.md (§2 phép chiếu/cỡ, §3 ramp & token, §8 pipeline) · hub .claude/docs/ArtStyle.md §7 · Tools/pixelfx (docs/AUTHORING.md, skills/pixelfx/SKILL.md, src/fx/bladewake/*) · demo GDD/07-Game-Feel.md §1–§8, GDD/Data/EnemyAttacks.csv. Được dùng bởi: doc hero (41 sheet/hero), doc quái/boss, doc biome/hazard, doc UI/HUD, doc hiệu năng; agent dựng VFX; dev Unity (VfxPool, shader SpriteActor/SpriteAdd, PAL_LUT).
Hạng cỡ VFX — khung tối đa theo tỉ lệ thậtHạng cỡ VFX — khung tối đa theo tỉ lệ thậtVFX XL: 480×270 px · ult, sóng boss, Lặng Nuốt Sân11 · VFX XL 480×270VFX L: 256×176 px · kỹ năng, nện r64–96, Vỡ Âm r9022 · VFX L 256×176VFX M: 160×128 px · cung combo (vd 156×104), đạn + nổ, ĐÁP, nổ r4833 · VFX M 160×128VFX S: 32×32 px · tia trúng, nhặt, glyph 8×8/12×12, glint 5×544 · VFX S 32×32tỉ lệ thật (1 art px = 0.85 px vẽ)
Nguồn: doc 31 §5.
Số VFX spec theo hạng cỡSố VFX spec theo hạng cỡS: 304 (23%)M: 656 (50%)L: 246 (19%)XL: 110 (8%)1316VFXS — 304 (23%)M — 656 (50%)L — 246 (19%)XL — 110 (8%)
Nguồn: data/av/*.json (size_class).
Trần instance cùng lúc theo hạngTrần instance cùng lúc theo hạngSS: 160160MM: 6464LL: 2424XLXL: 44
Nguồn: doc 31 §5.
Khung body tối đa / clip theo hạng actorKhung body tối đa / clip theo hạng actorBoss XL: 192×160 px · BS_B1 7211 · Boss XL 192×160Mini-boss L: 160×128 px · MB_B4_1 dài 9622 · Mini-boss L 160×128Tinh Anh M: 112×96 px · EL_B1_01 5633 · Tinh Anh M 112×96Hero: 96×96 px · H01 Varek (demo)44 · Hero 96×96Quái S: 64×64 px · EN_B1_01 32, EN_B1_02 2655 · Quái S 64×64NPC hub: 64×64 px · NPC_RAM 4466 · NPC hub 64×64Triệu hồi hero: 64×64 px · phường kèn H1277 · Triệu hồi hero 64×64tỉ lệ thật (1 art px = 1.88 px vẽ)
Nguồn: doc 30 §2.3.
Chiều cao đứng tối đa theo hạng (art px)Chiều cao đứng tối đa theo hạng (art px)HeroHero: 36 px36 pxQuái SQuái S: 48 px48 pxTinh Anh MTinh Anh M: 64 px64 pxMini-boss LMini-boss L: 80 px80 pxBoss XLBoss XL: 96 px96 pxNPC hubNPC hub: 44 px44 pxTriệu hồi heroTriệu hồi hero: 36 px36 px
Nguồn: doc 30 §2.3 (số lớn nhất trong cột Chiều cao đứng).
Độ dài từng mục (nghìn ký tự)Độ dài từng mục (nghìn ký tự)1. Đọc được giữa bầy (150–250 quái)1. Đọc được giữa bầy (150–250 quái): 1.8k1.8k2. Luật 3/4 top-down2. Luật 3/4 top-down: 2.6k2.6k3. Sở hữu & màu FX3. Sở hữu & màu FX: 1.9k1.9k4. Ngôn ngữ thời gian4. Ngôn ngữ thời gian: 1.6k1.6k5. Hạng cỡ VFX5. Hạng cỡ VFX: 0.7k0.7k6. Ngân sách hạt & trần hiệu năng6. Ngân sách hạt & trần hiệu năng: 1.6k1.6k7. Khớp hitbox ↔ hình7. Khớp hitbox ↔ hình: 0.9k0.9k8. Nâng hạng tất định8. Nâng hạng tất định: 1.2k1.2k9. Mẫu VFX spec (cuối)9. Mẫu VFX spec (cuối): 2.7k2.7k10. Ba ví dụ điền đủ10. Ba ví dụ điền đủ: 7.8k7.8k11. Thư viện VFX dùng chung (VFX_SHARE…11. Thư viện VFX dùng chung (VFX_SHARED_<slug>, 74 mục): 13.8k13.8k12. Checklist — agent dựng 1 VFX với p…12. Checklist — agent dựng 1 VFX với pixelfx: 2.5k2.5k13. Quy tắc cho dev/AI13. Quy tắc cho dev/AI: 1.1k1.1k14. Quyết định đã chốt14. Quyết định đã chốt: 2.2k2.2k
Bấm tên mục để nhảy tới mục đó.
Mục lục chi tiết (## và ###)

21. Đọc được giữa bầy (150–250 quái)

Thứ bậc hiển thị (cao → thấp): tell Y/P/N → thân hero + vòng chân + x-ray → FX hero → số sát thương → thân địch → FX địch → hazard trang trí → môi trường. Không lớp thấp nào được che lớp cao hơn.

#LuậtSố
R1Tell trên màn≤ 4 tell Y + ≤ 3 tell P sàn từ quái thường, ≤ 5 tell P tổng (gồm hazard, Ấn, mutator, Khăn Tang) (INV-08)
R2FX hero nhường telltrong r24 quanh viền vùng P: FX hero α × 0.70 (11 §1); FX hero không bao giờ vẽ trên lớp prioritize
R3Hình khốiFX hero = ĐẶC: lõi #fff6f0 + viền slot; FX địch = RỖNG: lõi tối/lạnh V ≤ 0.45 + viền sáng V ≤ 0.90 (INV-01c) — phân biệt được khi lọc xám
R4Độ phủFX additive phủ trung bình ≤ 1.5 × diện tích view; mọi pixel ≤ 6 lớp trong suốt chồng; FX 1 đòn hero (trừ ult) ≤ 25% diện tích view 480×270
R5Trúng đòn hàng loạt≤ 16 VFX trúng mới/frame; quá trần: vẫn nháy trắng 0.07 s + số cho MỌI mục tiêu, bỏ tia lửa của mục tiêu xa hero nhất
R6Quái chết hàng loạt≤ 12 VFX chết mới/frame (Bible §10.4); quá trần: chỉ hất văng + tan dither (shader, 0 sheet)
R7Glyph trạng thái (10 §5)địch: glyph 8×8 ramp hero đang chơi, vẽ trên vòng chân quái (neo feet, sy +4), ≤ 1 glyph, ưu tiên STUN > DISARM > PIN > BLIND > DREAD > BIND > SHOCK > FROST > EMBER > ROT > SLOW; loop thân sts_* ≤ 2/quái; hero: glyph bạc #c8c8d0 trên vòng chân hero, ≤ 3 xếp ngang cách 2 px + icon HUD có thanh thời gian
R8Môi trường độngbụi/tro/lá trang trí ≤ 40 hạt/view, α ≤ 0.35, S ≤ 40%, luôn dưới lớp tell (INV-18)
R9Chớp màn≤ 2 chớp/giây, α ≤ 0.35, 1–3 frame; không nháy > 3 lần/giây (an toàn nhạy sáng); tắt được ở Trợ năng
R10Số sát thươnglớp BattleDmgText, 1 mesh, ≤ 260 số; không đè HUD/chữ thông báo (07 §4)
R11Mù màu (11 §6)Y: glint đổi thành hình thoi ◇ 5×5 (boss 7×7) + viền trắng nháy giữ; P: thêm gạch chéo 45° 1 px cách 4 px trong vùng + ▲ 7×6 cạnh !; N giữ chấm (đã khác hình)

32. Luật 3/4 top-down

2.1 Phép chiếu (= 30 §2.1, VIEW.tilt 0.5)

Quy ước pixelfx (y màn hướng xuống, h = cao dương lên). Điểm sàn (x, z) cao h → màn (sx, sy) = (x, 0.5·z − h).

Hình trên sàn (đơn vị px sàn thật)Trên mànCông thức
Tròn bán kính relip bán trục rx = r, ry = r/2vẽ midpoint ellipse nguyên: rx = round(r), ry = round(r/2); tâm tại pixel tâm
Vành (ring) r, dày w2 elip (r ± w/2)dày trên màn = w ở Đông/Tây, w/2 ở Bắc/Nam
Rẻ quạt r, cung α, hướng θbiên P(φ) = (r·cosφ, 0.5·r·sinφ), φ ∈ [θ − α/2, θ + α/2]θ: 0 = e, π/2 = s (xuống màn)
Đoạn thẳng dài L hướng θdài màn L_s = L·√(cos²θ + 0.25·sin²θ)vd Kẻ Mực 320 px: e/w 320, n/s 160, chéo 253
Chữ nhật L × W (vd 200 × 32, 320 × 24)4 góc qua (x, 0.5·z)rộng màn W·√(sin²θ + 0.25·cos²θ)
Tốc độ v theo θv_s = v·√(cos²θ + 0.25·sin²θ)đạn 120 px/s bay dọc = 60 px/s trên màn (đúng, không bù)
  • Đạn bay thẳng: cao mặc định h = 18 (khoảng 16–24 theo vũ khí), bóng riêng ở h = 0.
  • Đạn vòng cầu (lob, ném bom, cối): h(t) = 4·H·u·(1 − u), u = t/T; H mặc định = 0.35 × cự ly, kẹp 24–96 px; vòng tím đích vẽ từ lúc bắn (INV-13).
  • Nổ toả: hạt phun cả 3 chiều (spray + spawn3), không phun phẳng như góc ngang.
  • Đòn vung đứng (slash) cần tilt 0.6–1.1 để không biến mất khi nhìn hướng n/s (pixelfx swing).

2.2 Độ cao & bóng

  • Vật có h > 2 px = trên không → bóng sàn shadow #0a0810: rx = round(0.45·rộng), ry = round(rx/2), co theo rx × max(0.5, 1 − h/64), α 0.45 → 0.25 tại h = 64.
  • Mọi FX "đứng" (cột lửa, tia sét, cột tro) có chân trên sàn: 1 elip sáng/tối tại chân trên lớp floor.
  • Sàn bị đánh: dấu sàn (nứt, cháy xém) = decal floor_decal, sống 1.5–8 s, tan dither.

2.3 Neo (pivot)

feet (chân actor) · impact (điểm trúng) · muzzle (nòng/đầu gậy = socket tip@hit) · floor (điểm sàn, h = 0) · socket:<tên> (chest, head, overhead, hand_main… 30 §5.3). Đòn vung neo feet người đánh; FX sàn neo floor; đạn neo tâm đạn với bóng neo floor dưới đạn.

2.4 Lớp sort (5 lớp, ánh xạ Unity)

Lớp VFX (layer)Unity sorting layer · orderChứa
floor_decalFXBot · 0–9cháy xém, vũng, vùng sàn của hero, vũng sáng, khói sàn
shadowFXBot · 10bóng tiếp xúc, bóng vật bay
floor_tellFXBot · 20–29vùng N (20), vùng P (25), vòng đích đạn P (27) — trên bóng để bầy không che
bodyGamePlayLayer1 (Y-sort theo actor): vfx-back order −1, vfx +1; FX địch mang theo thân: GamePlayLayer2nửa xa của cung chém / vòng (drawBack), aura, trạng thái quanh thân
overheadFxLayertrúng đòn, đạn, nổ, cung chém trên không, nhặt đồ
overhead ưu tiênPrioritizeglint Y, viền trắng nháy, ! tím, hào quang P, x-ray hero, glyph trạng thái, ◆ Tro Nhớ
screencamera overlay (UI dưới HUD) · số: BattleDmgTextchớp màn, viền tối, tint World chậm

43. Sở hữu & màu FX

owner_classAiMàuHìnhtint
HEROđòn, kỹ năng, ult, triệu hồi, đạn phản, vùng sàn heroramp slot 30 §3.2 (r0..r7) + lõi #fff6f0; chớp #ffffff ≤ 2 frame; H01 thêm vàng kim ≤ 2 px/frameĐẶC, lõi trắng nóngEXPORT (xuất --opts palette mỗi hero)
ENEMYđòn, đạn, phép, aura của địchramp thân biome 30 §3.4 + nhấn biome; lõi V ≤ 0.45, viền V ≤ 0.90, S viền ≤ 60%; cấm hue 340–10° S > 30%RỖNG, lõi tốiBIOME + ALT (mask điểm nhấn)
TELLcảnh báo Y/P/NCHỈ #ffd84a (Y), #b14cff (P), #e8e4f0 chấm (N) + trắng nháyY: glint 4-cánh 5×5 px (boss 7×7) + viền trắng 1 px quanh thân; P: elip fill 25% + viền 2 px + hào quang 2 px + ! 7×9; N: viền chấm 2 px + chấm thưa 15%FIXED
ENVhazard trang trí, khí quyểnS ≤ 40%, α ≤ 0.35mềm, dưới tellBIOME
SHAREDhệ thống: spawn, chết, nhặt, trạng thái, khiên, màntrung tính (ash-neutral, ngà, trắng) hoặc tô theo herotheo mục §11HERO_LUT / FIXED
  • HERO_LUT: sheet xám chỉ mục 9 bậc (#000…#fff → r0..r8), runtime tô bằng hàng hero trong PAL_LUT (30 §3.5): 1 sheet cho 12 hero.
  • Trạng thái do hero gây (STS_EMBER/FROST/SHOCK/ROT/BIND/DREAD) = ramp hero đang chơi + glyph hình dạng riêng (INV-01f): EMBER lửa · FROST tinh thể · SHOCK zigzag · ROT bọt · BIND xích · DREAD mắt. Nhóm CONTROL (10 §5.1): STUN sao xoay · MUTE chuông gạch · BLIND bụi · DISARM lưỡi gãy · SLOW sóng ngang · PIN cọc. Màu không mang nghĩa nguyên tố — hình mang nghĩa. Trạng thái trên hero: bạc #c8c8d0, không ramp hero.
  • Đạn địch bị ĐÁP phản: đổi sang ramp hero + lõi #fff6f0 ngay frame phản (INV-01a); tốc ×1.6.
  • Chí mạng: chớp trắng #ffffff (không vàng, INV-01a); số chí mạng ngà + "!" (screen-space).
  • Ấn tro spawn: #e8e4f0; khi chơi H02 đổi viền gạch đứt 2 px (INV-01e).
  • Vật phẩm/tiền: cấm vàng bão hoà (dải tell) — Vàng Mã Vàng Mã CUR_PAPER_GOLD = giấy ngà #d8cfb4 + dấu mực; Tro Hồn Tro Hồn CUR_SOUL_ASH = #e8e4f0; Mảnh Vọng Mảnh Vọng CUR_ECHO_SHARD = ngà-lam #cfd8e8 + viền slot hero.

54. Ngôn ngữ thời gian

Mỗi FX có 3 pha: anticipation (tụ, có thể = windup thân) → impact (frame trắng/nhả, 1–2 frame) → dissipate (nguội theo ramp, rơi, tan; kết rỗng). Nhanh vào, chậm ra: ease.outQuart/outExpo.

Lớp hiệu ứngAntic.ImpactDissipateTổngfpsFrame
Tia trúng (hit spark)00.03 (1 frame trắng)0.20–0.270.30309
Cung chém hero (combo)0 (windup ở thân)0.03–0.050.15–0.250.30–0.60309–18
Đạn: nòng / bay / nổ0.10 / — / 00.030.20–0.30nòng 0.13 · bay loop · nổ 0.3330 · bay 154 · 4–8 L · 10
Vùng sàn hero (nện, nổ)0.05–0.100.050.30–0.600.40–0.75 (sóng lan 0.33)3012–23
Kỹ năng lớn0.15–0.300.050.40–1.000.6–1.43018–42
Ult0.30–0.600.07 + khựng1.0–3.01.5–4.03045–120
Tell Yglint 1 tại đầu windup (4 frame) · glint 2 đúng 0.12 s trước va chạm (4 frame) · viền trắng nháy ≥ 2 frame——= windup304 + 4
Tell P (sàn)viền 2 px đúng cỡ cuối từ tick 0, α 0.6 → 1.0; fill 25% lớn dần từ tâm, đầy đúng tick va chạm; windup vùng ≥ 0.45 s (S/M), ≥ 0.60 s (L/XL) (11 Q1, chặt hơn INV-03)0.10 (fill → 60% rồi tắt)0.20windup + 0.30runtime—
Vùng Nhiện 0.20—tan 0.30theo thời lượng vùng12 loop8 L
Trạng thái (loop)vào 0.10—ra 0.15loop128–12 L
Spawn ấn tro0.60 (INV-14)00.150.753023
Xoáy triệu hồi1.00—0.201.203036
Chết quái0loé 0.09tro 0.400.503015
Nhặt đồ00.030.200.23307
Chớp màn00.033–0.100.10≤ 0.20301–3 + 3
  • Sheet luôn 30 fps (meta.pixelfx.fps); loop được 12/15 fps. Hitstop = runtime đóng băng FX + thân của 2 bên (không nướng); slow-mo chạy trên đồng hồ World, FX của hero H12 (máy nhịp) chạy đồng hồ Hero.
  • Windup thân ≠ FX: runtime ép windup clip vào startup CSV; FX impact neo đúng frame chạm (hits[0].t).

65. Hạng cỡ VFX

HạngKhung tối đa (art px)Bán kính sàn tương ứngVí dụTrần instance cùng lúc
S32×32r ≤ 16tia trúng, nhặt, glyph 8×8/12×12, glint 5×5160
M160×128r ≤ 56cung combo (vd 156×104), đạn + nổ, ĐÁP, nổ r4864
L256×176r ≤ 112kỹ năng, nện r64–96, Vỡ Âm r9024
XL480×270r ≤ 240 (vành, sàn: vẽ thủ tục)ult, sóng boss, Lặng Nuốt Sân4
  • Hạng tính theo khung lớn nhất trong 8 hướng; bậc thang Area (§8) có thể đẩy FX lên hạng trên (tính trần theo hạng mới).
  • Tổng instance ≤ 252 < pool 320. Vòng/vùng sàn r > 112 KHÔNG làm sheet: vẽ thủ tục bằng shader elip pixel (viền + fill + chấm/gạch), sheet chỉ cho hạt/trang trí đi kèm.
  • Ô (cell) sheet = khung nhỏ nhất ôm mọi frame của hướng đó (pixelfx tự cắt); PAD 2 khi đóng gói.

76. Ngân sách hạt & trần hiệu năng

6.1 Trần cứng (Steam Deck 60 fps, p95 ≤ 16.6 ms, Bible §10.4)

MụcTrầnKhi đầy
Hạt (mọi Particles/Bits runtime)1.500bỏ hạt mới của FX ưu tiên thấp nhất
Trong đó tia lửa/mảnh700bỏ mới
Sheet VFX khác nhau đang phát40FX mới dùng sheet thứ 41 → thay bằng VFX_SHARED_hit_* gần nhất
Instance VFX (pool)320 (S 160 · M 64 · L 24 · XL 4)cướp instance cũ nhất cùng hạng, trừ tell
VFX trúng mới / frame16R5
VFX chết mới / frame12R6
Vũng sáng động24 (hero ≤ 8)bỏ vũng nhỏ nhất
Afterimage hero6 bản sống (1 bản/0.03 s, 60% → 0 trong 0.18 s)—
Decal động64xoá cũ nhất
Số sát thương260vòng tròn ghi đè (07 §4)
Chi phí dựng 1 frame pixelfx (offline)< 2 ms (check.mjs)tối ưu trước export
  • Ưu tiên khi cướp/bỏ (cao → thấp): tell > FX hero đang điều khiển > ult > trúng lên Tinh Anh/Boss > FX địch > trúng lên quái S > chết quái S > môi trường.
  • Mọi VFX là sheet phát bằng sprite instanced (cùng atlas, cùng material SpriteAdd/SpriteActor); không ParticleSystem Unity cho FX gameplay.

6.2 LOD dưới tải (đo p95 frame 1 s trượt, hoặc số quái sống)

MứcBật khiCắt
L0mặc định—
L1quái ≥ 180 hoặc p95 > 15.0 mshạt ×0.6 · trúng 10/frame · chết 8/frame · môi trường động tắt · preset Deck bắt đầu ở L1
L2quái ≥ 220 hoặc p95 > 16.6 mshạt ×0.35 · trúng 6 · chết 6 · đuôi đạn địch tắt · afterimage 1 bản/0.06 s · vũng sáng ≤ 12
L3p95 > 20 ms trong 2 schỉ còn: tell, FX lõi hero (không hạt), nháy trắng, hitstop, số, vòng chân, x-ray
  • KHÔNG BAO GIỜ cắt: tell Y/P/N, nháy trắng trúng (INV-10), vòng chân + x-ray (INV-09), ấn spawn (INV-14), vùng đích đạn P (INV-13).
  • Hạ mức ngay khi vượt ngưỡng; nâng lại sau 3 s liên tục dưới ngưỡng − 1 ms (trễ để không nhấp nháy).

87. Khớp hitbox ↔ hình

LuậtĐòn heroĐòn địch
Nguồn sự thậthitbox từ data (CSV); VFX dựng theo số đónhư hero
Phủhình phủ ≥ 90% diện tích hitboxhình phủ 100% hitbox
Lệch biênhitbox được lớn hơn hình ≤ 4 px (dễ trúng) · hình vượt hitbox ≤ 6 px (S/M), ≤ 10 px (L/XL)hitbox nhỏ hơn hình 2 px (công bằng); KHÔNG BAO GIỜ lớn hơn hình
Đạnbán kính va = bán kính lõi + 2 pxbán kính va = bán kính lõi − 1 px; vẽ ≥ 4 px đường kính lõi
Tell P—viền 2 px nằm ĐÚNG trên biên hitbox; fill = toàn hitbox
Sóng lansát thương theo reach từng frame của sheet (packer đo nửa ngang vòng/mây đục ≥ 50% trên hàng pivot; lan theo max cộng dồn trong wave_spread_time 0.33 s) (07 §6.1)vành sóng thủ tục: hitbox = vành đang vẽ frame đó
Rẻ quạtbiên P(φ) §2.1 trùng mép cung chém ± 4 px—
  • QA: bật overlay debug (hình sàn hitbox vẽ elip 1 px) trên ảnh chụp 8 hướng (--dirs) + 1 ảnh in-game; ghi sai số đo vào spec (hitbox.match).

98. Nâng hạng tất định

  • Hạng kỹ năng I/II/III, Edge/Relic tăng Area, Count, Duration: chỉ đổi THAM SỐ, không đổi màu (trừ hạng III: viền sáng thêm 1 bậc r6 → r7), không sheet mới cho hạng III (Bible §10.3).
  • Seed cố định: seed = fnv1a32(VFX id) mod 2^16; mọi hạng dùng cùng seed → cùng hình, chỉ lớn hơn.
  • Thang cỡ sheet (mọi FX có hitbox theo Area, kể cả cung combo M): xuất 4 bậc s ∈ {1.0, 1.3, 1.7, 2.2} bằng --opts {"radius": r_base × s}. Runtime: tỉ lệ đích t = r_đích / r_base → chọn bậc k = argmin |ln(t / s_k)| → scale runtime t / s_k (luôn trong [0.87, 1.15] với 0.87 ≤ t ≤ 2.53), Point filter, làm tròn bề ngang về số chẵn px. t < 0.87 → bậc 1.0 ×0.87; t > 2.53 → bậc 2.2 ×1.15 (kẹp hình); viền sàn thủ tục vẫn đúng r thật (hitbox luôn khớp viền).
  • Bậc 1.0 + 1.3 nạp đầu run; bậc 1.7/2.2 nạp lười khi Area của build ≥ 1.49 (tính trong ngân sách 8 trang hero; vượt → bỏ bậc 2.2, kẹp ở 1.7 ×1.15 = 1.96).
  • FX không có hitbox (tia trúng, nhặt, glyph): giữ cỡ, chỉ đổi số lượng (Count) hoặc thời lượng.
  • Bảng tham số mỗi hạng ghi trong spec (rank): I {r, n, dur} · II · III; cấm công thức ngẫu nhiên lúc chạy.
  • Ví dụ: H01 SK02 nện r64 × Area 1.4 = 89.6 → t = 1.4 → bậc 1.3, scale 1.077; Area 2.0 → t = 2.0 → bậc 2.2, scale 0.909.

109. Mẫu VFX spec (cuối)

File: Design/ArtSpecs/vfx/<VFX_ID>.md, 1 file/VFX; hàng tóm tắt đồng bộ vào bảng VFX của doc chủ (hero/quái/boss). ★ = bắt buộc trước export.

Field★Định nghĩaGiá trị cho phép
id★ID duy nhất = tên sheetVFX_<ownerId>_<slug>; ownerId ∈ ID Bible (Varek H01, Hàng Cọc Tro H01_SK03, Trăng Máu H01_UL1, Cầu Bùa EN_B1_03_A01, Hồi Chuông Tang BS_B1_A02, Nổ Chết EM05, Đàn Vồ MUT04, Đầm Vải Liệm B2…) hoặc SHARED UI HUB; slug snake thường ≤ 24 ký tự
owner_class★ai sở hữu màuHERO ENEMY TELL ENV SHARED (§3)
tint★cách tôEXPORT (ramp hero lúc xuất) · HERO_LUT (xám chỉ mục, tô runtime) · BIOME (+ ALT khi có mask) · FIXED
trigger★sự kiện + mốc tt = 0 = khung chạm / nhả / spawn; vd attack1 hit, windup start, projectile spawn, on_death, status_apply
layer★lớp sortfloor_decal shadow floor_tell body_back body_front overhead prioritize screen (§2.4)
size_class★hạng cỡS M L XL (§5)
canvas★khung vẽ hướng ew×h art px ≤ trần hạng; gốc origin [x,y]
pivot★neofeet impact muzzle floor socket:<name> (§2.3)
dirs★số hướng1 (đối xứng tròn) · 8 (xuất 8, gói 5, lật 3); tilt 0.6–1.1 nếu là cung vung
frames★số frame + fps + loopN @30 (loop được @12/15); loop true/false; duration s
phases★mốc 3 pha (s)antic [a,b] · impact [c,d] · dissipate [e,f]; kết rỗng ở duration
keyframes★diễn biếndanh sách t → mô tả (white frame, lan, giữ, nguội, rỗng)
primitives★công cụ pixelfxswing slash band floorRing floorDisc floorGlow shadeFloor Particles(kind) Bits(kind) Lights spray slam p.disc … + tham số chính
palette★màu≤ 6 hex tối → sáng + lõi (#fff6f0 HERO / tối ENEMY); nguồn: 30 §3.2/§3.4/§3.6 hoặc PAL.<x>
particleshạtkind × count, tốc px/s, đời s, màu, trọng lực (950 px/s²)/cản, bóng có/không
lightánh sáng additivek 0.2–0.5, bán kính px, đời s; vũng sàn có/không
easing★gia tốcoutQuart outExpo inOutQuad linear + freeze (s)
hitbox★ nếu gây sát thươnghình sàn + khớpcircle r · ring r w · sector r α · line L W · rect L W · proj r; match = phủ %/lệch px đo được (§7); wave = reach hoặc procedural
ranknâng hạngbảng I/II/III {r, n, dur} + thang s (§8)
variantsbiến thểseed (mặc định §8), Dạng Rèn (--opts palette), ALT, mù màu
perf★ngân sáchô lớn nhất px, frame/hướng, trang atlas, instance trần, số Lights
lod★mức bị cắtnever (tell, flash) · L1 · L2 · L3
sfxâm đi kèmSFX_<ownerId>_<slug>
source★nguồnreuse <pixelfx id> · recolor <id> --opts · new src/fx/<cat>/<name>.js; file mượn kỹ thuật
export★lệnhnode tools/render.mjs <id> --sheet [--dirs] --opts '{…}' --seed N --out <dir> hoặc node tools/bw-fx.mjs <name> / hero.mjs
review★duyệtcheck.mjs sạch · inv01_check 0 lỗi · overlay hitbox · art-style-reviewer pass · ngày

1110. Ba ví dụ điền đủ

10.1 Cung chém cận chiến — H01_COMBO_A_1 (alias A1, clip attack1 32 frame, hit frame 11): t = 0 … VFX_H01_a1_slash (có sẵn: heroes/varek-attack1)

  • owner_class HERO · tint EXPORT · trigger combo A1 (HeroMoves.csv A1: startup 0.08, active 0.06, recovery 0.22, post_rate 1.6, dmg 14, radius 44, arc 150, step 10, knockback 16, hitstop 0.035).
  • layer body_back (nửa xa cung, vfx-back) + body_front (nửa gần + tia lửa, vfx); lên mục tiêu: on_hit (dmg_kind lưỡi sắc) t = 0 tại frame chạm hits[0].t; ≤ 16 VFX t… VFX_SHARED_hit_slash (overhead).
  • size_class M · canvas 156×104 hướng e, origin [40,84] (ô se 156×127, pivot [44,80]) · pivot feet (chân Varek) · dirs 8, tilt 1.
  • frames 32 @30, one-shot, 1.07 s gồm windup tác giả 0.30 + hiệu ứng 0.60 + freeze nướng 0.07; hitFrame 11 (se). Runtime: windup ép vào 0.08 s, bỏ frame freeze, đuôi ×1.6.
  • phases: antic [−0.30, 0] (ở thân) · impact [0, 0.05] · dissipate [0.05, 0.60].
  • keyframes: −0.30 GUARD · −0.15 WIND (lưỡi gần ra sau vai, lean −4, crouch 4) · −0.04 cuộn sâu · 0.00 CUT snap (bước +5, lean +5, ghost bật), cung hiện, mép trước trắng nóng · 0.03 chạm: tia lửa + chớp tại (50, −22), floorGlow r30 · 0.05 THRU snap · 0.05–0.20 vệt nguội theo ramp, tia lửa rơi nảy · 0.42 GUARD · 0.60 rỗng.
  • primitives: swing {cx:7, cd:0, cy:−24, R:27, sy:0.62, rot:−0.32, a0:−2.5, dir:1, span:3.2, W:11, t0:−0.02, tilt:1, turn:0} qua bladeArc ở cả 2 lớp; arcSparks(ps,R,ARC,C,8); impact(ps,lights,R,50,0,−22,0.35,C,0.8); p.floorGlow(50,0,30,C[5], 0.35 → 0 trong 0.3 s); act dust t0 x12 n5, x−10 n3.
  • palette: #6e1024 #a8162e #e0283a #ff4836 #ff9050 #ffe0b4 + lõi #fff6f0, frame trắng #ffffff 1 frame; afterimage #a01830.
  • particles: 8 SPARK dọc cung (kéo dài theo tốc, g 950, nảy), màu C[8..5]; tia chạm qua spray toả đủ chiều; không khói.
  • light: 1 Lights.add tại điểm chạm r 18, k 0.35, đời 0.15 s.
  • easing: quét snap-in, vệt nguội outQuart ~0.15 s; freeze 0.07 (tác giả) / 0.035 (runtime); không rung camera.
  • hitbox: sector r44 α150 hướng ngắm, gốc = chân trước bước = elip màn 88×44. Mũi lưỡi = cx + R = 34 px từ chân sau bước (+10) = 44 ✓; chớp chạm x50 vượt mép 6 px ✓. match: phủ ≥ 90%, vượt ≤ 6 px (đo trên --dirs).
  • rank (thang Area §8): s 1.0 → R27 W11 (r44) · 1.3 → R40 W13 (r57) · 1.7 → R58 W15 (r75) · 2.2 → R80 W18 (r97, sang hạng L).
  • variants: Dạng Rèn --opts palette; seed 4 (canon demo, giữ).
  • perf: ô ≤ 160×130, ≤ 32 frame/hướng, ≤ 3 bản sống, 1 light · lod L3 bỏ tia lửa (giữ cung) · sfx HeroAttackCut heroId=H01 moveIndex=1 (H01_COMBO_A_1; H01_UL3_ECHO dư … SFX_H01_a1_swing.
  • source: heroes/varek-attack1.js, _reaver.js (ramp bladeArc arcSparks impact keepIn), _varek.js · export: node tools/hero.mjs varek attack1 → node Tools/bw-pack.mjs varek · review: act.mjs --dir s|n, check.mjs sạch.

10.2 Đạn địch tell vàng — EN_B1_03_A01 (1 viên) và EN_B1_03_A02 (3 viên quạt 18°): t = 0 = rời … VFX_EN_B1_03_A01_orb (Cầu Bùa của Thầy Bùa Tro)

  • owner_class ENEMY (+ phần TELL) · tint BIOME + ALT (điểm nhấn 186° → alt khi chơi H10/H12) · trigger Cầu Bùa EN_B1_03_A01 (EnemyAttacks.csv: projectile gold, windup 0.55, recovery 0.40, dmg 10, tầm 300, bán kính 5, tốc 120, thời gian hồi chiêu 3.0; từ phút 3 quạt 3 viên lệch 18°, 1 token đạn).
  • 4 phần, 4 sheet:
PhầnlayerHạng · khung · dirsFramesMô tả
chargebody_frontS · 16×16 · 116 @30 (0.55 s, giữ frame cuối tới khi bắn)quả cầu tụ ở muzzle (đầu gậy): lõi #2e464c, viền #9ff3ff lớn 2 → 12 px; glint 1 windup_start (glint 1) và impact − 0.12 s (glint 2; đạn: ETA ≤ 0.12 s… VFX_SHARED_tell_glint_y tại t = −0.55
flightoverheadS · 16×16 · 16 @15 looplõi tối #2e464c → #476e75 đường kính 12 px, viền 1 px #9ff3ff, vành ngoài 1 px #ffd84a nháy 8 Hz (runtime bật/tắt mỗi 0.0625 s, không nướng vào sheet; 11 §2 Y_REFLECT); đuôi 3 chấm rỗng α 0.6/0.4/0.2 cách 4 px; bóng shadow 5×3 tại h = 0
burstoverheadS · 32×24 · 110 @30chạm hero/tường: vành rỗng nở r4 → r12 (elip), 6 GRIT lạnh rơi, rỗng tại 0.33 s
reflectoverheadS · 16×16 · 16 @15 loopsau ĐÁP: HERO_LUT lõi #fff6f0 + viền slot, tốc ×1.6 (192 px/s), dmg ×3, xuyên 3; chạm = on_crit t = 0 cùng frame chạm, phát sau hit_* cùng điểm (order +1) VFX_SHARED_hit_crit nếu chí mạng, không thì orb_burst tô hero
  • phases: antic [−0.55, 0] · impact t = 0 (rời gậy, 1 frame viền trắng) · bay tới 2.5 s (300 px / 120) · dissipate burst 0.33 s.
  • Tell Y (INV-02): glint 1 đầu windup · glint 2 + viền trắng 2 frame tại ETA − 0.12 s (runtime tính ETA = khoảng cách tới hero / tốc, cập nhật mỗi frame, bắn glint 2 khi ETA ≤ 0.12 lần đầu) · SFX tinh. Vành vàng chỉ trên đạn, không trên gậy (INV-01a).
  • hitbox: proj r5 (lõi vẽ r6 → nhỏ hơn hình 1 px ✓); bay ở h = 18; va chạm tính trên sàn (bóng).
  • palette B1 (30 §3.3–3.4): #2e464c #476e75 #68a3a8 #9ff3ff + tell #ffd84a + #ffffff (viền nháy); ALT: #5b586c #8a8699 #b9b5c6 #e8e4f0.
  • light: flight 1 light r 8 k 0.2 (L2 tắt) · perf: 4 sheet, ô ≤ 32×24, ≤ 9 viên sống (3 Thầy Bùa × 3), 0 hạt khi bay · lod: vành vàng, glint, viền trắng = never; đuôi L2.
  • source: src/fx/bladewake/orb.js thêm knob hollow (mặc định false giữ demo; true = lõi tối + viền sáng), orb-burst.js recolor; glint-gold.js dùng chung · export: thêm mục orb_hollow: {fx: "bladewake/orb", opts: {hollow: true, palette: […]}} vào bảng tên của tools/bw-fx.mjs, rồi node tools/bw-fx.mjs orb_hollow orb_burst.

10.3 Vùng sàn tím của boss — BS_B1_A02 windup start t = −0.90 s; t = 0 = boss nện chuông (clip att… VFX_BS_B1_A02_toll_ring (Hồi Chuông Tang)

  • owner_class TELL (vành) + ENEMY (trang trí) · tint FIXED · trigger Hồi Chuông Tang BS_B1_A02 (EnemyAttacks.csv BS01_B2: ring violet, windup 0.90, chạy 1.1, recovery 0.70, dmg 26, tầm 240, dày 18). P2: 2 vòng cách 0.6 s. Đòn chữ ký boss: miễn token tím, nhưng khi đang windup thì không tell P nào khác được bắt đầu (INV-08).
  • size_class XL thủ tục (không sheet cho vành) + 2 sheet phụ.
  • Thời gian & hình (r tính px sàn, tâm = chân boss):
t (s)Hình
−0.90hào quang P quanh boss (windup_start đòn P → impact VFX_SHARED_tell_aura_p, prioritize), ! tím (windup_start đòn P → impact VFX_SHARED_tell_bang_p) trên overhead, SFX ù trầm; vòng tầm tối đa r 240 viền 1 px #b14cff α 0.35 (floor_tell 25)
−0.90 → 0vành xuất phát r 20 dày 18: viền 2 px đúng cỡ từ tick 0, α 0.6 → 1.0; fill 25% lớn dần từ tâm dải, đầy đúng t = 0 (INV-02, 11 §1); windup 0.90 ≥ 0.60 (XL) ✓
0boss nện chuông (clip attack3); BS_B1_A02 t = 0 (chuông chạm sàn) và BS_B1_A14 mỗi vành (t = 0 / 0.90… VFX_BS_B1_A02_bell_flash (M, 48×32, 8 frame, overhead, #c9c2b0 → #ffffff 1 frame, không tím)
0 → 1.1vành chạy r(t) = 20 + 200·t; dải [r − 9, r + 9]: fill 25% #b14cff, viền 2 px mép ngoài α 1.0, mép trong α 0.6; dày màn 18 px Đông/Tây, 9 px Bắc/Nam (§2.1); bụi BS_B1_A02 / BS_B1_A14: 0 → 1.10 s sau mỗi vành, 8 cái/0.1 s rải đều t… VFX_BS_B1_A02_dust (sheet phụ 2: recolor dash_start t = 0 tại chân VFX_SHARED_dash_dust ramp B1 Họ A, 1 hướng, S 16×12, 9 @30) 8 cái/0.1 s rải đều trên mép ngoài, sống 0.3 s
1.1 → 1.3vành tại r 240 tan α → 0; vòng tầm tối đa tắt
  • hitbox: ring r(t) w16 (hình 18 → hitbox 16, nhỏ hơn 2 px ✓); mỗi mục tiêu trúng ≤ 1 lần/vành; Lướt xuyên dải = Né Hoàn Hảo; wave procedural (vành đang vẽ = vùng trúng frame đó).
  • Mù màu: gạch chéo 45° 1 px cách 4 px trong dải (R11).
  • palette: #b14cff (fill α 0.25, viền α 1.0/0.6), không màu khác trong vành; hào quang/! dùng sheet chung.
  • perf: 1 mesh vành 64 đoạn, shader elip pixel snap 1 art px (1 draw call) · bụi ≤ 24 instance S · lod: vành, vòng tầm, hào quang, ! = never; bụi L2.
  • sfx: EnemyWindupStart attackId=BS_B1_A02|BS_B1_A14 tellClass=P (từ frame đ… SFX_BS_B1_A02_hum (−0.90), EnemyImpact attackId=BS_B1_A02 tellClass=P (attack3 f27 = vành bắt đầ… SFX_BS_B1_A02_toll (0) · source: shader TellRing (runtime, dùng chung mọi tell P dạng vành/đĩa/rẻ quạt) + bladewake/violet-ring.js chỉ làm tham chiếu hình (không phát sheet cho vành 1.0) · review: chụp 8 vị trí hero quanh boss, overlay hitbox, đo lệch ≤ 1 px mỗi mép.

1211. Thư viện VFX dùng chung (VFX_SHARED_<slug>, 74 mục)

owner_class SHARED. Nguồn: reuse = sheet demo/pixelfx dùng nguyên · recolor = xuất lại với --opts palette (HERO_LUT: ramp xám 9 bậc) · new = tác giả mới · shader = runtime, 0 sheet. Thư mục Unity: Assets/ArtAsset/Vfx/Pixel/SHARED/. Thường trú trong ≤ 3 trang chung (30 §8.4).

#idNội dung (1 dòng)LớpHạngTintNguồn
1on_hit (dmg_kind lưỡi sắc) t = 0 tại frame chạm hits[0].t; ≤ 16 VFX t… VFX_SHARED_hit_slashtrúng lưỡi sắc: vệt 3 tia + 6 SPARK, 8 hướngoverheadSHERO_LUTrecolor bladewake/hit-crimson
2on_hit (dmg_kind cùn) t = 0 tại frame chạm VFX_SHARED_hit_blunttrúng cùn (búa, đe, găng, nắp): vòng dội + 4 GRIToverheadSHERO_LUTrecolor impacts/blunt-hit
3on_hit (dmg_kind mũi nhọn / đạn hero) t = 0 tại frame chạm VFX_SHARED_hit_piercetrúng mũi nhọn (giáo, tên, compa): chớp mũi + 3 STREAK theo hướng, 8 hướngoverheadSHERO_LUTrecolor impacts/hit-spark
4on_hit (đạn/nổ hero) t = 0 tại điểm nổ VFX_SHARED_hit_blasttrúng nổ (đạn hoả mai, Đinh nổ): nổ tròn r8overheadSHERO_LUTrecolor explosions/small-explosion
5on_hit hit_class HEAVY hoặc finisher, t = 0 tại frame chạm; hitstop r… VFX_SHARED_hit_heavyđòn kết/nặng: chớp chữ thập + vành sàn r16overheadMHERO_LUTrecolor bladewake/hit-heavy
6on_crit t = 0 cùng frame chạm, phát sau hit_* cùng điểm (order +1) VFX_SHARED_hit_critchí mạng: chớp #ffffff 2 frame + 4 tia ngà (không vàng, INV-01a)overheadSFIXEDrecolor impacts/crit-hit
7status_apply STS_EMBER cùng frame trúng (thay hit_* thường của cú đó) VFX_SHARED_hit_embertrúng gây STS_EMBER: + 3 tàn hình lửaoverheadSHERO_LUTrecolor impacts/hit-spark + fire/candle
8status_apply STS_FROST cùng frame trúng VFX_SHARED_hit_frosttrúng gây STS_FROST: + 3 mảnh tinh thểoverheadSHERO_LUTrecolor ice/ice-shatter
9status_apply STS_SHOCK cùng frame trúng VFX_SHARED_hit_shocktrúng gây STS_SHOCK: + 2 zigzag 1 pxoverheadSHERO_LUTrecolor lightning/zap-hit
10status_apply STS_ROT cùng frame trúng VFX_SHARED_hit_rottrúng gây STS_ROT: + 3 bọt vỡoverheadSHERO_LUTrecolor nature/acid-splash
11on_hit bị chặn (mục tiêu đang có khiên Y: EN_B1_04, EN_B4_01, EM09) t… VFX_SHARED_hit_blockedđòn hero vào khiên địch: tia "keng" xám-lam #8fa3a0overheadSFIXEDrecolor bladewake/block-spark
12on_hero_hurt t = 0 tại frame chạm VFX_SHARED_hit_on_herohero trúng đòn: chớp trắng + vụn ash-neutraloverheadSFIXEDrecolor impacts/hit-flash
13answer_success t = 0 tại frame ĐÁP chạm (trong cửa sổ ĐÁP của hero) VFX_SHARED_answer_flashĐÁP trúng tell Y: chớp tròn trắng + vành slot r12 tại điểm chạmoverheadMHERO_LUTrecolor bladewake/parry-flash
14answer_perfect t = 0 tại nhịp ĐÁP cuối của chuỗi VFX_SHARED_answer_perfectĐÁP trọn chuỗi/hoàn hảo: + 8 tia toả + vành sàn r24overheadMHERO_LUTrecolor impacts/parry
15perfect_dodge t = 0 tại tick Lướt xuyên hitbox đòn địch VFX_SHARED_dodge_perfectNé Hoàn Hảo: vành sàn r20 nở 0.2 s + 1 bóng trắngfloor_decal + bodyMHERO_LUTnew
16poise_break t = 0 tại frame Thế về 0 VFX_SHARED_guard_breakVỡ Thế Tinh Anh/Boss: 10 mảnh ngà văng + vành sàn r32overheadMFIXEDrecolor spawn/shatter-death
17counter_window_open t = 0 khi địch vào trạng thái phản được VFX_SHARED_counter_markdấu Phản ✦ 7×7 trên overhead địch 0.6 sprioritizeSHERO_LUTnew
18shield_broken t = 0 tại frame khiên về 0 (shieldbreak hoặc ĐÁP vào kh… VFX_SHARED_shield_breakkhiên địch vỡ (EN_B1_04, EN_B4_01, EM09): 8 mảnh tro + loéoverheadMFIXEDrecolor ice/ice-shatter
19status_apply STS_EMBER → loop; tắt khi trạng thái hết/chết VFX_SHARED_sts_emberSTS_EMBER: 2 tàn quanh thân, loop 8 @12bodySHERO_LUTrecolor status/burning
20status_apply STS_FROST (mỗi lớp thêm 1 instance) VFX_SHARED_sts_frostSTS_FROST: tinh thể bám chân, loopbodySHERO_LUTrecolor status/frozen
21status_apply STS_SHOCK → loop VFX_SHARED_sts_shockSTS_SHOCK: zigzag nhảy giữa 2 điểm thân, loopbodySHERO_LUTrecolor lightning/electrified
22status_apply STS_ROT → loop VFX_SHARED_sts_rotSTS_ROT: bọt nổi từ thân, loopbodySHERO_LUTrecolor status/poisoned
23status_apply STS_BIND → loop VFX_SHARED_sts_bindSTS_BIND: 2 vòng xích elip quanh eo, loopbodySHERO_LUTnew (tham chiếu nature/root-snare)
24status_apply STS_DREAD → loop VFX_SHARED_sts_dreadSTS_DREAD: mắt mở trên đầu + thân run 1 pxbody + prioritizeSHERO_LUTrecolor shadow/hex-sigil
25status_apply STS_STUN → loop VFX_SHARED_sts_stunSTS_STUN (mọi nguồn): 3 sao tro xoay elip trên đầu, loopprioritizeSFIXEDrecolor status/stunned
26status_apply STS_SLOW → loop VFX_SHARED_sts_slowSTS_SLOW (nước, bãi xương, bụi EN_B2_05, EM11): sóng ngang bụi tro ở chân, loopfloor_decalSFIXEDrecolor status/slowed
27status_apply STS_MUTE lên hero → loop VFX_SHARED_sts_muteSTS_MUTE (EN_B6_02, BS_FINAL, BS_TRUE; chỉ lên hero): chuông ngà bị gạch trên đầu + vòng ngà rỗngprioritizeSFIXEDnew
28status_apply STS_BLIND → loop VFX_SHARED_sts_blindSTS_BLIND (H11 Hất Đất): bụi đất xoáy quanh đầu quái, loopbodySHERO_LUTrecolor status/confused
29status_apply STS_DISARM t = 0 (one-shot, sau đó glyph DISARM) VFX_SHARED_sts_disarmSTS_DISARM (H04): 2 mảnh lưỡi gãy nảy ở hand_main quái 0.3 s rồi glyphbodySHERO_LUTnew
30status_apply STS_PIN t = 0 (one-shot cắm, giữ frame cuối) VFX_SHARED_sts_pinSTS_PIN (H02 Đóng Nắp, H11 hố): cọc ghim xuyên bóng chân + 4 vụn sànfloor_decal + bodySHERO_LUTnew (tham chiếu nature/earth-spike)
31status_apply bất kỳ STS_* → hiện glyph; status_end → ẩn VFX_SHARED_sts_glyphsatlas glyph 8×8 × 12: EMBER lửa · FROST tinh thể · SHOCK zigzag · ROT bọt · BIND xích · DREAD mắt · STUN sao · MUTE chuông gạch · BLIND bụi · DISARM lưỡi gãy · SLOW sóng ngang · PIN cọc (10 §5.1); trên quái = ramp hero, trên hero = bạc #c8c8d0prioritizeSHERO_LUT / FIXEDnew
32director_spawn t = 0 khi đặt ấn; quái bật tại t = 0.60 VFX_SHARED_spawn_markấn tro spawn 0.6 s, elip r10 #e8e4f0 vòng LIỀN + xoáy tro, không sát thương (INV-14); biến thể dashed khi chơi H02: viền gạch đứt 2 px (INV-01e), cùng id, sheet _dashedfloor_tellSFIXEDreuse bladewake/spawn-ash (+ recolor dashed)
33summon_cast t = 0; quái triệu hồi xuất hiện tại t = 1.00 VFX_SHARED_summon_vortexxoáy triệu hồi trung tính 1.0 s r16 (boss/Tinh Anh, EM04)floor_tellMFIXEDrecolor arcane/portal
34clip spawn frame 0 (sau spawn_mark) VFX_SHARED_spawn_riseđất/tro bung khi quái trồi lên (clip spawn)overheadSBIOMErecolor spawn/summon-rise
35on_death quái S t = 0 tại frame chết; ≤ 12 VFX chết mới/frame (R6), q… VFX_SHARED_death_schết S: loé 0.09 s + tro + 5–8 mảnh xương theo hướng đònoverheadSBIOME + ALTreuse bladewake/death-ash
36on_death quái M t = 0 VFX_SHARED_death_mchết M: tro lớn + vành sàn r24 + 12 mảnhoverheadMBIOME + ALTrecolor death-ash (size 1.6)
37on_death quái L hoặc Tinh Anh t = 0 VFX_SHARED_death_lchết L: cột tro 48 px + vành r40overheadLBIOME + ALTnew
38boss_death t = 0 tại frame đầu clip death VFX_SHARED_death_xlchết boss: 3 nổ tro nối tiếp 0.4 s + cột tro 96 px + sóng đẩy thủ tục (không tím)overhead + floor_decalXLBIOMEnew
39corpse_ready (sau hất/squash 0.30 s) t = 0 VFX_SHARED_dissolve_dithertan xác Bayer 4×4 0.4 s theo pixel spritebody——shader
40on_death (mọi hạng) t = 0.30 sau death_* VFX_SHARED_corpse_stainvết tro sàn sau chết, sống 8 s, tan dither 0.5 sfloor_decalSBIOMEreuse bladewake/decal-ash-stain
41xp_drop t = 0 khi quái chết rơi XP; loop tới khi magnet kéo VFX_SHARED_pickup_xpmảnh XP trên sàn, loop: lõi ash-neutral + viền slotfloor_decal + overheadSHERO_LUTrecolor bladewake/xp-shard
42pickup_collected t = 0 khi vật chạm bán kính nhặt hero VFX_SHARED_pickup_collectđồ bay vào hero (vệt hút 1 px slot khi nam châm kéo) + chớp nhỏ 0.23 soverheadSHERO_LUTrecolor pickups/collect-burst
43drop CUR_PAPER_GOLD t = 0; loop tới khi nhặt VFX_SHARED_pickup_paper_goldVàng Mã (Vàng Mã CUR_PAPER_GOLD): tờ giấy ngà #d8cfb4 xoay, dấu mựcoverheadSFIXEDrecolor pickups/coin-spin
44drop CUR_SOUL_ASH t = 0; loop tới khi nhặt VFX_SHARED_pickup_soul_ashTro Hồn (Tro Hồn CUR_SOUL_ASH): nhúm tro #e8e4f0 lơ lửngoverheadSFIXEDrecolor pickups/crystal-shard
45drop CUR_ECHO_SHARD t = 0 (mini-boss chết) VFX_SHARED_pickup_echo_shardMảnh Vọng (Mảnh Vọng CUR_ECHO_SHARD): mảnh ngà-lam #cfd8e8 + cột sáng 32 pxoverheadMHERO_LUTrecolor pickups/loot-beam
46drop heal t = 0; loop tới khi nhặt VFX_SHARED_pickup_healcầu hồi máu (bình, rơi hiếm)overheadSHERO_LUTrecolor bladewake/heal-orb
47reward_spawn RSC/BOS/MBS/SEC t = 0 khi rương mở VFX_SHARED_chest_relicrương Relic mở + cột sáng ngà 48 px chỉ chỗ Relic/thưởng trên sàn (loop tới khi nhặt)overheadMFIXEDreuse bladewake/chest-open + recolor pickups/loot-beam
48level_up t = 0 khi XP vượt ngưỡng; màn chọn thẻ mở tại t = 0.50 VFX_SHARED_leveluplên cấp: vành sàn r24 + tia lênbodyMHERO_LUTrecolor bladewake/levelup (không chữ nướng)
49resonance_activate t = 0 VFX_SHARED_resonance_onCộng Hưởng bật: 2 vành sàn đồng tâm r16/r28floor_decalMHERO_LUTrecolor holy/blessing
50evolution_applied t = 0 khi màn thẻ đóng VFX_SHARED_evolution_forgeTiến Hoá: búa tia lửa + vỏ đồng bao quanh thẻ/thânoverheadLHERO_LUTnew
51ult_gauge_full t = 0; loop tới khi dùng Ult VFX_SHARED_ult_readyDư Âm (ULT_GAUGE) đầy: viền slot quanh thân nháy 1 lần/1.0 sbodySHERO_LUTnew
52windup_start (glint 1) và impact − 0.12 s (glint 2; đạn: ETA ≤ 0.12 s… VFX_SHARED_tell_glint_yglint 4 cánh 5×5 #ffd84a, 4 frame (INV-02); boss 7×7 (11 §1); mù màu = thoi ◇prioritizeSFIXEDreuse bladewake/glint-gold
53glint 2 (impact − 0.12 s) → impact VFX_SHARED_tell_rim_yviền trắng nháy ≥ 2 frame trên thân/đạn đang tell Yprioritize—FIXEDshader (SpriteActor)
54windup_start của đòn P (t = 0); va chạm tại t = windup VFX_SHARED_tell_zone_pvùng P thủ tục (đĩa, vành, rẻ quạt, đường): fill 25% + viền 2 px sáng dầnfloor_tellthủ tụcFIXEDshader TellRing
55windup_start đòn P → impact VFX_SHARED_tell_bang_pdấu ! tím 7×9 trên overhead (11 §1); mù màu thêm ▲ 7×6prioritizeSFIXEDrecolor ui/exclamation
56windup_start đòn P → impact VFX_SHARED_tell_aura_phào quang tím quanh thân (viền 2 px nhấp 4 Hz)prioritizeMFIXEDnew
57zone_spawn t = 0; sát thương bắt đầu t = 0.30; zone_end → tan VFX_SHARED_tell_zone_nvùng N: viền chấm 2 px + chấm thưa 15% #e8e4f0floor_tellthủ tụcFIXEDshader TellRing (dotted)
58projectile_spawn đạn P (t = 0); tới đích t = ETA ≥ 0.45 VFX_SHARED_tell_proj_p_pathđường/vòng đích của đạn P trên sàn ≥ 0.45 s trước khi tới (INV-13)floor_tellthủ tụcFIXEDshader TellRing
59ash_read (CV đổi thế) t = 0; ash_forget → mờ 0.5 s VFX_SHARED_ash_eyeTro Nhớ đổi thế: ◆ ash-eye 7×7 trên overhead + mắt loé 0.6 s; ◆ nhỏ 5×5 trên ấn spawn của loài đang có CV; mờ 0.5 s khi CV ngủ/quên (14 §14)prioritizeSFIXEDnew
60elite_spawn t = 0 (sau summon/spawn_mark) VFX_SHARED_elite_markglyph Ấn 8×8 (16 glyph EM01–EM16) trên overhead Tinh AnhprioritizeSFIXEDnew
61shield_gain t = 0; loop tới hết khiên VFX_SHARED_shield_herokhiên hero (Relic/Edge): vành elip slot quanh thân, nửa xa ở body_backbodyMHERO_LUTrecolor holy/divine-shield
62hero_heal t = 0 VFX_SHARED_heal_pulsehồi máu: 6 MOTE bay lên + vành sàn r12bodySHERO_LUTrecolor holy/heal
63hero_revive t = 0 tại frame HP về 0 có Relic hồi sinh VFX_SHARED_revivehồi sinh (Relic): cột sáng ngà 64 px + vành r32 + tro rơi ngượcoverheadLHERO_LUTrecolor holy/resurrection
64dash_start → dash_end (mỗi 0.03 s 1 bản) VFX_SHARED_dash_afterimagebản sao thân tô slot 60% → 0 trong 0.18 s, 1 bản/0.03 s (gốc; hero thêm chi tiết riêng)body—HERO_LUTshader (runtime copy)
65dash_start t = 0 tại chân VFX_SHARED_dash_dustbụi chân khi Lướt, 8 hướngfloor_decalSBIOMEreuse bladewake/dust-dash
66counter_success / answer_perfect t = 0 VFX_SHARED_screen_flash_whitechớp trắng 2 frame α 0.35 (Phản đòn, ĐÁP hoàn hảo)screen—FIXEDshader
67ult_burst t = 0 VFX_SHARED_screen_flash_ultchớp slot 3 frame α 0.30 khi Ult nổ chínhscreen—HERO_LUTshader
68world_slow_start → world_slow_end VFX_SHARED_screen_world_slowtint lạnh α 0.12 khi đồng hồ World chậm (Né Hoàn Hảo 25%)screen—FIXEDshader
69hero_hp < 25% → loop; ≥ 25% → tắt 0.3 s VFX_SHARED_screen_lowhpviền tối tro 24 px khi HP < 25%, nhịp 1 Hzscreen—FIXEDshader
70boss_phase_change t = 0 VFX_SHARED_screen_phaseboss chuyển pha: chớp ngà 2 frame + sóng đẩy thủ tục r160 (không tím)screen + floor_decalXLFIXEDshader + bladewake/violet-ring recolor ngà
71spec chủ gọi (đòn, kỹ năng, ult, hazard, tell): t = 0 tại tick spawn … VFX_SHARED_floor_ellipseshader elip sàn có tham số cho mọi vùng/vành/đĩa/rẻ quạt/đường/chữ nhật vẽ thủ tục (§5: r > 112, mọi tell P/N); bí danh cũ FloorRing/EllipseRing/HeroRing/HeroDisc → FloorEllipsefloor_decal / floor_tellXL thủ tụcFIXEDshader FloorEllipse
72spec chủ gọi (vũng sáng light.floor_pool, quầng sàn env/hero/boss): t… VFX_SHARED_floor_glowquầng sáng sàn mềm elip 2:1, mép dither, không viền (vũng sáng light.floor_pool, quầng boss/env, chân cột sáng); mode ring; khác nét offline p.floorGlow của pixelfxfloor_decalXL thủ tụcFIXEDshader FloorGlow
73spec chủ gọi (chớp, tint, viền tối, chuyển cảnh): t = 0 tại sự kiện c… VFX_SHARED_screen_fxshader màn hình 4 mode: flash · tint · vignette · wipe; #66 #67 #70 = preset flash, #68 = tint, #69 = vignettescreen—FIXEDshader ScreenFX
74spec chủ gọi (dây móc, xích, tơ, tia nối 2 điểm): t = 0 khi nối; cập … VFX_SHARED_rope_linedây/xích/tia nối 2 điểm, mode chain · beam · silk (bí danh ChainBeam/SilkLine/chain_line → RopeLine)body_frontthủ tụcFIXEDshader RopeLine
  • TellRing = FloorEllipse (#71) với màu tell cố định (#b14cff P, #e8e4f0 N, rim 2, fill 0.25/0.15); dùng ở #54, #57, #58 và mọi tell vành/vùng của chủ; không FX nào khác được dùng preset này.
  • Tổng: 59 mục có sheet (reuse 6 · recolor 39 · new 14; + 2 sheet phụ: spawn_mark_dashed, cột sáng của chest_relic) + 15 mục shader/thủ tục (0 sheet; #70 kèm 1 sheet recolor trang trí). Tính vào dòng "Trạng thái/hazard/hub/UI" + cột "Dùng lại thư viện pixelfx" của Bible §10.3.
  • Mục nào chưa đủ cho 1 đòn riêng → làm VFX_<ownerId>_<slug> của chủ, KHÔNG thêm mục SHARED ngoài 74 mục này khi chưa có quyết định ghi ngày. Vùng sàn / quầng sàn / màn hình / dây trong spec chủ dùng shader #71–#74 (+ preset TellRing); tên shader thủ tục khác (bí danh cũ) → đổi tên về #71–#74.

1312. Checklist — agent dựng 1 VFX với pixelfx

  1. ID & chủ: đặt VFX_<ownerId>_<slug> (Bible §11); kiểm chưa trùng; xác định owner_class + tint (§3). Đòn địch: đọc adaptive_source — biến thể ASH dùng CHUNG sheet với BASE (INV-15: không đổi tell/hitbox).
  2. Số gameplay: lấy windup/active/recovery/bán kính/cung/tốc/dmg từ CSV của chủ; tell Y/P/N từ doc chủ. Thiếu số → dừng, không đoán.
  3. Thư viện trước: node tools/list.mjs <từ khoá> + docs/CATALOG.md + §11; render 2–3 ứng viên, xem records/<id>/contact.png. Đủ dùng → reuse/recolor (--opts palette), sang bước 8.
  4. Viết spec: Design/ArtSpecs/vfx/<VFX_ID>.md đủ field ★ (§9): hạng cỡ (§5), lớp (§2.4), pha thời gian (§4), hitbox (§7), rank (§8), perf + LOD (§6).
  5. Nháp: node tools/new.mjs <category>/<name> (vòng lặp: --loop); hướng mở → 3 nháp -a/-b/-c, render tất cả, giữ 1. Viết hướng e; vòng/vùng = hình sàn (floorRing, shadeFloor, band(..., p.V.k, ...)), nổ = spray + spawn3, vật bay có bóng; không Math.random/Date; tôn trọng o.palette, o.seed.
  6. Nhìn – sửa ≥ 3 vòng: node tools/render.mjs <id> [--dirs] [--all] [--mp4]; sửa lỗi tệ nhất mỗi vòng theo bảng "you see → fix" của skills/pixelfx/SKILL.md (mush, speckle, floaty, washed out, side-view…). Có thân diễn → act + node tools/act.mjs <id> --dir s và --dir n.
  7. Kiểm máy: node tools/check.mjs <id> sạch (biên, kết rỗng, seam loop, seed, < 2 ms/frame, act keys).
  8. Màu: py -3 Tools/artcheck/inv01_check.py <png> --kind vfx_hero|vfx_enemy --id <ownerId> = 0 lỗi; HERO: viền slot + lõi #fff6f0, đặc; ENEMY: lõi tối, rỗng, không đỏ thẫm, không dải tell; TELL chỉ 3 màu tell.
  9. Hitbox: overlay hình sàn hitbox lên sheet --dirs + 1 ảnh in-game; đo phủ % và lệch px; ghi hitbox.match. Fail → chỉnh tham số pixelfx, không chỉnh hitbox data.
  10. Xuất: node tools/render.mjs <id> --sheet [--dirs] --opts '{…}' --seed N --out <dir> (FX Bladewake: thêm mục vào tools/bw-fx.mjs; hero: tools/hero.mjs) → thang Area 4 bậc nếu có (§8) → node Tools/bw-pack.mjs khi thuộc atlas actor.
  11. Nhập Unity: PNG + JSON vào Assets/ArtAsset/Vfx/Pixel/<ownerId>/ (SHARED: SHARED/); PixelArtImportRules cắt, pivot = meta.pixelfx.pivot, PPU 16; gán sorting layer/order theo layer (§2.4); đăng ký vào bảng VFX của doc chủ (id → sheet, fps, loop, hạng, LOD).
  12. Duyệt: contact sheet + strip + ảnh in-game ×1/×4 trên sàn biome đích giữa 200 quái → subagent art-style-reviewer = pass; test 5 s (P4) nếu là FX hero chữ ký (nhận ra hero qua 3 s FX ≥ 80%, P6). Ghi review vào spec. Nháp không giữ → xoá.

1413. Quy tắc cho dev/AI

  • Mọi VFX phải có spec (§9) trước khi export; không spec = không vào Assets/.
  • Tell chỉ dùng #ffd84a / #b14cff / #e8e4f0 chấm theo đúng hình INV-02; không FX nào khác được mượn màu hoặc hình đó (glint 4 cánh, elip fill 25% viền 2 px, viền chấm).
  • FX hero = đặc + lõi #fff6f0 + viền slot; FX địch = rỗng + lõi tối; màu hero xuất qua ramp 30 §3.2 hoặc HERO_LUT, không tự pha.
  • Vòng/vùng/nón trên sàn tuân §2.1 (elip 2:1); vật bay có bóng; không phun phẳng; không xoay ảnh để ngắm.
  • Vùng sàn r > 112 và mọi tell P/N = vẽ thủ tục (TellRing), không sheet.
  • Hình = hitbox theo §7; đòn địch: hitbox ≤ hình; sửa hình chứ không nới hitbox địch.
  • Tôn trọng trần §6.1 và LOD §6.2; không bao giờ cắt tell, nháy trắng trúng, vòng chân, x-ray, ấn spawn.
  • Nâng hạng chỉ đổi tham số, seed cố định, thang 4 bậc (§8).
  • Ưu tiên reuse → recolor → new; FX mới tác giả trên nhánh art/<slug> trong Tools/pixelfx, push/merge khi dev đồng ý.
  • Không dùng ParticleSystem Unity cho FX gameplay; không chữ nướng trong sheet (ui/level-up có chữ tiếng Anh → không dùng).
  • Không ghi tên game/studio/thương hiệu có thật vào spec hay file trong repo.

1514. Quyết định đã chốt

QQuyết địnhLý do
Lớp sort5 lớp gốc + floor_tell trên shadow trong FXBotbầy 250 quái đổ bóng không được che tell sàn (INV-18)
Vành/vùng lớnr > 112 và mọi tell P/N vẽ thủ tụcđúng r tuyệt đối với hitbox, 1 draw call, không tốn trang atlas
2026-11-07 — "≤ 40 sheet VFX hoạt động" (Bible §10.4)hiểu là ≤ 40 sheet KHÁC NHAU đang phát; instance kẹp bởi pool 320demo đo 16 trúng/frame × 10 frame đã > 40 instance; Bible không đổi số
Hạng cỡS 32×32 · M 160×128 · L 256×176 · XL 480×270cung combo canon 156×104 phải là M; XL = 1 view
Thang Area4 sheet bậc 1.0/1.3/1.7/2.2, scale runtime ≤ ±15%giữ 1 cỡ pixel (VP1) mà vẫn khớp hitbox (thay scale demo 0.6–2.6)
Hitbox bất đối xứnghero ≤ hình + 4 px; địch ≤ hình − 2 pxdễ trúng cho người chơi, công bằng khi bị đánh (P3, INV-15)
2026-11-07 — đạn Cầu Bùa EN_B1_03_A01demo "lõi trắng" → lõi tối + viền #9ff3ff + vành #ffd84aINV-01c: FX địch rỗng, lõi trắng chỉ cho hero
Chí mạngchớp trắng, không vàng (demo 07 §3 "chí mạng nháy vàng" bỏ)INV-01a
Trạng thái1 sheet HERO_LUT + glyph/trạng thái cho 12 hero; đủ 12 STS_* (6 BUILD + 6 CONTROL của 10 §5.1), glyph trên vòng chânINV-01f, 0 sheet thêm mỗi hero; khớp vị trí glyph của 10 §5
2026-11-07 — gộp mục thư việnspawn_mark_dashed → biến thể của spawn_mark; magnet_trail → pickup_collect; relic_beam → chest_relic; 3 chỗ trống = sts_blind sts_disarm sts_pin; cc_stun/debuff_slow/debuff_silence đổi tên sts_stun/sts_slow/sts_mutegiữ trần 70 mục mà phủ đủ 12 trạng thái của 10
2026-11-07 — lõi đạn Y_REFLECTgiữ lõi tối #2e464c + viền #9ff3ff (INV-01c); 11 §2 ghi "lõi #9ff3ff tâm trắng" → doc 11 cần sửa theo BibleBible thắng doc con; tâm trắng = ngôn ngữ FX hero
LOD4 mức L0–L3 theo p95 + số quái, trễ nâng 3 sgiữ 60 fps Deck (MS01b) mà không bao giờ mất tell
Thư viện chungđúng 74 mục VFX_SHARED_*; thêm mục cần quyết định ghi ngàychặn trùng lặp, giữ ≤ 3 trang chung
2026-11-07 — thêm 4 shader dùng chung có tham số thay ~50 tên shader runtime#71 FloorEllipse · #72 FloorGlow · #73 ScreenFX (flash/tint/vignette/wipe) · #74 RopeLine (chain/beam/silk); TellRing = preset của FloorEllipse; 70 → 74 mục (0 sheet thêm)spec AV đặt ~50 tên shader không tham số; khớp SHARED__vfx.json (74 mục)