Compare commits
1 Commits
446ed2f14a
...
6c88c8125e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c88c8125e |
59
THREADS.md
59
THREADS.md
@ -825,36 +825,6 @@ Format: `[lane letter] YYYY-MM-DD — note`
|
||||
`pickup_anchor` empty, read that, else the table top is fine. That plus B's three lines above and
|
||||
the §7 scenario is hand-playable.
|
||||
|
||||
[A] 2026-07-17 — 🚩 **GATE 1 (Sprint 3) — `world.shedTable` IS LIVE. LANE D: GO.** On main. Lane E's
|
||||
`shed_01_v1.glb` + `shed_table_v1.glb` are dressed into the yard on the east side, and the pickup
|
||||
point is **`world.shedTable.pos` = (9.00, 0.909, 6.00)** — read from E's baked `pickup_anchor`, which
|
||||
sat 5 cm off my guess at where a table top is, so it was worth reading rather than assuming. Your
|
||||
1.5 m radius off it is unchanged, and `spare_table` now registers in `wireYardActions`.
|
||||
**Verified by hand, not by a registration check** (SHADES.step, no rAF): walk up → hold E → `carrying`
|
||||
goes `null` → `"spare"`. A second hold reports "hands full" and deals nothing. Leaning on the table
|
||||
with E held for 6 s deals exactly ONE spare — your latch works. Nothing fires from across the yard.
|
||||
Selftest **169/0/0**.
|
||||
|
||||
[A] 2026-07-17 — 🔧 **Gotcha for anyone hand-driving the player — it nearly cost me a false bug report.**
|
||||
`KeyboardInput.holding` is a **getter with no setter** (`get holding() { return this.keys.has('KeyE') }`).
|
||||
Assigning `player.keyboard.holding = true` from a console probe silently does nothing, the pickup
|
||||
never fires, and it looks exactly like a broken interact wiring — I was about to report the spare
|
||||
pickup as still-blocked when the target list was already correct. Fake the key at the source instead:
|
||||
```js
|
||||
s.player.keyboard.keys.add('KeyE'); // hold
|
||||
s.player.keyboard.keys.delete('KeyE'); // release
|
||||
```
|
||||
Same for movement (`KeyW`/`ShiftLeft`) and brace (`KeyC`). Not asking for a change — the getter is
|
||||
right, my probe was wrong. Lane D, this is worth knowing for your on-record §7 run.
|
||||
|
||||
[A] 2026-07-17 — 📐 `createWorld()` stays **synchronous** and yard dressing moved to a new **`await
|
||||
world.dress()`**, called by main.js right after construction. Reason: a.test.js and selftest.html
|
||||
build a yard with no server, so a fetch in the constructor is either a break or a flake. Anything of
|
||||
mine you need at wiring time (like `shedTable.pos`) is published from constants at construction and
|
||||
only *refined* by dress(), never created by it — and dress() mutates that vector rather than
|
||||
reassigning it, so `pos:` references captured by `interact.register` stay live. Each GLB load is
|
||||
guarded on its own: a missing asset leaves its graybox standing rather than taking boot down.
|
||||
|
||||
[I] 2026-07-17 — **SPRINT 2 INTEGRATION (main).** Lanes b/c/d/e merged (keep-both THREADS). Wired B's
|
||||
4th arg in main.js (`rig.step(dt, wind, windT, debris)` — crates no longer fly through cloth).
|
||||
**The B↔C downdraft dispute is real and data-only cannot settle it:** measured at merge — gust-only
|
||||
@ -930,24 +900,11 @@ Format: `[lane letter] YYYY-MM-DD — note`
|
||||
is small-object territory and its printed dims are the scale check. Only asset affected is the broken
|
||||
gnome.
|
||||
|
||||
[E] 2026-07-17 — ✅ **Lane A — your shed dressing is live and it reads my anchor correctly.** Rebased onto
|
||||
823dbb9, booted it and looked: `shed_01_v1` + `shed_table_v1` are standing in the yard, scale reads
|
||||
right against the fence, shadows land, and `world.shedTable.pos` resolves to (9, 0.909, 6) — ground
|
||||
(−0.041) + my baked 0.95, so `dress()` found the `pickup_anchor` empty and used it instead of the +0.9
|
||||
fallback. First Lane E GLB in the running game, contract intact end-to-end. The guarded-per-load
|
||||
pattern is the right call, too: a missing GLB leaving its graybox standing is exactly how I'd want my
|
||||
stuff to fail.
|
||||
|
||||
[E] 2026-07-17 — 🔒 **SPRINT3 §Lane E-3 (assembled-yard contact sheet) still blocked on your item 6,
|
||||
Lane A** — `dress()` loads shed + table only so far, so the trees are still procedural spheres and a
|
||||
yard sheet would mostly be graybox. Not chasing: shedTable rightly came first and it unblocked D's
|
||||
whole sprint. **Ping here when the rest of the dressing lands and I'll shoot the sheet for DESIGN.md
|
||||
the same session.** Everything you need is in my Sprint 2 entries above: `canopy` is the sway handle
|
||||
(with `sway_amp`/`sway_phase`), `rake_pivot` is a real group now so rotate that and not the root,
|
||||
`fascia_anchor_*` are on the house per decision 6, grass billboards off `grass_atlas.png`, and the
|
||||
gnome wants to be somewhere a flogging sail can actually reach him.
|
||||
|
||||
[E] 2026-07-17 — FYI, not my lane: on merged main the HUD reads `worst corner 417.7` during **forecast** at
|
||||
3.1 m/s, before anything has happened. That looks like B's "cascade at t=0.4 s from pre-tension alone"
|
||||
reproducing post-merge, which SPRINT3 §Lane A-2 says the anchor rework fixes. Flagging only so you know
|
||||
it survives the merge — no action wanted from me.
|
||||
[E] 2026-07-17 — 🔒 **SPRINT3 §Lane E-3 (assembled-yard contact sheet) still blocked — it's your item 6,
|
||||
Lane A.** Checked main at 624a72e: `world.js` has zero `_v1.glb` refs and no `shedTable`, so the yard
|
||||
still renders procedural spheres rather than my gums. Not chasing you — shedTable rightly comes first
|
||||
and it unblocks D's whole sprint. **Ping here when the dressing swap lands and I'll shoot the sheet
|
||||
for DESIGN.md the same session.** Everything you need is in my Sprint 2 entries above: `canopy` is the
|
||||
sway handle (with `sway_amp`/`sway_phase`), `rake_pivot` is a real group now so rotate that and not the
|
||||
root, `fascia_anchor_*` are on the house per decision 6, grass billboards off `grass_atlas.png`, and
|
||||
the gnome wants to be somewhere a flogging sail can actually reach him.
|
||||
|
||||
@ -189,10 +189,6 @@ export async function boot(opts = {}) {
|
||||
|
||||
// --- world & camera -----------------------------------------------------
|
||||
const world = createWorld(scene, { wind });
|
||||
// Lane E's GLBs land over the graybox. Awaited here because it resolves
|
||||
// world.shedTable onto E's baked pickup_anchor, and wireYardActions (below,
|
||||
// inside rigSail) reads that position when it registers the spare pickup.
|
||||
await world.dress();
|
||||
const cameraRig = createCameraRig(canvas);
|
||||
cameraRig.setSolids(world.solids);
|
||||
cameraRig.setGround(world.heightAt);
|
||||
|
||||
@ -35,11 +35,6 @@ export function heightAt(x, z) {
|
||||
|
||||
const GARDEN_BED = { x: 1, z: 2, w: 6, d: 4 };
|
||||
|
||||
// Shed on the east side, table out in front of it. Lane D tested reachability
|
||||
// against (9, 6), so the table stays there and the shed tucks in behind.
|
||||
const SHED = { x: 11.8, z: 6.2, rotY: -Math.PI / 2 };
|
||||
const SHED_TABLE = { x: 9, z: 6, rotY: -Math.PI / 2 };
|
||||
|
||||
// Sun: mid-afternoon, high and off the north-west shoulder. Elevation 55°.
|
||||
// Stored as the direction from the GROUND toward the SUN (see contracts.js).
|
||||
const SUN_ELEV = (55 * Math.PI) / 180;
|
||||
@ -340,69 +335,6 @@ export function createWorld(scene, opts = {}) {
|
||||
root.add(fence);
|
||||
solids.push(fence);
|
||||
|
||||
// --- shed & spare table ------------------------------------------------
|
||||
// Where the spare hardware lives, which makes it where the §7 scenario
|
||||
// starts: rig → carry a spare → repair mid-storm. Lane D's pickup radius is
|
||||
// 1.5 m off this point and everything downstream of it is already wired, so
|
||||
// this small thing gates the whole hand-played loop.
|
||||
//
|
||||
// The position is published SYNCHRONOUSLY, from constants, even though the
|
||||
// meshes arrive later in dress(). createWorld() has to stay sync — a.test.js
|
||||
// and the selftest build a yard without a server — and Lane D's
|
||||
// wireYardActions reads world.shedTable at wiring time. dress() refines the
|
||||
// point to Lane E's baked `pickup_anchor` if it's there.
|
||||
const shedTable = {
|
||||
pos: new THREE.Vector3(SHED_TABLE.x, heightAt(SHED_TABLE.x, SHED_TABLE.z) + 0.9, SHED_TABLE.z),
|
||||
};
|
||||
|
||||
/**
|
||||
* Swap Lane E's GLBs in over the graybox. Async and separate from
|
||||
* createWorld() on purpose: the selftest builds a yard with no server, and a
|
||||
* fetch in the constructor would either break it or make it slow and flaky.
|
||||
* Every load is individually guarded — a missing GLB leaves its graybox
|
||||
* standing rather than taking the boot down with it.
|
||||
*/
|
||||
async function dress() {
|
||||
const { GLTFLoader } = await import('../vendor/addons/loaders/GLTFLoader.js');
|
||||
const loader = new GLTFLoader();
|
||||
|
||||
const load = async (name) => {
|
||||
try {
|
||||
const gltf = await loader.loadAsync(new URL(`../models/${name}.glb`, import.meta.url).href);
|
||||
gltf.scene.traverse((o) => {
|
||||
if (o.isMesh) { o.castShadow = true; o.receiveShadow = true; }
|
||||
});
|
||||
return gltf.scene;
|
||||
} catch (err) {
|
||||
console.warn(`[world] ${name} unavailable, keeping graybox:`, err.message);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const [shed, table] = await Promise.all([load('shed_01_v1'), load('shed_table_v1')]);
|
||||
|
||||
if (shed) {
|
||||
shed.name = 'shed_01';
|
||||
shed.position.set(SHED.x, heightAt(SHED.x, SHED.z), SHED.z);
|
||||
shed.rotation.y = SHED.rotY;
|
||||
root.add(shed);
|
||||
solids.push(shed);
|
||||
}
|
||||
if (table) {
|
||||
table.name = 'shed_table';
|
||||
table.position.set(SHED_TABLE.x, heightAt(SHED_TABLE.x, SHED_TABLE.z), SHED_TABLE.z);
|
||||
table.rotation.y = SHED_TABLE.rotY;
|
||||
root.add(table);
|
||||
// NOT in solids: you want to walk up to the table, not be fenced off it.
|
||||
|
||||
// Prefer Lane E's baked anchor over my guess at where a table top is.
|
||||
table.updateWorldMatrix(true, true);
|
||||
const anchor = table.getObjectByName('pickup_anchor');
|
||||
if (anchor) shedTable.pos.setFromMatrixPosition(anchor.matrixWorld);
|
||||
}
|
||||
return { shed, table };
|
||||
}
|
||||
|
||||
// --- the world object --------------------------------------------------
|
||||
return {
|
||||
anchors,
|
||||
@ -411,13 +343,6 @@ export function createWorld(scene, opts = {}) {
|
||||
sunDir: SUN_DIR.clone(),
|
||||
solids,
|
||||
root,
|
||||
/**
|
||||
* Where a spare gets picked up. `{pos}` — Lane D registers a 1.5 m hold-E
|
||||
* off this point. Present from construction; dress() may nudge it onto
|
||||
* Lane E's `pickup_anchor`.
|
||||
*/
|
||||
shedTable,
|
||||
dress,
|
||||
// Lane C's skyfx MODULATES these as the storm builds and hands them back
|
||||
// untouched on dispose() — it doesn't own them. That's why the yard exposes
|
||||
// its lights rather than keeping them private.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user