Commit Graph

114 Commits (aed600abd2a4809e126ff23315081bc0356cd6bc)

Author SHA1 Message Date
VinPropane 90a17bc43d NEO-22: Extract WASD locomotion for gdlint max-file-lines
Move the WASD physics tick into player_locomotion_wasd.gd so player.gd
stays under the 1600-line CI cap. Fix gdlint class order (enum before
consts), load-constant naming, and wrap long doc lines. Update NEO-22
review and plan; refresh gdlintrc comment.
2026-04-17 20:13:36 -04:00
VinPropane 76ff2cddac NEO-22: clear idle anchor during WASD so stop does not snap back
Stable idle latches _idle_anchor_active and _hold_idle_anchor clamps XZ each
tick. Locomotion bypasses that branch, so the anchor stayed at the pre-walk
position while the capsule moved; releasing keys ran idle again and
_hold_idle_anchor teleported to the stale anchor.
2026-04-17 19:37:58 -04:00
VinPropane a2c6c9f93e NEO-22: add move-stream API and WASD client locomotion
Introduce POST /game/players/{id}/move-stream with ordered targets, full-chain
validation before apply, and PositionStateResponse. Godot client uses camera-
relative WASD, queues samples, and snaps to stream responses; debug builds keep
click-to-move via ground_pick. Update READMEs, E1.M1 snapshot, and tests.
2026-04-17 19:21:33 -04:00
VinPropane 9bdd928c80 NEON-29: Fix gdlint (player returns/lines, split idle tests, gdlintrc cap) 2026-04-15 23:48:15 -04:00
VinPropane 2b72d6bcb9 NEON-29: Prototype smooth hill piece, movement script updates, NEO-22 plan
Add prototype_smooth_hill_piece for QA geometry alongside main scene wiring.
Refresh player locomotion and main scene integration from stashed work.
Track docs/plans/NEO-22-implementation-plan.md (WASD replaces click-to-move).
2026-04-15 23:39:47 -04:00
VinPropane a7ad695143 NEON-29: Apply stashed WIP (main.tscn, movement validation, docs) 2026-04-13 13:24:05 -04:00
VinPropane 4a51e64f25 Merge branch 'main' into NEON-29-expand-prototype-district 2026-04-13 13:22:51 -04:00
VinPropane 7e17ff563b chore: point docs and rules at Linear NEO issue ids
Migrate Jira NEON-* references to Linear NEO-* and linear.app links in
docs, Cursor rules, READMEs, and traceability comments. Renamed
implementation plans and dated reviews to NEO filenames.

Branch is based on origin/main with this commit only (no NEON-29
gameplay chain). client/README follows main’s district/map copy;
player.gd matches main aside from NEO-14 debug trace prefixes.
2026-04-13 13:15:32 -04:00
VinPropane 2333d29ece NEON-29: End column stair ghost-walk (arrive + stuck release).
Traces showed has_goal=true, vlat&&ncol, MOVE_SPEED XZ flipping while
stable=false: vert_err ~0.31 stayed above VERT_ARRIVE_EPS so arrival never
cleared the goal — not idle jitter.

