- arena.js (window.Arena) + arena.css: semua digambar prosedural di kanvas, tanpa gambar baru. Lapisan belakang (antara latar dan petarung): awan yang bergeser (memudar saat melewati menara/atap lewat kotak keep per arena), burung walet, camar, kelelawar yang melintas sesekali, kilau air dan perahu layar kecil (Azure Harbor), sungai berkilau (Moonrise), debu cahaya dan berkas cahaya (Sunspire), daun dan kelopak jatuh (Elderwood), kunang-kunang, bintang berkedip dan bintang jatuh (malam). Lapisan depan: siluet penonton di tepi bawah (dua baris, topi kerucut, bendera, lentera) yang melompat dan mengangkat tangan saat kombo 5/8/12 dan K.O., serta bertepuk saat kombo besar berakhir.
- Cuaca per pertandingan: Otomatis (deterministik dari arena: semua cerah, Elderwood kabut tipis, Moonrise malam), Cerah, Hujan (garis miring dua lapis, percikan di lantai, awan gelap, kilat lembut), Kabut (pita kabut bergeser), Senja (tint hangat, cahaya cakrawala dan matahari), Malam (tint biru, bintang, sorotan lantai yang mengikuti petarung). Hanya tampilan: tidak menyentuh mekanik, random() mesin, atau Date; semua gerak adalah fungsi waktu tanpa status (hash bilangan bulat), jadi advance() dan jeda aman.
- Efek latar di Pengaturan: Penuh/Ringan/Mati (konoha.arena.v1; bawaan Ringan di HP). Gerak dikurangi (Access.motion atau prefers-reduced-motion) membekukan waktu latar dan mematikan burung, perahu, daun, debu, bintang jatuh, kilat, dan lompatan penonton. Modul mematikan diri bila gambar berulang kali galat.
- Biaya dijaga setelah diukur pada rasterisasi perangkat lunak: vinyet dan kerudung warna depan jadi elemen DOM #arena-vig (nol biaya kanvas), kabut berupa ubin siap-ukuran digambar 1:1, gradasi langit lewat strip 1x256, blend besar memakai source-over; tanpa kerucut cahaya.
- Kait: game.js draw() dua baris (Arena.back sesudah drawBackground, Arena.front di akhir); menu.js Arena.decorate di akhir render() dan weather: Arena.pick di startMatch (pembungkus __game.startMatch mencatatnya hanya bila pertandingan mulai; Arcade, Survival, tutorial memakai Otomatis); index.html dua tag di baris sendiri sebelum </main>. Baris Cuaca disisipkan di sisi kiri tombol mulai, jadi tinggi layar arena tidak bertambah (diukur: 1280x720 dan 1024x520 sama seperti sebelumnya).
- Mode ringan: node --check dan smoke lulus tanpa galat halaman; tampilan diuji manual oleh pemilik. precache.js dan files.json perlu dibangun ulang oleh integrator.
Panel Dummy kini muncul di sisi kiri (bisa dipindah ke kanan dengan tombol di kepala panel) supaya penghitung kombo besar di kanan tidak tertutup, dan z-index panel dibuat di bawah timer mode (.form-timers) yang tembus klik sehingga timer tetap terlihat.
Perbaikan AI: CPU hampir tidak pernah memakai skill 2 milik Ethanol Man (TAWA MELEDAK) dan Solo Man (SARUNG PUTAR). Penyebabnya, cpuPick selalu mendahulukan pukulan dasar (161 px) yang menutup lingkaran jurus area (135 dan 140 px), dan penutup kombo cpuFollowUp tidak pernah lolos cpuLands. Kini cpuAreaKit/cpuAreaFits mendahulukan jurus area pemusat-diri bila lawan di dalam lingkarannya (selisih 12 px, sejajar tinggi, tidak sedang berjalan keluar, pukulan pemain yang sedang disiapkan tidak mendarat lebih dulu), dan CPU berdiri lebih rapat saat jurus itu siap. Karakter lain dan urutan random() mesin tidak berubah.
Rival adaptif (ai.js, window.AIAdapt): CPU di versus mengingat kebiasaan pemain dalam satu pertandingan lewat jendela bergulir (melompat, memblok, memukul dekat, menembak dari jauh) dan menggeser sedikit antiAir, evade, punish, speed, aggression, dan peluang jurus didahulukan. Kekuatan mengikuti tingkat (easy hampir nol), dua arah, tanpa membaca tombol dan tanpa menyentuh damage atau HP. Layar hasil menampilkan satu kalimat "Rival belajar: kamu sering ..." bila ada kebiasaan dominan. Reset di startMatch.
Latihan lanjutan (training.js, training.css): tombol DUMMY di arena latihan membuka panel dengan perilaku dummy (Diam, Blok terus, Lompat terus, Serang acak, Ikuti pemain, CPU penuh), Reset posisi, Tampilkan hitbox, Tampilkan frame data (startup, aktif, recovery, total, jangkauan), Darah dummy tak terbatas, penghitung kombo dan damage, serta Rekam dan Putar ulang input pemain (maksimal 10 detik, dijadwalkan menurut waktu simulasi dengan benih random() yang sama, hasil dibandingkan dengan rekaman). Hanya aktif di latihan biasa, tidak di tutorial.
Kait di game.js dibuat satu baris (Training dan AIAdapt dipanggil dengan ?.). Catatan di docs/ENGINE_NOTES.md, laporan keseimbangan, dan komentar uji pasangan diperbarui. precache.js dan files.json tidak disentuh: perlu dibangun ulang oleh integrator untuk berkas baru.
Modul baru hazard.js (+ hazard.css), tanpa gambar atau pustaka baru; semua digambar prosedural di kanvas.
- Bellora: genting jatuh dari menara (6 damage). Sunspire: silau matahari, layar memutih sebentar tanpa damage.
Harbor: ombak dari kiri yang mendorong ke kanan sampai garis batas (3 damage). Elderwood: dua akar menyembul (5 damage).
Moonrise: petir arkana di lingkaran rune (7 damage).
- Aba-aba tepat 1 detik (cincin atau garis di lantai, kilau di langit, suara sound(), teks "Awas: ..."); baris kecil
"Bahaya: <nama>" di papan nama arena. Dapat dihindari dengan lompat atau geser.
- Hanya versus (Arcade, Survival, dua pemain); latihan dan tutorial tidak. Pertama 6-12 dtk, lalu tiap 9-14 dtk; tidak di
4 dtk pertama, saat ultimate atau sinematik, saat petarung jatuh, atau di 3,5 dtk terakhir ronde.
- Deterministik (pengacak LCG sendiri berbenih mesin + ronde + arena, waktu dari dt simulasi), simetris untuk pemain, CPU, dan
P2; damage kecil, tidak pernah mematikan (sisa 1 HP), tanpa luka atau kombo. CPU mencoba keluar zona lewat rencana sidestep.
- Pengaturan "Bahaya arena" Aktif/Mati (bawaan Aktif) dan Hazard.enabled untuk tantangan khusus; hormati Kurangi gerakan.
- Kait game.js: Hazard.step di step(), Hazard.draw (back, front) di draw(), dan __game.hazardCtx. Uji manual: ?hazard=cepat
atau Hazard.trigger().
Tombol TUTORIAL kecil di pojok kiri atas menu utama (di luar alur bilah, jadi tinggi menu tidak berubah) memulai latihan terpandu di arena latihan:
karakter terakhir yang dimainkan (atau Mega Chan) melawan dummy diam. Panel instruksi di bawah header HUD menampilkan delapan langkah berurutan
(gerak, lompat, kombo 3 pukulan, uppercut dan tinju maju, skill I dan O, blok lalu parry, lempar, ultimate) dengan tombol yang harus ditekan,
centang otomatis saat terdeteksi, tombol LEWATI dan KELUAR, serta penanda selesai (+50 koin satu kali, flag di Meta.save.eggs['code:tutorial']).
Di layar sentuh teks dan sasaran memakai tombol layar.
- tutorial.js, tutorial.css: modul baru (deteksi dari hero.state/jumps/action/blocking/cooldowns, pembungkus receiveHit hanya untuk mengamati hasil parry/blok).
- game.js: dua kait kecil di __game: stats() (kombo dan damage) dan dummyAttack(slow) (serangan dummy atas perintah, pembuka diperlambat untuk latihan parry).
- menu.js: satu baris memanggil Tutorial.decorate di akhir render(). index.html: tag tutorial.css dan tutorial.js (sebelum menu.js).
- docs/ENGINE_NOTES.md: catatan alur dan kait baru.
Kotak lipat "Bantuan & aksesibilitas" disisipkan ke Pengaturan lewat JS (pilihan tersimpan di localStorage, tiap pilihan punya Atur ulang, plus Atur ulang semua).
Bantuan (hanya sisi pemain): Kombo otomatis (satu ketukan Spasi = rantai 3 pukulan), Blok otomatis (serangan dari depan ditahan lewat jalur blok biasa),
Tanpa cooldown (skill dan jurus toko tanpa cooldown, ultimate siap paling lama 5 dtk), Pemulihan darah pelan (+2 HP/dtk).
Aksesibilitas: ukuran teks Normal/Besar/Sangat besar (variabel CSS), mode buta warna protanopia/deuteranopia/tritanopia (filter SVG pada arena dan HUD,
bar HP lawan bergaris dan lapisan cadangan bertitik), Kurangi gerakan (otomatis mengikuti prefers-reduced-motion atau dipaksa; pengali Access.motion
untuk getaran layar, zoom K.O., kilat, dan animasi latar), Kontras tinggi untuk HUD.
Kait kecil di game.js, feel.js, dan vs.js memakai window.Access secara malas (tanpa modul semuanya no-op); catatan mesin diperbarui.
Mode ringan: diuji node --check dan smoke (tanpa galat halaman); keadaan pilihan aktif dan tampilan belum diuji, pengguna menguji manual.
- stats.js (window.MatchStats): statistik pemain 1 per pertandingan versus (juga 2 pemain, Arcade, Survival, Bayangan; latihan tidak): damage keluar/diterima (selisih HP per langkah), kombo terpanjang, counter hit, parry, blok, lempar, akurasi serangan dasar/skill 1/skill 2/ultimate (jurus dihitung mengenai sekali per pemakaian), ronde dan durasi (jumlah waktu fase fight, waktu simulasi tanpa Date.now)
- game.js: kait satu baris di startMatch/reset (reset), advanceMatch (tick), cast/startAttack (cast), hitDummy/dotDamage (hit lewat hitSource), heroGuard (parry/block), event 'complete' (finish -> info.stats)
- vs.js + stats.css: tombol STATISTIK di kepala layar hasil membuka kartu 4x3 di atas tombol aksi (digulir sendiri bila ruang kurang, Esc menutup), muat di 520 px dan ponsel lanskap; tanpa info.stats tidak ada tombol
- meta.js: award memanggil commit ke Meta.save.stats (kunci baru dmgDealt, dmgTaken, parries, blocks, throws, counters, rounds, playSec, statMatches; simpanan lama terbaca 0; bestCombo ikut naik ke kombo terbaik seluruh ronde); tab Koleksi menampilkan ringkasan seumur hidup
- index.html: dua tag baru di baris sendiri; catatan mesin diperbarui. Mode ringan: node --check dan smoke lulus, tampilan dan angka diuji manual oleh pemilik
4.6: touchlayout.js dan touchlayout.css. Di layar sentuh, Pengaturan mendapat baris "Tata letak tombol" (ATUR) yang membuka editor layar penuh: pad arah, tombol aksi, dan panel tambahan bisa diseret dan diubah ukurannya dengan pegangan sudut (papan ketik: panah dan + -). Simpanan di localStorage (konoha.touchlayout.v1), posisi dijepit ke dalam layar, ada ATUR ULANG dan BATAL. Editor memakai salinan visual di dialog modal sehingga tombol asli tidak mengirim input; touch.js tidak diubah, kontrol asli hanya mendapat kelas dan variabel CSS.
4.7: manifest.webmanifest (fullscreen dengan cadangan standalone, landscape, ikon any dan maskable 192/512 di assets/pwa dibuat tools/make_pwa_icons.py dari potret yang sudah ada), tautan manifest, ikon, dan apple-touch-icon di index.html dan mobile.html. pwa.js menangkap beforeinstallprompt dan menampilkan "Pasang aplikasi" di Pengaturan hanya bila tersedia (di HP melalui window.parent.KonohaPWA karena event datang ke mobile.html). sw.js menambah halaman cadangan offline.html di cache kecil terpisah; perilaku cache lama tetap.
tools/build_precache.py kini memuat manifest.webmanifest dan assets/pwa. .htaccess dan DEPLOY.md: MIME manifest. Catatan di ENGINE_NOTES dan README. precache.js dan files.json belum dibangun ulang.
Konflik index.html dan meta.js diselesaikan dengan mempertahankan kedua sisi: mystery.css dimuat sesudah story.css, content/mystery.js dan mystery.js dimuat di antara touch.js dan menu.js seperti di cabangnya, dan daftar pencapaian tersembunyi di Koleksi memuat penasaran_berat sekaligus reuni.
Konflik game.js di startMatch diselesaikan dengan mempertahankan kedua sisi: refreshPassives(matchStyles(...)) dari pasif dijalankan dulu, lalu setShadowFoe(...), dan info layar VS membawa styles sekaligus shadow. Urutan pengali di dotDamage dan receiveHit: pengali pasif dulu, lalu +10% Bayangan.
Konflik index.html, meta.js, vs.js diselesaikan dengan mempertahankan kedua sisi: urutan skrip content/passives.js, passives.js, content/quotes.js, content/dialogs.js sebelum vs.js; Meta mengekspor styleOf, setStyle, dan pairEgg; VS.show memanggil Passives.decorateVS lalu memakai durasi dur milik dialog.
- content/mystery.js: 5 slot dengan 3-4 petunjuk tiap slot (19 total); syarat dibaca dari Meta.save (menang, Survival, Arcade tamat, kombo, menang bersih, pencapaian, kejutan, dialog rahasia, barang toko). Teks samar dan lucu tanpa nama tokoh nyata.
- mystery.js dan mystery.css: siluet SVG sebaris dari bentuk locked.svg yang makin tajam tiap petunjuk terbuka, benda khas muncul di dua tahap terakhir, tanda tanya berubah, lencana n/total, titik BARU dan toast. Panel pratinjau memuat petunjuk terbuka, syarat petunjuk berikutnya dengan bilah progres, dan nomor slot.
- menu.js: empat pengait kecil (panel, dekorasi petak, pratinjau teks bawah roster, pesan saat ditekan). Slot tetap tidak bisa dipilih dan tetap data-fighter locked-N sehingga easter egg penasaran tetap jalan.
- meta.js: pencapaian tersembunyi PENASARAN BERAT bila semua petunjuk terbuka.
- ?mystery=N atau all di URL mempratinjau tahap tanpa menyimpan apa pun. Catatan mesin dan README diperbarui. Mode ringan: tanpa berkas uji baru, diuji manual oleh pemilik.