Belts carry 4 grains deep; stalled belts warn and stop animating (t45)

This commit is contained in:
2026-10-29 23:21:27 -04:00
parent 99aae0aae0
commit ac5f5a06d1
27 changed files with 335 additions and 51 deletions
+5 -2
View File
@@ -142,7 +142,7 @@ above, including:
short stubs stay for the next firing. The mold cleans itself and rakes the grate after dropping bars or clearing junk.
- **Screw conveyors carry no more than belts:** they move every other tick. For more throughput,
build more lines.
- **A heap on a belt moves as one**, up to 96 grains deep, not just its bottom layer. If a grain is blocked,
- **A belt carries a bed four grains deep** (one block, t45), with higher grains left loose. If a grain is blocked,
the load above it stands still and the belt slips underneath; the top no longer slides over
a stuck bottom. Filters still let their chosen materials drop through.
- **Pick** (middle mouse) selects the piece under the cursor with its direction,
@@ -447,7 +447,10 @@ above, including:
2026-10-26).** An overloaded belt line jammed against a screw conveyor above it. The owner
agreed that's realistic and stays the player's problem, but wants a warning on the stalled
belt and the animation stopped on everything affected, and belts limited to a realistic
load depth instead of carrying 96-grain stacks. Not built yet.
load depth instead of carrying 96-grain stacks. Built 2026-10-29: the owner chose
**4 grains (one block)**. Loaded transport warns after half a second without progress,
with a marker and advice to clear the outlet or heap. Only affected blocks stop animating;
a blocked cleated slope stops its whole run. Screens use their slower nudge cadence.
- **Cleats really push their pockets (t42 feedback, 2026-10-26).** The owner found the first
cleats passed through heavy loads while the material climbed as before, and wants cleats that
+28 -15
View File
@@ -167,6 +167,11 @@ flyers and blueprint ghosts. The GPU canvas sits behind the transparent overlay
`diagonal-screws.js` and `slope-belts.js` share the simulation join geometry with pixel colours,
smooth tags, ghosts and previews.
Transport backpressure lives in `src/sim/transport-status.js`: transient per-block load,
movement, jam age and animation clocks. Flat carry, screens, screws, cleats and bars report
progress; only the serial transport step updates it. Both looks use those clocks; smooth
receives a view-sized clock texture so geometry tags and shading fields remain intact.
## The browser shell
- `GAME` (`src/ui/state.js`) holds the UI state: tool, selected piece, build tab, drag,
@@ -244,7 +249,7 @@ Starter furnace designs and the milestone list shown in the notebook.
- functions: smelterBlueprint
- variables: STARTER_DESIGNS, MILESTONES
### src/sim/world.js (124 lines)
### src/sim/world.js (125 lines)
World state: the per-cell typed arrays, alloc(), ambient temperature by depth, waking.
- functions: emit, bagCap, discover, sharedArray, alloc, depthU, depthY, meanSurface, computeAmbient, fillNoise, renderDirtyXY, renderDirtyChunk, renderDirtyIdx, wakeXY, wakeHeatXY, wakeIdx, wakeHeatIdx
- variables: W, H, N, CW, CH, NCH, mat, temp, life, flags, stamp, part, mach, digp, noiseB, airS, netId, isPow, occ, surfY, dirtY, graniteY, basaltY, magmaY, roofY, AMB, worldSeed, surfBase, underD, shallowD, lapse, BW, BH, NB, blockP, blockV, ents, bgm, flyers, ghostBlocks, ghostMolds, renderDirty, awake, hot, hotLvl, powderArea, roofDirty, loadWakeOrder, loadWakePending, loadWakeIndex, tick, tickStamp, machines, molds, nets, pcells, powerDirty, beltL, beltR, screwLists, brokenMachines, ghostMachines, ghostBlocked, EV, bot, bag, bagTotal, player, seen, ledger, stats
@@ -284,7 +289,7 @@ Pipes, pumps and outlets: each joined line holds one liquid as a count, not as g
- functions: sideOf, pipeClosedSide, pipeJoins, rebuildPipes, pipeNetOf, pipeTakeShare, faceCell, pumpDraw, outletPour, pipesTick
- variables: PIPE_CAP, PUMP_RATE, OUTLET_RATE, PUMP_MAX_T, SIDE_V, PUMP_V, OUTLET_V, pipeNets, pipeNetAt, pipesDirty
### src/sim/machine-tick.js (158 lines)
### src/sim/machine-tick.js (160 lines)
Per-tick machine work: steam engines, fans, belts, filters, screw conveyors (machinesTick).
- functions: engineIntake, fanBlow, machinesTick
@@ -293,8 +298,8 @@ Travel-directed transport ends. Precomputed probes; world/plan queries allocate
- functions: pieceEnds, joinCandidate, endJoin, pieceJoins, endAt, joinIsDrop, joinSnap, nearMiss
- variables: JOIN_ENDS, NO_PIECE, NEAR_MISS_VIEW
### src/sim/conveyors.js (213 lines)
How belts, filters and screw conveyors move what is on or in them. What rests on a belt or filter rides along: the whole stack standing on the carrying surface steps one cell toward d together (belts run front of the line first, so the way ahead is clear). If a powder grain is blocked, the load above it stands still and the belt slips underneath. A filter's own material drops through it instead, unless it is already full.
### src/sim/conveyors.js (215 lines)
How belts, filters and screw conveyors move what is on or in them. What rests on a belt or filter rides along: the bottom four grains standing on the carrying surface steps one cell toward d together (belts run front of the line first, so the way ahead is clear). If a powder grain is blocked, the load above it stands still and the belt slips underneath. A filter's own material drops through it instead, unless it is already full.
- functions: conveyorStep, carryColumn, beltDrain, launchGrain, rebuildFilters, filterCarry, carryBeltsAndFilters, setFilter, filterRun, roomFor, screwSpread, screwIntake, screwAccepts, straightScrewNext, diagonalScrewNext
- variables: CARRY_DEPTH, filterR, filterL, filtersDirty
@@ -303,7 +308,12 @@ Throughput for the info overlay (t49): how many grains each belt, filter and scr
- functions: setFlowCounting, flowNote, flowCross, flowSlopeUnder, flowTick
- variables: flowOn, flowCount, flowRate
### src/sim/slope-conveyors.js (231 lines)
### src/sim/transport-status.js (38 lines)
Local backpressure: only loaded transport that cannot advance warns after half a second.
- functions: transportNote, transportStalled, transportClock, transportBegin, transportEnd, transportCleat, transportBar
- variables: STALL_TICKS, transportState
### src/sim/slope-conveyors.js (237 lines)
Cleats are rubber ribs standing up from a sloped belt's face, one every CLEAT_SPACING face cells. Loose grains treat them as solid (cleatMask). Nothing grips the bare face: grains slide down it until a cleat stops them. Each belt step moves every cleat one face cell along the belt, and the rib pushes whatever is in its way ahead of it, so the pocket in front rides along while anything heaped above the rib is left to roll back. If a rib can't push its way, its whole run stalls. Only uphill runs have cleats: downhill, the belt carries its load like a flat one.
- functions: ribMove, cleatFoot, ribCells, slopeUphill, slopeFaceAt, pushRow, scoop, pocketRoom, advanceCleat, slopeRunKey, slopeCleatsTick, rebuildCleatMask, expelFromRib, screenNudge, wakeCleatLoad
- variables: CLEAT_SPACING, CLEAT_HEIGHT, CLEAT_REACH, SCREEN_NUDGE_TICKS, cleatChunks, cleatMask, cleatCells, slopePhase, ribLog
@@ -317,7 +327,7 @@ Molds: cavities for castings; ingot troughs empty themselves below. Removal retu
- functions: moldCellsAt, canPlaceMold, newMoldRecord, addMold, castMix, cavityState, troughState, clearCavity, moldPlugCells, rakeAbove, furnaceJunkHint, unplugMold, ejectIngot, checkMolds, moldAt, tally, collectMold, removeMold
- variables: DROSS, grains, barWord
### src/sim/items.js (319 lines)
### src/sim/items.js (320 lines)
Bars and other loose objects (ents), and the bag: adding, taking, costs and refunds.
- functions: entSolidCell, entSupportCount, entFreeAt, entMark, spawnBar, removeEnt, entScrewAt, entScrewFree, entScrewMove, entScrewLane, entScrewEdge, entScrewEnter, entScrewTick, entDiagonalScrewTick, entBeltScrewEnter, entSlopeBeltTick, entTick, entsInCircle, bagAdd, bagTake, giveOrDrop, refundAt, canAfford, payCost, fmtMoney, costText, needText
- variables: BAR_W, BAR_H, entCurM, droppedLast
@@ -374,7 +384,7 @@ The same chunk schedule runs inline or in workers. Workers only own a pass at a
- functions: threadWorld, threadBind, threadContext, resetChunkWork, inlineChunkWork, chunkEvent, chunkWake, chunkHeat, chunkSeed, runChunks, mergeChunkWork, chunkPasses, threadParams, threadSetParams, threadSlot, threadExecute, threadPass, threadWait, threadFailure, threadMessage
- variables: simPool, chunkWork, inlineWork
### src/sim/tick.js (29 lines)
### src/sim/tick.js (31 lines)
simTick: one simulation step, in order.
- functions: simTick
@@ -412,7 +422,7 @@ Screw casing geometry shared by both looks, ghosts and placement previews. smoot
- functions: diagonalScrewJoins, straightScrewJoins, diagonalScrewShape, diagonalScrewBlock
- variables: SCREW_CLASS, diagonalJoins, diagonalAcross, diagonalAlong, diagonalCap
### src/render/cell.js (276 lines)
### src/render/cell.js (284 lines)
Rare-cell shading also treats built pieces as transparent surroundings.
- functions: builtForShade, cellPixel
@@ -443,7 +453,7 @@ GPU sources retain the CPU roof and transmission rules; directional relaxation f
Smooth slope geometry and cleats, ported from slope-belt-shader.js.
- variables: GPU_SMOOTH_SLOPE_HELPERS, GPU_SMOOTH_SLOPE_DRAW
### src/render/gpu/smooth-shader.js (369 lines)
### src/render/gpu/smooth-shader.js (371 lines)
Literal port of the legacy smooth shader; dpdy is reversed for WebGPU's top-left origin.
- variables: GPU_SMOOTH
@@ -451,7 +461,7 @@ Literal port of the legacy smooth shader; dpdy is reversed for WebGPU's top-left
- functions: smoothSurface
- variables: SM
### src/render/gpu/smooth.js (48 lines)
### src/render/gpu/smooth.js (50 lines)
Field mip levels preserve the legacy trilinear AO sample at level 2.2.
- functions: gpuSmoothInit, gpuSmoothTextures, gpuSmoothBindings, gpuSmoothUpload, gpuSmoothMips
- variables: GPU_FIELD_MIP
@@ -469,7 +479,7 @@ Whole-world textures retain clean chunks across camera moves.
Upload full chunks so scrolling within a resident chunk needs no extra copy.
- functions: gpuUploadChunks, gpuUploadStrip, gpuCheckUploads
### src/render/gpu/draw.js (92 lines)
### src/render/gpu/draw.js (94 lines)
Only exceptional blocks and their geometric neighbours run the CPU colour rules.
- functions: gpuOverrideHas, gpuOverrides, gpuDraw, gpuPresent
- variables: GPU_PATTERN
@@ -482,9 +492,9 @@ Scale colour without changing the smooth-look class.
Machine overlays: fans, engines, silo and the rest, drawn on top of the world.
- functions: cellRect, drawHazardRims, drawMachines, drawProcBlocks, drawSilo, drawSiloPixel, drawSiloWindow, drawRackBlocks
### src/render/overlays.js (370 lines)
### src/render/overlays.js (388 lines)
Other overlays: floating text, rain and snow, flow arrows, filter tags, molds, the bot, particles.
- functions: spawnFloater, drawRain, drawFlowArrows, drawJoinMark, drawJoinMarks, flowLoaded, drawFlowRates, pingImage, drawPing, drawHoveredVein, drawPingRecharge, drawRunOutline, drawFilterTags, drawFloaters, moldLabel, drawMolds, drawBot, spawnDebris, spawnSpark, spawnSuck, drawParticles
- functions: spawnFloater, drawRain, drawFlowArrows, drawJoinMark, drawJoinMarks, flowLoaded, drawFlowRates, pingImage, drawPing, drawHoveredVein, drawPingRecharge, drawRunOutline, drawFilterTags, drawFloaters, moldLabel, drawMolds, drawBot, spawnDebris, spawnSpark, spawnSuck, drawParticles, drawTransportStalls
- variables: PING_SPEED, PING_HOLD, PING_FADE, PING_BANDS, PING_GLINTS, GLINT_MS
### src/render/screw-heat.js (29 lines)
@@ -572,7 +582,7 @@ Hover work is shared by the cursor label and the vein outline.
- functions: oreLike, bitNeeded, pingVisible, cursorVein, hoveredVein, cursorLabelAlpha
- variables: CURSOR_ORES, cursorVeinCache, cursorLabelKey, cursorLabelSince
### src/ui/info.js (216 lines)
### src/ui/info.js (221 lines)
Discovery cards, hover info (I) and the cursor label.
- functions: showCard, howText, discoveryCard, reactionsOf, hoverInfo, renderInfo, drawCursorLabel, pipeContentsText
@@ -622,7 +632,7 @@ Shared world colours, minimap and full map.
Browser-only clocks; simulation code stays usable without a browser or a clock.
- variables: PERF_MARKS, PERF_FRAME, perfMarks, perfTimes, perfLast
### src/ui/loop.js (170 lines)
### src/ui/loop.js (171 lines)
The frame loop and boot.
- functions: scanVisible, frame, boot
- variables: lastT, acc, lastRender, frameMs, simMs, fpsSm, ambientT
@@ -686,6 +696,8 @@ The frame loop and boot.
- `test/t_slope_belts.js`: Sloped belts: transport, joins, sorting, persistence and the actual drag controls.
- `test/t_slopes.js`: Sloped walls: flow, sealed joints, building, refunds and persistence.
- `test/t_smooth.py`: The smooth look: the WebGPU pass compiles and draws, and the thermal lens still works.
- `test/t_stalls.js`: t45: finite carrying bed, local sustained jams, recovery, filters, screws and bars.
- `test/t_stalls.py`: t45: real transport warnings, hover, frozen animation and recovery in both looks.
- `test/t_stone.js`: Uses for waste rock and sand: glass bricks from a fan furnace, the Saw, the silo and builders' orders.
- `test/t_threads.js`: Shared allocation, checkerboard independence, and real worker-count determinism.
- `test/t_vacuum_collapse.js`: Real nozzle cuts into settled heaps, inline and through the real Node worker pool.
@@ -706,6 +718,7 @@ The frame loop and boot.
- `tools/test_perf.py`: Profiler checks: headers, summaries/comparison, and unchanged pixels/simulation with clocks on.
- `tools/use_venv.py`: Let browser scripts run with plain python3 by switching to the repo's .venv.
- `tools/where.py`: Turn a line number in dist/index.html into the source file and line it came from.
- `tools/experiments/belt-depth.js`: t45: sustained normal (one layer) and heavy (16 layers) flat-belt feeds, open sink.
- `tools/experiments/cast_sunk_mold.js`: Block-sized bit mold sunk into the ground with a stone furnace built over its funnel.
- `tools/experiments/factory_cost.js`: What does a running factory cost when the player is somewhere else? Builds K self-running modules in a generated world, far from the bot, and measures simulation time per tick. Each module: a coal + copper-ore furnace burning in a stone-block box, a spring feeding a water wheel, a shaft carrying its power to a 10-block belt that hauls sand off a hopper.
- `tools/experiments/flow.js`: Throughput of belts and screw conveyors: grains delivered per second. Whatever lands past the outlet is taken away, so the output pile never backs up into the line.
+13
View File
@@ -14,6 +14,19 @@ prints the failing checks.
## Headless suites
For t45, `node test/t_stalls.js` checks the four-grain bed, sustained local jams,
recovery, bars, cleated runs, slower screens and an overloaded closed loop.
`test/t_threads.js` includes loaded belts and slopes, and hashes stall/animation state
as well as cell bytes with inline, 1, 2 and 8 workers (including repeats).
`python3 test/t_stalls.py` checks both looks: hover advice, always-visible warnings,
fog, actual frozen belt/filter/screw pixels and clearing the blockage. It saves
`shots/t45-stalled.png` and `shots/t45-stalled-smooth.png`.
`node tools/experiments/belt-depth.js` measures sustained one- and sixteen-layer feeds
on a flat belt: seed 7, 220 warm-up ticks and 1200 measured ticks, with an open sink.
The side-fed lift comparison in `t_conveyors.js` now uses a four-grain bed in both
fixtures rather than the old sixty-grain heap and its hard-coded delivery baseline;
it retains the 90% comparison, conservation and all-lane checks.
For t69, `node test/t_screw_heat.js` checks full-cost repair, load preservation, undo,
all screw directions, the unchanged melt threshold, and saved damage/message state.
`python3 test/t_screw_heat.py` is the focused browser check for both looks, hover,
+17
View File
@@ -4,6 +4,23 @@ 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-29: t45 belt depth and visible transport stalls (Codex)
- Four-grain belt bed; local half-second jam warnings, hover advice and frozen/resuming
animation in both looks, including screws, screens, bars and whole cleated runs.
- Files: sim/{conveyors,machine-tick,slope-conveyors,transport-status,items,tick,world},
render/{cell,slope-belts,overlays,gpu/{draw,smooth,smooth-shader,smooth-slope}},
ui/{info,loop}, manifest; test/{t_stalls.js,t_stalls.py,t_conveyors,t_threads,fixtures/t45-loop},
tools/experiments/belt-depth.js, docs/{DESIGN,TESTING,PROJECT_MAP}, task and this log.
- New checks fail on original code; all 42 headless suites pass. Browser t_stalls.py,
play.py, t_smooth.py and t_gpu.py pass with host GPU; sandbox startup timed out.
Fixed GPU pan/zoom clock-buffer recreation caught by t_gpu.py. Worker counts 0/1/2/8
match cells and jam/clocks. Inspected shots/t45-stalled{,-smooth}.png. Map regenerated.
- Normal feed 30.0 -> 30.0, heavy 360.0 -> 90.0 grains/s; uphill 78.8. Preserved the
separate 96-cell cleat push bound. Updated lift fixture to the chosen four-grain bed;
retained its 90% comparison, conservation and all-lane checks. Worldgen untouched.
No open blockers; full browser suite not run. Ready for owner review; no commit.
## 2026-10-29: t89 custom game cursors (Codex)
- Finished interrupted work: hollow build arrow at the exact mouse, open coloured crosses for