ramanaprabhusana commited on
Commit
b1c04e2
·
verified ·
1 Parent(s): e87df2e

Improve RunRate Lab bat rig and swing posture

Browse files
Files changed (1) hide show
  1. app.py +150 -54
app.py CHANGED
@@ -2200,18 +2200,41 @@ GAME_HTML = r"""
2200
  ctx.stroke();
2201
  }
2202
 
2203
- function drawBat(gloveA, gloveB, angle, scale) {
2204
- const anchor = { x: (gloveA.x + gloveB.x) / 2, y: (gloveA.y + gloveB.y) / 2 };
2205
- const handleLen = 58 * scale;
2206
- const bladeLen = 112 * scale;
2207
- const handleW = 7 * scale;
2208
- const bladeTopW = 23 * scale;
2209
- const bladeBotW = 42 * scale;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2210
 
2211
  ctx.save();
2212
  ctx.translate(anchor.x, anchor.y);
2213
  ctx.rotate(angle);
2214
 
 
 
 
 
 
2215
  ctx.strokeStyle = "#4a3417";
2216
  ctx.lineWidth = handleW;
2217
  ctx.lineCap = "round";
@@ -2223,42 +2246,59 @@ GAME_HTML = r"""
2223
  ctx.strokeStyle = "#f8fafc";
2224
  ctx.lineWidth = 2 * scale;
2225
  for (let i = 0; i < 3; i += 1) {
2226
- const gx = (13 + i * 12) * scale;
2227
  ctx.beginPath();
2228
  ctx.moveTo(gx, -6 * scale);
2229
  ctx.lineTo(gx, 6 * scale);
2230
  ctx.stroke();
2231
  }
2232
 
2233
- const shoulder = handleLen + 10 * scale;
2234
- const toe = handleLen + bladeLen;
2235
- ctx.fillStyle = "#d8ae55";
 
 
 
 
 
 
 
 
 
2236
  ctx.strokeStyle = "#76551e";
2237
  ctx.lineWidth = 3 * scale;
2238
  ctx.beginPath();
2239
- ctx.moveTo(handleLen, -bladeTopW * 0.44);
2240
- ctx.quadraticCurveTo(shoulder - 4 * scale, -bladeTopW * 0.56, shoulder, -bladeTopW * 0.5);
2241
- ctx.lineTo(toe - 16 * scale, -bladeBotW * 0.5);
2242
- ctx.quadraticCurveTo(toe + 9 * scale, 0, toe - 16 * scale, bladeBotW * 0.5);
2243
- ctx.lineTo(shoulder, bladeTopW * 0.5);
2244
- ctx.quadraticCurveTo(shoulder - 5 * scale, bladeTopW * 0.58, handleLen, bladeTopW * 0.44);
 
2245
  ctx.closePath();
2246
- ctx.fill();
2247
  ctx.stroke();
2248
 
2249
  ctx.strokeStyle = "rgba(255,255,255,0.32)";
2250
  ctx.lineWidth = 2 * scale;
2251
  ctx.beginPath();
2252
- ctx.moveTo(shoulder + 8 * scale, -4 * scale);
2253
- ctx.lineTo(toe - 20 * scale, -11 * scale);
2254
  ctx.stroke();
2255
 
2256
- ctx.strokeStyle = "rgba(118,85,30,0.35)";
2257
  ctx.lineWidth = 1.5 * scale;
2258
  ctx.beginPath();
2259
- ctx.moveTo(shoulder + 5 * scale, 0);
2260
- ctx.lineTo(toe - 22 * scale, 0);
2261
  ctx.stroke();
 
 
 
 
 
 
 
 
2262
  ctx.restore();
2263
  }
2264
 
