From f6bd968473e70839424dcabe678b62c613a83513 Mon Sep 17 00:00:00 2001 From: 44r0n7 <44r0n7+gitea@pm.me> Date: Fri, 30 Oct 2026 03:51:41 -0400 Subject: [PATCH] Downhill screens no longer shake on screen (t106) --- docs/DESIGN.md | 12 ++++++++---- docs/PROJECT_MAP.md | 6 +++--- docs/TESTING.md | 3 +++ docs/agent-log.md | 15 +++++++++++++++ src/render/gpu/smooth-slope.js | 3 +-- src/render/slope-belts.js | 11 +---------- test/t_slope_belt_art.js | 11 +++++++---- 7 files changed, 38 insertions(+), 23 deletions(-) diff --git a/docs/DESIGN.md b/docs/DESIGN.md index 23a51ed..a41ce58 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -98,6 +98,10 @@ Details and numbers live in the code and in `docs/systems/`. ## Decisions +- **Screen frames stay still (t106, 2026-10-30).** Removed visual shake from loaded + downhill screens in both looks: the owner dislikes it and wants consistency with flat + filters. Screens no longer shake visually; grain movement and sorting are unchanged. + - **Transport matches the t45 belt (t105, 2026-10-30).** The owner approved the flat belt and asked for the other transport pieces to keep the same pace and flow through mixed lines. The flat belt stays unchanged: 30 cells/s, 30 grains/s with one layer and 90 grains/s with a @@ -434,8 +438,8 @@ above, including: - **Conveyor drawing and sleep follow-up (t42/t43, 2026-10-26).** The owner wants visible rubber ribs on the actual cleat raster, filled corrugated far walls behind the load, and smooth continuous mesh with rails for inclined screens. Walls stop at the slope ends; - only loaded screens shake. Empty moving cleats must let chunks sleep. Keep pocket transport, - uphill throughput near 71 grains/s and exact sorting unchanged. + screens no longer shake visually (t106). Empty moving cleats must let chunks sleep. Keep + pocket transport, uphill throughput near 71 grains/s and exact sorting unchanged. - **Sidewall belts with moving cleats (t42, 2026-10-26; physics replaced by the entry below).** To replace the old full-column grip, use moving barrier lines rather than material cells: the barrier mask blocks normal @@ -455,8 +459,8 @@ above, including: with one mesh-contact nudge every 4 ticks (15 downhill steps/s plus gravity). Unselected bars step on that same cadence; selected bars fall through. Flat filters retain their linear transport. Sorting both slope shapes in either mode conserves the complete mix. - Both looks use a sturdy mesh frame with a small tick-based shake only while loaded; - idle mesh has no running belt animation. No old uphill-save migration was added. + Both looks use a sturdy mesh frame that no longer shakes visually (t106); + mesh has no running belt animation. No old uphill-save migration was added. - **Screw conveyors stay, in every direction (2026-10-26).** The owner asked whether screw conveyors are still needed now that belts climb 45°, whether they're realistic, and what a diff --git a/docs/PROJECT_MAP.md b/docs/PROJECT_MAP.md index 9e6ee81..9a57172 100644 --- a/docs/PROJECT_MAP.md +++ b/docs/PROJECT_MAP.md @@ -412,9 +412,9 @@ Drawing (src/render/): browser only. This file: the renderer state R, colour tab - functions: glowIndex, thermIdx, pipeCellColor, pipeBodyCell, thinPipeColor, buildSky, initRender, resizeRender, viewCells, updateCamera, snapCamera, screenToWorld, worldToScreenPx, renderMonoFont - variables: R, GLOW_W, GLOW_R, GLOW_G, GLOW_B, THERM, PC, TREE_R, TREE_G, TREE_B, BG, SKY_R, SKY_G, SKY_B -### src/render/slope-belts.js (167 lines) +### src/render/slope-belts.js (158 lines) Drawing only: the face stays on its simulation cells; the band hangs below it. -- functions: slopeBeltConnections, flatBeltCaps, prepareSlopeBelts, slopeBeltSegment, slopeBeltCorner, slopeBeltShape, slopeBeltAt, slopeBeltColor, screenLoaded, slopeWallShape, slopeWallAt, slopeDetailAt, slopePreviewCleat +- functions: slopeBeltConnections, flatBeltCaps, prepareSlopeBelts, slopeBeltSegment, slopeBeltCorner, slopeBeltShape, slopeBeltAt, slopeBeltColor, slopeWallShape, slopeWallAt, slopeDetailAt, slopePreviewCleat - variables: slopeBeltJoins, slopeBeltHalo, beltCaps, slopeAcross, slopeAlong, slopeDistance, slopeWallOwner ### src/render/diagonal-screws.js (79 lines) @@ -449,7 +449,7 @@ GPU sources retain the CPU roof and transmission rules; directional relaxation f - functions: gpuLightGrid, gpuLightBindings, gpuLight - variables: GPU_LIGHT, GPU_LIGHT_SPREAD, GPU_LIGHT_PACK -### src/render/gpu/smooth-slope.js (107 lines) +### src/render/gpu/smooth-slope.js (106 lines) Smooth slope geometry and cleats, ported from slope-belt-shader.js. - variables: GPU_SMOOTH_SLOPE_HELPERS, GPU_SMOOTH_SLOPE_DRAW diff --git a/docs/TESTING.md b/docs/TESTING.md index 4b5e5f0..a45ddc1 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -354,3 +354,6 @@ chain's output, conservation and per-join load counts. It uses `test/fixtures/t1 `t_threads.js` also compares that chain with 0/1/2/8 real workers. To photograph the same chain, pass the fixture followed by `tools/scenes/t105-chain.js` together as `tools/shot.py --js` (they must share one setup scope); use zoom 5, no lighting and a 1280×760 viewport. Check both looks when changing cleat geometry. + +`t106`: `t_slope_belt_art.js` checks that a loaded screen keeps the empty frame at ticks 2 +and 4. Screens no longer shake visually in either look; grain movement is unchanged. diff --git a/docs/agent-log.md b/docs/agent-log.md index 14cdf04..b1d0747 100644 --- a/docs/agent-log.md +++ b/docs/agent-log.md @@ -4,6 +4,21 @@ What agents have done, newest first. Add an entry for every piece of work: the d note or request it was for, what changed, the files touched, the tests run, and anything left open or not verified. Keep each entry short; the git history has the details. +## 2026-10-30: t106 downhill screen frames stay still (Codex) + +- Removed the loaded-screen shake flag, pixel/smooth drawing offsets and unused + `screenLoaded` helper. No simulation files changed; all src/sim JavaScript hashes match. +- Replaced the two shake checks with stable-frame equality at ticks 2 and 4; the new check + fails before the fix and passes after. Recorded the owner decision; regenerated the map. +- Files: render/{slope-belts,gpu/smooth-slope}, test/t_slope_belt_art.js, + docs/{DESIGN,TESTING,PROJECT_MAP,agent-log}, task t106. +- All 44 headless suites pass. Before/after raw output differs only in the replaced art checks + (saved under /tmp/t106-{before,after}). Build and map check pass. +- Browser golden fails at GPU.ok; smooth times out waiting for GAME.running. No workaround + attempted. Full `run_all.py --browser`: all headless pass, 12 browser suites fail, + Firefox smoke passes. Browser diagnostics report webgpu=false and SwiftShader; log at + /tmp/t106-browser.log. Screenshots and owner visual check remain. Task in Review; no commit. + ## 2026-10-30: t105 transport matches the t45 belt (Codex) - Shared diagonal cadence, six-grain vertical slope beds, taller cleat pockets and four-lane diff --git a/src/render/gpu/smooth-slope.js b/src/render/gpu/smooth-slope.js index 79b749f..9feb99c 100644 --- a/src/render/gpu/smooth-slope.js +++ b/src/render/gpu/smooth-slope.js @@ -10,8 +10,7 @@ fn slopeCorner(p: vec2f, a: vec2f, origin: f32) -> vec3f { var d: vec2f = p - a; var radius: f32 = length(d); return vec3f(radius - 1.85, origin + d.x, 2.0 + d.y); } -fn slopeShape(inputP: vec2f, worldOrigin: vec2f, grade: f32, joins: i32) -> vec3f { var p=inputP; - if ((joins & 64) != 0) { p.y -= 0.45; } +fn slopeShape(inputP: vec2f, worldOrigin: vec2f, grade: f32, joins: i32) -> vec3f { let p=inputP; var sy: f32 = select( 0.0, 4.0 , grade < 0.0 ); var a: vec2f = vec2f(-grade * 1.30814755, sy + 1.30814755); var b: vec2f = vec2f(4.0 - grade * 1.30814755, 4.0 - sy + 1.30814755); if ((joins & 1) != 0) { a.y = sy + 2.0; a.x = (a.y - sy - 2.61629509) / grade; } diff --git a/src/render/slope-belts.js b/src/render/slope-belts.js index 898774c..5a1b520 100644 --- a/src/render/slope-belts.js +++ b/src/render/slope-belts.js @@ -33,7 +33,7 @@ function prepareSlopeBelts(x0, y0, x1, y1) { if (c === BP_BELT || c === BP_FILTER) beltCaps[b] = flatBeltCaps(b); if (!isSlopeBelt(c)) continue; const face = beltFaceY(c, bx, by, bx * BS) * W + bx * BS; - slopeBeltJoins[b] = slopeBeltConnections(bx, by, c) | (netSat(face) > 0 ? 16 : 0) | (filterCfg.get(b)?.inv ? 32 : 0) | (isFilter(c) && netSat(face) > 0 && screenLoaded(b) && !transportStalled(b) && (tick & 2) ? 64 : 0); + slopeBeltJoins[b] = slopeBeltConnections(bx, by, c) | (netSat(face) > 0 ? 16 : 0) | (filterCfg.get(b)?.inv ? 32 : 0); for (let yy = Math.max(0, by - 2); yy <= Math.min(BH - 1, by + 1); yy++) for (let xx = Math.max(0, bx - 1); xx <= Math.min(BW - 1, bx + 1); xx++) slopeBeltHalo[yy * BW + xx] = 1; } @@ -54,7 +54,6 @@ function slopeBeltCorner(x, y, ax, ay, origin) { function slopeBeltShape(x, y, b, joins = slopeBeltJoins[b], code = blockP[b]) { const grade = beltGrade(code), ox = (b % BW) * BS, oy = ((b / BW) | 0) * BS; x -= ox; y -= oy; - if (isFilter(code) && (joins & 64)) y -= 0.45; const offset = 1.85 * Math.SQRT2, sy = grade < 0 ? 4 : 0; const normal = 1.85 * Math.SQRT1_2; let ax = -grade * normal, ay = sy + normal, bx = 4 - grade * normal, by = 4 - sy + normal; @@ -118,14 +117,6 @@ function slopeBeltColor(b, x, y, anim, br, bg, bb) { return (r | 0) | ((g | 0) << 8) | ((blue | 0) << 16); } -function screenLoaded(b) { - const bx = b % BW, by = (b / BW) | 0, c = blockP[b]; - for (let x = bx * BS; x < bx * BS + BS; x++) { - const i = (beltFaceY(c, bx, by, x) - 1) * W + x; - if (i >= 0 && (PH[mat[i]] === PH_POWDER || occ[i])) return true; - } - return false; -} // Filled far wall, in belt coordinates. Project onto the face so ends stop at the slope ends. let slopeWallOwner = -1; function slopeWallShape(x, y, b, code = blockP[b]) { diff --git a/test/t_slope_belt_art.js b/test/t_slope_belt_art.js index de57ac5..c3ccecd 100644 --- a/test/t_slope_belt_art.js +++ b/test/t_slope_belt_art.js @@ -113,10 +113,13 @@ for (const grade of [-1,1]) { flatWorld(run,160,120,112); run('placeBlock(BP_FILTER_DOWN,128,12,12,true);tick=0;prepareSlopeBelts(0,0,W,H);var idleJoins=slopeBeltJoins[12*BW+12];tick=2;prepareSlopeBelts(0,0,W,H);'); check('empty screen has a stable frame',run('slopeBeltJoins[12*BW+12]===idleJoins')); -run('setCell(47*W+48,SAND,20,0);prepareSlopeBelts(0,0,W,H);'); -check('loaded screen shakes the frame with the simulation tick',run('(slopeBeltJoins[12*BW+12]&64)!==0')); -run('tick=4;prepareSlopeBelts(0,0,W,H);'); -check('loaded frame returns on the next shake beat',run('(slopeBeltJoins[12*BW+12]&64)===0')); +check('loaded screen keeps the empty frame at ticks 2 and 4',run(`(() => { + for (const t of [2,4]) { + tick=t;setCell(47*W+48,SAND,20,0);prepareSlopeBelts(0,0,W,H); + if (slopeBeltJoins[12*BW+12]!==idleJoins) return false; + } + return true; +})()`)); flatWorld(run,160,120,112); run('for(let k=0;k<6;k++)placeBlock(BP_BELT_UP,1,12+k,20-k,true);rebuildPower();slopeCleatsTick(false);'); check('wall reaches the belt and cleat height, and clips its free ends',run(`(()=>{