Run vertical-route latch before arrival; when on floor with vlat&&ncol,
allow vert_err up to WALK_COLUMN_NEAR_ARRIVE_VERT (0.36 m) if horiz_dist
<= ARRIVE_EPS. Backup: clear_nav_goal after WALK_COLUMN_STUCK_FRAMES with
net drift < WALK_COLUMN_STUCK_MAX_DRIFT in the same regime.
2026-04-12 19:57:54 -04:00
VinPropane 50a8b609be NEON-29: Latch stable idle on ridged stair treads (idle jitter).
Idle jitter was not walk/peel: without has_goal, stable idle required
floor_normal·up >= 0.998. Tread+riser contacts often report ~0.996–0.997,
so stable idle never latched and rim settle nudge + idle move_and_slide
ran every tick. Use STABLE_IDLE_FLOOR_HOLD_MIN_UP_DOT (0.992) for the
floor-flat check when slide contacts are ridged and we are still using the
strict entry threshold.
2026-04-12 19:49:19 -04:00
VinPropane db7973d368 NEON-29: Tie tread XZ freeze to peel suspend + vert arrival band.
Replace vlat/ncol + tight vert_sep window (often missed or band-flickered) with:
peel suspend, horiz_dist <= 0.38 m, VERT_ARRIVE_EPS < verr <= 0.18 m, goal
not above feet. Aligns freeze with tread snap/peel regime; caps XZ against
5 m peel-suspend fallback.
2026-04-12 19:44:53 -04:00
VinPropane ea3903d8ab NEON-29: Freeze horizontal velocity on column tread wobble band.
When vlat&&ncol, XZ within ~0.92*ARRIVE_EPS, and vert_sep in a narrow band
above vertical-arrival noise, zero XZ velocity so nav slide cannot drive ~6 cm
Y oscillation on violet stairs. Descending fallback when column latch is off;
skip when goal is above feet (climb still needs XZ).
2026-04-12 19:41:39 -04:00
VinPropane ec903d9c11 NEON-29: Drop tread speed cap; widen stair continuation probe.
Remove WALK_TREAD_STABILITY horiz cap (it ran for whole vlat&&ncol band and
made the last steps sluggish without fixing jitter).

Raise WALK_CONTINUATION_MAX_BELOW_FEET 0.078→0.108 m so ~0.104 m tread drops
count as walk continuation; probe/debounced peel+snap stop flipping each tick.
Kept below ~0.25 m so ~0.3 m gold→floor void still rejects the slab.

Revert NAV_PATH_STEER_MIN_LOOKAHEAD to 0.22 m.
2026-04-12 19:15:27 -04:00
VinPropane 4a08ede736 NEON-29: Rename h_scale to avoid shadowing Node3D.scale. 2026-04-12 19:12:52 -04:00
VinPropane 50bb615763 NEON-29: Cap walk speed on tread stability band for stair jitter.
Steering reverse clamp was reverted (blocked arrival). Instead, when on floor
and (vlat && ncol && vert_sep band) or tight XZ + small vert_sep, clamp
horizontal speed to 1.35 m/s so move_and_slide does not drive riser ping-pong
at full MOVE_SPEED. Bump path steer min lookahead 0.22→0.28 m.
2026-04-12 19:12:43 -04:00
VinPropane bf968b1817 NEON-29: Revert steering reverse clamp (blocked arrival, void fall).
_walk_clamp_steering_reverse kept prior horizontal velocity whenever the new
steer-to-goal direction opposed current motion (dot < -0.35). That prevented
ever closing ARRIVE_EPS in many geometries, so walk never cleared, XZ stayed at
MOVE_SPEED, and air gravity could run indefinitely (y << 0).

Restore direct/path steering without the clamp; NAV_COLUMN_STEER_EXIT_DIST
back to 0.97.
2026-04-12 19:09:51 -04:00
VinPropane bfc70678c4 NEON-29: Reject 180° walk steering flips on stair edges.
Path lookahead vs direct goal could reverse horizontal velocity every physics
tick on treads (NEON-16), driving slide/snap Y jitter. Clamp new steer to
prior bearing when dot < -0.35 and speed is above a small threshold.

