diff --git a/public/assets/models/chicken_wing.glb b/public/assets/models/chicken_wing.glb new file mode 100644 index 0000000..373dd67 Binary files /dev/null and b/public/assets/models/chicken_wing.glb differ diff --git a/public/assets/models/chip_golden.glb b/public/assets/models/chip_golden.glb new file mode 100644 index 0000000..fed981c Binary files /dev/null and b/public/assets/models/chip_golden.glb differ diff --git a/public/assets/models/chip_raw.glb b/public/assets/models/chip_raw.glb new file mode 100644 index 0000000..245865a Binary files /dev/null and b/public/assets/models/chip_raw.glb differ diff --git a/public/assets/models/drain_rack.glb b/public/assets/models/drain_rack.glb new file mode 100644 index 0000000..6274ab6 Binary files /dev/null and b/public/assets/models/drain_rack.glb differ diff --git a/public/assets/models/egg_carton.glb b/public/assets/models/egg_carton.glb new file mode 100644 index 0000000..b92c2b5 Binary files /dev/null and b/public/assets/models/egg_carton.glb differ diff --git a/public/assets/models/fryer_basket.glb b/public/assets/models/fryer_basket.glb new file mode 100644 index 0000000..aca0e35 Binary files /dev/null and b/public/assets/models/fryer_basket.glb differ diff --git a/public/assets/models/fryer_pot.glb b/public/assets/models/fryer_pot.glb new file mode 100644 index 0000000..39907dd Binary files /dev/null and b/public/assets/models/fryer_pot.glb differ diff --git a/public/assets/models/mixing_bowl.glb b/public/assets/models/mixing_bowl.glb new file mode 100644 index 0000000..f020a90 Binary files /dev/null and b/public/assets/models/mixing_bowl.glb differ diff --git a/public/assets/models/slotted_spoon.glb b/public/assets/models/slotted_spoon.glb new file mode 100644 index 0000000..ad5942f Binary files /dev/null and b/public/assets/models/slotted_spoon.glb differ diff --git a/public/assets/models/stock_pot.glb b/public/assets/models/stock_pot.glb new file mode 100644 index 0000000..ceba2cf Binary files /dev/null and b/public/assets/models/stock_pot.glb differ diff --git a/public/assets/models/tall_glass.glb b/public/assets/models/tall_glass.glb new file mode 100644 index 0000000..682d5d7 Binary files /dev/null and b/public/assets/models/tall_glass.glb differ diff --git a/public/assets/models/wing_cooked.glb b/public/assets/models/wing_cooked.glb new file mode 100644 index 0000000..f22eb99 Binary files /dev/null and b/public/assets/models/wing_cooked.glb differ diff --git a/public/assets/models/wire_basket.glb b/public/assets/models/wire_basket.glb new file mode 100644 index 0000000..f14a3ae Binary files /dev/null and b/public/assets/models/wire_basket.glb differ diff --git a/scripts/gen-assets.sh b/scripts/gen-assets.sh index c96a03a..0e7119a 100755 --- a/scripts/gen-assets.sh +++ b/scripts/gen-assets.sh @@ -207,6 +207,7 @@ do_stations() { gen_3d chip_golden 257 "a single thick cut golden fried potato chip, crisp browned edges" # the egg bench gen_3d egg_carton 259 "an open cardboard egg carton holding six brown eggs, lid folded back" + gen_3d egg_carton_empty 260 "an open EMPTY cardboard egg carton with six empty moulded hollows, lid folded back, no eggs in it at all" gen_3d mixing_bowl 261 "a wide shallow white ceramic mixing bowl, empty, seen at a three quarter angle" gen_3d tall_glass 263 "a plain tall clear drinking glass of water, empty of anything else" # the poach bench diff --git a/src/scenes/eggbench.ts b/src/scenes/eggbench.ts index f293607..4055c64 100644 --- a/src/scenes/eggbench.ts +++ b/src/scenes/eggbench.ts @@ -100,6 +100,11 @@ export class EggBenchView implements View { carton.position.set(-1.7, BENCH_Y + 0.09, -0.9); carton.receiveShadow = true; this.root.add(carton); + // ponytail: NO carton prop here. The generated one ships with six eggs + // baked into the mesh, and this bench is entirely about which eggs are + // YOURS — draggable, float-tested, state-coloured. A carton that already + // has eggs in it is a lie the player has to see past. Wants an EMPTY tray; + // egg_carton_empty.glb is queued for it. // The glass of water, right — the lie detector. this.glass = new THREE.Mesh( diff --git a/src/scenes/fryerpot.ts b/src/scenes/fryerpot.ts index 4a96210..a461a70 100644 --- a/src/scenes/fryerpot.ts +++ b/src/scenes/fryerpot.ts @@ -19,6 +19,7 @@ import { } from '../sim/fryer'; import { el, Panel } from '../ui/hud'; import { loadBackdrop } from './props'; +import { loadProp } from './assets'; const POT_Y = 0.55; const POT_R = 1.05; @@ -107,11 +108,22 @@ export class FryerPotView implements View { ); pot.position.y = POT_Y - 0.05; this.root.add(pot); + // The oil surface stays procedural — it is the thermometer, and it has to + // shimmer, darken and be readable. Only the vessel gets replaced. + void loadProp('/assets/models/fryer_pot.glb', 2.05) + .then((prop) => { + prop.position.set(0, 0.04, 0); + pot.visible = false; + this.root.add(prop); + }) + .catch(() => undefined); + // Sized to the GLB pot's inner rim, not the understudy cylinder's — the + // oil poking out past the steel was the giveaway. this.oilSurf = new THREE.Mesh( - new THREE.CylinderGeometry(POT_R * 0.92, POT_R * 0.92, 0.05, 32), + new THREE.CylinderGeometry(POT_R * 0.64, POT_R * 0.64, 0.05, 32), new THREE.MeshStandardMaterial({ color: 0xc9a23a, roughness: 0.15, metalness: 0.3, transparent: true, opacity: 0.9 }), ); - this.oilSurf.position.y = POT_Y + 0.12; + this.oilSurf.position.y = POT_Y + 0.2; this.root.add(this.oilSurf); // The basket: a wire cage on a long handle, chips inside. @@ -127,6 +139,16 @@ export class FryerPotView implements View { handle.position.set(1.35, 0.18, 0); this.basketGrp.add(cage, handle); this.root.add(this.basketGrp); + void loadProp('/assets/models/fryer_basket.glb', 1.7) + .then((prop) => { + // Sits proud of the oil line: a basket you cannot see is a basket you + // cannot judge. The handle stays procedural — it reads as the thing + // your hand is on. + prop.position.set(0, -0.02, 0); + cage.visible = false; + this.basketGrp.add(prop); + }) + .catch(() => undefined); // The rack, stage left — where the resting happens. this.rack = new THREE.Mesh( @@ -136,6 +158,13 @@ export class FryerPotView implements View { this.rack.position.set(-2.5, 0.45, 0.6); this.rack.receiveShadow = true; this.root.add(this.rack); + void loadProp('/assets/models/drain_rack.glb', 1.8) + .then((prop) => { + prop.position.set(-2.5, 0.4, 0.6); + this.rack.visible = false; + this.root.add(prop); + }) + .catch(() => undefined); } reset(count = 8, cardText = '', askText = 'chips — twice. once for cooked, once for golden'): void { diff --git a/src/scenes/poach.ts b/src/scenes/poach.ts index f8043bd..8cc5867 100644 --- a/src/scenes/poach.ts +++ b/src/scenes/poach.ts @@ -21,6 +21,7 @@ import { } from '../sim/poach'; import { el, Panel } from '../ui/hud'; import { loadBackdrop } from './props'; +import { loadProp } from './assets'; const POT_Y = 0.55; const POT_R = 1.15; @@ -176,6 +177,19 @@ export class PoachView implements View { this.spoon.add(bowl, handle); this.spoon.visible = false; this.root.add(this.spoon); + // The real spoon rides INSIDE the group, so it inherits every move the + // lift animation makes; the procedural bowl+handle step aside. + void loadProp('/assets/models/slotted_spoon.glb', 1.9) + .then((prop) => { + // Measured, not guessed: the model is ~1.9 long in Z with the bowl at + // the +Z end, so it needs shifting back by half its length to put the + // BOWL — not the model's centre — under the egg. + prop.position.set(0, -0.14, -0.92); + bowl.visible = false; + handle.visible = false; + this.spoon.add(prop); + }) + .catch(() => undefined); } /** A fresh pot on `fuel`, cold water, no egg. */ diff --git a/src/scenes/pot.ts b/src/scenes/pot.ts index 034e89f..1e7ca1f 100644 --- a/src/scenes/pot.ts +++ b/src/scenes/pot.ts @@ -24,6 +24,7 @@ import { } from '../sim/pot'; import { el, Panel } from '../ui/hud'; import { loadBackdrop } from './props'; +import { loadProp } from './assets'; const POT_Y = 0.55; const POT_R = 1.2; @@ -107,6 +108,13 @@ export class PotView implements View { ); pot.position.y = POT_Y - 0.05; this.root.add(pot); + void loadProp('/assets/models/stock_pot.glb', 2.8) + .then((prop) => { + prop.position.set(0, 0.08, 0); + pot.visible = false; + this.root.add(prop); + }) + .catch(() => undefined); this.water = new THREE.Mesh( new THREE.CylinderGeometry(POT_R * 0.93, POT_R * 0.93, 0.06, 32), new THREE.MeshStandardMaterial({ color: 0x86aec2, roughness: 0.18, transparent: true, opacity: 0.8 }),