@@ -2269,28 +2309,88 @@ GAME_HTML = r"""
2269
  const x = base.x + shake;
2270
  const y = base.y + 18 * scale;
2271
  const progress = clamp((now - state.swingStart) / 420, 0, 1);
2272
- const finishProgress = state.mode === "between" ? 0.76 : progress;
2273
- let batAngle = -1.25;
2274
- let shoulderTilt = 0;
 
 
2275
  if (state.mode === "bowling" && state.charging) {
2276
- batAngle = -1.54 - clamp(state.power / 100, 0, 1) * 0.42;
2277
- shoulderTilt = -0.10;
 
 
 
2278
  } else if (state.swingState === "contact") {
2279
- batAngle = -1.70 + finishProgress * 1.28;
2280
- shoulderTilt = 0.20 * finishProgress;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2281
  } else if (state.swingState === "miss") {
2282
- batAngle = -1.58 + finishProgress * 0.88;
2283
- shoulderTilt = 0.10;
2284
- } else {
2285
- batAngle = -1.24;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2286
  }
2287
 
2288
  const hipY = y - 82 * scale;
2289
  const shoulderY = y - 178 * scale;
2290
  const headY = y - 232 * scale;
2291
  const footY = y + 18 * scale;
2292
- const leftGlove = { x: x + (30 + shoulderTilt * 35) * scale, y: shoulderY + 24 * scale };
2293
- const rightGlove = { x: x + (55 + shoulderTilt * 45) * scale, y: shoulderY + 38 * scale };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2294
 
2295
  ctx.save();
2296
  ctx.fillStyle = "rgba(0,0,0,0.26)";
@@ -2307,41 +2407,37 @@ GAME_HTML = r"""
2307
  ctx.fill();
2308
 
2309
  ctx.fillStyle = "#f8fafc";
2310
- roundedRect(x - 54 * scale, shoulderY, 108 * scale, 124 * scale, 26 * scale);
2311
  ctx.fill();
2312
  ctx.fillStyle = "#2563eb";
2313
- roundedRect(x - 68 * scale, shoulderY + 16 * scale, 136 * scale, 36 * scale, 15 * scale);
2314
  ctx.fill();
2315
  ctx.fillStyle = "#0f172a";
2316
- roundedRect(x - 42 * scale, shoulderY + 40 * scale, 84 * scale, 80 * scale, 13 * scale);
2317
  ctx.fill();
2318
 
2319
- drawLimb(x - 48 * scale, shoulderY + 30 * scale, x - 88 * scale, shoulderY + 82 * scale, 15 * scale, "#f8fafc");
2320
- drawLimb(x + 48 * scale, shoulderY + 30 * scale, leftGlove.x, leftGlove.y, 15 * scale, "#f8fafc");
2321
- drawLimb(leftGlove.x, leftGlove.y, rightGlove.x, rightGlove.y, 15 * scale, "#f8fafc");
 
2322
 
2323
- drawBat(leftGlove, rightGlove, batAngle, scale);
2324
 
2325
- ctx.fillStyle = "#facc15";
2326
- ctx.beginPath();
2327
- ctx.arc(leftGlove.x, leftGlove.y, 13 * scale, 0, Math.PI * 2);
2328
- ctx.fill();
2329
- ctx.beginPath();
2330
- ctx.arc(rightGlove.x, rightGlove.y, 13 * scale, 0, Math.PI * 2);
2331
- ctx.fill();
2332
 
2333
  ctx.fillStyle = "#f8fafc";
2334
  ctx.beginPath();
2335
- ctx.arc(x, headY, 32 * scale, 0, Math.PI * 2);
2336
  ctx.fill();
2337
  ctx.fillStyle = "#0f172a";
2338
  ctx.beginPath();
2339
- ctx.arc(x, headY - 9 * scale, 34 * scale, Math.PI, Math.PI * 2);
2340
  ctx.fill();
2341
  ctx.fillStyle = "rgba(15,23,42,0.95)";
2342
- ctx.fillRect(x - 36 * scale, headY - 9 * scale, 72 * scale, 9 * scale);
2343
  ctx.fillStyle = "rgba(56,189,248,0.58)";
2344
- ctx.fillRect(x - 28 * scale, headY + 10 * scale, 56 * scale, 6 * scale);
2345
  ctx.restore();
2346
  }
2347
 
 
2200
  ctx.stroke();
2201
  }
2202
 