Widen NAV_COLUMN_STEER_EXIT_DIST (0.97→1.12) to reduce path/direct mode
chatter when horiz_dist wobbles near the old band.
2026-04-12 19:07:15 -04:00
VinPropane 038505ea3e NEON-29: Gate descend lip snap on debounced ledge peel.
DESCEND_LIP_SNAP_CAP (0.1) ran whenever goal was below feet by geometry,
independent of probe debounce. Feet_y noise on treads toggled 0.32 vs 0.1
snap and caused ~2–3 cm Y jitter. Apply lip cap only when debounced peel is
armed and not in peel suspend; otherwise keep FLOOR_SNAP_MOVING.
2026-04-12 19:03:50 -04:00
VinPropane 73d26a90d7 NEON-29: Debounce floor probe for ledge peel and zero snap.
Continuation rays reject stair treads (~0.104 m) under WALK_CONTINUATION_MAX_BELOW_FEET
(0.078 m), so is_on_floor + probe flickered every tick and toggled peel vs full snap
(Y jitter ~1.0 m). Arm peel/snap aggression only after WALK_PEEL_PROBE_FALSE_FRAMES
consecutive probe failures; deep descent still arms immediately.

Widen horiz peel suspend (0.34→0.46 m vert, 2→5 m XZ) for goal/tread separation gaps.
2026-04-12 19:00:59 -04:00
VinPropane 4e47e9a037 NEON-29: Extend tread peel suspend when vlat unlatches.
Widen vertical-route latch off-sep (0.038→0.085) so descent toward floor
does not drop vlat while feet still wobble on stairs.

Add horiz+vert fallback: suspend peel and restore snap when vert_sep ≤0.34 m
and horiz_dist ≤2 m, covering ncol=false paths where goal Y matches slab
height but tread peel still fought snap (violet stairs ~y=0.92).
2026-04-12 18:55:41 -04:00
VinPropane 26ad33230d NEON-29: Suspend ledge peel on column treads to stop idle jitter.
When vertical route is latched and nav column steering is active, peel
plus zero floor snap caused a 3-frame limit cycle (NEON-16 traces).
Skip peel and restore normal snap while feet are within 0.48 m of the
goal surface vertically.
2026-04-12 18:51:07 -04:00
VinPropane 33b6db979e NEON-29: Stair descent — tighter continuation probe + stronger vertical accel
Lower WALK_CONTINUATION_MAX_BELOW_FEET to 0.078 m (under ~0.104 m treads) so
the next tread is not treated as forward walk support; ledge peel runs on
descents and pulls down onto each step instead of gliding with weak air gravity.

Raise PLAYER_VERTICAL_ACCEL_MULTIPLIER to 9× for peel, walk-air, and idle-air.
2026-04-12 18:47:38 -04:00
VinPropane b924707202 NEON-29: Faster vertical descent — accel multiplier + peel until feet arrive
Apply PLAYER_VERTICAL_ACCEL_MULTIPLIER (~2.45×) to walk-airborne gravity,
ledge peel integration, and idle-airborne gravity for snappier falls.

Peel used to clear when goal.y >= feet_y - DESCEND_GOAL_Y_MARGIN, which
stopped peeling ~6 cm above the click surface while XZ was already at the
destination — use vertical_arrival_error <= VERT_ARRIVE_EPS instead, with
a small guard when the goal is clearly above the feet (climb).
2026-04-12 18:44:51 -04:00
VinPropane a78b44263c NEON-29: Ledge peel via move_and_collide + fallback gravity
Direct global_position.y edits may not stick vs Jolt after move_and_slide.
Use move_and_collide for the peel step so motion goes through physics.

If get_gravity() is near zero, use -9.81 for peel, walk air, and idle air.
2026-04-12 18:41:20 -04:00
VinPropane fb1ac80fb0 NEON-29: Ledge peel via position — GROUNDED eats vy on floor
CharacterBody3D MOTION_MODE_GROUNDED move_and_slide clears downward
velocity while is_on_floor(), so gravity on velocity never produced
vertical motion off terrace lips (all prior probe/snap tweaks were no-ops).

After each walk move_and_slide, when the goal surface is below the feet
and probes/deep-descent say drop, accumulate peel_vy += g·dt and apply
global_position.y += peel_vy·dt. Airborne walk still uses velocity gravity.

