BLOBBO/dist/assets/main-DezSXIyG.js
type-two eed2eb2646 Lane B (Paint): splat pipeline, coverage compute, buff/threshold framework
The core invention: paint lands on the blob body where projectiles hit, live
per-colour coverage % is computed from a quantized UV mask, and coverage drives
buffs per GDD §6 MVP subset (RED speed+embers, GREEN grip, BLUE waterproof,
total→mass, 20% activate / 70% super+glow).

- src/paint/skin.ts       PaintSkin: Canvas-2D mask on mesh UVs → CanvasTexture;
                          splatAtPoint raycasts impact→face UV; dual soft-canvas
                          + hard quantized-index mask so coverage is exact
                          integer bucketing (never getImageData); 250ms cache;
                          scrub-hole cleanse; U-seam wrap.
- src/paint/coverage-math.ts  pure, unit-tested: countBuckets, coverage report,
                          buffStrength, computeModifiers.
- src/paint/cannon.ts     PaintCannon: gravity-arc glob projectiles (manual
                          swept sphere test), target-leading ballistic solve,
                          fires on interval AND machine:signal; emits paint:splatted.
- src/paint/buffs.ts      BuffSystem: coverage→modifiers each step + ember trail
                          (additive Points) + super-state emissive pulse.
- src/paint/hud.ts        PaintHUD: per-colour bars + active buff kit (throttled).
- src/paint/index.ts      exports + installPaint() wiring the inbound Lane C
                          protocol (request-splat proximity-gated / request-cleanse).
- src/demo/lane-b.ts      stub ball orbiting a RED and GREEN cannon; HUD live;
                          debug keys for fire/signal/flood/cleanse/pause.
- src/paint/coverage-math.test.ts  32 assertions (node --experimental-strip-types).

build: tsc strict + vite pass. No edits outside owned paths; contracts frozen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 20:13:30 +10:00

2 lines
1.1 KiB
JavaScript

import"./modulepreload-polyfill-B5Qt9EMX.js";import{d as p,k as m,M as h,c as f,j as u}from"./world-KhDGgEOv.js";function x(s){const{scene:y,physics:i,rapier:d}=s,c=new p(new m(60,1,60),new h({color:"#e8d9b8"}));c.position.y=-.5,c.receiveShadow=!0,y.add(c),i.createCollider(d.ColliderDesc.cuboid(30,.5,30).setTranslation(0,-.5,0));const o=new p(new f(.6,32,24),new h({color:"#F5F5F7",roughness:.35}));o.castShadow=!0,y.add(o);const a=i.createRigidBody(d.RigidBodyDesc.dynamic().setTranslation(0,3,0));i.createCollider(d.ColliderDesc.ball(.6).setRestitution(.4).setFriction(1),a);const e=new Set;addEventListener("keydown",n=>e.add(n.code)),addEventListener("keyup",n=>e.delete(n.code)),s.addSystem({update(){const t={x:0,z:0};(e.has("KeyW")||e.has("ArrowUp"))&&(t.z-=18),(e.has("KeyS")||e.has("ArrowDown"))&&(t.z+=18),(e.has("KeyA")||e.has("ArrowLeft"))&&(t.x-=18),(e.has("KeyD")||e.has("ArrowRight"))&&(t.x+=18),a.applyImpulse({x:t.x/60,y:0,z:t.z/60},!0);const l=a.translation();o.position.set(l.x,l.y,l.z);const r=a.rotation();o.quaternion.set(r.x,r.y,r.z,r.w)}}),s.onFrame(()=>{s.camera.lookAt(o.position)})}const w=await u(document.getElementById("app"));x(w);w.start();