2203
+ function drawGlove(x, y, angle, scale, flip = 1) {
2204
+ ctx.save();
2205
+ ctx.translate(x, y);
2206
+ ctx.rotate(angle + flip * 0.10);
2207
+ ctx.fillStyle = "#f8fafc";
2208
+ roundedRect(-12 * scale, -8 * scale, 24 * scale, 16 * scale, 5 * scale);
2209
+ ctx.fill();
2210
+ ctx.fillStyle = "#d8ae55";
2211
+ roundedRect(-13 * scale, 3 * scale, 12 * scale, 9 * scale, 4 * scale);
2212
+ ctx.fill();
2213
+ ctx.fillStyle = "rgba(15,23,42,0.18)";
2214
+ ctx.fillRect(-4 * scale, -4 * scale, 12 * scale, 2 * scale);
2215
+ ctx.fillRect(-4 * scale, 0, 12 * scale, 2 * scale);
2216
+ ctx.restore();
2217
+ }
2218
+
2219
+ function drawBat(topHand, bottomHand, angle, scale) {
2220
+ const anchor = topHand;
2221
+ const handSpacing = 16 * scale;
2222
+ const handleLen = 56 * scale;
2223
+ const bladeLen = 126 * scale;
2224
+ const handleW = 6 * scale;
2225
+ const bladeTopW = 18 * scale;
2226
+ const bladeMidW = 28 * scale;
2227
+ const bladeBotW = 40 * scale;
2228
 
2229
  ctx.save();
2230
  ctx.translate(anchor.x, anchor.y);
2231
  ctx.rotate(angle);
2232
 
2233
+ ctx.fillStyle = "rgba(0,0,0,0.22)";
2234
+ ctx.beginPath();
2235
+ ctx.ellipse(handleLen + bladeLen * 0.52, 14 * scale, bladeBotW * 0.55, 9 * scale, 0, 0, Math.PI * 2);
2236
+ ctx.fill();
2237
+
2238
  ctx.strokeStyle = "#4a3417";
2239
  ctx.lineWidth = handleW;
2240
  ctx.lineCap = "round";
 
2246
  ctx.strokeStyle = "#f8fafc";
2247
  ctx.lineWidth = 2 * scale;
2248
  for (let i = 0; i < 3; i += 1) {
2249
+ const gx = (11 + i * 11) * scale;
2250
  ctx.beginPath();
2251
  ctx.moveTo(gx, -6 * scale);
2252
  ctx.lineTo(gx, 6 * scale);
2253
  ctx.stroke();
2254
  }
2255
 
2256
+ ctx.fillStyle = "#d9b368";
2257
+ ctx.beginPath();
2258
+ ctx.moveTo(handleLen - 2 * scale, -bladeTopW * 0.50);
2259
+ ctx.quadraticCurveTo(handleLen + 10 * scale, -bladeTopW * 0.78, handleLen + 22 * scale, -bladeMidW * 0.48);
2260
+ ctx.lineTo(handleLen + bladeLen * 0.68, -bladeBotW * 0.44);
2261
+ ctx.quadraticCurveTo(handleLen + bladeLen + 8 * scale, -bladeBotW * 0.12, handleLen + bladeLen, 0);
2262
+ ctx.quadraticCurveTo(handleLen + bladeLen + 8 * scale, bladeBotW * 0.12, handleLen + bladeLen * 0.68, bladeBotW * 0.44);
2263
+ ctx.lineTo(handleLen + 22 * scale, bladeMidW * 0.48);
2264
+ ctx.quadraticCurveTo(handleLen + 10 * scale, bladeTopW * 0.78, handleLen - 2 * scale, bladeTopW * 0.50);
2265
+ ctx.closePath();
2266
+ ctx.fill();
2267
+
2268
  ctx.strokeStyle = "#76551e";
2269
  ctx.lineWidth = 3 * scale;
2270
  ctx.beginPath();
2271
+ ctx.moveTo(handleLen - 2 * scale, -bladeTopW * 0.50);
2272
+ ctx.quadraticCurveTo(handleLen + 10 * scale, -bladeTopW * 0.78, handleLen + 22 * scale, -bladeMidW * 0.48);
2273
+ ctx.lineTo(handleLen + bladeLen * 0.68, -bladeBotW * 0.44);
2274
+ ctx.quadraticCurveTo(handleLen + bladeLen + 8 * scale, -bladeBotW * 0.12, handleLen + bladeLen, 0);
2275
+ ctx.quadraticCurveTo(handleLen + bladeLen + 8 * scale, bladeBotW * 0.12, handleLen + bladeLen * 0.68, bladeBotW * 0.44);
2276
+ ctx.lineTo(handleLen + 22 * scale, bladeMidW * 0.48);
2277
+ ctx.quadraticCurveTo(handleLen + 10 * scale, bladeTopW * 0.78, handleLen - 2 * scale, bladeTopW * 0.50);
2278
  ctx.closePath();
 
2279
  ctx.stroke();
2280
 
2281
  ctx.strokeStyle = "rgba(255,255,255,0.32)";
2282
  ctx.lineWidth = 2 * scale;
2283
  ctx.beginPath();
2284
+ ctx.moveTo(handleLen + 18 * scale, -4 * scale);
2285
+ ctx.lineTo(handleLen + bladeLen * 0.74, -11 * scale);
2286
  ctx.stroke();
2287
 
2288
+ ctx.strokeStyle = "rgba(118,85,30,0.28)";
2289
  ctx.lineWidth = 1.5 * scale;
2290
  ctx.beginPath();
2291
+ ctx.moveTo(handleLen + 14 * scale, 0);
2292
+ ctx.lineTo(handleLen + bladeLen * 0.76, 0);
2293
  ctx.stroke();
2294
+
2295
+ ctx.fillStyle = "#1f1600";
2296
+ ctx.beginPath();
2297
+ ctx.arc(handSpacing * 0.22, 0, 2.2 * scale, 0, Math.PI * 2);
2298
+ ctx.fill();
2299
+ ctx.beginPath();
2300
+ ctx.arc(handSpacing, 0, 2.2 * scale, 0, Math.PI * 2);
2301
+ ctx.fill();
2302
  ctx.restore();
2303
  }