Set physics/3d/default_gravity=9.81 explicitly in project.godot.
2026-04-12 18:36:53 -04:00
VinPropane 55ce6f3e3b NEON-29: Deep-descent walk gravity bypass for violet deck vs floor goal
Rays and is_on_floor() can still agree the capsule is supported while the
authoritative click is on the main floor far below (TerracePlatformB lip).

When feet are >0.42 m above the goal surface Y, always add walk gravity and
zero moving floor snap. Shorter drops (e.g. gold step to floor) still use
the probe heuristic only.
2026-04-12 18:31:01 -04:00
VinPropane 91b802c679 NEON-29: Fix walk ledge probes for descending + same-column clicks
Degenerate XZ (velocity and want_goal_h ~0) made _walk_has_close_floor_probe_below
return after center-only, suppressing ledge gravity for the whole move.

Add _resolve_walk_probe_dir_xz: when goal surface is below feet, prefer
horizontal bearing to the goal, else nav path lookahead, else fallbacks.
Non-descending motion keeps velocity-first probes.

Remove the nav-column-only want_goal_h override (superseded by descending
branch). Reverts the regression where the capsule stayed on violet until XZ.
2026-04-12 18:25:22 -04:00
VinPropane db1f4da068 NEON-29: Aim walk ledge probes at click when nav column descends
Column steering follows path tangents on the violet deck while the
authoritative goal sits on the lower floor; velocity-aligned support rays
kept hitting deck in the tangent direction and suppressed ledge gravity.
Use want_goal_h for probe offsets when vertical routing + column steer
+ on floor + goal surface below feet.
2026-04-12 18:18:43 -04:00
VinPropane c3fd9892e3 NEON-29: Ignore walk probe hits far below feet (void saw lower floor)
Down-rays use 0.32 m depth; a gold step is ~0.3 m above the slab, so a
forward sample over empty space still intersected the gray floor and
passed the up-normal test. That looked like continued support, so ledge
gravity and snap-off never fired.

Only treat a hit as walk support if its Y is within 0.14 m below the
current feet (one tread scale); deeper hits are a lower deck / pit.
2026-04-12 18:10:36 -04:00
VinPropane 6bd1acd9e7 NEON-29: Require forward floor probe to keep walk snap/gravity sane off ledges
Walk support used any ray hit under the foot disk, so the center sample
could still see the platform while the leading edge was over a void.
is_on_floor() stayed true from the lip, snap stayed strong, and vy was
zeroed each tick — horizontal skate until XZ arrival.

Now require a center hit plus at least one forward-biased sample in the
movement direction when horizontal intent is non-zero; use velocity XZ
for probe direction so nav/path steering matches the rays.
2026-04-12 18:08:01 -04:00
VinPropane 1f6625c659 NEON-29: Fix nav column steer ping-pong — path lookahead + air bee-line 2026-04-12 18:03:47 -04:00
VinPropane 7666cce7e5 NEON-29: Ledge fall — multi foot probes + zero snap when void
Single center ray + flat floor-normal gate missed tilted lip contacts
and still hit deck under capsule center while leading edge hung over void.
Moving FLOOR_SNAP_MOVING then cancelled gravity each tick.

Sample down rays at center and offsets along walk direction; depth 0.32;
set floor_snap_length 0 when is_on_floor but no probe hit.
2026-04-12 17:56:56 -04:00
VinPropane 6cb66d7567 NEON-29: Walk gravity when is_on_floor but feet probe finds void
Jolt + floor snap could keep is_on_floor true over open space toward a
lower click target, so vy stayed 0 until arrival. Add a short downward
ray under the capsule feet (WALK_SUPPORT_PROBE_DEPTH) and apply gravity
when no upward-facing hit is close, only on fairly level floor normals.
2026-04-12 17:50:09 -04:00
VinPropane 2821c5973b NEON-29: Fix nav path steer ping-pong (get_next_path_position)
Vertical+column branch scanned path for first point with XZ offset >5 cm;
Jolt moved the body across that edge each tick and flipped the chosen
waypoint → 180° velocity oscillation (vlat && ncol).

