M10 (code-complete, verification pending — see OPUS-BUILD-BRIEF-2.md §2):
- Brands with mechanical quality (WONDERSLICE 0.25 vs Crustworthy 0.8 etc.):
quality scales heat-map patchiness and crumb fragility. Bakery sourdough is
loaf-only.
- Slicing minigame: aim thickness, saw with vertical strokes; progress/wobble/
squash; wedge slices brown unevenly in the toaster (the bad cut follows you);
squash arrives as pre-existing damage.
- Bread Knife + THE BEST THING (heavy, soft-scalloped, saw eff 1.65) join the
drawer; on loaf days the drawer trip happens BEFORE toasting ("they are
waiting") and whatever you fish out is what you slice with.
- Day 9 handwritten (the inspector wants a doorstop with parallel faces),
procedural brands/loaf days from day 10, The Cut criterion (band + wedge +
squash, TBT signature bonus), cut line bank.
- Verified so far: day-9 ticket chips, knife-trip drawer with bread_knife AND
the_best_thing present, timer label, typecheck + build. Slicer end-to-end
play, tuning, and couplings assertions are itemised in the brief.
OPUS-BUILD-BRIEF-2.md — the prep bench: generalized ingredients + cutting
(slip, juice, piece-evenness CV), the judged mess field, oranges + ribbed
pyramid juicer (halve evenness caps yield, seeds by juicer tier, the
Juicernaut), the grater (zest/pith line, cheese needs cold, knuckles), onions
(sting that blurs REAL vision, the stop-short-of-the-stem criss-cross dice),
and bruschetta as the capstone (temperature planning, roast tomatoes on the
browning field, topping Clark-Evans, the sog clock vs doorstop slices).
Bakery asset batch partially failed (flux errors + one lost GLB) — regen
instructions with retries are in the brief §8.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
112 lines
6.2 KiB
Bash
Executable File
112 lines
6.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# TOASTSIM asset generation — 100% local, 100% free, via MODELBEAST on the M3 Ultra.
|
|
#
|
|
# ./scripts/gen-assets.sh 3d # product shot -> cutout -> GLB (slow: ~5 min each, gpu lane is serial)
|
|
# ./scripts/gen-assets.sh 2d # flux images (judge portraits, backdrops, ui)
|
|
# ./scripts/gen-assets.sh all
|
|
#
|
|
# Seeds are fixed so every asset is re-generatable. Style token is shared for coherence.
|
|
set -uo pipefail
|
|
|
|
MB_DIR="$HOME/Documents/MODELBEAST"
|
|
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
OUT_MODELS="$REPO/public/assets/models"
|
|
OUT_IMG="$REPO/public/assets/img"
|
|
mkdir -p "$OUT_MODELS" "$OUT_IMG"
|
|
|
|
cd "$MB_DIR" || exit 1
|
|
# shellcheck disable=SC1091
|
|
source data/agent.env
|
|
|
|
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"
|
|
|
|
# run_flux <seed> <prompt> [w] [h] -> asset id on stdout
|
|
run_flux() {
|
|
local seed="$1" prompt="$2" w="${3:-1024}" h="${4:-1024}"
|
|
./mb run flux_local -p prompt="$prompt" -p model=flux2-klein-4b -p steps=4 \
|
|
-p seed="$seed" -p width="$w" -p height="$h" --wait 2>/dev/null \
|
|
| awk '/image/{print $1}' | tail -1
|
|
}
|
|
|
|
# gen_3d <name> <seed> <prompt>
|
|
gen_3d() {
|
|
local name="$1" seed="$2" prompt="$3"
|
|
if [ -f "$OUT_MODELS/$name.glb" ]; then echo " = $name.glb exists, skipping"; return; fi
|
|
echo "→ [$name] flux..."
|
|
local img cut
|
|
img=$(run_flux "$seed" "$prompt, $STYLE, $SHOT")
|
|
[ -z "$img" ] && { echo " ! $name: flux failed"; return 1; }
|
|
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)
|
|
[ -z "$cut" ] && { echo " ! $name: bg_remove failed"; return 1; }
|
|
echo "→ [$name] mesh ($cut) — ~5 min..."
|
|
local tmp; tmp=$(mktemp -d)
|
|
./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
|
|
local glb; glb=$(find "$tmp" -iname '*.glb' | head -1)
|
|
if [ -n "$glb" ]; then mv "$glb" "$OUT_MODELS/$name.glb"; echo " ✓ $name.glb"; else echo " ! $name: no glb"; fi
|
|
rm -rf "$tmp"
|
|
}
|
|
|
|
# gen_2d <name> <seed> <prompt> [w] [h] [cutout]
|
|
gen_2d() {
|
|
local name="$1" seed="$2" prompt="$3" w="${4:-1024}" h="${5:-1024}" cutout="${6:-no}"
|
|
if [ -f "$OUT_IMG/$name.png" ]; then echo " = $name.png exists, skipping"; return; fi
|
|
echo "→ [$name] flux..."
|
|
local img; img=$(run_flux "$seed" "$prompt" "$w" "$h")
|
|
[ -z "$img" ] && { echo " ! $name: flux failed"; return 1; }
|
|
if [ "$cutout" = "cut" ]; then
|
|
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)
|
|
[ -n "$c" ] && img="$c"
|
|
fi
|
|
local tmp; tmp=$(mktemp -d)
|
|
./mb get "$img" -o "$tmp" >/dev/null 2>&1
|
|
local f; f=$(find "$tmp" -iname '*.png' -o -iname '*.jpg' | head -1)
|
|
[ -n "$f" ] && { mv "$f" "$OUT_IMG/$name.png"; echo " ✓ $name.png"; }
|
|
rm -rf "$tmp"
|
|
}
|
|
|
|
# ---- the judge: same person every time, seed fixed, only the expression phrase varies ----
|
|
JUDGE="portrait of a stern elderly australian food inspector, deep wrinkles, bushy grey eyebrows, thin wire glasses, grey moustache, wearing a brown cardigan over a shirt and tie, holding a clipboard, plain light grey background, head and shoulders, claymation stop-motion character, soft matte clay texture, warm studio light"
|
|
|
|
do_3d() {
|
|
gen_3d toaster 11 "a retro two-slot pop-up toaster, cream and chrome, with a browning dial"
|
|
gen_3d butter_dish 23 "a ceramic butter dish with a thick block of yellow butter on it, lid off"
|
|
gen_3d pb_jar 31 "an open glass jar of peanut butter, chunky brown spread visible, cream label"
|
|
gen_3d mitey_jar 37 "a small squat glass jar of dark brown yeast extract spread with a bright red and yellow label reading MITEY, lid off"
|
|
gen_3d plate 43 "a simple round white ceramic side plate, empty, seen at an angle"
|
|
}
|
|
|
|
do_2d() {
|
|
gen_2d judge_neutral 101 "$JUDGE, neutral unimpressed expression" 768 768 cut
|
|
gen_2d judge_intrigued 101 "$JUDGE, one eyebrow raised, mildly intrigued expression" 768 768 cut
|
|
gen_2d judge_impressed 101 "$JUDGE, small approving smile, impressed expression" 768 768 cut
|
|
gen_2d judge_disappointed 101 "$JUDGE, deeply disappointed frowning expression, looking down at clipboard" 768 768 cut
|
|
gen_2d judge_horrified 101 "$JUDGE, horrified appalled expression, eyes wide, recoiling" 768 768 cut
|
|
gen_2d bench_wood 202 "seamless top-down texture of a warm honey-toned wooden kitchen benchtop, subtle grain and knife marks, claymation soft matte look, flat even lighting, no objects" 1024 1024
|
|
gen_2d kitchen_backdrop 205 "blurry cosy 1970s australian kitchen interior background, warm cream tiles, soft bokeh, claymation set, no people, no text" 1280 768
|
|
gen_2d ticket_paper 210 "seamless texture of a plain cream paper order docket, faint blue lines, slightly crumpled, flat even lighting, no text" 512 512
|
|
gen_2d title_art 220 "a single slice of golden toast with a pat of butter melting on it, dramatic hero shot, claymation stop-motion, soft matte clay, warm rim light, plain dark background" 1024 768 cut
|
|
}
|
|
|
|
# ---- M10: the bakery (loaves), plus bruschetta ingredients for the milestone after ----
|
|
do_bakery() {
|
|
gen_3d sourdough_loaf 61 "a rustic sourdough boule loaf, round crusty artisan bread with flour-dusted scored top, unsliced"
|
|
gen_3d batard_loaf 67 "a rustic batard bread loaf, oval crusty artisan bread, scored diagonal cuts on top, unsliced"
|
|
gen_3d cutting_board 71 "a thick wooden cutting board with worn edge grain, rectangular with rounded corners"
|
|
gen_3d tomato_vine 73 "three ripe red tomatoes on a green vine, glossy"
|
|
gen_3d roast_tomatoes 79 "a small metal roasting tray of blistered roasted tomato halves, charred edges, juicy"
|
|
gen_3d cheese_hard 83 "a wedge of hard aged parmesan style cheese, pale gold, cracked granular texture"
|
|
gen_3d cheese_soft 89 "a small round of soft white brie style cheese with one wedge cut out showing creamy interior"
|
|
}
|
|
|
|
case "${1:-all}" in
|
|
3d) do_3d ;;
|
|
2d) do_2d ;;
|
|
bakery) do_bakery ;;
|
|
*) do_3d; do_2d ;;
|
|
esac
|
|
echo "done."
|