Mushrooms: three varieties for the prep bench, plus gen-assets machine fixes
- button_mushroom / portobello / king_oyster in the ingredient cast: slippery skins (0.55-0.8, the tomato treatment), soft flesh, portobello gills layered and weeping; new 'mushroom' cap-and-stem silhouette. - Verified via harness: dinner knife pressed on a button skates (1 slip, cut lands 0.157 off-aim; tomato baseline 2 slips / 0.218), The Best Thing bites clean through under the same press, sawing properly cuts center with zero slips. - gen-assets.sh: find MODELBEAST at ~/MODELBEAST, token from backnforth/.env, MB_HOST to the m3ultra queue; every mb stage retries 10x with 60s pause because m4pro's venvs are gone (ponytail-marked, remove when m4pro is healed). - launch.json: port 5273 (5173 taken by another session's server). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
faf196657e
commit
ee1eb8ebc3
@ -4,8 +4,8 @@
|
|||||||
{
|
{
|
||||||
"name": "toastsim",
|
"name": "toastsim",
|
||||||
"runtimeExecutable": "npm",
|
"runtimeExecutable": "npm",
|
||||||
"runtimeArgs": ["run", "dev"],
|
"runtimeArgs": ["run", "dev", "--", "--port", "5273"],
|
||||||
"port": 5173
|
"port": 5273
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
5
package-lock.json
generated
5
package-lock.json
generated
@ -1,13 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "toastsim",
|
"name": "toastsim",
|
||||||
"version": "1.0.0",
|
"version": "0.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "toastsim",
|
"name": "toastsim",
|
||||||
"version": "1.0.0",
|
"version": "0.1.0",
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dimforge/rapier3d-compat": "^0.19.3",
|
"@dimforge/rapier3d-compat": "^0.19.3",
|
||||||
"three": "^0.185.1"
|
"three": "^0.185.1"
|
||||||
|
|||||||
BIN
public/assets/models/batard_loaf.glb
Normal file
BIN
public/assets/models/batard_loaf.glb
Normal file
Binary file not shown.
BIN
public/assets/models/cheese_hard.glb
Normal file
BIN
public/assets/models/cheese_hard.glb
Normal file
Binary file not shown.
BIN
public/assets/models/cheese_soft.glb
Normal file
BIN
public/assets/models/cheese_soft.glb
Normal file
Binary file not shown.
BIN
public/assets/models/cutting_board.glb
Normal file
BIN
public/assets/models/cutting_board.glb
Normal file
Binary file not shown.
BIN
public/assets/models/roast_tomatoes.glb
Normal file
BIN
public/assets/models/roast_tomatoes.glb
Normal file
Binary file not shown.
BIN
public/assets/models/sourdough_loaf.glb
Normal file
BIN
public/assets/models/sourdough_loaf.glb
Normal file
Binary file not shown.
BIN
public/assets/models/tomato_vine.glb
Normal file
BIN
public/assets/models/tomato_vine.glb
Normal file
Binary file not shown.
@ -9,6 +9,7 @@
|
|||||||
set -uo pipefail
|
set -uo pipefail
|
||||||
|
|
||||||
MB_DIR="$HOME/Documents/MODELBEAST"
|
MB_DIR="$HOME/Documents/MODELBEAST"
|
||||||
|
[ -d "$MB_DIR" ] || MB_DIR="$HOME/MODELBEAST"
|
||||||
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
OUT_MODELS="$REPO/public/assets/models"
|
OUT_MODELS="$REPO/public/assets/models"
|
||||||
OUT_IMG="$REPO/public/assets/img"
|
OUT_IMG="$REPO/public/assets/img"
|
||||||
@ -16,17 +17,39 @@ mkdir -p "$OUT_MODELS" "$OUT_IMG"
|
|||||||
|
|
||||||
cd "$MB_DIR" || exit 1
|
cd "$MB_DIR" || exit 1
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
source data/agent.env
|
if [ -f data/agent.env ]; then source data/agent.env
|
||||||
|
else set -a; source "$HOME/Documents/backnforth/.env"; set +a; fi
|
||||||
|
export MB_HOST="${MB_HOST:-http://100.89.131.57:8777}"
|
||||||
|
|
||||||
STYLE="chunky stylized claymation kitchen prop, soft matte plastic look, warm colors"
|
STYLE="chunky stylized claymation kitchen prop, soft matte plastic look, warm colors"
|
||||||
SHOT="single object centered on plain light grey background, soft studio lighting, 3/4 view, chunky stylized game asset"
|
SHOT="single object centered on plain light grey background, soft studio lighting, 3/4 view, chunky stylized game asset"
|
||||||
|
|
||||||
|
# ponytail: m4pro node has dead venvs (2026-07-17) — jobs routed there fail in ~1s,
|
||||||
|
# so every stage retries up to 10x with a 60s pause until a healthy node takes it.
|
||||||
|
# Remove the loops once m4pro is fixed or pulled from the pool.
|
||||||
|
MB_TRIES=10 MB_PAUSE=60
|
||||||
|
|
||||||
# run_flux <seed> <prompt> [w] [h] -> asset id on stdout
|
# run_flux <seed> <prompt> [w] [h] -> asset id on stdout
|
||||||
run_flux() {
|
run_flux() {
|
||||||
local seed="$1" prompt="$2" w="${3:-1024}" h="${4:-1024}"
|
local seed="$1" prompt="$2" w="${3:-1024}" h="${4:-1024}" i out
|
||||||
./mb run flux_local -p prompt="$prompt" -p model=flux2-klein-4b -p steps=4 \
|
for i in $(seq 1 "$MB_TRIES"); do
|
||||||
-p seed="$seed" -p width="$w" -p height="$h" --wait 2>/dev/null \
|
out=$(./mb run flux_local -p prompt="$prompt" -p model=flux2-klein-4b -p steps=4 \
|
||||||
| awk '/image/{print $1}' | tail -1
|
-p seed="$seed" -p width="$w" -p height="$h" --wait 2>/dev/null \
|
||||||
|
| awk '/image/{print $1}' | tail -1)
|
||||||
|
[ -n "$out" ] && { echo "$out"; return; }
|
||||||
|
sleep "$MB_PAUSE"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# run_cutout <asset_id> -> asset id on stdout
|
||||||
|
run_cutout() {
|
||||||
|
local asset="$1" i out
|
||||||
|
for i in $(seq 1 "$MB_TRIES"); do
|
||||||
|
out=$(./mb run bg_remove_local --asset "$asset" -p resolution=2048 --wait 2>/dev/null \
|
||||||
|
| awk '/image/{print $1}' | tail -1)
|
||||||
|
[ -n "$out" ] && { echo "$out"; return; }
|
||||||
|
sleep "$MB_PAUSE"
|
||||||
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# gen_3d <name> <seed> <prompt> — each stage retries once (transient rsync/infra errors happen)
|
# gen_3d <name> <seed> <prompt> — each stage retries once (transient rsync/infra errors happen)
|
||||||
@ -42,24 +65,21 @@ gen_3d() {
|
|||||||
fi
|
fi
|
||||||
[ -z "$img" ] && { echo " ! $name: flux failed twice"; return 1; }
|
[ -z "$img" ] && { echo " ! $name: flux failed twice"; return 1; }
|
||||||
echo "→ [$name] cutout ($img)..."
|
echo "→ [$name] cutout ($img)..."
|
||||||
cut=$(./mb run bg_remove_local --asset "$img" -p resolution=2048 --wait 2>/dev/null | awk '/image/{print $1}' | tail -1)
|
cut=$(run_cutout "$img")
|
||||||
if [ -z "$cut" ]; then
|
[ -z "$cut" ] && { echo " ! $name: bg_remove failed after $MB_TRIES tries"; return 1; }
|
||||||
echo " ~ $name: bg_remove failed, retrying once..."
|
|
||||||
cut=$(./mb run bg_remove_local --asset "$img" -p resolution=2048 --wait 2>/dev/null | awk '/image/{print $1}' | tail -1)
|
|
||||||
fi
|
|
||||||
[ -z "$cut" ] && { echo " ! $name: bg_remove failed twice"; return 1; }
|
|
||||||
echo "→ [$name] mesh ($cut) — ~5 min..."
|
echo "→ [$name] mesh ($cut) — ~5 min..."
|
||||||
local try glb
|
local try glb
|
||||||
for try in 1 2; do
|
for try in $(seq 1 "$MB_TRIES"); do
|
||||||
local tmp; tmp=$(mktemp -d)
|
local tmp; tmp=$(mktemp -d)
|
||||||
./mb run hunyuan3d_mlx --asset "$cut" -p octree_resolution=256 -p texture_size=1024 \
|
./mb run hunyuan3d_mlx --asset "$cut" -p octree_resolution=256 -p texture_size=1024 \
|
||||||
-p max_num_view=6 --wait --download "$tmp" >/dev/null 2>&1
|
-p max_num_view=6 --wait --download "$tmp" >/dev/null 2>&1
|
||||||
glb=$(find "$tmp" -iname '*.glb' | head -1)
|
glb=$(find "$tmp" -iname '*.glb' | head -1)
|
||||||
if [ -n "$glb" ]; then mv "$glb" "$OUT_MODELS/$name.glb"; echo " ✓ $name.glb"; rm -rf "$tmp"; return 0; fi
|
if [ -n "$glb" ]; then mv "$glb" "$OUT_MODELS/$name.glb"; echo " ✓ $name.glb"; rm -rf "$tmp"; return 0; fi
|
||||||
rm -rf "$tmp"
|
rm -rf "$tmp"
|
||||||
[ "$try" = 1 ] && echo " ~ $name: no glb, retrying mesh once..."
|
echo " ~ $name: no glb (try $try/$MB_TRIES), pausing ${MB_PAUSE}s..."
|
||||||
|
sleep "$MB_PAUSE"
|
||||||
done
|
done
|
||||||
echo " ! $name: no glb after retry"
|
echo " ! $name: no glb after $MB_TRIES tries"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +92,7 @@ gen_2d() {
|
|||||||
[ -z "$img" ] && { echo " ! $name: flux failed"; return 1; }
|
[ -z "$img" ] && { echo " ! $name: flux failed"; return 1; }
|
||||||
if [ "$cutout" = "cut" ]; then
|
if [ "$cutout" = "cut" ]; then
|
||||||
echo "→ [$name] cutout..."
|
echo "→ [$name] cutout..."
|
||||||
local c; c=$(./mb run bg_remove_local --asset "$img" -p resolution=2048 --wait 2>/dev/null | awk '/image/{print $1}' | tail -1)
|
local c; c=$(run_cutout "$img")
|
||||||
[ -n "$c" ] && img="$c"
|
[ -n "$c" ] && img="$c"
|
||||||
fi
|
fi
|
||||||
local tmp; tmp=$(mktemp -d)
|
local tmp; tmp=$(mktemp -d)
|
||||||
|
|||||||
@ -169,6 +169,25 @@ export class PrepView implements View {
|
|||||||
mesh.scale.set(1, 0.85, 1);
|
mesh.scale.set(1, 0.85, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'mushroom': {
|
||||||
|
// Cap on a stem; group extent stays ~size so the shared y-offset works.
|
||||||
|
mesh = new THREE.Mesh(new THREE.SphereGeometry(r, 24, 16), skin);
|
||||||
|
mesh.scale.set(1, 0.6, 1);
|
||||||
|
mesh.position.y = ing.size * 0.15;
|
||||||
|
const stemMat = new THREE.MeshStandardMaterial({
|
||||||
|
color: new THREE.Color().setRGB(...ing.colors.flesh, THREE.SRGBColorSpace),
|
||||||
|
roughness: 0.7,
|
||||||
|
});
|
||||||
|
const stem = new THREE.Mesh(
|
||||||
|
new THREE.CylinderGeometry(r * 0.35, r * 0.42, ing.size * 0.6, 16),
|
||||||
|
stemMat,
|
||||||
|
);
|
||||||
|
stem.position.y = -ing.size * 0.15;
|
||||||
|
stem.castShadow = true;
|
||||||
|
stem.receiveShadow = true;
|
||||||
|
g.add(stem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
mesh = new THREE.Mesh(new THREE.SphereGeometry(r, 28, 20), skin);
|
mesh = new THREE.Mesh(new THREE.SphereGeometry(r, 28, 20), skin);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
* 1 world unit ≈ 11cm, same convention as the loaf.
|
* 1 world unit ≈ 11cm, same convention as the loaf.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export type IngredientShape = 'sphere' | 'ovoid' | 'block' | 'wedge' | 'bulb';
|
export type IngredientShape = 'sphere' | 'ovoid' | 'block' | 'wedge' | 'bulb' | 'mushroom';
|
||||||
|
|
||||||
export interface Ingredient {
|
export interface Ingredient {
|
||||||
id: string;
|
id: string;
|
||||||
@ -39,7 +39,10 @@ export type IngredientId =
|
|||||||
| 'parmesan'
|
| 'parmesan'
|
||||||
| 'brie'
|
| 'brie'
|
||||||
| 'cucumber'
|
| 'cucumber'
|
||||||
| 'avocado';
|
| 'avocado'
|
||||||
|
| 'button_mushroom'
|
||||||
|
| 'portobello'
|
||||||
|
| 'king_oyster';
|
||||||
|
|
||||||
export const INGREDIENTS: Record<IngredientId, Ingredient> = {
|
export const INGREDIENTS: Record<IngredientId, Ingredient> = {
|
||||||
tomato: {
|
tomato: {
|
||||||
@ -136,4 +139,39 @@ export const INGREDIENTS: Record<IngredientId, Ingredient> = {
|
|||||||
seeds: { count: 1, pocket: 'core' },
|
seeds: { count: 1, pocket: 'core' },
|
||||||
colors: { skin: [0.16, 0.2, 0.1], flesh: [0.78, 0.85, 0.5] },
|
colors: { skin: [0.16, 0.2, 0.1], flesh: [0.78, 0.85, 0.5] },
|
||||||
},
|
},
|
||||||
|
// The mushrooms: dry-slick skin that skates under a pressed blade, soft
|
||||||
|
// flesh once the edge bites. Three varieties, three different fights.
|
||||||
|
button_mushroom: {
|
||||||
|
id: 'button_mushroom',
|
||||||
|
name: 'button mushroom',
|
||||||
|
shape: 'mushroom',
|
||||||
|
size: 0.3,
|
||||||
|
// Tiny and rolls away from the blade — the slip is the whole challenge.
|
||||||
|
skin: { resistance: 0.15, slippery: 0.75 },
|
||||||
|
flesh: { resistance: 0.15, moisture: 0.35 },
|
||||||
|
roastable: true,
|
||||||
|
colors: { skin: [0.92, 0.88, 0.8], flesh: [0.97, 0.95, 0.9] },
|
||||||
|
},
|
||||||
|
portobello: {
|
||||||
|
id: 'portobello',
|
||||||
|
name: 'portobello',
|
||||||
|
shape: 'mushroom',
|
||||||
|
size: 0.85,
|
||||||
|
skin: { resistance: 0.2, slippery: 0.55 },
|
||||||
|
// Gills crumble when mistreated, and it weeps dark juice.
|
||||||
|
flesh: { resistance: 0.2, moisture: 0.45, layered: true },
|
||||||
|
roastable: true,
|
||||||
|
colors: { skin: [0.45, 0.32, 0.22], flesh: [0.82, 0.76, 0.66] },
|
||||||
|
},
|
||||||
|
king_oyster: {
|
||||||
|
id: 'king_oyster',
|
||||||
|
name: 'king oyster',
|
||||||
|
shape: 'ovoid',
|
||||||
|
size: 1.0,
|
||||||
|
// Mostly one dense smooth stem — cuts like a slippery little log.
|
||||||
|
skin: { resistance: 0.2, slippery: 0.8 },
|
||||||
|
flesh: { resistance: 0.35, moisture: 0.3 },
|
||||||
|
roastable: true,
|
||||||
|
colors: { skin: [0.9, 0.87, 0.78], flesh: [0.96, 0.94, 0.88] },
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user