- index.html: WIMVEE GLYTCH match-the-glitch prototype (playable)
- docs/FKTRY_LORE.md: world bible / MODELBEAST asset codex
- fktry/: vite+three+TS scaffold, contracts, main loop, seed data
- fktry/MASTERPLAN.md + CONTRACTS.md + lanes/LANE-{SIM,RENDER,UI,SCREEN,DATA}.md:
round protocol and Round 1 orders for parallel Opus 4.8 executors
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
76 lines
4.2 KiB
Markdown
76 lines
4.2 KiB
Markdown
# LANE-SIM — deterministic factory simulation
|
||
|
||
You are an Opus 4.8 executor on the SIM lane of FKTRY. Read `../MASTERPLAN.md` and
|
||
`../CONTRACTS.md` before anything else; the world bible is `../../docs/FKTRY_LORE.md`.
|
||
|
||
**Mission:** the headless, deterministic heart of the game. Grid, entities, belts,
|
||
recipes, power, events. If the renderer were deleted, your sim should still be fully
|
||
playable through unit tests. You are the lane the other four trust with their lives.
|
||
|
||
**Owned paths:** `src/sim/**` (including your tests: `src/sim/*.test.ts`).
|
||
**Never touch:** contracts, main.ts, other lanes, data JSONs (request changes via NOTES).
|
||
|
||
**Standing rules (all rounds):**
|
||
- Deterministic: seedable RNG (write your own mulberry32-style helper), no wall-clock,
|
||
no unseeded Math.random. Same seed + same commands = identical snapshots.
|
||
- Every mechanic lands with tests. `npm test` green before you write NOTES.
|
||
- Performance target: 1,000 entities + 5,000 belt items at 30 tps without heroics.
|
||
Prefer flat arrays and index maps over object soup. Don't allocate in the tick loop
|
||
when avoidable.
|
||
- Snapshot may reuse buffers, but its SHAPE must always match `SimSnapshot`.
|
||
|
||
---
|
||
|
||
## CURRENT ORDERS — Round 1 (goal: milestone M1 "FLOW")
|
||
|
||
Replace the stub in `src/sim/index.ts` with a real implementation:
|
||
|
||
1. **World + placement.** Tile grid (start 64×64, world-centered). `place` command:
|
||
validate footprint fits and tiles are free, spawn `EntityState`, emit `placed`.
|
||
`remove` (emit `removed`, refund nothing yet), `rotate`, `setPaused`. Invalid
|
||
commands are silently dropped (UI will preview validity later).
|
||
2. **Belts.** `kind:'belt'` entities carry up to 2 items each as `BeltItem` (t: 0..1),
|
||
moving at `beltSpeed` tiles/sec. Items transfer to the belt/machine the belt points
|
||
into (dir). Items on a belt keep minimum spacing 0.45. Belt→machine: push into
|
||
`inputBuf` if the machine's current recipe wants that item and buffer < 2× recipe
|
||
need; otherwise the item waits (belt backs up — this is core Factorio feel, get it
|
||
right). Machine→belt: outputs pop onto an adjacent belt facing away, one item per
|
||
available slot.
|
||
3. **Crafting.** Machines with recipes: when `inputBuf` covers `inputs`, consume,
|
||
run `ticks` (progress 0..1), emit `crafted`, deposit `outputs` into `outputBuf`.
|
||
If `outputBuf` holds ≥ 4× outputs, machine stalls with `jammed:"output full"`
|
||
(emit `jammed` once per stall, not per tick). Extractors need no inputs. Machines
|
||
with multiple recipes use `setRecipe`; default to `recipes[0]`.
|
||
4. **Bandwidth (power) v1.** Sum powerGen (power kind) vs powerDraw of all entities +
|
||
active recipe `bandwidth` (note: negative recipe bandwidth GENERATES — quantizer
|
||
compression pays power, per lore). If draw > gen: global speed multiplier =
|
||
gen/draw for all progress and belt movement (brownout), emit `brownout` on/off
|
||
edges, set `snapshot.bandwidth` accordingly. No storage/buffer tanks yet.
|
||
5. **Shipping.** `kind:'shipper'` consumes ANY item arriving in its input, increments
|
||
`shippedTotal`, emits `shipped`. Track the single active commission (first in
|
||
data): fill `commissionProgress`, emit `commissionDone` once satisfied.
|
||
6. **Tests** (minimum): placement collision; belt line moves an item end to end in
|
||
the expected tick count; belt back-pressure (full line stops cleanly, no item
|
||
loss/dupe); demux recipe consumes 2 ore → 1 luma + 1 slurry; brownout halves
|
||
speed at draw=2×gen; determinism (two sims, same seed+commands, 500 ticks,
|
||
deep-equal snapshots); shipping increments and fires commissionDone.
|
||
|
||
**Definition of done:** with the dev server running, the orchestrator can (via UI or
|
||
console `__fktryBus.dispatch(...)`) place extractor→belts→demuxer→quantizer→
|
||
mosh-reactor→shipper and watch `shippedTotal.melt` climb. All tests green. NOTES
|
||
written (decisions, gotchas, what you'd tackle in round 2).
|
||
|
||
---
|
||
|
||
## NOTES (append-only log, newest at bottom — template below)
|
||
|
||
```
|
||
### Round N — YYYY-MM-DD — [your model]
|
||
SHIPPED: what actually works now (verified how)
|
||
DECISIONS: choices you made inside your mandate
|
||
BLOCKED/BROKEN: anything not working, honestly
|
||
CONTRACT REQUEST: (if any)
|
||
PROPOSAL: (ideas for the orchestrator, optional)
|
||
NEXT: what you'd do next round if asked
|
||
```
|