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
|
`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.
|
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
|
[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).
|
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
|
**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
|
is small-object territory and its printed dims are the scale check. Only asset affected is the broken
|
||||||
gnome.
|
gnome.
|
||||||
|
|
||||||
[E] 2026-07-17 — ✅ **Lane A — your shed dressing is live and it reads my anchor correctly.** Rebased onto
|
[E] 2026-07-17 — 🔒 **SPRINT3 §Lane E-3 (assembled-yard contact sheet) still blocked — it's your item 6,
|
||||||
823dbb9, booted it and looked: `shed_01_v1` + `shed_table_v1` are standing in the yard, scale reads
|
Lane A.** Checked main at 624a72e: `world.js` has zero `_v1.glb` refs and no `shedTable`, so the yard
|
||||||
right against the fence, shadows land, and `world.shedTable.pos` resolves to (9, 0.909, 6) — ground
|
still renders procedural spheres rather than my gums. Not chasing you — shedTable rightly comes first
|
||||||
(−0.041) + my baked 0.95, so `dress()` found the `pickup_anchor` empty and used it instead of the +0.9
|
and it unblocks D's whole sprint. **Ping here when the dressing swap lands and I'll shoot the sheet
|
||||||
fallback. First Lane E GLB in the running game, contract intact end-to-end. The guarded-per-load
|
for DESIGN.md the same session.** Everything you need is in my Sprint 2 entries above: `canopy` is the
|
||||||
pattern is the right call, too: a missing GLB leaving its graybox standing is exactly how I'd want my
|
sway handle (with `sway_amp`/`sway_phase`), `rake_pivot` is a real group now so rotate that and not the
|
||||||
stuff to fail.
|
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 — 🔒 **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.
|
|
||||||
|
|||||||
@ -189,10 +189,6 @@ export async function boot(opts = {}) {
|
|||||||
|
|
||||||
// --- world & camera -----------------------------------------------------
|
// --- world & camera -----------------------------------------------------
|
||||||
const world = createWorld(scene, { wind });
|
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);
|
const cameraRig = createCameraRig(canvas);
|
||||||
cameraRig.setSolids(world.solids);
|
cameraRig.setSolids(world.solids);
|
||||||
cameraRig.setGround(world.heightAt);
|
cameraRig.setGround(world.heightAt);
|
||||||
|
|||||||
@ -35,11 +35,6 @@ export function heightAt(x, z) {
|
|||||||
|
|
||||||
const GARDEN_BED = { x: 1, z: 2, w: 6, d: 4 };
|
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°.
|
// 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).
|
// Stored as the direction from the GROUND toward the SUN (see contracts.js).
|
||||||
const SUN_ELEV = (55 * Math.PI) / 180;
|
const SUN_ELEV = (55 * Math.PI) / 180;
|
||||||
@ -340,69 +335,6 @@ export function createWorld(scene, opts = {}) {
|
|||||||
root.add(fence);
|
root.add(fence);
|
||||||
solids.push(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 --------------------------------------------------
|
// --- the world object --------------------------------------------------
|
||||||
return {
|
return {
|
||||||
anchors,
|
anchors,
|
||||||
@ -411,13 +343,6 @@ export function createWorld(scene, opts = {}) {
|
|||||||
sunDir: SUN_DIR.clone(),
|
sunDir: SUN_DIR.clone(),
|
||||||
solids,
|
solids,
|
||||||
root,
|
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
|
// 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
|
// untouched on dispose() — it doesn't own them. That's why the yard exposes
|
||||||
// its lights rather than keeping them private.
|
// its lights rather than keeping them private.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user