GDD v0.1: full design doc, idea capture, MODELBEAST farm client + concept wave 1
Fall Guys x Splatoon x Micro Machines — paint-coverage-as-loadout blob racer. GDD.md is the review artifact: feature tiers, draft 7-colour buff table, tech recommendation (web-first three.js+Rapier), milestones, Opus 4.8 lanes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
commit
1506c12759
216
GDD.md
Normal file
216
GDD.md
Normal file
@ -0,0 +1,216 @@
|
||||
# BLOBBO — Game Design Document
|
||||
|
||||
**v0.1 — draft for John's review, 2026-07-17.**
|
||||
Raw idea capture: [docs/IDEA.md](docs/IDEA.md). Everything below is proposed-for-review;
|
||||
⚠️ marks decisions that need John's sign-off before Opus 4.8 execution lanes are written.
|
||||
|
||||
---
|
||||
|
||||
## 1. Pitch
|
||||
|
||||
**Fall Guys × Splatoon × Micro Machines.** Up to dozens of friendly white blobby
|
||||
dudes race giant absurd Rube-Goldberg obstacle courses. Paint cannons along the
|
||||
course spray colour — whatever sticks to your body is your loadout: **the relative
|
||||
% coverage of each colour is your buff kit.** The course paints you; being painted
|
||||
changes how you race the course.
|
||||
|
||||
**The invention nobody else has:** paint coverage measured *on your own body* as
|
||||
the skill system, inside a physics-comedy racer where the course is one giant
|
||||
player-triggered machine.
|
||||
|
||||
## 2. Pillars
|
||||
|
||||
1. **Comedy through physics** — soft wobbly blobs, out-of-scale props, telegraphed
|
||||
chain reactions. Funny beats fair; fair beats random.
|
||||
2. **Paint is everything** — identity, buffs, weight, size, strategy all read off
|
||||
your painted body. No HUD-first design: your state is visible on you.
|
||||
3. **Readable chaos** — every contraption telegraphs ~0.5s before it fires.
|
||||
Getting flattened must feel earned/funny, never random (random = ragequit).
|
||||
4. **One goo universe** — players are goo; the world fights back with other goo
|
||||
(paint, honey, oil, mud, water, bubbles). Viscosity playground, not gimmick pile.
|
||||
|
||||
## 3. The Blobbo
|
||||
|
||||
Friendly white soft-body blob — Michelin-man silhouette, fewer rolls, big eyes.
|
||||
Starts every race clean/white. Accumulates paint as a visible skin layer.
|
||||
Soft-body wobble is cosmetic (shader/spring jiggle over a rigid physics proxy —
|
||||
see §9); the comedy is in the wobble, the determinism is in the capsule.
|
||||
|
||||
## 4. Core loop
|
||||
|
||||
Race an obstacle course → paint cannons/zones spray colour → manage your coverage
|
||||
mix (seek, avoid, cleanse, smudge) → coverage grants buffs that change traversal →
|
||||
buffs + weight + size interact with the course machinery → finish placement →
|
||||
next round / next course.
|
||||
|
||||
## 5. Feature list
|
||||
|
||||
Tiers: **[MVP]** first playable · **[V1]** launch · **[V2]** post-launch/stretch.
|
||||
|
||||
### 5.1 Paint system (the core)
|
||||
- **[MVP]** 7 main colours; per-player texture-space coverage mask; live % per colour.
|
||||
- **[MVP]** Buff activates at threshold (⚠️ proposal: ≥20% coverage), strength
|
||||
scales with %; dominant colour drives visual/audio identity.
|
||||
- **[V1]** **Secondary blends**: two adjacent colours both ≥20% → blend effect
|
||||
replaces/joins the pair (see §6 table). Way more permutations, mastery =
|
||||
deliberately building a mix.
|
||||
- **[V1]** **Super-state**: ≥70% one colour = amped version of the buff **with a
|
||||
drawback** — you glow, you're a target, one detergent bubble wrecks you.
|
||||
- **[MVP]** **Cleansing**: detergent bubbles on course (full or partial cleanse ⚠️),
|
||||
water rinses gradually.
|
||||
- **[V1]** **Contact smudging**: bumping other blobs *transfers* paint both ways
|
||||
(⚠️ transfer vs. plain removal — transfer is funnier and more strategic).
|
||||
- **[V2]** Paint flaking: growing stretches/cracks paint off in pickup-able flakes.
|
||||
|
||||
### 5.2 Weight (paint = mass)
|
||||
- **[MVP]** Coverage adds mass: heavy blobs sink pressure plates, tip see-saws,
|
||||
wobble slower, launch shorter; clean blobs are light and flingable.
|
||||
- **[MVP]** Detergent bubbles double as tactical weight-drops.
|
||||
- **[V1]** Buoyancy inversion underwater: clean floats (fast surface lane),
|
||||
painted sinks (slow bottom lane, better pickups).
|
||||
|
||||
### 5.3 Scale (environment scale as mechanic)
|
||||
- **[V1]** Colour-driven size: ⚠️ purple = grow, pink = shrink (see §6). Big =
|
||||
heavy/blocks/easy target; small = pipe shortcuts/hard to hit/flung far.
|
||||
- **[V1]** Paint dilution: growing increases surface area → your % coverage drops.
|
||||
Size trades directly against your buff loadout.
|
||||
- **[V1]** Scale zones: shrink sections racing *inside* the machine (marble runs,
|
||||
domino chains, gear guts); giant sections stomping over a model town while tiny
|
||||
racers dodge your feet.
|
||||
- **[V2]** Players as course furniture: a giant blob is a platform/counterweight
|
||||
for tiny blobs — the machine incorporates the players.
|
||||
|
||||
### 5.4 Course-as-machine (Rube Goldberg)
|
||||
- **[MVP]** Contraption toolkit: see-saws, boots, buckets, conveyors, dominoes,
|
||||
gears, catapults, fans — **triggered by players, not timers**. Everyone upstream
|
||||
rigs the course for everyone downstream.
|
||||
- **[MVP]** Telegraph rule: every chain reaction winds up visibly ~0.5s before firing.
|
||||
- **[V1]** Colour-keyed machinery: mechanisms respond only to blobs of their
|
||||
colour (green valve needs a mostly-green blob → shortcut opens for them + any
|
||||
tailgaters). Emergent alliances, zero UI.
|
||||
- **[V1]** Persistent course state: triggered contraptions stay tripped/reset
|
||||
slowly; sprayed paint lingers on surfaces as slip/grip zones. Back of the pack
|
||||
races a messier course — chaos as natural rubber-banding.
|
||||
- **[V2]** Gravity switches as contraption outputs: a lever flips gravity for a
|
||||
zone; heavy blobs slam, light blobs drift. Ceiling-runs through upside-down rooms.
|
||||
|
||||
### 5.5 Physics zones & surfaces
|
||||
- **[V1]** **Underwater**: buoyancy lanes + gradual paint rinse (shortcut costs loadout).
|
||||
- **[V2]** **Zero-g**: momentum pinball; paint floats as wobbly globs mid-air —
|
||||
fly through one to wear it.
|
||||
- **[V1]** **Honey**: slow but sticky — climb walls/ceilings. Traversal tool.
|
||||
- **[V1]** **Oil**: fast, no steering, luge; fire-buffed blob ignites a trail
|
||||
behind them (emergent trap-laying).
|
||||
- **[V1]** **Mud = anti-paint**: coats brown, masks colours, suppresses buffs until
|
||||
washed — makes water double-edged.
|
||||
- **[MVP]** Surface material framework (friction/stick/flow per material) so all
|
||||
of the above are data, not code.
|
||||
|
||||
### 5.6 World & tone
|
||||
- **[MVP]** Out-of-scale everyday settings (Micro Machines DNA): giant kitchen
|
||||
tables, gardens, bathtubs, desks; comically huge and tiny props.
|
||||
- **[V1]** Course sections themed as rooms of one absurd oversized house.
|
||||
|
||||
### 5.7 Format & multiplayer
|
||||
- **[MVP]** Local-feel party size first: 8-player online rooms, single race.
|
||||
- **[V1]** 30–40 player fields, multi-round elimination show (Fall Guys format).
|
||||
- **[V1]** **Server-authoritative simulation + anti-cheat from day one** — cheating
|
||||
is what soured Fall Guys; non-negotiable design constraint, not a patch.
|
||||
- **[V2]** Spectator/replay clips (the game is a clip generator — lean in).
|
||||
|
||||
## 6. Draft colour/buff table ⚠️ (the big review item)
|
||||
|
||||
7 mains on a wheel; adjacent pairs blend. All names/effects are proposals.
|
||||
|
||||
| Colour | Buff | Effect | Drawback / texture |
|
||||
|---|---|---|---|
|
||||
| **Red** | BURN | Speed-boost flame trail; ignites oil; melts wax/ice barriers | Slowly burns itself off (self-consuming coverage) |
|
||||
| **Orange** | BOUNCE | Rubberized — higher bounces, contraptions launch you further | Harder to stop precisely |
|
||||
| **Yellow** | ZAP | Trigger colour-keyed machinery at range; static bump-stun | Attracts to metal (yanked toward rails/magnets) |
|
||||
| **Green** | GRIP | Sticky feet — immune to oil/ice slip, climb like honey, hold on through gravity flips | Slower top speed |
|
||||
| **Blue** | SLICK | Waterproof (no rinse), swim jets, leaves a slippery trail | Your own trail is slippery to you too |
|
||||
| **Purple** | MEGA | Grow big + heavy — plates, see-saws, shoving, blocking | Paint dilutes as you grow; huge target |
|
||||
| **Pink** | MINI | Shrink small + light — pipe shortcuts, hard to hit, mega-flung | Can't trigger plates; gusts/fans own you |
|
||||
|
||||
Example blends (adjacent, both ≥20%) — final list needs a full pass:
|
||||
- Red+Orange **METEOR** — flaming cannonball launches, smash light barriers.
|
||||
- Orange+Yellow **PINBALL** — each bounce zaps nearby machinery.
|
||||
- Yellow+Green **MAGNET** — stick to metal surfaces/rails, ride them.
|
||||
- Green+Blue **SNAILGOD** — climbable slime trail others can also use.
|
||||
- Blue+Purple **TSUNAMI** — heavy water cannonball; splash rinses nearby players.
|
||||
- Pink+Red **ROCKET** — tiny + flaming = fastest projectile in the game.
|
||||
|
||||
## 7. Courses (initial set sketch)
|
||||
|
||||
1. **Breakfast Rush** [MVP greybox] — giant kitchen table; toaster launchers,
|
||||
cereal avalanches, milk river (water zone), butter pat (oil).
|
||||
2. **The Machine** [V1] — you shrink and race *through* the Rube Goldberg engine
|
||||
that powers the house: marble runs, dominoes, gears.
|
||||
3. **Bathtime** [V1] — bathtub ocean, soap-bubble cleansers everywhere, honey
|
||||
(shampoo) walls, mud garden outside the window.
|
||||
4. **Model Village** [V2] — grow-shrink alternating; giants stomp the village
|
||||
while minis race through it.
|
||||
|
||||
## 8. Asset plan (MODELBEAST — local, free)
|
||||
|
||||
- **Concept wave (queued now)**: blobbo character sheet, painted variants, course
|
||||
vistas, contraption props, paint cannon, bubble zone, logo explorations —
|
||||
`flux_local` on the m3ultra farm.
|
||||
- **Mesh wave (after concept review)**: hero props + blobbo base mesh via
|
||||
image→GLB (`hunyuan3d_mlx` / `trellis_mac` / `sf3d`), Blender finish on ultra.
|
||||
- Blobbo is a **bespoke simple mesh** (sphere-blob + blend shapes), not a
|
||||
character_kit humanoid — the 2-base-mesh fleet rule doesn't apply, but clips/
|
||||
rigs stay out of web builds per licensing zones (all generated = 🟢 web-ok).
|
||||
- Paint itself is **procedural** (shader + splat decals), not generated art.
|
||||
|
||||
## 9. Tech stack ⚠️ (recommendation, needs sign-off)
|
||||
|
||||
**Recommend: web-first, three.js + Rapier (WASM), server-authoritative Node room
|
||||
server, docker-deployed to the games VPS (partly.party) like the other games.**
|
||||
|
||||
- Fits the existing pipeline: GLB assets, browser distribution, docker deploys,
|
||||
MRPGI/character-kit tooling knowledge.
|
||||
- **Soft-body is faked**: rigid capsule/sphere physics proxy + cosmetic jiggle
|
||||
(vertex springs/shader). Real soft-body × 40 players × netcode is not shippable;
|
||||
fake wobble is indistinguishable in comedy terms.
|
||||
- **Paint = Splatoon technique**: per-player UV-space mask texture, splats
|
||||
rendered into it, GPU mip/reduction pass → live coverage %. Cheap, exact.
|
||||
- Server runs headless Rapier as authority; clients interpolate. MVP at 8 players,
|
||||
architecture sized for 40.
|
||||
- **Decision gate**: if browser perf caps out at M1 milestone, port call to
|
||||
Godot 4 (native) — flagged early, evaluated with data.
|
||||
|
||||
## 10. Milestones
|
||||
|
||||
- **M0 — Playground**: one greybox course, blob movement + jiggle, camera. Feels funny to walk.
|
||||
- **M1 — Paint MVP**: splat pipeline, coverage %, 3 colours + buffs (Red/Green/Blue), bubbles, weight. *Decision gate on stack.*
|
||||
- **M2 — The Machine**: contraption toolkit, telegraphs, surface materials, Breakfast Rush course.
|
||||
- **M3 — Multiplayer**: 8-player rooms, server authority, smudging, race format.
|
||||
- **M4 — The Show**: all 7 colours + blends, scale system, 2nd course, juice/VFX/audio, 40-player test.
|
||||
|
||||
## 11. Opus 4.8 execution lanes (preview — full instructions after this doc is approved)
|
||||
|
||||
- **Lane A — Engine/feel**: bootstrap, blob controller, camera, jiggle, greybox playground.
|
||||
- **Lane B — Paint**: splat pipeline, coverage compute, buff/threshold/blend framework.
|
||||
- **Lane C — Machine**: contraption toolkit, triggers/telegraphs, surface materials, gravity/zones.
|
||||
- **Lane D — Netcode**: room server, authoritative sim, interpolation, anti-cheat posture.
|
||||
- **Lane E — Art**: MODELBEAST asset flow → GLB integration, paint shader look-dev, VFX.
|
||||
|
||||
Lanes A–C can start in parallel worktrees; D after A stabilizes the sim contract;
|
||||
E continuous. Each lane gets its own instruction doc + acceptance criteria.
|
||||
|
||||
## 12. Risks
|
||||
|
||||
1. **Netcode × physics** — the classic killer. Mitigation: fake soft-body, authoritative server, small MVP player count.
|
||||
2. **Readability under chaos** — mitigation: telegraph rule as a pillar, paint identity visible on bodies.
|
||||
3. **Scope** — this doc is huge. Mitigation: tiers are real; MVP is one course, 3 colours, 8 players.
|
||||
4. **Cheating** — server authority from day one; never trust client physics.
|
||||
|
||||
## 13. Open questions for review ⚠️
|
||||
|
||||
1. Buff table (§6) — right 7? right effects? purple/pink as the size pair?
|
||||
2. Thresholds: 20% activate / 70% super — feel right?
|
||||
3. Smudge = transfer (steal paint) or removal only?
|
||||
4. Detergent bubbles: full cleanse or dominant-colour-only?
|
||||
5. Tech stack sign-off (§9) — web-first OK?
|
||||
6. Name check: BLOBBO vs. globbo (folder says globbo, repo says BLOBBO).
|
||||
14
README.md
Normal file
14
README.md
Normal file
@ -0,0 +1,14 @@
|
||||
# BLOBBO
|
||||
|
||||
Fall Guys × Splatoon × Micro Machines: wobbly blob racers on giant Rube-Goldberg
|
||||
courses where **the paint that lands on you is your loadout** — relative %
|
||||
coverage per colour = your buffs, weight, and size.
|
||||
|
||||
- **[GDD.md](GDD.md)** — the design document (v0.1, in review). Start here.
|
||||
- [docs/IDEA.md](docs/IDEA.md) — the original raw idea capture (2026-07-17).
|
||||
- [tools/mb.py](tools/mb.py) — MODELBEAST farm client (concept art / mesh gen
|
||||
on the local render farm). `tools/concept-wave-1.json` = first asset wave.
|
||||
- `assets/concepts/` — generated concept art (review gate for the mesh wave).
|
||||
|
||||
Status: **pre-production.** GDD under review; next step is per-lane execution
|
||||
instructions (see GDD §11) once features are signed off.
|
||||
BIN
assets/concepts/blobbo-character-sheet.png
Normal file
BIN
assets/concepts/blobbo-character-sheet.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 872 KiB |
BIN
assets/concepts/blobbo-painted-fire.png
Normal file
BIN
assets/concepts/blobbo-painted-fire.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 899 KiB |
BIN
assets/concepts/course-breakfast-rush.png
Normal file
BIN
assets/concepts/course-breakfast-rush.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
106
docs/IDEA.md
Normal file
106
docs/IDEA.md
Normal file
@ -0,0 +1,106 @@
|
||||
# GLOBBO — paint-buff blob racing
|
||||
|
||||
*Captured 2026-07-17. Raw idea, pre-design.*
|
||||
|
||||
## Elevator pitch
|
||||
Fall Guys × Splatoon. Friendly white blobby dudes (Michelin-man-ish, fewer rolls)
|
||||
race a giant absurd Rube-Goldberg obstacle course. Paint cannons along the course
|
||||
spray colour; whatever sticks to you matters — **your relative % coverage of each
|
||||
colour is your buff/skill loadout**. The course paints you, and being painted
|
||||
changes how you play the course.
|
||||
|
||||
## Core mechanic — paint as loadout
|
||||
- 7 primary colours, each mapped to a buff/effect (e.g. mostly-red = on fire /
|
||||
speed burn, blue = ?, green = ?, etc.)
|
||||
- Buffs scale with (or unlock at) **relative % of total coverage** — probably a
|
||||
minimum threshold so trace splatter doesn't flicker buffs on/off.
|
||||
- **Secondary blends**: adjacent colours mix (red+yellow zones on your body, or
|
||||
overall ratio ≈ orange) → way more permutations than 7. Mastery = deliberately
|
||||
building a blend, not just grabbing one colour.
|
||||
- Course gives repeated chances at each colour → routing decisions: detour for
|
||||
the paint you want vs. straight line.
|
||||
|
||||
## Counterplay / paint economy
|
||||
- **Detergent bubbles** on course: cleanse (full or partial?) — reset a bad mix.
|
||||
- **Bumping other players smudges paint off/onto each other** — contact matters,
|
||||
griefers can wipe your carefully built loadout, or you can steal/share colour.
|
||||
- Open Q: does smudging transfer colour (I take some of yours) or just remove?
|
||||
Transfer is funnier and more strategic.
|
||||
|
||||
## Tone / physics
|
||||
- Gravity-heavy, Rube-Goldberg-esque, out-of-scale props (comically huge and
|
||||
tiny things) — absurd and funny, not sweaty.
|
||||
- Blob physics: soft-body wobble is half the comedy (see Fall Guys, Gang Beasts,
|
||||
Human Fall Flat).
|
||||
|
||||
## Course as machine (the extra Rube Goldberg twist)
|
||||
- **Players are the marbles**: contraptions are triggered by blobs, not timers.
|
||||
See-saw → boot → bucket → conveyor → paint dump on the tunnel below. Everyone
|
||||
upstream is constantly (accidentally or deliberately) rigging the course for
|
||||
everyone downstream.
|
||||
- **Paint = weight**: coverage adds mass. Heavy blobs sink pressure plates and
|
||||
tip see-saws but wobble slower / launch shorter. Merges the paint system and
|
||||
the contraption system into one — route for colour *and* for mass, and
|
||||
detergent bubbles become tactical weight-drops, not just buff-resets.
|
||||
- **Colour-keyed machinery**: some mechanisms only respond to a blob of their
|
||||
colour (mostly-green blob turns the green valve → shortcut opens for them and
|
||||
anyone tailgating). Emergent temporary alliances, no UI.
|
||||
- **The course remembers**: triggered contraptions stay tripped / reset slowly;
|
||||
sprayed paint lingers on surfaces as slip/grip zones (Splatoon-style). The
|
||||
back of the pack races a messier course than the leaders — chaos as natural
|
||||
rubber-banding.
|
||||
- **Readability rule**: every chain reaction telegraphs for ~0.5s (winding
|
||||
gears, teetering buckets) so getting flattened reads as funny/earned, never
|
||||
random. Random deaths are what make ragdoll racers rage-inducing.
|
||||
|
||||
## Scale play (environment scale as a mechanic, not just art)
|
||||
- **Scale zones**: shrink sections where you race *inside* the machine (marble
|
||||
runs, domino chains, between gears); giant sections where you stomp over a
|
||||
model town and the tiny racers dodge your footsteps.
|
||||
- **A colour controls size** (e.g. purple = grow, pink = shrink) — plugs into
|
||||
weight/contraption systems: big = heavy, triggers plates, blocks paths, easy
|
||||
paint target; small = light, pipe shortcuts, hard to hit, flung far.
|
||||
- **Paint stretches with you**: growing dilutes coverage % (surface area up,
|
||||
paint spread thin, maybe flakes off for others to grab); shrinking
|
||||
concentrates it. Size trades directly against your buff loadout.
|
||||
- **Players as course furniture**: a giant blob is a platform/obstacle/
|
||||
counterweight for tiny blobs — the machine incorporates the players.
|
||||
- Prior art: Superliminal (perspective scale tricks), Katamari (scale
|
||||
escalation), Grounded (tiny-scale traversal).
|
||||
|
||||
## Physics zones & surfaces (everything is goo/viscosity)
|
||||
- **Gravity switches**: contraption outputs, not fixed — a lever flips gravity
|
||||
for a zone. Heavy painted blobs slam to the new floor, light clean blobs
|
||||
drift. Ceiling-running through upside-down oversized rooms.
|
||||
- **Underwater**: buoyancy = inverse weight. Clean blobs float across the top
|
||||
(fast lane), paint-heavy blobs sink (slow lane, better pickups?). Water
|
||||
slowly rinses paint — underwater shortcuts cost loadout.
|
||||
- **Zero-g / space**: momentum pinball; paint floats as wobbly globs in the
|
||||
air — fly through one to wear it. Mid-air coating unique to zero-g.
|
||||
- **Honey**: slow but sticky = climb walls/ceilings. Traversal tool.
|
||||
- **Oil**: fast, no steering, luge. Fire-buff blob crossing oil ignites a
|
||||
trail behind them — emergent trap-laying.
|
||||
- **Mud = anti-paint**: coats you brown, masks colours, suppresses buffs until
|
||||
washed off. The debuff you wear; makes water sections double-edged.
|
||||
- Theme glue: players are goo, environment fights back with other goo. One
|
||||
coherent viscosity playground, not a gimmick grab-bag.
|
||||
|
||||
## Open questions
|
||||
- Buff table for the 7 primaries + which blends do what.
|
||||
- Threshold model: min % to activate? dominant-colour-only? top-2 blend?
|
||||
- Is 100% one colour a super-state ("all red = on fire") with a downside
|
||||
(visible, targetable, one bubble ruins you)?
|
||||
- Player count / real-time netcode (Fall Guys did 60; soft-body + paint sim +
|
||||
50 players online is the hard engineering problem).
|
||||
- Does paint also affect the *course* (Splatoon-style ink on surfaces = grip /
|
||||
slip zones) or only the player?
|
||||
- Anti-cheat from day one — cheating is literally what soured Fall Guys.
|
||||
|
||||
## Prior art
|
||||
- **Fall Guys** — the racing/format template (the game John couldn't name).
|
||||
- **Splatoon** — paint identity, coverage %, but coverage is territory not self.
|
||||
- **Micro Machines / Re-Volt / Toy Commander** — out-of-scale courses: tiny
|
||||
racers in giant everyday environments (breakfast tables, supermarkets, a
|
||||
whole house). The scale-absurdity tone reference.
|
||||
- (Not these but adjacent: Army Men, Toy Soldiers — toy-scale combat, not racing.)
|
||||
- Key novelty: coverage is measured **on your own body** and is your skill kit.
|
||||
BIN
tools/__pycache__/mb.cpython-314.pyc
Normal file
BIN
tools/__pycache__/mb.cpython-314.pyc
Normal file
Binary file not shown.
34
tools/concept-wave-1.json
Normal file
34
tools/concept-wave-1.json
Normal file
@ -0,0 +1,34 @@
|
||||
[
|
||||
{
|
||||
"name": "blobbo-character-sheet",
|
||||
"prompt": "Character concept turnaround sheet for a friendly white blob mascot creature, soft rounded body like a simplified michelin man with subtle segments, big cute glossy eyes, tiny smile, stubby arms and feet, front view and side view, clean light studio background, modern 3D game character concept art, playful stylized look"
|
||||
},
|
||||
{
|
||||
"name": "blobbo-painted-fire",
|
||||
"prompt": "Friendly white blob mascot creature mid-run in a racing pose, splattered head to toe in bright red and orange paint that glows like embers, drips and splats, leaving small flames behind, energetic game concept art, vibrant colors, light background"
|
||||
},
|
||||
{
|
||||
"name": "course-breakfast-rush",
|
||||
"prompt": "Game environment concept art, wide shot: an obstacle course race across a giant breakfast table from a tiny creature's perspective, absurd rube goldberg machines, toaster catapult launching toast, cereal box avalanche, milk river, sugar cube stepping stones, ramps and see-saws made of cutlery, bright playful saturated colors"
|
||||
},
|
||||
{
|
||||
"name": "prop-paint-cannon",
|
||||
"prompt": "Game prop concept art on white background: a chunky oversized cartoon paint cannon loaded with bright yellow paint, friendly toy-like design, mounted on a wooden rube goldberg contraption with big gears and a big red lever, paint drips around the muzzle"
|
||||
},
|
||||
{
|
||||
"name": "prop-bubble-cleanser",
|
||||
"prompt": "Game environment prop concept: a giant bubble wand archway over a race track blowing iridescent soap bubbles and foam, sparkling clean zone, playful cartoon style, bright lighting, concept art"
|
||||
},
|
||||
{
|
||||
"name": "prop-contraption-sheet",
|
||||
"prompt": "Concept art sheet of rube goldberg contraptions for a physics racing game, white background: giant boot on a spring kicking a paint bucket, wooden see-saw, conveyor belt, giant dominoes, huge interlocking gears, catapult, chunky friendly toy-like designs, bright colors"
|
||||
},
|
||||
{
|
||||
"name": "logo-blobbo",
|
||||
"prompt": "Video game logo, the word BLOBBO written in fat glossy white blob letters dripping with rainbow paint splatters, bold and playful, centered on a clean white background, vibrant, professional game branding"
|
||||
},
|
||||
{
|
||||
"name": "course-model-village",
|
||||
"prompt": "Comedic game concept art: a giant friendly white blob creature covered in purple paint stomping carefully through a tiny model village racetrack while tiny blob creatures race between its feet, dramatic scale difference, bright cheerful colors, wide shot"
|
||||
}
|
||||
]
|
||||
186
tools/mb.py
Normal file
186
tools/mb.py
Normal file
@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env python3
|
||||
"""mb.py — BLOBBO client for the MODELBEAST farm (m3ultra central queue :8777).
|
||||
|
||||
Contract per ~/Documents/MESHGOD/scripts/mb_recon.py (verified 2026-07-16):
|
||||
Bearer MB_TOKEN (env, else ~/Documents/backnforth/.env), POST /api/jobs,
|
||||
poll GET /api/jobs/{id}, retrieve own assets by parent_job (never newest-glob —
|
||||
concurrent jobs race). Job JSON may carry raw control chars — strip pre-parse.
|
||||
Guest tier: max 4 active jobs, enforced here with a submit window.
|
||||
|
||||
Usage:
|
||||
mb.py gen "<prompt>" out.png one flux_local image
|
||||
mb.py batch prompts.json outdir/ [{"name":..,"prompt":..,"operator"?,"params"?}]
|
||||
mb.py img2glb in.png out.glb [operator] image -> mesh (default hunyuan3d_mlx)
|
||||
mb.py jobs list my recent jobs
|
||||
"""
|
||||
import json, mimetypes, os, sys, time, urllib.request, urllib.error, uuid
|
||||
|
||||
HOST = os.environ.get('MB_HOST', 'http://100.89.131.57:8777')
|
||||
MAX_ACTIVE = 4
|
||||
|
||||
|
||||
def token():
|
||||
t = os.environ.get('MB_TOKEN')
|
||||
if t:
|
||||
return t
|
||||
for line in open(os.path.expanduser('~/Documents/backnforth/.env')):
|
||||
if line.startswith('MB_TOKEN='):
|
||||
return line.split('=', 1)[1].strip()
|
||||
sys.exit('no MB_TOKEN')
|
||||
|
||||
|
||||
def req(path, data=None, headers=None, raw=False):
|
||||
h = {'Authorization': f'Bearer {token()}'}
|
||||
h.update(headers or {})
|
||||
r = urllib.request.Request(HOST + path, data=data, headers=h)
|
||||
body = urllib.request.urlopen(r, timeout=180).read()
|
||||
if raw:
|
||||
return body
|
||||
s = body.decode('utf-8', 'replace')
|
||||
return json.loads(''.join(c if c >= ' ' or c in '\t' else ' ' for c in s))
|
||||
|
||||
|
||||
def submit(operator, params=None, asset_id=None):
|
||||
"""Returns job id, or None on 429 (farm throttles submits harder than the
|
||||
4-active contract — observed 429 on the 4th rapid submit, 2026-07-17)."""
|
||||
payload = {'operator': operator, 'params': params or {}}
|
||||
if asset_id:
|
||||
payload['asset_id'] = asset_id
|
||||
try:
|
||||
j = req('/api/jobs', data=json.dumps(payload).encode(),
|
||||
headers={'Content-Type': 'application/json'})
|
||||
except urllib.error.HTTPError as e:
|
||||
if e.code == 429:
|
||||
return None
|
||||
raise
|
||||
return j['id']
|
||||
|
||||
|
||||
def status(jid):
|
||||
return req(f'/api/jobs/{jid}').get('status')
|
||||
|
||||
|
||||
def upload(path):
|
||||
boundary = uuid.uuid4().hex
|
||||
ctype = mimetypes.guess_type(path)[0] or 'application/octet-stream'
|
||||
name = os.path.basename(path)
|
||||
body = (f'--{boundary}\r\nContent-Disposition: form-data; name="file"; filename="{name}"\r\n'
|
||||
f'Content-Type: {ctype}\r\n\r\n').encode() + open(path, 'rb').read() + f'\r\n--{boundary}--\r\n'.encode()
|
||||
a = req('/api/assets', data=body, headers={'Content-Type': f'multipart/form-data; boundary={boundary}'})
|
||||
return a.get('id') or (a.get('items') or [a])[0].get('id')
|
||||
|
||||
|
||||
def outputs_for(jid, suffix=None):
|
||||
a = req('/api/assets?limit=200')
|
||||
items = a if isinstance(a, list) else a.get('items', [])
|
||||
mine = [x for x in items if x.get('parent_job') == jid]
|
||||
if suffix:
|
||||
mine = [x for x in mine if str(x.get('filename', x.get('name', ''))).endswith(suffix)]
|
||||
return mine
|
||||
|
||||
|
||||
def fetch(asset_id, out):
|
||||
data = req(f'/api/assets/{asset_id}/file', raw=True)
|
||||
open(out, 'wb').write(data)
|
||||
return len(data)
|
||||
|
||||
|
||||
def wait(jid, label='', interval=6):
|
||||
t0 = time.time()
|
||||
while True:
|
||||
st = status(jid)
|
||||
if st in ('done', 'error', 'cancelled'):
|
||||
print(f'[mb] {label or jid}: {st} ({int(time.time()-t0)}s)', flush=True)
|
||||
return st
|
||||
time.sleep(interval)
|
||||
|
||||
|
||||
def cmd_gen(prompt, out):
|
||||
jid = submit('flux_local', {'prompt': prompt})
|
||||
if wait(jid, out) != 'done':
|
||||
sys.exit(1)
|
||||
outs = outputs_for(jid)
|
||||
if not outs:
|
||||
sys.exit('[mb] no output asset for job')
|
||||
n = fetch(outs[0]['id'], out)
|
||||
print(f'[mb] wrote {out} ({n//1024}KB)')
|
||||
|
||||
|
||||
def cmd_batch(spec_path, outdir):
|
||||
jobs = json.load(open(spec_path))
|
||||
os.makedirs(outdir, exist_ok=True)
|
||||
done_names = {os.path.splitext(f)[0] for f in os.listdir(outdir)}
|
||||
jobs = [j for j in jobs if j['name'] not in done_names]
|
||||
if done_names:
|
||||
print(f'[mb] resume: skipping {len(done_names)} already in {outdir}', flush=True)
|
||||
pending, active, results = list(jobs), {}, {}
|
||||
while pending or active:
|
||||
while pending and len(active) < MAX_ACTIVE:
|
||||
job = pending[0]
|
||||
params = dict(job.get('params', {}))
|
||||
if 'prompt' in job:
|
||||
params.setdefault('prompt', job['prompt'])
|
||||
jid = submit(job.get('operator', 'flux_local'), params)
|
||||
if jid is None:
|
||||
print('[mb] throttled (429), backing off 15s', flush=True)
|
||||
time.sleep(15)
|
||||
break
|
||||
pending.pop(0)
|
||||
active[jid] = job
|
||||
print(f'[mb] submitted {job["name"]} -> {jid}', flush=True)
|
||||
time.sleep(6)
|
||||
for jid in list(active):
|
||||
st = status(jid)
|
||||
if st in ('done', 'error', 'cancelled'):
|
||||
job = active.pop(jid)
|
||||
results[job['name']] = st
|
||||
if st == 'done':
|
||||
outs = outputs_for(jid)
|
||||
if outs:
|
||||
name = str(outs[0].get('filename', outs[0].get('name', 'out')))
|
||||
ext = os.path.splitext(name)[1] or '.png'
|
||||
out = os.path.join(outdir, job['name'] + ext)
|
||||
n = fetch(outs[0]['id'], out)
|
||||
print(f'[mb] {job["name"]}: done -> {out} ({n//1024}KB)', flush=True)
|
||||
else:
|
||||
print(f'[mb] {job["name"]}: done but no asset visible', flush=True)
|
||||
results[job['name']] = 'done-no-asset'
|
||||
else:
|
||||
print(f'[mb] {job["name"]}: {st}', flush=True)
|
||||
bad = {k: v for k, v in results.items() if v != 'done'}
|
||||
print(f'[mb] batch complete: {len(results)-len(bad)}/{len(results)} ok'
|
||||
+ (f' — failed: {bad}' if bad else ''))
|
||||
|
||||
|
||||
def cmd_img2glb(img, out, operator='hunyuan3d_mlx'):
|
||||
aid = upload(img)
|
||||
print(f'[mb] uploaded {os.path.basename(img)} -> asset {aid}')
|
||||
jid = submit(operator, {}, asset_id=aid)
|
||||
if wait(jid, out, interval=10) != 'done':
|
||||
sys.exit(1)
|
||||
outs = outputs_for(jid, '.glb')
|
||||
if not outs:
|
||||
sys.exit('[mb] no glb for job')
|
||||
n = fetch(outs[0]['id'], out)
|
||||
print(f'[mb] wrote {out} ({n//1024}KB)')
|
||||
|
||||
|
||||
def cmd_jobs():
|
||||
j = req('/api/jobs?limit=20')
|
||||
items = j if isinstance(j, list) else j.get('items', [])
|
||||
for x in items:
|
||||
print(x.get('id'), x.get('operator'), x.get('status'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
cmd = sys.argv[1] if len(sys.argv) > 1 else ''
|
||||
if cmd == 'gen':
|
||||
cmd_gen(sys.argv[2], sys.argv[3])
|
||||
elif cmd == 'batch':
|
||||
cmd_batch(sys.argv[2], sys.argv[3])
|
||||
elif cmd == 'img2glb':
|
||||
cmd_img2glb(*sys.argv[2:5])
|
||||
elif cmd == 'jobs':
|
||||
cmd_jobs()
|
||||
else:
|
||||
sys.exit(__doc__)
|
||||
Loading…
Reference in New Issue
Block a user