2304
 
 
2309
  const x = base.x + shake;
2310
  const y = base.y + 18 * scale;
2311
  const progress = clamp((now - state.swingStart) / 420, 0, 1);
2312
+ const easeOut = 1 - Math.pow(1 - progress, 3);
2313
+ let batAngle = -1.18;
2314
+ let handReach = 0;
2315
+ let handLift = 0;
2316
+ let torsoLean = 0;
2317
  if (state.mode === "bowling" && state.charging) {
2318
+ const charge = clamp(state.power / 100, 0, 1);
2319
+ batAngle = -1.58 - charge * 0.34;
2320
+ handReach = -8 * charge;
2321
+ handLift = -18 * charge;
2322
+ torsoLean = -0.05;
2323
  } else if (state.swingState === "contact") {
2324
+ if (state.selectedShot === "Loft") {
2325
+ batAngle = -1.72 + easeOut * 1.46;
2326
+ handReach = 26 * easeOut;
2327
+ handLift = -16 * easeOut;
2328
+ torsoLean = 0.14 * easeOut;
2329
+ } else if (state.selectedShot === "Cut / Pull") {
2330
+ batAngle = -1.66 + easeOut * 1.12;
2331
+ handReach = 22 * easeOut;
2332
+ handLift = -6 * easeOut;
2333
+ torsoLean = 0.08 * easeOut;
2334
+ } else if (state.selectedShot === "Defend") {
2335
+ batAngle = -1.46 + easeOut * 0.62;
2336
+ handReach = 8 * easeOut;
2337
+ handLift = 2 * easeOut;
2338
+ torsoLean = 0.03 * easeOut;
2339
+ } else {
2340
+ batAngle = -1.64 + easeOut * 0.96;
2341
+ handReach = 18 * easeOut;
2342
+ handLift = -2 * easeOut;
2343
+ torsoLean = 0.08 * easeOut;
2344
+ }
2345
  } else if (state.swingState === "miss") {
2346
+ batAngle = -1.56 + easeOut * 0.72;
2347
+ handReach = 10 * easeOut;
2348
+ handLift = -4 * easeOut;
2349
+ torsoLean = 0.04 * easeOut;
2350
+ } else if (state.mode === "between" && state.lastInsight) {
2351
+ if (state.lastInsight.shot === "Loft") {
2352
+ batAngle = -0.32;
2353
+ handReach = 24;
2354
+ handLift = -12;
2355
+ torsoLean = 0.10;
2356
+ } else if (state.lastInsight.shot === "Defend") {
2357
+ batAngle = -0.86;
2358
+ handReach = 8;
2359
+ handLift = 2;
2360
+ torsoLean = 0.02;
2361
+ } else if (state.lastInsight.shot === "Cut / Pull") {
2362
+ batAngle = -0.58;
2363
+ handReach = 18;
2364
+ handLift = -2;
2365
+ torsoLean = 0.06;
2366
+ } else {
2367
+ batAngle = -0.70;
2368
+ handReach = 16;
2369
+ handLift = -2;
2370
+ torsoLean = 0.06;
2371
+ }
2372
  }
