Imported from rushairer/NeonWings-Pan (
AGENTS.md). Install upstream withnpx skills add rushairer/NeonWings-Pan. Copyright stays with the author.
NeonWings-Pan contributor and agent guide
- NeonWings-Pan is fully independent from rushairer/NeonWings at commit 5ebcb1de1adb288b41a3c5e387f747bc49271c19. Never auto-sync or write to the source repository.
- Use neon_wings_pan_ localStorage keys to avoid clashes across GitHub Pages paths.
- Fact source is this repository's current
main. Read this file and ROADMAP.md before changes. - Target: handheld-first arcade shoot-'em-up for AYANEO AIR MINI, with web keyboard fallback.
- Keep the logical game field at 1280 × 960 (4:3); use letterboxing rather than nonlinear viewport stretching.
- Preserve all five stages, boss transitions, the two original fighters, weapon drops, bomb rewards and multiple loops unless explicitly changing gameplay.
- Whenever browser-loaded JS changes, ensure the appropriate script URLs in index.html have a fresh version query matching package.json; test script URL versions in tests/platform.test.cjs. A green Pages deployment does not guarantee an existing browser refreshed its old cached scripts.
- Gamepad defaults: B and RT fire, A bombs, Y triggers Overdrive, Start pauses/resumes, Select toggles fullscreen. Remapping is limited to fire/bomb/Overdrive combat actions; physical B confirms menus, and Start/Select are never remapped.
- Backgrounding or focus loss must not advance gameplay or force unexpected resume; avoid stuck firing inputs.
- Do not make Web Audio or vibration mandatory; unsupported browser APIs must degrade gracefully.
- Prefer dependency-free static delivery while the v23 foundation is being stabilized; new build dependencies require a documented rationale.
- Keep game content and platform helpers separate. Do not mix UI/canvas resize calculations with combat simulation logic.
- The 1280x960 fighter/mode selector layout is defined in
src/select-layout.js; use it fromdrawSelectScreen()rather than hardcoding vertical positions. Protect at least 40 logical px between the mode frame and either selected ship highlight, plus separate Training hint, fighter captions, detail card and score footer. Update geometry tests if the design changes. - White P conductive piercing rules belong in
src/white-weapon.js: every direct hit guarantees a 360-radius first electricity wave via GREEN geometry. Per-direct-hit independent RNG unlocks a second wave at 50%, then a third at 10% conditional on the second (5% unconditional); strict max three hops. Each wave uses targets reached in the preceding wave as new origins, and each secondary hit ALWAYS deals 60% of original direct-shot power (never drops per hop). One projectile has a shared victim ledger for direct/piercing/electric hits, preventing repeated enemy/Boss damage. Keep original shield, Boss part and score rules; white-blue arcs are visual only, capped at 96. Tests must fix random rolls and assert no fourth propagation or nondeterministic failure. - BROWN P LOCK LASER rules belong in
src/brown-weapon.js: the eleventh P color emits ZERO projectile bullets when equipped, but holding FIRE continuously ray-locks the nearest viable forward enemy, living Boss turret or Boss hull. Resolve actual first obstruction along the aimed segment; never pierce rear targets. Tick 1.15 normal damage per 0.101 combat seconds to ONLY the contact target, via existing shield/Boss weakpoint/Overdrive pipelines. Beam is cosmetic and damage must never be computed in drawing; release FIRE, swap weapon, target disappearance, pause and transitions stop advancing or clear locks. Maximum 1300 logical-unit forward range. Prevent accidental bullet spawning through the usual firePlayerWeapons path, and protect with deterministic obstruction/laser and Boss tests. - LIME P ORBIT rules belong in
src/lime-weapon.js: the twelfth P color must fire two ordinary starter-grade bullets at the player's muzzle (x + 62; y - 10 and + 12) on every firing action, never teleport diamond satellites to a prepopulated ring. Initial vx = 1100 and r = 9, damage = 1.15 normally; draw via the SAME rectangular bullet-sprite path as regular BLUE, but retain a lime-colored core. Only their flight trajectory is special: ease the distance from the moving player from initial muzzle radius onto a radius-360 orbit over 0.48 active seconds, clockwise (screen y-down) at 2.8 rad/s. Interpolate player movement in swept arc segments so there are no discontinuities or phantom early 360-ring hits; once at the rim, maintain an exact radius 360 about the moving player. Each normal bullet does starter-grade 1.15 direct damage with ordinary fighter/Overdrive scaling, collides via sub-segmented outward-and-circular arcs with exactly one enemy/Boss contact before removal, lives 3.2 active combat seconds and has NO hard projectile quantity limit. LIME orbiters are exempt from the ordinary player bullet quota and are never deleted to make room for later shots; ONLY TTL expiration, normal one-hit collision and run reset reclaim orbs. Normal bullets keep their bounded separate quota. Cover sustained held-FIRE and >360 generated LIME shots with regression tests; avoid artificial fixed counts. The last still-live arc must be collision-tested even if shot TTL expires on the same update. Offscreen arc phases must not prematurely despawn; the faint ring guide is cosmetic without GREEN-type passive damage. Already fired orbs remain tied to player position after switching P, subject to their existing TTL. Protect status, pause, Boss parts, shields, render performance and 14-color P drop ratios with tests. - ORANGE P on-hit blast rules belong in
src/orange-weapon.js: ORANGE is the tenth P pickup, with two starter-grade orange bullets each firing action (ordinary 1.15 damage power and base cadence, regardless of weapon level). Each shot explodes ONCE on its FIRST swept enemy or Boss/turret collision. The explosion center is the earliest swept contact, with radius 100 logical units including enemy circles and Boss hull AABB; each target, including the direct target, takes precisely 3× original bullet power, not 1×+3×. Preserve shields and Boss weak-point turret priority; a non-direct Boss in the AoE gets a single hull hit. Snapshot targets before applying initial blast damage so splitter children and newly spawned Bosses cannot be damaged on the same impact. No chaining or multi-hit of the same target from one shot. Draw orange FX for 0.35 combat seconds at full 100 radius, capped to 48 live effects; rendering never deals damage. Preserve all other P weapon semantics and protect with unit/integration tests. - PINK P homing/burst/proc rules belong in
src/pink-weapon.js: the ninth collectible fires exactly ONE visibly pink tracking bullet per firing action with base damage 1.15 at any weapon level, lifetime bounded at 3.6s. After every TWO actions rest for 0.4s; a separate 15% chance per action fires one BONUS missile homing through the existing bounded missile system at precisely 25× the normal pink bullet damage (28.75 pre-scaling; ratio remains 25× under Overdrive/ship scaling). PINK special missile has a black 100 × 100 game-unit silhouette and radius-50 hitbox; YELLOW missiles keep radius 14. On its single direct collision, draw a pink 360-radius explosion (using GREEN P's rule), and apply exactly 1× ordinary PINK bullet damage to each OTHER nearby living enemy or a nearby non-direct Boss hull. Direct target receives 25× only, never extra AoE. The adjacent explosion remains exactly 1× because splashDamage divides by the current special multiplier; never inherit 25× secondary damage. Snapshot enemy and Boss targets before direct damage so splitter children/new Boss cannot be AoE hit on that same missile. Keep splash nonrecursive and preserve shield/turret rules. Cap pink blast visuals at 12 instances, TTL 0.55 seconds, freeze on pause; drawing must never inflict damage. Never count impacts as firing actions; switching weapons resets the pink volley streak but never disables launched guided projectiles or existing RED stars/GRAY counters. Tracking acquires a viable enemy/Boss each active simulation step, uses swept collision/weakpoints/shields and keeps velocity when no target. Preserve missile cap, other weapon rules, and regression tests. - SKY P health-adaptive rules belong in
src/sky-weapon.js: game.hp (not game.player.hp) is the sole authoritative current health in hearts. >3 hearts emits two starter-grade light-blue 2.5× power bullets; <=3 (including 3) emits two normal-strength guided shots with original BLACK's 5-second/50% slow-on-hit marker and SAME existing blue slow-glow visual on enemies and Bosses, not separate slow logic/FX. Snapshot fire mode into each bullet at emission; already-fired shots do not switch modes after HP changes. Low-HP shots seek nearest living enemy/Boss, expire in 3.6s, and continue after weapon swaps. Include SKY in 14-color drops, script order/build, cache versions, HUD, and tests. The firing cadence remains starter-grade regardless of generic weapon level. - GRAY P control rules belong in
src/gray-weapon.js: on each tagged projectile's real collision, exactly one outcome: 20% push enemy away in bullet direction by 100 game coordinates; next 5% stun for 0.5 real active-combat seconds; remaining 75% multiply the same projectile's damage by 1.5 with NO control effects. Knockback and stun retain the base 1.0× damage. Apply multiplier through existing enemy frontal shields and Boss hull/turret weak-point damage, never to unrelated weapons; unit tests must lock both probability boundaries and mutual exclusivity. Apply to shield hits and Boss hull/turret contacts. The Boss arena clamps knockback and updates the anchor to prevent scripted snap-back. All enemy movement (including scripted zigzag) and attacks, carrier escort production, Boss movement/telegraphs and ready shots MUST freeze while stunned. Repeated stuns refresh 0.5 seconds, BLACK slow ages simultaneously without double time discount; no timer ages during pause/transition. Knock/stun effects already inflicted survive player weapon changes. The 0.5s stun render must show a golden progress ellipse, three rotating stars and STUN text for any stunned enemy/Boss, cosmetically only with no extra damage/status mutation. GRAY volley scheduling belongs insrc/gray-weapon.js: a two-bullet firing action is ONE volley; after every five volleys rest 0.4 seconds, then start a new streak. Never count bullet collisions or individual projectiles. The gray streak is independent of RED stars and is reset when switching to another weapon color, but not when collecting GRAY again. - Black P slowdown rules belong in
src/black-weapon.js: only black-tagged player bullet hits apply a 5-second target debuff halving both movement progress and attack frequency. Apply to standard enemies and Bosses, including shield/turret hits; refresh 5s on repeated hits, no stacking, and do not modify already-launched enemy bullets. Freeze during pause/transitions and let statuses expire after switching to other weapons. While active, draw blue glow as visuals only, without extra damage or particles. Protect all weapon colors and Boss state machines with tests. - Green P timing/hit geometry belongs in
src/green-weapon.js: passive glowing radius-360 ring, exactly 2 HP per global 0.4-second pulse for each intersecting enemy or Boss hull during active combat (5 HP/s per target), no requirement to hold fire. The global pulse clock starts from equipping green and advances without targets; enemy contact/entry/exit must never start or reset it. Ordinary shots must exactly match blue Lv.1 starting bullets and cadence regardless of overall weapon level, without blue-only upgrades/Overdrive lance. Use normal damage pipelines; freeze across pause/transitions, reset timer on weapon switch, and protect RED stars/other weapons against regressions. - RAINBOW P PRISM probability rules belong in
src/rainbow-weapon.js, a FIFTEENTH collectible P colorP_RAINBOW/rainbow. Each firing action emits exactly ONE starter-grade projectile or ONE replacement PINK missile from the centered muzzle, then waits 0.4 active-combat seconds before another emission irrespective of weapon level; make exactly ONE random roll per action among eight mutually exclusive outcomes:homing13% (YELLOW-inspired target-seeking bullet, not extra missile),slow13% (BLACK marker+visual),missile9% (REPLACE bullet with PINK's exact 100-unit BLACK tracking special rocket, 25x direct + 360-range 1x OTHER-target explosion),chain13% (DARK RED 50%-per-extra-hit, at most 30 full original-power hits),gray13% (GRAY per-hit 20/5/75 RNG),conductive13% (WHITE through-target penetration AND 60%-power multi-hop conductivity, not an invented white missile),orbit13% (LIME real muzzle shot, radius-360 curving orbit), andblast13% (ORANGE radius-100 3x explosion). 7*13+9 MUST total 100, boundaries are lower-inclusive, upper-exclusive (9% missile covers [0.26,0.35)); no second hidden proc from DARK RED, PINK or YELLOW when RAINBOW chooses a bullet. Reuse EXISTING contact callbacks/status/piercing/missile/shape implementations, never approximate their semantics or trigger random on every frame. RAINBOW missile is PINK-special 25x, not DARK RED's 10x; its splash remains 1x. Other established P drops/normal bullets, star UI and projectile budgets are unaffected; orbiters remain naturally TTL-bound but no count cap. Preserve per-projectile tags across weapon swaps. Keep RAINBOW in the 15-color uniform P pool, versioned browser JS and static build, and cover all eight tags, probability edge cases, Boss/shields and renderer in unit/integration tests. - DARK RED P CHAIN belongs in
src/dark-red-weapon.js, a FOURTEENTH P colorP_DARK_RED/darkred, distinct from ordinary RED P. Fire two starter-grade straight 1.15-damage projectiles per firing action at the baseline rate. The FIRST actual enemy/Boss/turret hit deals normal FULL 100%-strength damage, and each subsequent hit on that SAME victim needs a NEW independent Math.random()<0.50 roll. Hard maximum THIRTY TOTAL complete 100%-strength damage events (29 extras), including when the impact came from a DARK RED guided rocket. Once the original victim dies or a Boss turret breaks/Boss dies, never continue, transfer to a neighbor/splitter child or through turret into hull; never roll beyond cap or after victim death. Run EVERY event via existing damageEnemy/damageBoss so shield absorption, score, 2.35× Boss weak-point damage, one-time 6.5% turret-break hull penalty and fighter/Overdrive scaling remain standard. Every TWO-bullet DARK RED firing action independently rolls a 5% chance to add ONE BONUS homing rocket (not per projectile/contact/chain hit). That special shares PINK's 100-game-unit rocket silhouette, radius-50 swept collision, homing/retarget and 360-radius impact explosion, but uses DARK RED rocket body/fins/trail/blast colors. Its direct impact always deals 1000% = 10× ordinary DARK RED bullet strength PER chained direct hit (11.5 unscaled). Explosion to OTHER nearby pre-existing targets is still only ONE ordinary 1× bullet hit, NO repeated chain, excluding the already-hit victim and any newly split children. Preserve PINK 15%/25× rules and YELLOW 14-radius rockets. Shared missile capacity remains 48 and dark-red blasts share the bounded PINK visual explosion pool; combat effects must NEVER occur inside render. Weapon swaps never erase already launched darkRedChain bullets/rockets. RED stars/fan remain independent; RED HUD and star messages appear ONLY when ordinary RED equipped. Test RNG <0.5 versus ==0.5, missile <0.05 versus ==0.05, exactly 30 hits/29 rolls, dead victims, turret-break, missiles, shields, Boss and 14 drop slots. Version/browser-copy the standalone runtime. - Red P special/timing/star rules belong in
src/red-weapon.js: two normal parallel lines, 0.4s rest after 5 + stars volleys, 10% chance per ordinary volley (no overlap), exactly 250 shots within ±10° over 3s of active combat, star gained only on completion (max 5). Keep red stars across weapon swaps, subtract only for HP-damaging hits, never change other weapon cadence. RED star HUD and STAR UP/MAX STARS message visibility is permitted ONLY if game.weaponType === 'red'; a fan that completes after swapping away still grants stars silently and the saved stars reappear when RED is re-equipped. Protect these invariants with unit and browser integration tests. - Keep scoring, graze detection, hit penalties, active timers and fighter Overdrive rules in
src/combat.js. Do not grant more than one graze per enemy bullet or charge/combo rewards from Bomb kills; stage transitions and pause must not consume active time. - One Overdrive input maps to one physical button distinct from primary/secondary fire and Bomb; respect older persisted settings and preserve Start/Select/B menu actions.
- Boss targetable weapon modules belong in
src/boss-parts.js: route bullet/missile swept hits to surviving mounts before the Boss hull; part-break rewards are one-shot; turret destruction must change actual attack cadence. - Ranked local top-five records, grades and achievement definitions belong in
src/records.js. Keep Classic and Boss Rush history separate, Training unranked (no badge farming), and protect play from corrupt/disabled localStorage. Only finalize a ranked run once at Game Over or Boss Rush clear; first Classic clear can unlock its milestone without duplicating leaderboard entries. - Arcade mode definitions and post-Boss routing belong in
src/modes.js. Keep Classic default, original endless-loop semantics and Classic high-score key unchanged. Boss Rush must never enter regular enemy waves; Training must remain unranked and allow repeated stage practice, with distinct configurable starting equipment. - After the first five-stage clear, show a non-timed ENDING state with saved high score. Continue to Loop 2 explicitly; do not regress the infinite loop progression.
- Stage hazards and procedural parallax belong in
src/worlds.js: warn before damage; use the existing HP/invulnerability path; freeze outside active play; reset per stage; avoid external assets and unbounded particles. - Enemy special mechanics belong in
src/enemy-behaviors.js. Shield absorption precedes hull damage; splitter/carrier children have spawn caps and cannot increase wave kills, combo, Overdrive energy or loot. Keep Stage 1 formations within Stage 1 enemy roster. - Collisions use
src/collision.jsswept segments for fast projectiles. Check all damaging bullet contacts before awarding any graze for that frame; rendering FX and projectile arrays have explicit per-type budgets. Do not claim FPS compliance from unit tests alone. - Before shipping, run
npm run check,npm test,npm run build. Do not equate passing unit tests with actual AYANEO hardware validation. - Store configuration locally without secret keys; gracefully handle storage denial and corrupted data.
- Update README/ROADMAP for user-visible changes. Use small, scoped commits to main and never force-push.
