SNKRX-3D 1
Fable 5 xhigh
Summary
Feasibility probe for a "SNKRX look in real 3D" prototype: a new 3D-exploration/SNKRX-3D/ project was created, a 10k-enemy look spike was built and locked (slab shape + soft shading), and Phase 0 of a faithful port of 062026's Swordsman slice (arena, seekers, player, contact damage, shield) was implemented, calibrated against the real Box2D math, and approved. Owner's closing verdict: "I only wanted to know if this was feasible and it was." Project pauses here; phases 1-5 (Cleave / Leap Slam / Surge / Blade Dance / HUD B) are fully specced in the design brief below, and the planned Opus 5 Blender terrain/props track was never spawned.
Direction discussion (lots-of-enemies, high camera):
- Owner pitched a new 3D-exploration direction off five reference images: hordes of enemies, very high camera, tiny controlled character — citing Sir, We Have an Orc Problem (Mumpitz Games, 89% Very Positive, 100k wishlists) and a "100,000+ enemies turn into a fluid" dev clip.
- Feasibility analysis: the 3D-exploration engine's layer3 path is already instanced (custom-mesh batches grow on demand; only built-in primitives cap at 4096/frame), so rendering was never the bottleneck — per-entity Lua work was. Estimated Lua ceiling ~10-20k SoA; 100k would need a C swarm + bulk submit binding.
- Owner capped scope: "we absolutely do not need 100k enemies. The very high cap at 10k is more than enough" — pure Lua viable, no engine changes.
- Owner's priority: "test and iterate on the look first before anything else, it has to look like the 2D SNKRX/Orblike/etc SNKRX-template examples we've built this year."
Look spike (SNKRX-3D project creation):
- New folder per the experiments-survive rule: main.lua / swarm.lua / mesh_gen.lua / palette.lua + anchor/ copy from Chibi + monogram.ttf + run.bat.
- Enemy = procedurally generated rounded-slab custom mesh mirroring the 2D seeker (14x6, corner r=3, extruded, no bottom face), instanced via layer3_mesh.
- The SNKRX breathe translated CPU-side: 33-step packed-color LUT between palette breathe partners (red<->orange enemies, snkrx_blue<->light_blue player), indexed per entity per frame — per-pixel vs per-entity indistinguishable at 10-45 px on screen.
- SoA sim: seek + wander + separation on a dense-array grid with padding ring (no hash lookups), cell = separation radius, separation staggered every-other-frame per enemy with cached force. Perf: 28.8 -> 12.5 -> 8.8 ms at 10k headless (2500: 1.5 ms).
- Look toggles: L unlit/soft/cel, K slab/box/blob, C camera pitch presets, B breathe, counts 1-5. Owner locked: slab + soft (ambient 0.72, wrap 1).
Pivot to the 062026 Swordsman port:
- Owner: make it look like 062026, copy the Swordsman kit, "everything should be exactly the same, as close as possible, except in 3D"; add little hills + 3D props via Opus 5 doing Blender work; "Run it yourself, take screenshots."
- Research: full read of 062026 player.lua Swordsman methods (cleave / start_leap_slam / update_leap_slam / leap_land / blade dance trio / surge / update_walk / hit / draw / on_shield_break / refresh_cooldowns), main.lua tunables (SWORDSMAN/CLEAVE/LEAP/SURGE/BLADE_DANCE/SHIELD blocks), an Explore-agent extraction of area.lua rect lifecycle (0.05s X-only open tween, damage at t=0.05 full-size, 0.15s white flash, 7-blink death, alpha-20 fill, unconditional corner brackets at min(w,h)*0.1), seeker.lua (steering calls, push impl, hit/die/spawn FX numbers, HP bar geometry), fx.lua (hit_circle shrink-only, particle velocity->width remap unclamped, rotating particles, trail system in flicker.lua with dash 5/6 + 50%-hold fade, fx_status_text 'using' mode, fx_refresh wipe).
- Key discoveries: 062026 is a SINGLE fixed 480x270 screen with BW=6 edge walls and a static camera; swordsman_spec = linear_gradient snkrx_yellow->yellow (scale 0.35, param 0.25, offset 0.427); enemy breathe is a WORLD-SPACE organic field (spatial color bands).
Desktop control corrected + the video workflow:
- Launched 062026 windowed + computer-use for reference screenshots; owner interrupted: "Let me take screenshots instead, this gets in the way of my other tasks." Saved as standing feedback (no desktop control mid-session).
- Owner recorded E:/media/anchor_gO6RkAu3Zh.mp4 (1440x810@60, 37.7s) — "it contains everything the game does visually." Frame survey via ffmpeg contact sheets (2 fps, timestamped tiles) identified Cleave squares, SURGE word + trail, Leap X telegraph + airborne grow, Blade Dance multi-square burst, death splats, HUD B.
- Found the engine's own capture path for my eyes going forward: --render mode / engine_render_setup(dir) + engine_render_save_frame() -> PNGs at game resolution (used as the --shots scripted capture mode).
Phase 0 design brief (agreed) and build:
- Scale 0.05 m/px; arena 24x13.5 m; fixed camera framing the arena with the vista zone visible past the far wall (Opus terrain's future home); all 2D FX as world-space ground geometry (foreshortens correctly) except text/bars as a projected 2D overlay; real Y for the Leap (accepted default); systems ported verbatim (shield.lua verbatim; stats/buff deferred to Phase 3).
- Built: fx.lua (hit circles as flat disc mesh, particles as flat rounded quads with spin/zag, hard change_color swaps at 062026's 0.6/0.3/0.5 fractions), player.lua (walk feel with pi visual spins + squash + stop spring, mouse aim via layer3_unproject ground ray, shield-first hit with mixed-color contact puffs, break drama minus sparks sheet + refresh wipe), swarm rework (hp/springs/push/flash/wall-bump streak/contact latch in SoA), gradient texture on a UV'd player mesh (flash = untextured twin), Lua-side world->screen projection for HP/shield bars, hit_stop wiring via engine_set_time_scale, --verify + --shots modes.
- Iterated via captures: fixed framing (near wall in frame, pivot_z south bias), confirmed palette fidelity by pixel-sampling the PNG (walls charcoal-lit 44/47/50; player gradient mid-body 238/173/38).
- Contact model bug found by verify: soft separation let pressed enemies sink into the player and the latch never re-armed (1 contact total). Fix: positional ring resolution at the contact radius (Box2D-solidity stand-in) + hysteresis reachable by the knockback cycle.
Physics recalibration (owner: "Your calculation on enemy speed and hit reactions and so on is off"):
- Root cause: I had derived kinematic stand-ins analytically instead of replicating. Read the real engine bindings: Anchor2 Box2D runs at pixels_per_meter=64, converts forces/impulses/velocities at the binding; seeker 14x6 box @ density 1 = 0.0205 kg. Therefore accel = force48.76 px/s^2 (~9760 px/s^2 at the 200 cap = velocity converges ~81% PER FRAME — near-instant; my budget was 24x too sluggish) and knockback dv = impulse48.76 px/s (force 6 = 293 px/s fling; mine was 3.3x too weak).
- Also found: steering_wander args are (distance=64, radius=32, jitter=16) — I had distance/radius swapped; steering_separate is a direction-only average of normalized away-vectors; the per-frame pipeline is steer(each capped 200, sum capped 200) -> PRE-step speed clamp -> integrate + damping(3 free / 6 pushed) -> move, with pushes skipping steering AND clamp.
- Box2D crowds are solid: added an enemy-enemy positional pair-packing pass at 10 px.
- Refactored ALL gameplay to native 062026 px units (arena 480x270 centered; only draw calls multiply by PX=0.05) so future ability constants port verbatim.
- Camera feedback "top is a bit too angled still": top preset 78 -> 86 degrees (near-straight-down, fits the whole arena — visually the 2D frame), per-preset pivot_z.
- Verify contacts went 2 -> 9 in the same scenario; flagged to owner that the liked shield-break knockback is now 3.3x stronger (the faithful value).
Shield-break crash fix (swarm.lua:419 "compare number with nil"):
- The solid-packing pass computes grid-cell keys from positions it is itself mutating; a shield break flings the pressed ring (~487 px/s) and pair displacements near a wall can put a position more than one cell (16 px) outside bounds mid-pass -> cell key walks off the dense grid's padding ring -> head[key] = nil ->
j > icompares nil. - Fix: cell keys from bounds-clamped coords + displaced neighbors clamped immediately. Added the exact reproducer to --verify (player teleported to a wall at frame 500, forced re-break at 560 with the ring pressed). Clean.
State at close: Phase 0 done and approved as a feasibility answer. If resumed: phases 1-5 per the brief; spawn Opus 5 for Blender terrain (gentle hills in-arena, vista beyond walls) + palette-tinted props via mesh3_load_obj; memory topic project_snkrx_3d.md carries the full spec pointers.
🔒 Only the summary of this log is public. Private because it's related to SNKRX.