Upload index.html
Browse files- index.html +18 -12
index.html
CHANGED
|
@@ -152,7 +152,7 @@ function step(dt){
|
|
| 152 |
b.temp=Math.max(0,Math.min(1,b.temp));
|
| 153 |
// buoyancy: screen y grows downward, so negative ay = rising.
|
| 154 |
// hot = light (rises), cold = heavy (sinks); bigger blobs weigh more
|
| 155 |
-
const ay=(0.5-b.temp)*
|
| 156 |
// melting: cold wax is thick/solid-ish, hot wax melts and flows freely
|
| 157 |
const melt=b.temp; // 0=cold(solid) → 1=hot(liquid)
|
| 158 |
const drag=(1.35+(b.r-42)*0.012)*(1.35-0.7*melt); // hot = less drag = more fluid
|
|
@@ -183,11 +183,11 @@ function step(dt){
|
|
| 183 |
if(!blobs.includes(bn.a)||!blobs.includes(bn.b)){bonds.splice(i,1);continue;}
|
| 184 |
const dx=bn.b.x-bn.a.x,dy=bn.b.y-bn.a.y,d=Math.hypot(dx,dy)||0.001;
|
| 185 |
// spring force: pull back toward ideal distance (they're stuck together)
|
| 186 |
-
const f=(d-bn.ideal)*
|
| 187 |
bn.a.vx+=ux*f*dt;bn.a.vy+=uy*f*dt;
|
| 188 |
bn.b.vx-=ux*f*dt;bn.b.vy-=uy*f*dt;
|
| 189 |
// break bond if they drift too far apart
|
| 190 |
-
if(d>bn.ideal*
|
| 191 |
}
|
| 192 |
|
| 193 |
// --- smooth transitions: blobs never appear, vanish or split instantly ---
|
|
@@ -234,9 +234,12 @@ function step(dt){
|
|
| 234 |
if((a.partner&&a.partner===c)||(c.partner&&c.partner===a))continue;
|
| 235 |
const dx=c.x-a.x,dy=c.y-a.y,d=Math.hypot(dx,dy)||0.001,rs=a.r+c.r;
|
| 236 |
// small blobs that collide get stuck together (bond) instead of absorbing
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
|
|
|
|
|
|
|
|
|
| 240 |
}
|
| 241 |
// skip absorption for bonded pairs (they stay as lumpy clusters)
|
| 242 |
if(bonds.some(b=>(b.a===a&&b.b===c)||(b.a===c&&b.b===a)))continue;
|
|
@@ -256,11 +259,12 @@ function step(dt){
|
|
| 256 |
}
|
| 257 |
}
|
| 258 |
|
| 259 |
-
//
|
|
|
|
| 260 |
for(const b of blobs){
|
| 261 |
if(b.abs||b.childOf||b.bud)continue;
|
| 262 |
-
if(b.r>
|
| 263 |
-
const r2=b.r*0.
|
| 264 |
const nx=b.x+Math.cos(ang)*b.r*0.72,ny=b.y+Math.sin(ang)*b.r*0.72;
|
| 265 |
if(halfWidth(ny)-r2>10&&ny>LIQ_TOP+r2+6&&ny<LIQ_BOT-r2-6){
|
| 266 |
const child={x:nx,y:ny,vx:b.vx+Math.cos(ang)*(20+Math.random()*14),vy:b.vy+Math.sin(ang)*(20+Math.random()*14)-10,r:r2*0.15,temp:b.temp,seed:Math.random()*1000,budding:true};
|
|
@@ -276,7 +280,7 @@ function step(dt){
|
|
| 276 |
if(b.abs||b.childOf||b.bud)continue;
|
| 277 |
const er=b.r*WAXR;
|
| 278 |
const botY=LIQ_BOT-er*0.9-6; // this blob's floor (size-dependent)
|
| 279 |
-
if(b.y>botY-16&&b.temp>0.45&&b.r>20&&Math.random()<dt*(b.temp-0.3)*
|
| 280 |
const r2=b.r*(0.13+Math.random()*0.09); // small fizz droplet
|
| 281 |
const ang=Math.PI/2+(Math.random()-0.5)*1.6; // lower arc of the blob
|
| 282 |
const nx=b.x+Math.cos(ang)*b.r*0.86,ny=b.y+Math.sin(ang)*b.r*0.86;
|
|
@@ -310,8 +314,10 @@ function step(dt){
|
|
| 310 |
|
| 311 |
// blobs fizz: hotter wax sheds tiny air bubbles off its surface, like
|
| 312 |
// carbonation coming out of solution (no interaction with the blobs)
|
|
|
|
| 313 |
for(const b of blobs){
|
| 314 |
-
|
|
|
|
| 315 |
const rr=b.r*WAXR;
|
| 316 |
const ang=Math.random()*Math.PI*2;
|
| 317 |
let x=b.x+Math.cos(ang)*rr*(1.02+Math.random()*0.1);
|
|
@@ -337,7 +343,7 @@ function step(dt){
|
|
| 337 |
q.vy-=dt*6; // accelerate upward as it rises
|
| 338 |
q.y+=q.vy*dt;
|
| 339 |
q.x+=Math.sin(time*3+q.ph)*q.wob*dt; // gentle sideways wiggle
|
| 340 |
-
if(q.y<LIQ_TOP+4||blobBubs.length>
|
| 341 |
}
|
| 342 |
}
|
| 343 |
|
|
|
|
| 152 |
b.temp=Math.max(0,Math.min(1,b.temp));
|
| 153 |
// buoyancy: screen y grows downward, so negative ay = rising.
|
| 154 |
// hot = light (rises), cold = heavy (sinks); bigger blobs weigh more
|
| 155 |
+
const ay=(0.5-b.temp)*165-(b.r-42)*1.1;
|
| 156 |
// melting: cold wax is thick/solid-ish, hot wax melts and flows freely
|
| 157 |
const melt=b.temp; // 0=cold(solid) → 1=hot(liquid)
|
| 158 |
const drag=(1.35+(b.r-42)*0.012)*(1.35-0.7*melt); // hot = less drag = more fluid
|
|
|
|
| 183 |
if(!blobs.includes(bn.a)||!blobs.includes(bn.b)){bonds.splice(i,1);continue;}
|
| 184 |
const dx=bn.b.x-bn.a.x,dy=bn.b.y-bn.a.y,d=Math.hypot(dx,dy)||0.001;
|
| 185 |
// spring force: pull back toward ideal distance (they're stuck together)
|
| 186 |
+
const f=(d-bn.ideal)*5.25,ux=dx/d,uy=dy/d;
|
| 187 |
bn.a.vx+=ux*f*dt;bn.a.vy+=uy*f*dt;
|
| 188 |
bn.b.vx-=ux*f*dt;bn.b.vy-=uy*f*dt;
|
| 189 |
// break bond if they drift too far apart
|
| 190 |
+
if(d>bn.ideal*4.5)bonds.splice(i,1);
|
| 191 |
}
|
| 192 |
|
| 193 |
// --- smooth transitions: blobs never appear, vanish or split instantly ---
|
|
|
|
| 234 |
if((a.partner&&a.partner===c)||(c.partner&&c.partner===a))continue;
|
| 235 |
const dx=c.x-a.x,dy=c.y-a.y,d=Math.hypot(dx,dy)||0.001,rs=a.r+c.r;
|
| 236 |
// small blobs that collide get stuck together (bond) instead of absorbing
|
| 237 |
+
// but only if BOTH are small - large blobs are greedy and absorb small ones
|
| 238 |
+
const bothSmall=a.r<35&&c.r<35;
|
| 239 |
+
if(bothSmall&&!bonds.some(b=>(b.a===a&&b.b===c)||(b.a===c&&b.b===a))){
|
| 240 |
+
// very small beads (r<15) get an even wider bond threshold to catch fast-moving passes
|
| 241 |
+
const thresh=a.r<15||c.r<15?rs*1.3:rs*1.05;
|
| 242 |
+
if(d<thresh)bonds.push({a,b:c,ideal:rs*0.6});
|
| 243 |
}
|
| 244 |
// skip absorption for bonded pairs (they stay as lumpy clusters)
|
| 245 |
if(bonds.some(b=>(b.a===a&&b.b===c)||(b.a===c&&b.b===a)))continue;
|
|
|
|
| 259 |
}
|
| 260 |
}
|
| 261 |
|
| 262 |
+
// large blobs split into two big pieces (not strictly equal sized)
|
| 263 |
+
// hotter wax is more liquid and splits more readily
|
| 264 |
for(const b of blobs){
|
| 265 |
if(b.abs||b.childOf||b.bud)continue;
|
| 266 |
+
if(b.r>45&&Math.random()<dt*(0.8+b.temp*1.5)){
|
| 267 |
+
const r2=b.r*(0.35+Math.random()*0.2),ang=Math.random()*Math.PI*2;
|
| 268 |
const nx=b.x+Math.cos(ang)*b.r*0.72,ny=b.y+Math.sin(ang)*b.r*0.72;
|
| 269 |
if(halfWidth(ny)-r2>10&&ny>LIQ_TOP+r2+6&&ny<LIQ_BOT-r2-6){
|
| 270 |
const child={x:nx,y:ny,vx:b.vx+Math.cos(ang)*(20+Math.random()*14),vy:b.vy+Math.sin(ang)*(20+Math.random()*14)-10,r:r2*0.15,temp:b.temp,seed:Math.random()*1000,budding:true};
|
|
|
|
| 280 |
if(b.abs||b.childOf||b.bud)continue;
|
| 281 |
const er=b.r*WAXR;
|
| 282 |
const botY=LIQ_BOT-er*0.9-6; // this blob's floor (size-dependent)
|
| 283 |
+
if(b.y>botY-16&&b.temp>0.45&&b.r>20&&Math.random()<dt*(b.temp-0.3)*0.3125){ // 75% fewer small beads
|
| 284 |
const r2=b.r*(0.13+Math.random()*0.09); // small fizz droplet
|
| 285 |
const ang=Math.PI/2+(Math.random()-0.5)*1.6; // lower arc of the blob
|
| 286 |
const nx=b.x+Math.cos(ang)*b.r*0.86,ny=b.y+Math.sin(ang)*b.r*0.86;
|
|
|
|
| 314 |
|
| 315 |
// blobs fizz: hotter wax sheds tiny air bubbles off its surface, like
|
| 316 |
// carbonation coming out of solution (no interaction with the blobs)
|
| 317 |
+
// bigger blobs fizz more, tiny bits barely bubble
|
| 318 |
for(const b of blobs){
|
| 319 |
+
const sizeFactor=0.25+(b.r/50)*0.75; // r=10→0.4, r=30→0.7, r=50→1.0, r=80→1.25
|
| 320 |
+
if(Math.random()<dt*(0.16+b.temp*0.55)*sizeFactor){ // ~1.9x more air bubbles
|
| 321 |
const rr=b.r*WAXR;
|
| 322 |
const ang=Math.random()*Math.PI*2;
|
| 323 |
let x=b.x+Math.cos(ang)*rr*(1.02+Math.random()*0.1);
|
|
|
|
| 343 |
q.vy-=dt*6; // accelerate upward as it rises
|
| 344 |
q.y+=q.vy*dt;
|
| 345 |
q.x+=Math.sin(time*3+q.ph)*q.wob*dt; // gentle sideways wiggle
|
| 346 |
+
if(q.y<LIQ_TOP+4||blobBubs.length>180)blobBubs.splice(i,1);
|
| 347 |
}
|
| 348 |
}
|
| 349 |
|