2373
 
2374
  const hipY = y - 82 * scale;
2375
  const shoulderY = y - 178 * scale;
2376
  const headY = y - 232 * scale;
2377
  const footY = y + 18 * scale;
2378
+ const torsoShift = torsoLean * 34 * scale;
2379
+ const leftShoulder = { x: x - 48 * scale + torsoShift, y: shoulderY + 28 * scale };
2380
+ const rightShoulder = { x: x + 44 * scale + torsoShift, y: shoulderY + 28 * scale };
2381
+ const topHand = { x: x + (26 + handReach) * scale, y: shoulderY + (32 + handLift) * scale };
2382
+ const bottomHand = {
2383
+ x: topHand.x + Math.cos(batAngle) * 18 * scale,
2384
+ y: topHand.y + Math.sin(batAngle) * 18 * scale
2385
+ };
2386
+ const leftElbow = {
2387
+ x: (leftShoulder.x + topHand.x) / 2 + 4 * scale,
2388
+ y: (leftShoulder.y + topHand.y) / 2 + 7 * scale
2389
+ };
2390
+ const rightElbow = {
2391
+ x: (rightShoulder.x + bottomHand.x) / 2 + 16 * scale,
2392
+ y: (rightShoulder.y + bottomHand.y) / 2 + 10 * scale
2393
+ };
2394
 
2395
  ctx.save();
2396
  ctx.fillStyle = "rgba(0,0,0,0.26)";
 
2407
  ctx.fill();
2408
 
2409
  ctx.fillStyle = "#f8fafc";
2410
+ roundedRect(x - 54 * scale + torsoShift, shoulderY, 108 * scale, 124 * scale, 26 * scale);
2411
  ctx.fill();
2412
  ctx.fillStyle = "#2563eb";
2413
+ roundedRect(x - 68 * scale + torsoShift, shoulderY + 16 * scale, 136 * scale, 36 * scale, 15 * scale);
2414
  ctx.fill();
2415
  ctx.fillStyle = "#0f172a";
2416
+ roundedRect(x - 42 * scale + torsoShift, shoulderY + 40 * scale, 84 * scale, 80 * scale, 13 * scale);
2417
  ctx.fill();
2418
 
2419
+ drawLimb(leftShoulder.x, leftShoulder.y, leftElbow.x, leftElbow.y, 15 * scale, "#f8fafc");
2420
+ drawLimb(leftElbow.x, leftElbow.y, topHand.x, topHand.y, 15 * scale, "#f8fafc");
2421
+ drawLimb(rightShoulder.x, rightShoulder.y, rightElbow.x, rightElbow.y, 15 * scale, "#f8fafc");
2422
+ drawLimb(rightElbow.x, rightElbow.y, bottomHand.x, bottomHand.y, 15 * scale, "#f8fafc");
2423
 
2424
+ drawBat(topHand, bottomHand, batAngle, scale);
2425
 
2426
+ drawGlove(topHand.x, topHand.y, batAngle - 0.08, scale, -1);
2427
+ drawGlove(bottomHand.x, bottomHand.y, batAngle + 0.02, scale, 1);
 
 
 
 
 
2428
 
2429
  ctx.fillStyle = "#f8fafc";
2430
  ctx.beginPath();
2431
+ ctx.arc(x + torsoShift, headY, 32 * scale, 0, Math.PI * 2);
2432
  ctx.fill();
2433
  ctx.fillStyle = "#0f172a";
2434
  ctx.beginPath();
2435
+ ctx.arc(x + torsoShift, headY - 9 * scale, 34 * scale, Math.PI, Math.PI * 2);
2436
  ctx.fill();
2437
  ctx.fillStyle = "rgba(15,23,42,0.95)";
2438
+ ctx.fillRect(x - 36 * scale + torsoShift, headY - 9 * scale, 72 * scale, 9 * scale);
2439
  ctx.fillStyle = "rgba(56,189,248,0.58)";
2440
+ ctx.fillRect(x - 28 * scale + torsoShift, headY + 10 * scale, 56 * scale, 6 * scale);
2441
  ctx.restore();
2442
  }
2443