Use NavigationAgent3D.get_next_path_position() when navigation not
finished; fall back to auth goal when finished or degenerate.
2026-04-12 17:37:48 -04:00
VinPropane 865eed2e53 NEON-29: Ease flat-floor idle latch (HUD XZ drift)
Raise stable-idle floor up-dot entry to 0.998 so Jolt normals on a flat
box can latch the idle anchor; 0.999 rarely tripped and corrective
move_and_slide + rim/bump nudges kept moving XZ.

Add STABLE_IDLE_ENTER_STREAK_FRAMES (2) before first latch; arrival
path still latches immediately. Unlatch budget 8→10 ticks.
2026-04-12 17:33:49 -04:00
VinPropane edec9158e4 NEON-29: Hysteresis for walk vertical routing (tread ping-pong)
feet_y wobble from move_and_slide on approach treads crossed
DESCEND_GOAL_Y_MARGIN each frame, toggling path vs direct steer.
Schmitt latch (WALK_VERT_ROUTE_LATCH_ON_SEP/OFF_SEP) with reset on
nav lifecycle. Extend debug_idle_trace with feet_y, vert_sep, vlat,
ncol. Add player_test for latch reset.
2026-04-12 17:17:36 -04:00
VinPropane 46f8851a1a NEON-29: Hold-threshold stable idle + physics HUD coords
While _idle_stable_latched, use STABLE_IDLE_FLOOR_HOLD_MIN_UP_DOT (0.992) for
idle_support floor flatness so tread-edge normal flicker does not unlatch as
often. idle_support_is_stable gains optional min_flat_up_dot; unlatch streak 8.
Prototype position label updates in main _physics_process. Add GdUnit for param.
2026-04-12 17:13:37 -04:00
VinPropane 5f6058b0ce NEON-29: Stable idle on flat tread next to riser (loose+ridged)
loose_ticks+ridged no longer forces ~0.8s corrective idle when floor normal
is still level (tread corner with vertical riser). Gate that branch on
shallow floor (dot < IDLE_RIM_MIN_FLOOR_UP_DOT). Bump unlatch streak to 5.
Update GdUnit + NEON-29 plan.
2026-04-12 17:09:55 -04:00
VinPropane 8d9ad0ecd3 NEON-29: Stable idle latch + Y anchor for approach treads
Hold latched zero-vel idle through STABLE_IDLE_UNLATCH_TICKS consecutive
unstable readings so thin tread lips do not drop into corrective move_and_slide
every other frame. Idle anchor now freezes Y as well as XZ. Reset latch on
goal/snap/arrival; seed latch on arrival when support is stable after idle tick.
Update hold_idle_anchor GdUnit expectation.
2026-04-12 17:06:30 -04:00
VinPropane ff6c337e1d NEON-29: Hysteresis for nav column steering (walk ping-pong)
Single-radius switch at DIRECT_APPROACH_RADIUS let horiz_dist cross every
frame between direct-to-goal and nav-path steering, flipping velocity ~180°.
Schmitt band NAV_COLUMN_STEER_ENTER/EXIT with latched _walk_nav_column_steering;
reset on new goal, snap, arrival, clear.
2026-04-12 17:02:17 -04:00
VinPropane 0f4c23b815 NEON-29: Reduce flat-floor idle XZ jitter after walks
Stop forcing moving floor_max_angle for the full post-stop window on open
flat support; tighten ridged wallish threshold; relax stable floor dot;
on arrival, take stable-idle path when support is already stable after
one idle tick. Add GdUnit case for shallow seam normals.
2026-04-12 16:56:40 -04:00
VinPropane 1867e3e45c NEON-29: Fix idle jitter on flat treads after stop
idle_support_is_stable no longer treats every post-stop loose-tick frame as
unstable; only slide normals showing floor+wall (lip) keep corrective idle.
Deduplicate ridged-contact check via idle_slide_contacts_are_ridged.
Relax STABLE_IDLE_FLOOR_MIN_UP_DOT slightly for Jolt normal flicker.
Update GdUnit cases and NEON-29 plan note.
2026-04-12 16:50:21 -04:00
VinPropane dbd9d67f45 NEON-29: Cap step assist to navigation agent_max_climb (0.35 m).
TerracePlatformB top is ~0.6 m above the floor; agent_max_climb only
limited nav links, while chained step assist could still climb in one
click. Refuse assist when goal surface is more than 0.35 m above feet
so the gold TerraceStepB path (or a second click) is required.
2026-04-12 01:12:10 -04:00
VinPropane e448075797 NEON-29: Bee-line walk to goal; nav path only for vertical routing.
Default get_next_path_position steering caused crawl/stuck behavior with
Jolt at 120 Hz. Steer XZ toward the authoritative target always except
when the goal surface is meaningfully above/below the feet and the
player is within DIRECT_APPROACH_RADIUS — then use the baked path for
ramps/treads. Update README and NEON-29 plan.
2026-04-12 01:07:35 -04:00
VinPropane 4df71ac0cc NEON-29: Fix floor walk stall from tight nav agent distances.
Revert path_desired_distance and target_desired_distance to 0.35; 0.22
was below practical per-tick progress toward waypoints and led to
oscillation or stuck path state. When NavigationAgent reports finished
but horizontal distance still exceeds ARRIVE_EPS, steer directly
toward the authoritative goal in XZ.
2026-04-12 01:03:40 -04:00
VinPropane 3a7658f55f NEON-29: Roll back walk oscillation on treads (stall replan, seam clear).
Remove walk-stall nav replan and seam-based step-assist clearing that
churned targets and toggled floor_block_on_wall on small rises. Restore
0.11 m assist with 8-tick cooldown; cap wallish snap only when the goal
is meaningfully above the feet. Drop descending_stall floor_block branch.
Document rollback in the implementation plan.
2026-04-12 00:56:13 -04:00
VinPropane 8d1785d288 NEON-29: Clear step assist on seam walls; replan nav on walk stall
Step assist stayed active when is_on_wall from mesh seams after landing on
the goal height — keep reduced snap and odd slides. Clear assist when
vert_err and feet vs goal show we are on the target slab.

If horizontal speed stays low with a far goal, refresh NavigationAgent3D
target after 8 ticks to break stale paths.
2026-04-12 00:53:36 -04:00
VinPropane b96bec7981 NEON-29: Teal cardinal — snap cap during climb, descend stall, assist tune
Cap walk floor snap to WALK_STEP_ASSIST_SNAP when climbing into a blocking
wall (stops 0.32m snap fighting step assist). Restore descend lip snap cap;
relax floor_block when descend stalls (low vh, still far in xz). Step assist
lift 0.16 m, cooldown 1 tick.
2026-04-12 00:45:02 -04:00
VinPropane d81e915a0a NEON-29: Teal pad lips — wall normal assist, rim descend, +12mm lift
Step assist: use is_on_wall + get_wall_normal opposing want; keep slide loop
with dot < -0.02.

Descend: relax floor_block on shallow floor normal at internal edges; widen
vertical-ish slide threshold slightly.

Raise TerracePlatformA Y by 0.012 m vs main floor for coplanarity.
2026-04-12 00:42:25 -04:00
VinPropane 81ceeaab27 NEON-29: Doc fix — lip QA on TerracePlatformA, not Terrace B
Clarify README, plan, and player.gd comments: screenshots were the large
SE pad (10×10, 0.3 m step), not the NW TerraceStepB/TerracePlatformB pair.
2026-04-12 00:39:04 -04:00