@almadar/ui 5.85.0 → 5.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1224,12 +1224,12 @@ function kebabToPascal(name) {
1224
1224
  }).join("");
1225
1225
  }
1226
1226
  function loadLib(key, importer) {
1227
- let p2 = libPromises.get(key);
1228
- if (!p2) {
1229
- p2 = importer();
1230
- libPromises.set(key, p2);
1227
+ let p = libPromises.get(key);
1228
+ if (!p) {
1229
+ p = importer();
1230
+ libPromises.set(key, p);
1231
1231
  }
1232
- return p2;
1232
+ return p;
1233
1233
  }
1234
1234
  function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
1235
1235
  const Lazy = React74__default.lazy(async () => {
@@ -5327,28 +5327,28 @@ var init_ConfettiEffect = __esm({
5327
5327
  ),
5328
5328
  "aria-hidden": "true",
5329
5329
  children: [
5330
- particles.map((p2) => {
5331
- const rad = p2.angle * Math.PI / 180;
5332
- const tx = Math.cos(rad) * p2.distance;
5333
- const ty = Math.sin(rad) * p2.distance - 20;
5330
+ particles.map((p) => {
5331
+ const rad = p.angle * Math.PI / 180;
5332
+ const tx = Math.cos(rad) * p.distance;
5333
+ const ty = Math.sin(rad) * p.distance - 20;
5334
5334
  return /* @__PURE__ */ jsx(
5335
5335
  Box,
5336
5336
  {
5337
5337
  className: "absolute rounded-sm",
5338
5338
  style: {
5339
- left: `${p2.left}%`,
5339
+ left: `${p.left}%`,
5340
5340
  top: "50%",
5341
- width: p2.size,
5342
- height: p2.size,
5343
- backgroundColor: p2.color,
5344
- animation: `confetti-burst ${duration - p2.delay}ms ease-out ${p2.delay}ms forwards`,
5341
+ width: p.size,
5342
+ height: p.size,
5343
+ backgroundColor: p.color,
5344
+ animation: `confetti-burst ${duration - p.delay}ms ease-out ${p.delay}ms forwards`,
5345
5345
  opacity: 0,
5346
5346
  "--confetti-tx": `${tx}px`,
5347
5347
  "--confetti-ty": `${ty}px`,
5348
- "--confetti-rotate": `${p2.rotation}deg`
5348
+ "--confetti-rotate": `${p.rotation}deg`
5349
5349
  }
5350
5350
  },
5351
- p2.id
5351
+ p.id
5352
5352
  );
5353
5353
  }),
5354
5354
  /* @__PURE__ */ jsx("style", { children: `
@@ -6259,8 +6259,8 @@ var init_AnimatedGraphic = __esm({
6259
6259
  const el = containerRef.current;
6260
6260
  if (!el || !strokeColor) return;
6261
6261
  const paths = el.querySelectorAll("path, line, polyline, polygon, circle, ellipse, rect");
6262
- paths.forEach((p2) => {
6263
- p2.style.stroke = strokeColor;
6262
+ paths.forEach((p) => {
6263
+ p.style.stroke = strokeColor;
6264
6264
  });
6265
6265
  }, [resolvedSvg, strokeColor]);
6266
6266
  useEffect(() => {
@@ -6268,23 +6268,23 @@ var init_AnimatedGraphic = __esm({
6268
6268
  if (!el || !resolvedSvg) return;
6269
6269
  if (animation === "draw" || animation === "fill") {
6270
6270
  const paths = el.querySelectorAll("path, line, polyline, polygon, circle, ellipse, rect");
6271
- paths.forEach((p2) => {
6272
- if ("getTotalLength" in p2 && typeof p2.getTotalLength === "function") {
6273
- const len = p2.getTotalLength();
6274
- p2.style.strokeDasharray = `${len}`;
6275
- p2.style.strokeDashoffset = `${len}`;
6271
+ paths.forEach((p) => {
6272
+ if ("getTotalLength" in p && typeof p.getTotalLength === "function") {
6273
+ const len = p.getTotalLength();
6274
+ p.style.strokeDasharray = `${len}`;
6275
+ p.style.strokeDashoffset = `${len}`;
6276
6276
  }
6277
6277
  if (animation === "fill") {
6278
- p2.style.fillOpacity = "0";
6278
+ p.style.fillOpacity = "0";
6279
6279
  }
6280
6280
  });
6281
6281
  }
6282
6282
  if (animation === "morph") {
6283
6283
  const paths = el.querySelectorAll("path, circle, ellipse, rect, polygon");
6284
- paths.forEach((p2) => {
6285
- p2.style.transform = "scale(0)";
6286
- p2.style.transformOrigin = "center";
6287
- p2.style.opacity = "0";
6284
+ paths.forEach((p) => {
6285
+ p.style.transform = "scale(0)";
6286
+ p.style.transformOrigin = "center";
6287
+ p.style.opacity = "0";
6288
6288
  });
6289
6289
  }
6290
6290
  }, [resolvedSvg, animation]);
@@ -9554,8 +9554,8 @@ function shapeBounds(shape) {
9554
9554
  case "polygon":
9555
9555
  if (!shape.points || shape.points.length === 0) return null;
9556
9556
  {
9557
- const xs = shape.points.map((p2) => p2.x);
9558
- const ys = shape.points.map((p2) => p2.y);
9557
+ const xs = shape.points.map((p) => p.x);
9558
+ const ys = shape.points.map((p) => p.y);
9559
9559
  const minX = Math.min(...xs);
9560
9560
  const minY = Math.min(...ys);
9561
9561
  return {
@@ -9681,13 +9681,13 @@ function drawShape(ctx, shape, width, height) {
9681
9681
  }
9682
9682
  case "path": {
9683
9683
  if (!shape.path) break;
9684
- const p2 = new Path2D(shape.path);
9684
+ const p = new Path2D(shape.path);
9685
9685
  if (fill) {
9686
9686
  ctx.fillStyle = fill;
9687
- ctx.fill(p2);
9687
+ ctx.fill(p);
9688
9688
  }
9689
9689
  ctx.strokeStyle = stroke;
9690
- ctx.stroke(p2);
9690
+ ctx.stroke(p);
9691
9691
  break;
9692
9692
  }
9693
9693
  case "text": {
@@ -12744,7 +12744,7 @@ function renderStateMachineToDomData(stateMachine, options = {}, config = DEFAUL
12744
12744
  }
12745
12745
  let domOutputs;
12746
12746
  if (outputs.length > 0) {
12747
- const maxX = Math.max(...Object.values(positions).map((p2) => p2.x));
12747
+ const maxX = Math.max(...Object.values(positions).map((p) => p.x));
12748
12748
  const maxOutputLength = Math.max(...outputs.map((o) => o.length));
12749
12749
  const boxWidth = Math.max(200, maxOutputLength * 7 + 30);
12750
12750
  const lineHeight = 22;
@@ -13726,7 +13726,7 @@ var init_BookViewer = __esm({
13726
13726
  }
13727
13727
  });
13728
13728
  function BoxPattern({
13729
- p: p2,
13729
+ p,
13730
13730
  m,
13731
13731
  bg = "transparent",
13732
13732
  border = false,
@@ -13739,7 +13739,7 @@ function BoxPattern({
13739
13739
  return /* @__PURE__ */ jsx(
13740
13740
  Box,
13741
13741
  {
13742
- padding: p2,
13742
+ padding: p,
13743
13743
  margin: m,
13744
13744
  bg,
13745
13745
  border,
@@ -15654,13 +15654,13 @@ function useRenderInterpolation(options = {}) {
15654
15654
  const prevMap = /* @__PURE__ */ new Map();
15655
15655
  for (const e of prev.entities) prevMap.set(e.id, e);
15656
15656
  for (const c of curr.entities) {
15657
- const p2 = prevMap.get(c.id);
15658
- if (!p2) {
15657
+ const p = prevMap.get(c.id);
15658
+ if (!p) {
15659
15659
  out.set(c.id, { x: c.x, y: c.y });
15660
15660
  } else {
15661
15661
  out.set(c.id, {
15662
- x: p2.x + (c.x - p2.x) * alpha,
15663
- y: p2.y + (c.y - p2.y) * alpha
15662
+ x: p.x + (c.x - p.x) * alpha,
15663
+ y: p.y + (c.y - p.y) * alpha
15664
15664
  });
15665
15665
  }
15666
15666
  }
@@ -16409,8 +16409,8 @@ function Canvas2D({
16409
16409
  if (isFree) return 0;
16410
16410
  return (gridHeight - 1) * (scaledTileWidth / 2);
16411
16411
  }, [isFree, gridHeight, scaledTileWidth]);
16412
- const validMoveSet = useMemo(() => new Set(validMoves.map((p2) => `${p2.x},${p2.y}`)), [validMoves]);
16413
- const attackTargetSet = useMemo(() => new Set(attackTargets.map((p2) => `${p2.x},${p2.y}`)), [attackTargets]);
16412
+ const validMoveSet = useMemo(() => new Set(validMoves.map((p) => `${p.x},${p.y}`)), [validMoves]);
16413
+ const attackTargetSet = useMemo(() => new Set(attackTargets.map((p) => `${p.x},${p.y}`)), [attackTargets]);
16414
16414
  const spriteUrls = useMemo(() => {
16415
16415
  const urls = [];
16416
16416
  for (const tile of sortedTiles) {
@@ -17128,1278 +17128,6 @@ var init_Canvas2D = __esm({
17128
17128
  }
17129
17129
  });
17130
17130
 
17131
- // components/game/shared/effects.ts
17132
- var EMPTY_EFFECT_STATE;
17133
- var init_effects = __esm({
17134
- "components/game/shared/effects.ts"() {
17135
- EMPTY_EFFECT_STATE = {
17136
- particles: [],
17137
- sequences: [],
17138
- overlays: []
17139
- };
17140
- }
17141
- });
17142
-
17143
- // components/game/shared/canvasEffects.ts
17144
- function getOffscreenCtx(w, h) {
17145
- if (!_offscreen) {
17146
- if (typeof OffscreenCanvas !== "undefined") {
17147
- _offscreen = new OffscreenCanvas(w, h);
17148
- } else {
17149
- _offscreen = document.createElement("canvas");
17150
- }
17151
- }
17152
- if (_offscreen.width < w) _offscreen.width = w;
17153
- if (_offscreen.height < h) _offscreen.height = h;
17154
- if (!_offCtx) {
17155
- _offCtx = _offscreen.getContext("2d");
17156
- }
17157
- return _offCtx;
17158
- }
17159
- function drawTintedImage(ctx, img, x, y, w, h, tint, alpha, blendMode = "source-over") {
17160
- if (w <= 0 || h <= 0) return;
17161
- const oc = getOffscreenCtx(w, h);
17162
- oc.clearRect(0, 0, w, h);
17163
- oc.globalCompositeOperation = "source-over";
17164
- oc.drawImage(img, 0, 0, w, h);
17165
- oc.globalCompositeOperation = "source-atop";
17166
- oc.fillStyle = `rgb(${tint.r}, ${tint.g}, ${tint.b})`;
17167
- oc.fillRect(0, 0, w, h);
17168
- const prevAlpha = ctx.globalAlpha;
17169
- const prevBlend = ctx.globalCompositeOperation;
17170
- ctx.globalAlpha = alpha;
17171
- ctx.globalCompositeOperation = blendMode;
17172
- ctx.drawImage(_offscreen, 0, 0, w, h, x, y, w, h);
17173
- ctx.globalAlpha = prevAlpha;
17174
- ctx.globalCompositeOperation = prevBlend;
17175
- }
17176
- function randRange(min, max) {
17177
- return min + Math.random() * (max - min);
17178
- }
17179
- function spawnParticles(config, animTime) {
17180
- const particles = [];
17181
- for (let i = 0; i < config.count; i++) {
17182
- const angle = randRange(config.angleMin, config.angleMax);
17183
- const speed = randRange(config.velocityMin, config.velocityMax);
17184
- const spriteUrl = config.spriteUrls[Math.floor(Math.random() * config.spriteUrls.length)];
17185
- particles.push({
17186
- spriteUrl,
17187
- x: config.originX + randRange(-config.spread, config.spread),
17188
- y: config.originY + randRange(-config.spread, config.spread),
17189
- vx: Math.cos(angle) * speed,
17190
- vy: Math.sin(angle) * speed,
17191
- gravity: config.gravity,
17192
- rotation: Math.random() * Math.PI * 2,
17193
- rotationSpeed: randRange(config.rotationSpeedMin ?? -2, config.rotationSpeedMax ?? 2),
17194
- scale: randRange(config.scaleMin, config.scaleMax),
17195
- scaleSpeed: config.scaleSpeed ?? 0,
17196
- alpha: config.alpha ?? 1,
17197
- fadeRate: config.fadeRate ?? -1.5,
17198
- tint: { ...config.tint },
17199
- blendMode: config.blendMode ?? "source-over",
17200
- spawnTime: animTime,
17201
- lifetime: randRange(config.lifetimeMin, config.lifetimeMax)
17202
- });
17203
- }
17204
- return particles;
17205
- }
17206
- function spawnSequence(config, animTime) {
17207
- return {
17208
- frameUrls: config.frameUrls,
17209
- x: config.originX,
17210
- y: config.originY,
17211
- frameDuration: config.frameDuration,
17212
- startTime: animTime,
17213
- loop: config.loop ?? false,
17214
- scale: config.scale ?? 1,
17215
- tint: config.tint ?? null,
17216
- alpha: config.alpha ?? 1,
17217
- blendMode: config.blendMode ?? "source-over"
17218
- };
17219
- }
17220
- function spawnOverlay(config, animTime) {
17221
- return {
17222
- spriteUrl: config.spriteUrl,
17223
- x: config.originX,
17224
- y: config.originY,
17225
- alpha: config.alpha ?? 0.8,
17226
- fadeRate: config.fadeRate ?? -0.5,
17227
- pulseAmplitude: config.pulseAmplitude ?? 0,
17228
- pulseFrequency: config.pulseFrequency ?? 2,
17229
- scale: config.scale ?? 1,
17230
- blendMode: config.blendMode ?? "source-over",
17231
- spawnTime: animTime,
17232
- lifetime: config.lifetime ?? 2e3
17233
- };
17234
- }
17235
- function updateEffectState(state, animTime, deltaMs) {
17236
- const dt = deltaMs / 1e3;
17237
- const particles = state.particles.map((p2) => ({
17238
- ...p2,
17239
- x: p2.x + p2.vx * dt,
17240
- y: p2.y + p2.vy * dt,
17241
- vy: p2.vy + p2.gravity * dt,
17242
- rotation: p2.rotation + p2.rotationSpeed * dt,
17243
- scale: Math.max(0, p2.scale + p2.scaleSpeed * dt),
17244
- alpha: Math.max(0, p2.alpha + p2.fadeRate * dt)
17245
- })).filter((p2) => p2.alpha > 0.01 && animTime - p2.spawnTime < p2.lifetime);
17246
- const sequences = state.sequences.filter((s) => {
17247
- const elapsed = animTime - s.startTime;
17248
- const totalDuration = s.frameUrls.length * s.frameDuration;
17249
- return s.loop || elapsed < totalDuration;
17250
- });
17251
- const overlays = state.overlays.map((o) => ({
17252
- ...o,
17253
- alpha: Math.max(0, o.alpha + o.fadeRate * dt)
17254
- })).filter((o) => o.alpha > 0.01 && animTime - o.spawnTime < o.lifetime);
17255
- return { particles, sequences, overlays };
17256
- }
17257
- function drawEffectState(ctx, state, animTime, getImage) {
17258
- for (const o of state.overlays) {
17259
- const img = getImage(o.spriteUrl);
17260
- if (!img) continue;
17261
- let alpha = o.alpha;
17262
- if (o.pulseAmplitude > 0) {
17263
- const elapsed = (animTime - o.spawnTime) / 1e3;
17264
- alpha += Math.sin(elapsed * o.pulseFrequency * Math.PI * 2) * o.pulseAmplitude;
17265
- alpha = Math.max(0, Math.min(1, alpha));
17266
- }
17267
- const w = img.naturalWidth * o.scale;
17268
- const h = img.naturalHeight * o.scale;
17269
- const prevAlpha = ctx.globalAlpha;
17270
- const prevBlend = ctx.globalCompositeOperation;
17271
- ctx.globalAlpha = alpha;
17272
- ctx.globalCompositeOperation = o.blendMode;
17273
- ctx.drawImage(img, o.x - w / 2, o.y - h / 2, w, h);
17274
- ctx.globalAlpha = prevAlpha;
17275
- ctx.globalCompositeOperation = prevBlend;
17276
- }
17277
- for (const s of state.sequences) {
17278
- const elapsed = animTime - s.startTime;
17279
- let frameIndex = Math.floor(elapsed / s.frameDuration);
17280
- if (s.loop) {
17281
- frameIndex = frameIndex % s.frameUrls.length;
17282
- } else if (frameIndex >= s.frameUrls.length) {
17283
- continue;
17284
- }
17285
- const img = getImage(s.frameUrls[frameIndex]);
17286
- if (!img) continue;
17287
- const w = img.naturalWidth * s.scale;
17288
- const h = img.naturalHeight * s.scale;
17289
- if (s.tint) {
17290
- drawTintedImage(ctx, img, s.x - w / 2, s.y - h / 2, w, h, s.tint, s.alpha, s.blendMode);
17291
- } else {
17292
- const prevAlpha = ctx.globalAlpha;
17293
- const prevBlend = ctx.globalCompositeOperation;
17294
- ctx.globalAlpha = s.alpha;
17295
- ctx.globalCompositeOperation = s.blendMode;
17296
- ctx.drawImage(img, s.x - w / 2, s.y - h / 2, w, h);
17297
- ctx.globalAlpha = prevAlpha;
17298
- ctx.globalCompositeOperation = prevBlend;
17299
- }
17300
- }
17301
- for (const p2 of state.particles) {
17302
- const img = getImage(p2.spriteUrl);
17303
- if (!img) continue;
17304
- const w = img.naturalWidth * p2.scale;
17305
- const h = img.naturalHeight * p2.scale;
17306
- ctx.save();
17307
- ctx.translate(p2.x, p2.y);
17308
- ctx.rotate(p2.rotation);
17309
- drawTintedImage(ctx, img, -w / 2, -h / 2, w, h, p2.tint, p2.alpha, p2.blendMode);
17310
- ctx.restore();
17311
- }
17312
- }
17313
- function hasActiveEffects(state) {
17314
- return state.particles.length > 0 || state.sequences.length > 0 || state.overlays.length > 0;
17315
- }
17316
- function getAllEffectSpriteUrls(manifest) {
17317
- const urls = [];
17318
- const base = manifest.baseUrl;
17319
- if (manifest.particles) {
17320
- for (const value of Object.values(manifest.particles)) {
17321
- if (Array.isArray(value)) {
17322
- value.forEach((v) => urls.push(`${base}/${v}`));
17323
- } else if (typeof value === "string") {
17324
- urls.push(`${base}/${value}`);
17325
- }
17326
- }
17327
- }
17328
- if (manifest.animations) {
17329
- for (const frames of Object.values(manifest.animations)) {
17330
- if (Array.isArray(frames)) {
17331
- frames.forEach((f3) => urls.push(`${base}/${f3}`));
17332
- }
17333
- }
17334
- }
17335
- return urls;
17336
- }
17337
- var _offscreen, _offCtx;
17338
- var init_canvasEffects = __esm({
17339
- "components/game/shared/canvasEffects.ts"() {
17340
- _offscreen = null;
17341
- _offCtx = null;
17342
- }
17343
- });
17344
-
17345
- // components/game/shared/combatPresets.ts
17346
- function p(manifest, key) {
17347
- const particles = manifest.particles;
17348
- if (!particles) return [];
17349
- const val = particles[key];
17350
- if (Array.isArray(val)) return val.map((v) => `${manifest.baseUrl}/${v}`);
17351
- if (typeof val === "string") return [`${manifest.baseUrl}/${val}`];
17352
- return [];
17353
- }
17354
- function anim(manifest, key) {
17355
- const animations = manifest.animations;
17356
- if (!animations) return [];
17357
- const val = animations[key];
17358
- if (Array.isArray(val)) return val.map((v) => `${manifest.baseUrl}/${v}`);
17359
- return [];
17360
- }
17361
- function createCombatPresets(manifest) {
17362
- return {
17363
- // =====================================================================
17364
- // MELEE — slash (red) + dirt + scratch + flash sequence
17365
- // =====================================================================
17366
- melee: (originX, originY) => {
17367
- const particles = [
17368
- {
17369
- spriteUrls: p(manifest, "slash"),
17370
- count: 6,
17371
- originX,
17372
- originY,
17373
- spread: 8,
17374
- velocityMin: 40,
17375
- velocityMax: 120,
17376
- angleMin: -PI2 * 0.8,
17377
- angleMax: -PI2 * 0.2,
17378
- gravity: 0,
17379
- tint: { r: 255, g: 60, b: 40 },
17380
- scaleMin: 0.3,
17381
- scaleMax: 0.6,
17382
- lifetimeMin: 300,
17383
- lifetimeMax: 500,
17384
- fadeRate: -2.5
17385
- },
17386
- {
17387
- spriteUrls: p(manifest, "dirt"),
17388
- count: 4,
17389
- originX,
17390
- originY: originY + 10,
17391
- spread: 12,
17392
- velocityMin: 20,
17393
- velocityMax: 60,
17394
- angleMin: -PI2 * 0.9,
17395
- angleMax: -PI2 * 0.1,
17396
- gravity: 120,
17397
- tint: { r: 180, g: 140, b: 90 },
17398
- scaleMin: 0.15,
17399
- scaleMax: 0.3,
17400
- lifetimeMin: 400,
17401
- lifetimeMax: 700,
17402
- fadeRate: -1.8
17403
- },
17404
- {
17405
- spriteUrls: p(manifest, "scratch"),
17406
- count: 2,
17407
- originX,
17408
- originY,
17409
- spread: 5,
17410
- velocityMin: 10,
17411
- velocityMax: 30,
17412
- angleMin: -PI2 * 0.7,
17413
- angleMax: -PI2 * 0.3,
17414
- gravity: 0,
17415
- tint: { r: 255, g: 200, b: 150 },
17416
- scaleMin: 0.25,
17417
- scaleMax: 0.4,
17418
- lifetimeMin: 200,
17419
- lifetimeMax: 400,
17420
- fadeRate: -3
17421
- }
17422
- ];
17423
- const sequences = [];
17424
- const flashFrames = anim(manifest, "flash");
17425
- if (flashFrames.length > 0) {
17426
- sequences.push({
17427
- frameUrls: flashFrames,
17428
- originX,
17429
- originY,
17430
- frameDuration: 35,
17431
- scale: 0.4
17432
- });
17433
- }
17434
- return {
17435
- particles: particles.filter((pc) => pc.spriteUrls.length > 0),
17436
- sequences,
17437
- overlays: [],
17438
- screenShake: 4,
17439
- screenFlash: null
17440
- };
17441
- },
17442
- // =====================================================================
17443
- // RANGED — muzzle + trace + smoke + explosion sequence
17444
- // =====================================================================
17445
- ranged: (originX, originY) => {
17446
- const particles = [
17447
- {
17448
- spriteUrls: p(manifest, "muzzle"),
17449
- count: 3,
17450
- originX,
17451
- originY,
17452
- spread: 4,
17453
- velocityMin: 60,
17454
- velocityMax: 150,
17455
- angleMin: -PI2 * 0.6,
17456
- angleMax: -PI2 * 0.4,
17457
- gravity: 0,
17458
- tint: { r: 255, g: 220, b: 100 },
17459
- scaleMin: 0.2,
17460
- scaleMax: 0.4,
17461
- lifetimeMin: 200,
17462
- lifetimeMax: 400,
17463
- fadeRate: -3
17464
- },
17465
- {
17466
- spriteUrls: p(manifest, "trace"),
17467
- count: 5,
17468
- originX,
17469
- originY,
17470
- spread: 3,
17471
- velocityMin: 100,
17472
- velocityMax: 200,
17473
- angleMin: -PI2 * 0.55,
17474
- angleMax: -PI2 * 0.45,
17475
- gravity: 0,
17476
- tint: { r: 255, g: 200, b: 80 },
17477
- scaleMin: 0.15,
17478
- scaleMax: 0.3,
17479
- lifetimeMin: 150,
17480
- lifetimeMax: 300,
17481
- fadeRate: -4
17482
- },
17483
- {
17484
- spriteUrls: p(manifest, "smoke").slice(0, 3),
17485
- count: 3,
17486
- originX,
17487
- originY: originY + 5,
17488
- spread: 6,
17489
- velocityMin: 10,
17490
- velocityMax: 30,
17491
- angleMin: -PI2 * 0.8,
17492
- angleMax: -PI2 * 0.2,
17493
- gravity: -20,
17494
- tint: { r: 200, g: 200, b: 200 },
17495
- scaleMin: 0.2,
17496
- scaleMax: 0.35,
17497
- lifetimeMin: 500,
17498
- lifetimeMax: 800,
17499
- fadeRate: -1.5
17500
- }
17501
- ];
17502
- const sequences = [];
17503
- const explosionFrames = anim(manifest, "smokeExplosion");
17504
- if (explosionFrames.length > 0) {
17505
- sequences.push({
17506
- frameUrls: explosionFrames,
17507
- originX,
17508
- originY,
17509
- frameDuration: 50,
17510
- scale: 0.35
17511
- });
17512
- }
17513
- return {
17514
- particles: particles.filter((pc) => pc.spriteUrls.length > 0),
17515
- sequences,
17516
- overlays: [],
17517
- screenShake: 2,
17518
- screenFlash: null
17519
- };
17520
- },
17521
- // =====================================================================
17522
- // MAGIC — twirl (purple) + spark (purple) + star
17523
- // =====================================================================
17524
- magic: (originX, originY) => {
17525
- const particles = [
17526
- {
17527
- spriteUrls: p(manifest, "twirl"),
17528
- count: 5,
17529
- originX,
17530
- originY,
17531
- spread: 15,
17532
- velocityMin: 20,
17533
- velocityMax: 80,
17534
- angleMin: 0,
17535
- angleMax: PI2 * 2,
17536
- gravity: -30,
17537
- tint: { r: 180, g: 80, b: 255 },
17538
- scaleMin: 0.2,
17539
- scaleMax: 0.5,
17540
- lifetimeMin: 500,
17541
- lifetimeMax: 900,
17542
- fadeRate: -1.2,
17543
- blendMode: "lighter",
17544
- rotationSpeedMin: -4,
17545
- rotationSpeedMax: 4
17546
- },
17547
- {
17548
- spriteUrls: p(manifest, "spark"),
17549
- count: 8,
17550
- originX,
17551
- originY,
17552
- spread: 20,
17553
- velocityMin: 30,
17554
- velocityMax: 100,
17555
- angleMin: 0,
17556
- angleMax: PI2 * 2,
17557
- gravity: -15,
17558
- tint: { r: 200, g: 120, b: 255 },
17559
- scaleMin: 0.1,
17560
- scaleMax: 0.25,
17561
- lifetimeMin: 300,
17562
- lifetimeMax: 600,
17563
- fadeRate: -2,
17564
- blendMode: "lighter"
17565
- },
17566
- {
17567
- spriteUrls: p(manifest, "star"),
17568
- count: 4,
17569
- originX,
17570
- originY,
17571
- spread: 10,
17572
- velocityMin: 15,
17573
- velocityMax: 50,
17574
- angleMin: -PI2,
17575
- angleMax: 0,
17576
- gravity: -40,
17577
- tint: { r: 220, g: 180, b: 255 },
17578
- scaleMin: 0.15,
17579
- scaleMax: 0.3,
17580
- lifetimeMin: 600,
17581
- lifetimeMax: 1e3,
17582
- fadeRate: -1,
17583
- blendMode: "lighter"
17584
- }
17585
- ];
17586
- const overlays = [];
17587
- const circleUrls = p(manifest, "circle");
17588
- if (circleUrls.length > 0) {
17589
- overlays.push({
17590
- spriteUrl: circleUrls[0],
17591
- originX,
17592
- originY,
17593
- alpha: 0.5,
17594
- fadeRate: -0.6,
17595
- pulseAmplitude: 0.2,
17596
- pulseFrequency: 3,
17597
- scale: 0.5,
17598
- blendMode: "lighter",
17599
- lifetime: 1200
17600
- });
17601
- }
17602
- return {
17603
- particles: particles.filter((pc) => pc.spriteUrls.length > 0),
17604
- sequences: [],
17605
- overlays,
17606
- screenShake: 0,
17607
- screenFlash: null
17608
- };
17609
- },
17610
- // =====================================================================
17611
- // HEAL — circle (green) + star (green) + light (green, pulse)
17612
- // =====================================================================
17613
- heal: (originX, originY) => {
17614
- const particles = [
17615
- {
17616
- spriteUrls: p(manifest, "circle"),
17617
- count: 6,
17618
- originX,
17619
- originY,
17620
- spread: 15,
17621
- velocityMin: 10,
17622
- velocityMax: 40,
17623
- angleMin: -PI2,
17624
- angleMax: -PI2 * 0.3,
17625
- gravity: -50,
17626
- tint: { r: 80, g: 255, b: 120 },
17627
- scaleMin: 0.15,
17628
- scaleMax: 0.35,
17629
- lifetimeMin: 600,
17630
- lifetimeMax: 1e3,
17631
- fadeRate: -0.8,
17632
- blendMode: "lighter"
17633
- },
17634
- {
17635
- spriteUrls: p(manifest, "star"),
17636
- count: 5,
17637
- originX,
17638
- originY,
17639
- spread: 12,
17640
- velocityMin: 15,
17641
- velocityMax: 50,
17642
- angleMin: -PI2 * 0.9,
17643
- angleMax: -PI2 * 0.1,
17644
- gravity: -60,
17645
- tint: { r: 100, g: 255, b: 140 },
17646
- scaleMin: 0.1,
17647
- scaleMax: 0.2,
17648
- lifetimeMin: 500,
17649
- lifetimeMax: 800,
17650
- fadeRate: -1.2,
17651
- blendMode: "lighter"
17652
- }
17653
- ];
17654
- const overlays = [];
17655
- const lightUrls = p(manifest, "light");
17656
- if (lightUrls.length > 0) {
17657
- overlays.push({
17658
- spriteUrl: lightUrls[0],
17659
- originX,
17660
- originY,
17661
- alpha: 0.6,
17662
- fadeRate: -0.4,
17663
- pulseAmplitude: 0.25,
17664
- pulseFrequency: 2.5,
17665
- scale: 0.6,
17666
- blendMode: "lighter",
17667
- lifetime: 1500
17668
- });
17669
- }
17670
- return {
17671
- particles: particles.filter((pc) => pc.spriteUrls.length > 0),
17672
- sequences: [],
17673
- overlays,
17674
- screenShake: 0,
17675
- screenFlash: null
17676
- };
17677
- },
17678
- // =====================================================================
17679
- // DEFEND / SHIELD — star (blue) + circle (blue, pulse)
17680
- // =====================================================================
17681
- defend: (originX, originY) => {
17682
- const particles = [
17683
- {
17684
- spriteUrls: p(manifest, "star"),
17685
- count: 8,
17686
- originX,
17687
- originY,
17688
- spread: 18,
17689
- velocityMin: 10,
17690
- velocityMax: 35,
17691
- angleMin: 0,
17692
- angleMax: PI2 * 2,
17693
- gravity: 0,
17694
- tint: { r: 80, g: 160, b: 255 },
17695
- scaleMin: 0.12,
17696
- scaleMax: 0.25,
17697
- lifetimeMin: 600,
17698
- lifetimeMax: 1e3,
17699
- fadeRate: -0.8,
17700
- blendMode: "lighter",
17701
- rotationSpeedMin: -1,
17702
- rotationSpeedMax: 1
17703
- }
17704
- ];
17705
- const overlays = [];
17706
- const circleUrls = p(manifest, "circle");
17707
- if (circleUrls.length > 0) {
17708
- overlays.push({
17709
- spriteUrl: circleUrls[0],
17710
- originX,
17711
- originY,
17712
- alpha: 0.6,
17713
- fadeRate: -0.3,
17714
- pulseAmplitude: 0.2,
17715
- pulseFrequency: 2,
17716
- scale: 0.6,
17717
- blendMode: "lighter",
17718
- lifetime: 1500
17719
- });
17720
- }
17721
- return {
17722
- particles: particles.filter((pc) => pc.spriteUrls.length > 0),
17723
- sequences: [],
17724
- overlays,
17725
- screenShake: 0,
17726
- screenFlash: null
17727
- };
17728
- },
17729
- // shield aliases to defend
17730
- shield: (originX, originY) => {
17731
- const particles = [
17732
- {
17733
- spriteUrls: p(manifest, "star"),
17734
- count: 10,
17735
- originX,
17736
- originY,
17737
- spread: 20,
17738
- velocityMin: 8,
17739
- velocityMax: 30,
17740
- angleMin: 0,
17741
- angleMax: PI2 * 2,
17742
- gravity: 0,
17743
- tint: { r: 60, g: 180, b: 255 },
17744
- scaleMin: 0.1,
17745
- scaleMax: 0.22,
17746
- lifetimeMin: 700,
17747
- lifetimeMax: 1200,
17748
- fadeRate: -0.7,
17749
- blendMode: "lighter",
17750
- rotationSpeedMin: -0.8,
17751
- rotationSpeedMax: 0.8
17752
- }
17753
- ];
17754
- const overlays = [];
17755
- const circleUrls = p(manifest, "circle");
17756
- if (circleUrls.length > 0) {
17757
- overlays.push({
17758
- spriteUrl: circleUrls[0],
17759
- originX,
17760
- originY,
17761
- alpha: 0.7,
17762
- fadeRate: -0.25,
17763
- pulseAmplitude: 0.25,
17764
- pulseFrequency: 1.8,
17765
- scale: 0.7,
17766
- blendMode: "lighter",
17767
- lifetime: 1800
17768
- });
17769
- }
17770
- return {
17771
- particles: particles.filter((pc) => pc.spriteUrls.length > 0),
17772
- sequences: [],
17773
- overlays,
17774
- screenShake: 0,
17775
- screenFlash: null
17776
- };
17777
- },
17778
- // =====================================================================
17779
- // HIT — spark (orange) + flash (5 frames) + screen shake/flash
17780
- // =====================================================================
17781
- hit: (originX, originY) => {
17782
- const particles = [
17783
- {
17784
- spriteUrls: p(manifest, "spark"),
17785
- count: 10,
17786
- originX,
17787
- originY,
17788
- spread: 8,
17789
- velocityMin: 50,
17790
- velocityMax: 150,
17791
- angleMin: 0,
17792
- angleMax: PI2 * 2,
17793
- gravity: 80,
17794
- tint: { r: 255, g: 180, b: 50 },
17795
- scaleMin: 0.08,
17796
- scaleMax: 0.2,
17797
- lifetimeMin: 200,
17798
- lifetimeMax: 500,
17799
- fadeRate: -2.5
17800
- }
17801
- ];
17802
- const sequences = [];
17803
- const flashFrames = anim(manifest, "flash");
17804
- if (flashFrames.length > 0) {
17805
- sequences.push({
17806
- frameUrls: flashFrames.slice(0, 5),
17807
- originX,
17808
- originY,
17809
- frameDuration: 40,
17810
- scale: 0.3
17811
- });
17812
- }
17813
- return {
17814
- particles: particles.filter((pc) => pc.spriteUrls.length > 0),
17815
- sequences,
17816
- overlays: [],
17817
- screenShake: 3,
17818
- screenFlash: { r: 255, g: 50, b: 50, duration: 150 }
17819
- };
17820
- },
17821
- // critical aliases to hit with bigger shake
17822
- critical: (originX, originY) => {
17823
- const particles = [
17824
- {
17825
- spriteUrls: p(manifest, "flame"),
17826
- count: 8,
17827
- originX,
17828
- originY,
17829
- spread: 12,
17830
- velocityMin: 60,
17831
- velocityMax: 180,
17832
- angleMin: 0,
17833
- angleMax: PI2 * 2,
17834
- gravity: 60,
17835
- tint: { r: 255, g: 120, b: 30 },
17836
- scaleMin: 0.15,
17837
- scaleMax: 0.4,
17838
- lifetimeMin: 300,
17839
- lifetimeMax: 600,
17840
- fadeRate: -2
17841
- },
17842
- {
17843
- spriteUrls: p(manifest, "spark"),
17844
- count: 12,
17845
- originX,
17846
- originY,
17847
- spread: 10,
17848
- velocityMin: 80,
17849
- velocityMax: 200,
17850
- angleMin: 0,
17851
- angleMax: PI2 * 2,
17852
- gravity: 100,
17853
- tint: { r: 255, g: 200, b: 60 },
17854
- scaleMin: 0.06,
17855
- scaleMax: 0.18,
17856
- lifetimeMin: 200,
17857
- lifetimeMax: 400,
17858
- fadeRate: -3
17859
- }
17860
- ];
17861
- const sequences = [];
17862
- const flashFrames = anim(manifest, "flash");
17863
- if (flashFrames.length > 0) {
17864
- sequences.push({
17865
- frameUrls: flashFrames,
17866
- originX,
17867
- originY,
17868
- frameDuration: 30,
17869
- scale: 0.5
17870
- });
17871
- }
17872
- return {
17873
- particles: particles.filter((pc) => pc.spriteUrls.length > 0),
17874
- sequences,
17875
- overlays: [],
17876
- screenShake: 6,
17877
- screenFlash: { r: 255, g: 80, b: 0, duration: 200 }
17878
- };
17879
- },
17880
- // =====================================================================
17881
- // DEATH — dirt (gray) + explosion + black smoke + scorch (ground)
17882
- // =====================================================================
17883
- death: (originX, originY) => {
17884
- const particles = [
17885
- {
17886
- spriteUrls: p(manifest, "dirt"),
17887
- count: 8,
17888
- originX,
17889
- originY,
17890
- spread: 10,
17891
- velocityMin: 30,
17892
- velocityMax: 100,
17893
- angleMin: 0,
17894
- angleMax: PI2 * 2,
17895
- gravity: 100,
17896
- tint: { r: 140, g: 140, b: 140 },
17897
- scaleMin: 0.15,
17898
- scaleMax: 0.35,
17899
- lifetimeMin: 500,
17900
- lifetimeMax: 900,
17901
- fadeRate: -1.2
17902
- }
17903
- ];
17904
- const sequences = [];
17905
- const explosionFrames = anim(manifest, "explosion");
17906
- if (explosionFrames.length > 0) {
17907
- sequences.push({
17908
- frameUrls: explosionFrames,
17909
- originX,
17910
- originY,
17911
- frameDuration: 60,
17912
- scale: 0.5
17913
- });
17914
- }
17915
- const blackSmokeFrames = anim(manifest, "blackSmoke");
17916
- if (blackSmokeFrames.length > 0) {
17917
- sequences.push({
17918
- frameUrls: blackSmokeFrames,
17919
- originX,
17920
- originY: originY - 10,
17921
- frameDuration: 50,
17922
- scale: 0.4,
17923
- alpha: 0.7
17924
- });
17925
- }
17926
- const overlays = [];
17927
- const scorchUrls = p(manifest, "scorch");
17928
- if (scorchUrls.length > 0) {
17929
- overlays.push({
17930
- spriteUrl: scorchUrls[0],
17931
- originX,
17932
- originY: originY + 10,
17933
- alpha: 0.6,
17934
- fadeRate: -0.15,
17935
- scale: 0.4,
17936
- lifetime: 4e3
17937
- });
17938
- }
17939
- return {
17940
- particles: particles.filter((pc) => pc.spriteUrls.length > 0),
17941
- sequences,
17942
- overlays,
17943
- screenShake: 0,
17944
- screenFlash: null
17945
- };
17946
- },
17947
- // =====================================================================
17948
- // BUFF — star (gold) + symbol + flare (gold, pulse)
17949
- // =====================================================================
17950
- buff: (originX, originY) => {
17951
- const particles = [
17952
- {
17953
- spriteUrls: p(manifest, "star"),
17954
- count: 6,
17955
- originX,
17956
- originY,
17957
- spread: 15,
17958
- velocityMin: 15,
17959
- velocityMax: 50,
17960
- angleMin: -PI2,
17961
- angleMax: 0,
17962
- gravity: -30,
17963
- tint: { r: 255, g: 215, b: 50 },
17964
- scaleMin: 0.12,
17965
- scaleMax: 0.25,
17966
- lifetimeMin: 600,
17967
- lifetimeMax: 1e3,
17968
- fadeRate: -0.8,
17969
- blendMode: "lighter"
17970
- },
17971
- {
17972
- spriteUrls: p(manifest, "symbol"),
17973
- count: 2,
17974
- originX,
17975
- originY: originY - 10,
17976
- spread: 8,
17977
- velocityMin: 5,
17978
- velocityMax: 20,
17979
- angleMin: -PI2 * 0.7,
17980
- angleMax: -PI2 * 0.3,
17981
- gravity: -20,
17982
- tint: { r: 255, g: 230, b: 100 },
17983
- scaleMin: 0.2,
17984
- scaleMax: 0.35,
17985
- lifetimeMin: 800,
17986
- lifetimeMax: 1200,
17987
- fadeRate: -0.6,
17988
- blendMode: "lighter"
17989
- }
17990
- ];
17991
- const overlays = [];
17992
- const flareUrls = p(manifest, "flare");
17993
- if (flareUrls.length > 0) {
17994
- overlays.push({
17995
- spriteUrl: flareUrls[0],
17996
- originX,
17997
- originY,
17998
- alpha: 0.5,
17999
- fadeRate: -0.3,
18000
- pulseAmplitude: 0.3,
18001
- pulseFrequency: 2,
18002
- scale: 0.5,
18003
- blendMode: "lighter",
18004
- lifetime: 1500
18005
- });
18006
- }
18007
- return {
18008
- particles: particles.filter((pc) => pc.spriteUrls.length > 0),
18009
- sequences: [],
18010
- overlays,
18011
- screenShake: 0,
18012
- screenFlash: null
18013
- };
18014
- },
18015
- // =====================================================================
18016
- // DEBUFF — scorch (dark) + smoke (purple tint)
18017
- // =====================================================================
18018
- debuff: (originX, originY) => {
18019
- const particles = [
18020
- {
18021
- spriteUrls: p(manifest, "scorch"),
18022
- count: 4,
18023
- originX,
18024
- originY,
18025
- spread: 12,
18026
- velocityMin: 15,
18027
- velocityMax: 40,
18028
- angleMin: -PI2,
18029
- angleMax: 0,
18030
- gravity: -20,
18031
- tint: { r: 120, g: 40, b: 160 },
18032
- scaleMin: 0.15,
18033
- scaleMax: 0.3,
18034
- lifetimeMin: 500,
18035
- lifetimeMax: 800,
18036
- fadeRate: -1
18037
- },
18038
- {
18039
- spriteUrls: p(manifest, "smoke").slice(0, 3),
18040
- count: 3,
18041
- originX,
18042
- originY,
18043
- spread: 10,
18044
- velocityMin: 8,
18045
- velocityMax: 25,
18046
- angleMin: -PI2 * 0.8,
18047
- angleMax: -PI2 * 0.2,
18048
- gravity: -15,
18049
- tint: { r: 100, g: 50, b: 140 },
18050
- scaleMin: 0.2,
18051
- scaleMax: 0.35,
18052
- lifetimeMin: 600,
18053
- lifetimeMax: 1e3,
18054
- fadeRate: -0.8
18055
- }
18056
- ];
18057
- const overlays = [];
18058
- const circleUrls = p(manifest, "circle");
18059
- if (circleUrls.length > 0) {
18060
- overlays.push({
18061
- spriteUrl: circleUrls[0],
18062
- originX,
18063
- originY,
18064
- alpha: 0.4,
18065
- fadeRate: -0.4,
18066
- pulseAmplitude: 0.15,
18067
- pulseFrequency: 2,
18068
- scale: 0.45,
18069
- lifetime: 1200
18070
- });
18071
- }
18072
- return {
18073
- particles: particles.filter((pc) => pc.spriteUrls.length > 0),
18074
- sequences: [],
18075
- overlays,
18076
- screenShake: 0,
18077
- screenFlash: null
18078
- };
18079
- },
18080
- // =====================================================================
18081
- // AOE — explosion (large) + flame + spark (radial) + screen shake
18082
- // =====================================================================
18083
- aoe: (originX, originY) => {
18084
- const particles = [
18085
- {
18086
- spriteUrls: p(manifest, "flame"),
18087
- count: 10,
18088
- originX,
18089
- originY,
18090
- spread: 20,
18091
- velocityMin: 40,
18092
- velocityMax: 140,
18093
- angleMin: 0,
18094
- angleMax: PI2 * 2,
18095
- gravity: 40,
18096
- tint: { r: 255, g: 140, b: 30 },
18097
- scaleMin: 0.2,
18098
- scaleMax: 0.5,
18099
- lifetimeMin: 400,
18100
- lifetimeMax: 800,
18101
- fadeRate: -1.5
18102
- },
18103
- {
18104
- spriteUrls: p(manifest, "spark"),
18105
- count: 15,
18106
- originX,
18107
- originY,
18108
- spread: 15,
18109
- velocityMin: 60,
18110
- velocityMax: 200,
18111
- angleMin: 0,
18112
- angleMax: PI2 * 2,
18113
- gravity: 60,
18114
- tint: { r: 255, g: 180, b: 60 },
18115
- scaleMin: 0.06,
18116
- scaleMax: 0.15,
18117
- lifetimeMin: 200,
18118
- lifetimeMax: 500,
18119
- fadeRate: -2.5
18120
- }
18121
- ];
18122
- const sequences = [];
18123
- const explosionFrames = anim(manifest, "explosion");
18124
- if (explosionFrames.length > 0) {
18125
- sequences.push({
18126
- frameUrls: explosionFrames,
18127
- originX,
18128
- originY,
18129
- frameDuration: 50,
18130
- scale: 0.6
18131
- });
18132
- }
18133
- return {
18134
- particles: particles.filter((pc) => pc.spriteUrls.length > 0),
18135
- sequences,
18136
- overlays: [],
18137
- screenShake: 5,
18138
- screenFlash: { r: 255, g: 160, b: 0, duration: 180 }
18139
- };
18140
- }
18141
- };
18142
- }
18143
- var PI2;
18144
- var init_combatPresets = __esm({
18145
- "components/game/shared/combatPresets.ts"() {
18146
- PI2 = Math.PI;
18147
- }
18148
- });
18149
- function CanvasEffectEngine({
18150
- actionType,
18151
- x,
18152
- y,
18153
- duration = 2e3,
18154
- intensity = 1,
18155
- onComplete,
18156
- className,
18157
- assetManifest,
18158
- width = 400,
18159
- height = 300
18160
- }) {
18161
- const canvasRef = useRef(null);
18162
- const stateRef = useRef({ ...EMPTY_EFFECT_STATE });
18163
- const lastTimeRef = useRef(0);
18164
- const rafRef = useRef(0);
18165
- const imageCacheRef = useRef(/* @__PURE__ */ new Map());
18166
- const [shakeOffset, setShakeOffset] = useState({ x: 0, y: 0 });
18167
- const [flash, setFlash] = useState(null);
18168
- const shakeRef = useRef({ x: 0, y: 0, intensity: 0 });
18169
- const presets = useMemo(() => createCombatPresets(assetManifest), [assetManifest]);
18170
- const spriteUrls = useMemo(() => getAllEffectSpriteUrls(assetManifest), [assetManifest]);
18171
- useEffect(() => {
18172
- const cache = imageCacheRef.current;
18173
- for (const url of spriteUrls) {
18174
- if (!cache.has(url)) {
18175
- const img = new Image();
18176
- img.crossOrigin = "anonymous";
18177
- img.src = url;
18178
- cache.set(url, img);
18179
- }
18180
- }
18181
- }, [spriteUrls]);
18182
- const getImage = useCallback((url) => {
18183
- const img = imageCacheRef.current.get(url);
18184
- return img?.complete ? img : void 0;
18185
- }, []);
18186
- useEffect(() => {
18187
- const now = performance.now();
18188
- const effectX = x || width / 2;
18189
- const effectY = y || height / 2;
18190
- const preset = presets[actionType](effectX, effectY);
18191
- const state = stateRef.current;
18192
- for (const emitter of preset.particles) {
18193
- const scaledEmitter = { ...emitter, count: Math.round(emitter.count * intensity) };
18194
- state.particles.push(...spawnParticles(scaledEmitter, now));
18195
- }
18196
- for (const seqConfig of preset.sequences) {
18197
- state.sequences.push(spawnSequence(seqConfig, now));
18198
- }
18199
- for (const ovConfig of preset.overlays) {
18200
- state.overlays.push(spawnOverlay(ovConfig, now));
18201
- }
18202
- if (preset.screenShake > 0) {
18203
- shakeRef.current.intensity = preset.screenShake * intensity;
18204
- }
18205
- if (preset.screenFlash) {
18206
- const { r, g, b, duration: flashDur } = preset.screenFlash;
18207
- setFlash({ color: `rgb(${r}, ${g}, ${b})`, alpha: 0.3 });
18208
- setTimeout(() => setFlash(null), flashDur);
18209
- }
18210
- const timer = setTimeout(() => {
18211
- onComplete?.();
18212
- }, duration);
18213
- return () => clearTimeout(timer);
18214
- }, []);
18215
- useEffect(() => {
18216
- const canvas = canvasRef.current;
18217
- if (!canvas) return;
18218
- const ctx = canvas.getContext("2d");
18219
- if (!ctx) return;
18220
- function loop(animTime) {
18221
- const delta = lastTimeRef.current > 0 ? animTime - lastTimeRef.current : 16;
18222
- lastTimeRef.current = animTime;
18223
- stateRef.current = updateEffectState(stateRef.current, animTime, delta);
18224
- if (shakeRef.current.intensity > 0.2) {
18225
- const i = shakeRef.current.intensity;
18226
- shakeRef.current.x = (Math.random() - 0.5) * i * 2;
18227
- shakeRef.current.y = (Math.random() - 0.5) * i * 2;
18228
- shakeRef.current.intensity *= 0.85;
18229
- setShakeOffset({ x: shakeRef.current.x, y: shakeRef.current.y });
18230
- } else if (shakeRef.current.intensity > 0) {
18231
- shakeRef.current = { x: 0, y: 0, intensity: 0 };
18232
- setShakeOffset({ x: 0, y: 0 });
18233
- }
18234
- ctx.clearRect(0, 0, width, height);
18235
- drawEffectState(ctx, stateRef.current, animTime, getImage);
18236
- if (hasActiveEffects(stateRef.current)) {
18237
- rafRef.current = requestAnimationFrame(loop);
18238
- }
18239
- }
18240
- rafRef.current = requestAnimationFrame(loop);
18241
- return () => cancelAnimationFrame(rafRef.current);
18242
- }, [width, height, getImage]);
18243
- const shakeStyle = shakeOffset.x !== 0 || shakeOffset.y !== 0 ? { transform: `translate(${shakeOffset.x}px, ${shakeOffset.y}px)` } : {};
18244
- return /* @__PURE__ */ jsxs(
18245
- Box,
18246
- {
18247
- className: cn("absolute inset-0 pointer-events-none z-10", className),
18248
- style: shakeStyle,
18249
- children: [
18250
- flash && /* @__PURE__ */ jsx(
18251
- Box,
18252
- {
18253
- className: "absolute inset-0 z-20 pointer-events-none rounded-container",
18254
- style: { backgroundColor: flash.color, opacity: flash.alpha }
18255
- }
18256
- ),
18257
- /* @__PURE__ */ jsx(
18258
- "canvas",
18259
- {
18260
- ref: canvasRef,
18261
- width,
18262
- height,
18263
- className: "absolute inset-0 w-full h-full",
18264
- style: { imageRendering: "pixelated" }
18265
- }
18266
- )
18267
- ]
18268
- }
18269
- );
18270
- }
18271
- function EmojiEffect({
18272
- actionType,
18273
- x,
18274
- y,
18275
- duration = 800,
18276
- intensity = 1,
18277
- onComplete,
18278
- className,
18279
- effectSpriteUrl,
18280
- assetBaseUrl
18281
- }) {
18282
- const [visible, setVisible] = useState(true);
18283
- const [phase, setPhase] = useState("enter");
18284
- useEffect(() => {
18285
- const enterTimer = setTimeout(() => setPhase("active"), 100);
18286
- const exitTimer = setTimeout(() => setPhase("exit"), duration * 0.7);
18287
- const doneTimer = setTimeout(() => {
18288
- setVisible(false);
18289
- onComplete?.();
18290
- }, duration);
18291
- return () => {
18292
- clearTimeout(enterTimer);
18293
- clearTimeout(exitTimer);
18294
- clearTimeout(doneTimer);
18295
- };
18296
- }, [duration, onComplete]);
18297
- if (!visible) return null;
18298
- const config = ACTION_EMOJI[actionType] ?? ACTION_EMOJI.melee;
18299
- const scaleVal = phase === "enter" ? 0.3 : phase === "active" ? intensity : 0.5;
18300
- const opacity = phase === "exit" ? 0 : 1;
18301
- const resolvedSpriteUrl = effectSpriteUrl ? effectSpriteUrl.startsWith("http") || effectSpriteUrl.startsWith("/") ? effectSpriteUrl : assetBaseUrl ? `${assetBaseUrl.replace(/\/$/, "")}/${effectSpriteUrl}` : effectSpriteUrl : void 0;
18302
- return /* @__PURE__ */ jsxs(
18303
- Box,
18304
- {
18305
- className: cn(
18306
- "fixed pointer-events-none z-50 flex items-center justify-center",
18307
- "transition-all ease-out",
18308
- className
18309
- ),
18310
- style: {
18311
- left: x,
18312
- top: y,
18313
- transform: `translate(-50%, -50%) scale(${scaleVal})`,
18314
- opacity,
18315
- transitionDuration: phase === "enter" ? "100ms" : "300ms"
18316
- },
18317
- children: [
18318
- /* @__PURE__ */ jsx(
18319
- Box,
18320
- {
18321
- className: "absolute rounded-pill animate-ping",
18322
- style: {
18323
- width: 48 * intensity,
18324
- height: 48 * intensity,
18325
- backgroundColor: config.color,
18326
- opacity: 0.25
18327
- }
18328
- }
18329
- ),
18330
- resolvedSpriteUrl ? /* @__PURE__ */ jsx(
18331
- "img",
18332
- {
18333
- src: resolvedSpriteUrl,
18334
- alt: config.label,
18335
- className: "relative drop-shadow-lg",
18336
- style: {
18337
- width: `${3 * intensity}rem`,
18338
- height: `${3 * intensity}rem`,
18339
- objectFit: "contain",
18340
- imageRendering: "pixelated"
18341
- }
18342
- }
18343
- ) : /* @__PURE__ */ jsx(
18344
- "span",
18345
- {
18346
- className: "relative text-3xl drop-shadow-lg",
18347
- style: { fontSize: `${2 * intensity}rem` },
18348
- role: "img",
18349
- "aria-label": config.label,
18350
- children: config.emoji
18351
- }
18352
- )
18353
- ]
18354
- }
18355
- );
18356
- }
18357
- function CanvasEffect({
18358
- effectSpriteUrl,
18359
- assetBaseUrl,
18360
- ...props
18361
- }) {
18362
- const eventBus = useEventBus();
18363
- const mergedProps = { effectSpriteUrl, assetBaseUrl, ...props };
18364
- const { completeEvent, onComplete, ...rest } = mergedProps;
18365
- const handleComplete = useCallback(() => {
18366
- if (completeEvent) eventBus.emit(`UI:${completeEvent}`, {});
18367
- onComplete?.();
18368
- }, [completeEvent, eventBus, onComplete]);
18369
- const enhancedProps = { ...rest, onComplete: handleComplete };
18370
- if (rest.assetManifest) {
18371
- return /* @__PURE__ */ jsx(CanvasEffectEngine, { ...enhancedProps, assetManifest: rest.assetManifest });
18372
- }
18373
- return /* @__PURE__ */ jsx(EmojiEffect, { ...enhancedProps });
18374
- }
18375
- var ACTION_EMOJI;
18376
- var init_CanvasEffect = __esm({
18377
- "components/game/2d/organisms/CanvasEffect.tsx"() {
18378
- "use client";
18379
- init_cn();
18380
- init_useEventBus();
18381
- init_Box();
18382
- init_effects();
18383
- init_canvasEffects();
18384
- init_combatPresets();
18385
- ACTION_EMOJI = {
18386
- melee: { emoji: "\u2694\uFE0F", color: "var(--color-error)", label: "Slash" },
18387
- ranged: { emoji: "\u{1F3F9}", color: "var(--color-warning)", label: "Arrow" },
18388
- magic: { emoji: "\u2728", color: "var(--color-primary)", label: "Spell" },
18389
- heal: { emoji: "\u{1F49A}", color: "var(--color-success)", label: "Heal" },
18390
- buff: { emoji: "\u2B06\uFE0F", color: "var(--color-info)", label: "Buff" },
18391
- debuff: { emoji: "\u2B07\uFE0F", color: "var(--color-warning)", label: "Debuff" },
18392
- shield: { emoji: "\u{1F6E1}\uFE0F", color: "var(--color-info)", label: "Shield" },
18393
- aoe: { emoji: "\u{1F4A5}", color: "var(--color-error)", label: "Explosion" },
18394
- critical: { emoji: "\u{1F525}", color: "var(--color-error)", label: "Critical" },
18395
- defend: { emoji: "\u{1F6E1}\uFE0F", color: "var(--color-info)", label: "Defend" },
18396
- hit: { emoji: "\u{1F4A5}", color: "var(--color-error)", label: "Hit" },
18397
- death: { emoji: "\u{1F480}", color: "var(--color-error)", label: "Death" }
18398
- };
18399
- CanvasEffect.displayName = "CanvasEffect";
18400
- }
18401
- });
18402
-
18403
17131
  // lib/getNestedValue.ts
18404
17132
  function getNestedValue(obj, path) {
18405
17133
  if (obj === null || obj === void 0 || !path) {
@@ -19186,10 +17914,10 @@ var init_Chart = __esm({
19186
17914
  const set = [];
19187
17915
  const seen = /* @__PURE__ */ new Set();
19188
17916
  for (const s of series) {
19189
- for (const p2 of s.data) {
19190
- if (!seen.has(p2.label)) {
19191
- seen.add(p2.label);
19192
- set.push(p2.label);
17917
+ for (const p of s.data) {
17918
+ if (!seen.has(p.label)) {
17919
+ seen.add(p.label);
17920
+ set.push(p.label);
19193
17921
  }
19194
17922
  }
19195
17923
  }
@@ -19197,8 +17925,8 @@ var init_Chart = __esm({
19197
17925
  }, [series]);
19198
17926
  const valueAt = useCallback(
19199
17927
  (s, label) => {
19200
- const p2 = s.data.find((d) => d.label === label);
19201
- return p2 ? p2.value : 0;
17928
+ const p = s.data.find((d) => d.label === label);
17929
+ return p ? p.value : 0;
19202
17930
  },
19203
17931
  []
19204
17932
  );
@@ -19215,7 +17943,7 @@ var init_Chart = __esm({
19215
17943
  }
19216
17944
  let m = 1;
19217
17945
  for (const s of series) {
19218
- for (const p2 of s.data) if (p2.value > m) m = p2.value;
17946
+ for (const p of s.data) if (p.value > m) m = p.value;
19219
17947
  }
19220
17948
  return m;
19221
17949
  }, [series, stack, columnTotals]);
@@ -19475,10 +18203,10 @@ var init_Chart = __esm({
19475
18203
  const seen = /* @__PURE__ */ new Set();
19476
18204
  const out = [];
19477
18205
  for (const s of series) {
19478
- for (const p2 of s.data) {
19479
- if (!seen.has(p2.label)) {
19480
- seen.add(p2.label);
19481
- out.push(p2.label);
18206
+ for (const p of s.data) {
18207
+ if (!seen.has(p.label)) {
18208
+ seen.add(p.label);
18209
+ out.push(p.label);
19482
18210
  }
19483
18211
  }
19484
18212
  }
@@ -19487,7 +18215,7 @@ var init_Chart = __esm({
19487
18215
  const maxValue = useMemo(() => {
19488
18216
  let m = 1;
19489
18217
  for (const s of series) {
19490
- for (const p2 of s.data) if (p2.value > m) m = p2.value;
18218
+ for (const p of s.data) if (p.value > m) m = p.value;
19491
18219
  }
19492
18220
  return m;
19493
18221
  }, [series]);
@@ -19534,7 +18262,7 @@ var init_Chart = __esm({
19534
18262
  label
19535
18263
  };
19536
18264
  });
19537
- const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
18265
+ const linePath = points.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" ");
19538
18266
  const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
19539
18267
  return /* @__PURE__ */ jsxs("g", { children: [
19540
18268
  fill && /* @__PURE__ */ jsx(
@@ -19557,19 +18285,19 @@ var init_Chart = __esm({
19557
18285
  strokeDasharray: s.dashed ? "6 4" : void 0
19558
18286
  }
19559
18287
  ),
19560
- points.map((p2, idx) => /* @__PURE__ */ jsxs("g", { children: [
18288
+ points.map((p, idx) => /* @__PURE__ */ jsxs("g", { children: [
19561
18289
  /* @__PURE__ */ jsx(
19562
18290
  "circle",
19563
18291
  {
19564
- cx: p2.x,
19565
- cy: p2.y,
18292
+ cx: p.x,
18293
+ cy: p.y,
19566
18294
  r: "4",
19567
18295
  fill: "var(--color-card)",
19568
18296
  stroke: color,
19569
18297
  strokeWidth: "2",
19570
18298
  className: "cursor-pointer",
19571
18299
  onClick: () => onPointClick?.(
19572
- { label: p2.label, value: p2.value, color },
18300
+ { label: p.label, value: p.value, color },
19573
18301
  s.name
19574
18302
  )
19575
18303
  }
@@ -19577,13 +18305,13 @@ var init_Chart = __esm({
19577
18305
  showValues && series.length === 1 && /* @__PURE__ */ jsx(
19578
18306
  "text",
19579
18307
  {
19580
- x: p2.x,
19581
- y: p2.y - 10,
18308
+ x: p.x,
18309
+ y: p.y - 10,
19582
18310
  textAnchor: "middle",
19583
18311
  fill: "var(--color-foreground)",
19584
18312
  fontSize: "10",
19585
18313
  fontWeight: "500",
19586
- children: p2.value
18314
+ children: p.value
19587
18315
  }
19588
18316
  )
19589
18317
  ] }, idx))
@@ -19618,11 +18346,11 @@ var init_Chart = __esm({
19618
18346
  let mxX = data[0].x;
19619
18347
  let mnY = data[0].y;
19620
18348
  let mxY = data[0].y;
19621
- for (const p2 of data) {
19622
- if (p2.x < mnX) mnX = p2.x;
19623
- if (p2.x > mxX) mxX = p2.x;
19624
- if (p2.y < mnY) mnY = p2.y;
19625
- if (p2.y > mxY) mxY = p2.y;
18349
+ for (const p of data) {
18350
+ if (p.x < mnX) mnX = p.x;
18351
+ if (p.x > mxX) mxX = p.x;
18352
+ if (p.y < mnY) mnY = p.y;
18353
+ if (p.y > mxY) mxY = p.y;
19626
18354
  }
19627
18355
  return { minX: mnX, maxX: mxX, minY: mnY, maxY: mxY };
19628
18356
  }, [data]);
@@ -19652,11 +18380,11 @@ var init_Chart = __esm({
19652
18380
  frac
19653
18381
  );
19654
18382
  }),
19655
- data.map((p2, idx) => {
19656
- const cx = padding.left + (p2.x - minX) / rangeX * chartWidth;
19657
- const cy = padding.top + chartHeight - (p2.y - minY) / rangeY * chartHeight;
19658
- const r = p2.size ?? 5;
19659
- const color = p2.color ?? CHART_COLORS[idx % CHART_COLORS.length];
18383
+ data.map((p, idx) => {
18384
+ const cx = padding.left + (p.x - minX) / rangeX * chartWidth;
18385
+ const cy = padding.top + chartHeight - (p.y - minY) / rangeY * chartHeight;
18386
+ const r = p.size ?? 5;
18387
+ const color = p.color ?? CHART_COLORS[idx % CHART_COLORS.length];
19660
18388
  return /* @__PURE__ */ jsx(
19661
18389
  "circle",
19662
18390
  {
@@ -19668,13 +18396,13 @@ var init_Chart = __esm({
19668
18396
  className: "cursor-pointer hover:opacity-100",
19669
18397
  onClick: () => onPointClick?.(
19670
18398
  {
19671
- label: p2.label ?? `(${p2.x}, ${p2.y})`,
19672
- value: p2.y,
18399
+ label: p.label ?? `(${p.x}, ${p.y})`,
18400
+ value: p.y,
19673
18401
  color
19674
18402
  },
19675
18403
  "default"
19676
18404
  ),
19677
- children: /* @__PURE__ */ jsx("title", { children: p2.label ?? `(${p2.x}, ${p2.y})` })
18405
+ children: /* @__PURE__ */ jsx("title", { children: p.label ?? `(${p.x}, ${p.y})` })
19678
18406
  },
19679
18407
  idx
19680
18408
  );
@@ -24591,7 +23319,7 @@ var init_NodeSlotEditor = __esm({
24591
23319
  }
24592
23320
  }, []);
24593
23321
  const options = React74__default.useMemo(
24594
- () => [{ value: "", label: "\u2014 none \u2014" }, ...patterns.map((p2) => ({ value: p2, label: p2 }))],
23322
+ () => [{ value: "", label: "\u2014 none \u2014" }, ...patterns.map((p) => ({ value: p, label: p }))],
24595
23323
  [patterns]
24596
23324
  );
24597
23325
  const emit = (nextType, nextProps) => {
@@ -26075,11 +24803,11 @@ var init_OnboardingSpotlight = __esm({
26075
24803
  if (!step || typeof document === "undefined") return null;
26076
24804
  const isLast = stepIndex >= steps.length - 1;
26077
24805
  const backdrop = rect ? (() => {
26078
- const p2 = cutoutPadding;
26079
- const top = Math.max(0, rect.top - p2);
26080
- const left = Math.max(0, rect.left - p2);
26081
- const right = rect.right + p2;
26082
- const bottom = rect.bottom + p2;
24806
+ const p = cutoutPadding;
24807
+ const top = Math.max(0, rect.top - p);
24808
+ const left = Math.max(0, rect.left - p);
24809
+ const right = rect.right + p;
24810
+ const bottom = rect.bottom + p;
26083
24811
  return /* @__PURE__ */ jsxs(Fragment, { children: [
26084
24812
  /* @__PURE__ */ jsx("div", { className: DIM, style: { top: 0, left: 0, right: 0, height: top } }),
26085
24813
  /* @__PURE__ */ jsx("div", { className: DIM, style: { top: bottom, left: 0, right: 0, bottom: 0 } }),
@@ -27595,7 +26323,7 @@ var init_LineChart = __esm({
27595
26323
  }, [sortedData, width, height]);
27596
26324
  const linePath = useMemo(() => {
27597
26325
  if (points.length === 0) return "";
27598
- return points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
26326
+ return points.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" ");
27599
26327
  }, [points]);
27600
26328
  const areaPath = useMemo(() => {
27601
26329
  if (points.length === 0 || !showArea) return "";
@@ -27801,6 +26529,18 @@ var init_game = __esm({
27801
26529
  }
27802
26530
  });
27803
26531
 
26532
+ // components/game/shared/effects.ts
26533
+ var EMPTY_EFFECT_STATE;
26534
+ var init_effects = __esm({
26535
+ "components/game/shared/effects.ts"() {
26536
+ EMPTY_EFFECT_STATE = {
26537
+ particles: [],
26538
+ sequences: [],
26539
+ overlays: []
26540
+ };
26541
+ }
26542
+ });
26543
+
27804
26544
  // components/game/shared/makeAsset.ts
27805
26545
  function makeAsset(url, role, overrides = {}) {
27806
26546
  const defaults = ROLE_DEFAULTS[role] ?? { dimension: "2d", animations: ["static"], aspect: "1:1" };
@@ -27848,8 +26588,6 @@ var init_shared = __esm({
27848
26588
  init_isometric();
27849
26589
  init_spriteAnimation();
27850
26590
  init_spriteSheetConstants();
27851
- init_combatPresets();
27852
- init_canvasEffects();
27853
26591
  }
27854
26592
  });
27855
26593
  function GameCard({
@@ -29054,83 +27792,6 @@ var init_GameMenu = __esm({
29054
27792
  GameMenu.displayName = "GameMenu";
29055
27793
  }
29056
27794
  });
29057
- function useCanvasEffects({
29058
- manifest
29059
- }) {
29060
- const stateRef = useRef({ ...EMPTY_EFFECT_STATE });
29061
- const lastTimeRef = useRef(0);
29062
- const shakeRef = useRef({ x: 0, y: 0, intensity: 0 });
29063
- const [active, setActive] = useState(false);
29064
- const [screenShake, setScreenShake] = useState({ x: 0, y: 0 });
29065
- const [screenFlash, setScreenFlash] = useState(null);
29066
- const effectSpriteUrls = useMemo(
29067
- () => getAllEffectSpriteUrls(manifest),
29068
- [manifest]
29069
- );
29070
- const presets = useMemo(
29071
- () => createCombatPresets(manifest),
29072
- [manifest]
29073
- );
29074
- const spawnEffect = useCallback((type, screenX, screenY) => {
29075
- const now = performance.now();
29076
- const preset = presets[type](screenX, screenY);
29077
- const state = stateRef.current;
29078
- for (const emitter of preset.particles) {
29079
- state.particles.push(...spawnParticles(emitter, now));
29080
- }
29081
- for (const seqConfig of preset.sequences) {
29082
- state.sequences.push(spawnSequence(seqConfig, now));
29083
- }
29084
- for (const ovConfig of preset.overlays) {
29085
- state.overlays.push(spawnOverlay(ovConfig, now));
29086
- }
29087
- if (preset.screenShake > 0) {
29088
- shakeRef.current.intensity = preset.screenShake;
29089
- }
29090
- if (preset.screenFlash) {
29091
- const { r, g, b, duration } = preset.screenFlash;
29092
- setScreenFlash({ color: `rgb(${r}, ${g}, ${b})`, alpha: 0.3 });
29093
- setTimeout(() => setScreenFlash(null), duration);
29094
- }
29095
- setActive(true);
29096
- }, [presets]);
29097
- const drawEffects = useCallback((ctx, animTime, getImage) => {
29098
- const delta = lastTimeRef.current > 0 ? animTime - lastTimeRef.current : 16;
29099
- lastTimeRef.current = animTime;
29100
- stateRef.current = updateEffectState(stateRef.current, animTime, delta);
29101
- if (shakeRef.current.intensity > 0.2) {
29102
- const i = shakeRef.current.intensity;
29103
- shakeRef.current.x = (Math.random() - 0.5) * i * 2;
29104
- shakeRef.current.y = (Math.random() - 0.5) * i * 2;
29105
- shakeRef.current.intensity *= 0.85;
29106
- setScreenShake({ x: shakeRef.current.x, y: shakeRef.current.y });
29107
- } else if (shakeRef.current.intensity > 0) {
29108
- shakeRef.current = { x: 0, y: 0, intensity: 0 };
29109
- setScreenShake({ x: 0, y: 0 });
29110
- }
29111
- drawEffectState(ctx, stateRef.current, animTime, getImage);
29112
- const isActive = hasActiveEffects(stateRef.current);
29113
- if (!isActive && active) {
29114
- setActive(false);
29115
- }
29116
- }, [active]);
29117
- return {
29118
- effectSpriteUrls,
29119
- spawnEffect,
29120
- drawEffects,
29121
- hasActiveEffects: active,
29122
- screenShake,
29123
- screenFlash
29124
- };
29125
- }
29126
- var init_useCanvasEffects = __esm({
29127
- "components/game/shared/hooks/useCanvasEffects.ts"() {
29128
- "use client";
29129
- init_effects();
29130
- init_canvasEffects();
29131
- init_combatPresets();
29132
- }
29133
- });
29134
27795
  function pickPath(entry) {
29135
27796
  if (Array.isArray(entry.path)) {
29136
27797
  return entry.path[Math.floor(Math.random() * entry.path.length)];
@@ -31817,7 +30478,7 @@ function NegotiatorBoard({
31817
30478
  useEffect(() => {
31818
30479
  if (currentRound > prevRoundRef.current && lastPlayerAction) {
31819
30480
  const opponentPayoffEntry = payoffMatrix.find(
31820
- (p2) => p2.playerAction === lastPlayerAction && p2.opponentAction === lastOpponentAction
30481
+ (p) => p.playerAction === lastPlayerAction && p.opponentAction === lastOpponentAction
31821
30482
  );
31822
30483
  setHistory((prev) => [
31823
30484
  ...prev,
@@ -32110,14 +30771,14 @@ function SimulationCanvas({
32110
30771
  const ctx = canvas.getContext("2d");
32111
30772
  if (!ctx) return;
32112
30773
  const bodies = bodiesRef.current;
32113
- const p2 = presetRef.current;
30774
+ const p = presetRef.current;
32114
30775
  const w = widthRef.current;
32115
30776
  const h = heightRef.current;
32116
30777
  ctx.clearRect(0, 0, w, h);
32117
- ctx.fillStyle = p2.backgroundColor ?? "#1a1a2e";
30778
+ ctx.fillStyle = p.backgroundColor ?? "#1a1a2e";
32118
30779
  ctx.fillRect(0, 0, w, h);
32119
- if (p2.constraints) {
32120
- for (const c of p2.constraints) {
30780
+ if (p.constraints) {
30781
+ for (const c of p.constraints) {
32121
30782
  const a = bodies[c.bodyA];
32122
30783
  const b = bodies[c.bodyB];
32123
30784
  if (a && b) {
@@ -32140,7 +30801,7 @@ function SimulationCanvas({
32140
30801
  ctx.arc(pos.x, pos.y, body.radius, 0, Math.PI * 2);
32141
30802
  ctx.fillStyle = body.color ?? "#e94560";
32142
30803
  ctx.fill();
32143
- if (p2.showVelocity) {
30804
+ if (p.showVelocity) {
32144
30805
  ctx.beginPath();
32145
30806
  ctx.moveTo(pos.x, pos.y);
32146
30807
  ctx.lineTo(pos.x + body.vx * 0.1, pos.y + body.vy * 0.1);
@@ -32600,8 +31261,6 @@ var init_molecules = __esm({
32600
31261
  init_GameMenu();
32601
31262
  init_Canvas2D();
32602
31263
  init_useUnitSpriteAtlas();
32603
- init_CanvasEffect();
32604
- init_useCanvasEffects();
32605
31264
  init_GameAudioProvider();
32606
31265
  init_GameAudioToggle();
32607
31266
  init_useGameAudio();
@@ -32705,18 +31364,18 @@ var init_MathCanvas = __esm({
32705
31364
  });
32706
31365
  }
32707
31366
  }
32708
- for (const p2 of points) {
32709
- if (p2.x < xMin || p2.x > xMax || p2.y < yMin || p2.y > yMax) continue;
31367
+ for (const p of points) {
31368
+ if (p.x < xMin || p.x > xMax || p.y < yMin || p.y > yMax) continue;
32710
31369
  out.push({
32711
31370
  type: "circle",
32712
- x: mapX(p2.x),
32713
- y: mapY(p2.y),
32714
- radius: p2.radius ?? 4,
32715
- color: p2.color ?? "#dc2626",
32716
- fill: p2.color ?? "#dc2626"
31371
+ x: mapX(p.x),
31372
+ y: mapY(p.y),
31373
+ radius: p.radius ?? 4,
31374
+ color: p.color ?? "#dc2626",
31375
+ fill: p.color ?? "#dc2626"
32717
31376
  });
32718
- if (p2.label) {
32719
- out.push({ type: "text", x: mapX(p2.x) + 8, y: mapY(p2.y) - 8, text: p2.label, color: "#111827", fontSize: 12 });
31377
+ if (p.label) {
31378
+ out.push({ type: "text", x: mapX(p.x) + 8, y: mapY(p.y) - 8, text: p.label, color: "#111827", fontSize: 12 });
32720
31379
  }
32721
31380
  }
32722
31381
  for (const v of vectors) {
@@ -33235,13 +31894,13 @@ var init_MapView = __esm({
33235
31894
  shadowSize: [41, 41]
33236
31895
  });
33237
31896
  L.Marker.prototype.options.icon = defaultIcon;
33238
- const { useEffect: useEffect72, useRef: useRef68, useCallback: useCallback116, useState: useState110 } = React74__default;
31897
+ const { useEffect: useEffect71, useRef: useRef66, useCallback: useCallback114, useState: useState108 } = React74__default;
33239
31898
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
33240
31899
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
33241
31900
  function MapUpdater({ centerLat, centerLng, zoom }) {
33242
31901
  const map = useMap();
33243
- const prevRef = useRef68({ centerLat, centerLng, zoom });
33244
- useEffect72(() => {
31902
+ const prevRef = useRef66({ centerLat, centerLng, zoom });
31903
+ useEffect71(() => {
33245
31904
  const prev = prevRef.current;
33246
31905
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
33247
31906
  map.setView([centerLat, centerLng], zoom);
@@ -33252,7 +31911,7 @@ var init_MapView = __esm({
33252
31911
  }
33253
31912
  function MapClickHandler({ onMapClick }) {
33254
31913
  const map = useMap();
33255
- useEffect72(() => {
31914
+ useEffect71(() => {
33256
31915
  if (!onMapClick) return;
33257
31916
  const handler = (e) => {
33258
31917
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -33280,8 +31939,8 @@ var init_MapView = __esm({
33280
31939
  showAttribution = true
33281
31940
  }) {
33282
31941
  const eventBus = useEventBus2();
33283
- const [clickedPosition, setClickedPosition] = useState110(null);
33284
- const handleMapClick = useCallback116((lat, lng) => {
31942
+ const [clickedPosition, setClickedPosition] = useState108(null);
31943
+ const handleMapClick = useCallback114((lat, lng) => {
33285
31944
  if (showClickedPin) {
33286
31945
  setClickedPosition({ lat, lng });
33287
31946
  }
@@ -33290,7 +31949,7 @@ var init_MapView = __esm({
33290
31949
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
33291
31950
  }
33292
31951
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
33293
- const handleMarkerClick = useCallback116((marker) => {
31952
+ const handleMarkerClick = useCallback114((marker) => {
33294
31953
  onMarkerClick?.(marker);
33295
31954
  if (markerClickEvent) {
33296
31955
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -34363,7 +33022,7 @@ function TableView({
34363
33022
  children: [
34364
33023
  header,
34365
33024
  dnd.wrapContainer(body),
34366
- hasMore && /* @__PURE__ */ jsx(Box, { className: "flex justify-center py-3", children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: () => setVisibleCount((p2) => p2 + (pageSize || 5)), children: [
33025
+ hasMore && /* @__PURE__ */ jsx(Box, { className: "flex justify-center py-3", children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: () => setVisibleCount((p) => p + (pageSize || 5)), children: [
34367
33026
  /* @__PURE__ */ jsx(Icon, { name: "chevron-down", size: "xs", className: "mr-1" }),
34368
33027
  t("common.showMore"),
34369
33028
  " (",
@@ -37085,7 +35744,7 @@ var init_QrScanner = __esm({
37085
35744
  setCurrentFacing((f3) => f3 === "environment" ? "user" : "environment");
37086
35745
  }, []);
37087
35746
  const togglePause = useCallback(() => {
37088
- setIsPaused((p2) => !p2);
35747
+ setIsPaused((p) => !p);
37089
35748
  }, []);
37090
35749
  const handleMockScan = useCallback(() => {
37091
35750
  const result = {
@@ -40007,10 +38666,10 @@ var init_ModuleCard = __esm({
40007
38666
  ] })
40008
38667
  ] }, trait.name);
40009
38668
  }),
40010
- pages.length > 0 && /* @__PURE__ */ jsx("div", { className: "px-3 py-1.5 flex items-center gap-2 flex-wrap", children: pages.map((p2) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
38669
+ pages.length > 0 && /* @__PURE__ */ jsx("div", { className: "px-3 py-1.5 flex items-center gap-2 flex-wrap", children: pages.map((p) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
40011
38670
  /* @__PURE__ */ jsx("svg", { width: 10, height: 10, viewBox: "0 0 12 12", children: /* @__PURE__ */ jsx(AvlPage, { x: 6, y: 6, size: 5 }) }),
40012
- /* @__PURE__ */ jsx("span", { className: "text-xs font-mono text-[var(--color-muted-foreground)]", children: p2.route })
40013
- ] }, p2.name)) })
38671
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-mono text-[var(--color-muted-foreground)]", children: p.route })
38672
+ ] }, p.name)) })
40014
38673
  ]
40015
38674
  }
40016
38675
  );
@@ -41546,12 +40205,12 @@ var init_DocumentViewer = __esm({
41546
40205
  const handleZoomIn = useCallback(() => setZoom((z) => Math.min(z + 25, 200)), []);
41547
40206
  const handleZoomOut = useCallback(() => setZoom((z) => Math.max(z - 25, 50)), []);
41548
40207
  const handlePagePrev = useCallback(() => {
41549
- setCurrentPage((p2) => Math.max(p2 - 1, 1));
40208
+ setCurrentPage((p) => Math.max(p - 1, 1));
41550
40209
  eventBus.emit("UI:DOCUMENT_PAGE_CHANGE", { page: currentPage - 1 });
41551
40210
  }, [eventBus, currentPage]);
41552
40211
  const handlePageNext = useCallback(() => {
41553
40212
  if (totalPages) {
41554
- setCurrentPage((p2) => Math.min(p2 + 1, totalPages));
40213
+ setCurrentPage((p) => Math.min(p + 1, totalPages));
41555
40214
  eventBus.emit("UI:DOCUMENT_PAGE_CHANGE", { page: currentPage + 1 });
41556
40215
  }
41557
40216
  }, [totalPages, eventBus, currentPage]);
@@ -45850,7 +44509,7 @@ function WalkMinimap() {
45850
44509
  const graphH = 120;
45851
44510
  const nodeR = 10;
45852
44511
  const positions = activeTrait ? layoutGraph(activeTrait.states, activeTrait.transitions, activeTrait.initialState, graphW, graphH) : [];
45853
- const posMap = new Map(positions.map((p2) => [p2.state, p2]));
44512
+ const posMap = new Map(positions.map((p) => [p.state, p]));
45854
44513
  const visitedStates = new Set(
45855
44514
  coveredEdges.filter((e) => e.trait === walkStep.traitName).flatMap((e) => [e.from, e.to])
45856
44515
  );
@@ -49120,7 +47779,6 @@ var init_component_registry_generated = __esm({
49120
47779
  init_CTABanner();
49121
47780
  init_CalendarGrid();
49122
47781
  init_Canvas2D();
49123
- init_CanvasEffect();
49124
47782
  init_Card();
49125
47783
  init_CardGrid();
49126
47784
  init_Carousel();
@@ -49419,7 +48077,6 @@ var init_component_registry_generated = __esm({
49419
48077
  "CTABanner": CTABanner,
49420
48078
  "CalendarGrid": CalendarGrid,
49421
48079
  "Canvas2D": Canvas2D,
49422
- "CanvasEffect": CanvasEffect,
49423
48080
  "Card": Card,
49424
48081
  "CardGrid": CardGrid,
49425
48082
  "Carousel": Carousel,
@@ -52906,4 +51563,4 @@ function useGitHubBranches(owner, repo, enabled = true) {
52906
51563
  });
52907
51564
  }
52908
51565
 
52909
- export { ALL_PRESETS, ALMADAR_DND_MIME, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AuthLayout, Avatar, Badge, BehaviorView, BiologyCanvas, BloomQuizBlock, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, BuilderBoard, Button, ButtonGroup, CTABanner, CalendarGrid, Canvas2D, CanvasEffect, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, Center, Chart, ChartLegend, ChatBar, Checkbox, ChemistryCanvas, ChoiceButton, ClassifierBoard, Coachmark, CodeBlock, CodeRunnerPanel, CollapsibleSection, ComboCounter, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, ConnectionBlock, Container, ContentRenderer, ContentSection, ControlButton, ControlGrid, CounterTemplate, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DEFAULT_SLOTS, DIAMOND_TOP_Y, DamageNumber, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DebuggerBoard, DetailPanel, Dialog, DialogueBubble, Divider, DocBreadcrumb, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, ELEMENT_SELECTED_EVENT, EMPTY_EFFECT_STATE, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioContext, GameAudioProvider, GameAudioToggle, GameCard, GameHud, GameIcon, GameMenu, GameShell, GameTemplate, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, GridPicker, HStack, Header, HealthBar, HeroOrganism, HeroSection, I18nProvider, IDENTITY_BOOK_FIELDS, Icon, IconPicker, InfiniteScrollSentinel, Input, InputGroup, InstallBox, InventoryGrid, ItemSlot, JazariStateMachine, JsonTreeEditor, Label, LandingPageTemplate, LawReferenceTooltip, LearningCanvas, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingFooter, MarketingStatCard, MasterDetail, MasterDetailLayout, MathCanvas, MatrixQuestion, MediaGallery, Menu, Meter, MiniMap, Modal, ModalSlot, ModuleCard, Navigation, NegotiatorBoard, NodeSlotEditor, NotifyListener, NumberStepper, ObjectRulePanel, OnboardingSpotlight, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, Pagination, PatternTile, PhysicsCanvas, Popover, PositionedCanvas, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PropertyInspector, PullQuote, PullToRefresh, QrScanner, QuizBlock, Radio, RangeSlider, ReflectionBlock, RelationSelect, RepeatableFormSection, ReplyTree, ResourceBar, ResourceCounter, RichBlockEditor, RuleEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreDisplay, SearchInput, Section, SectionHeader, SegmentRenderer, Select, SequenceBar, SequencerBoard, ServiceCatalog, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Sparkline, Spinner, Split, SplitPane, SplitSection, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateArchitectBoard, StateIndicator, StateJsonView, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StatusEffect, StepFlow, StepFlowOrganism, SubagentTracePanel, SvgBranch, SvgConnection, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, TableView, Tabs, TagCloud, TagInput, TeamCard, TeamOrganism, TerrainPalette, TextHighlight, Textarea, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TurnIndicator, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UploadDropZone, VStack, VariablePanel, VersionDiff, ViolationAlert, VoteStack, WaypointMarker, WizardContainer, WizardNavigation, WizardProgress, boardEntity, bool, calculateAttackTargets, calculateValidMoves, cn, createCombatPresets, createInitialGameState, createTranslate, createUnitAnimationState, drawEffectState, drawSprite, drawTintedImage, getAllEffectSpriteUrls, getCurrentFrame, getTileDimensions, hasActiveEffects, inferDirection, isoToScreen, makeAsset, makeAssetMap, mapBookData, num, objAvailableActions, objAvailableEvents, objCurrentState, objIcon, objId, objMaxRules, objName, objRules, objStates, parseEditFocus, parseLessonSegments, parseMarkdownWithCodeBlocks, parseQueryBinding, pendulum, projectileMotion, resolveFieldMap, resolveFrame, resolveSheetDirection, rows, screenToIso, spawnOverlay, spawnParticles, spawnSequence, springOscillator, str, tickAnimationState, toCodeLanguage, transitionAnimation, unitHealth, unitPosition, unitTeam, updateEffectState, useAgentChat, useAnchorRect, useAuthContext, useCamera, useCanvasEffects, useCanvasGestures, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGameAudio, useGameAudioContext, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useImageCache, useInfiniteScroll, useLongPress, useOrbitalHistory, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSwipeGesture, useTapReveal, useTraitListens, useTranslate127 as useTranslate, useUIEvents, useUISlotManager, useUnitSpriteAtlas, useValidation, vec2 };
51566
+ export { ALL_PRESETS, ALMADAR_DND_MIME, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, Card2 as ActionCard, ActionPalette, ActionTile, ActivationBlock, Alert, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, Aside, AssetPicker, AuthLayout, Avatar, Badge, BehaviorView, BiologyCanvas, BloomQuizBlock, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, BuilderBoard, Button, ButtonGroup, CTABanner, CalendarGrid, Canvas2D, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, Center, Chart, ChartLegend, ChatBar, Checkbox, ChemistryCanvas, ChoiceButton, ClassifierBoard, Coachmark, CodeBlock, CodeRunnerPanel, CollapsibleSection, ComboCounter, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, ConnectionBlock, Container, ContentRenderer, ContentSection, ControlButton, ControlGrid, CounterTemplate, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DEFAULT_SLOTS, DIAMOND_TOP_Y, DamageNumber, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DebuggerBoard, DetailPanel, Dialog, DialogueBubble, Divider, DocBreadcrumb, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, ELEMENT_SELECTED_EVENT, EMPTY_EFFECT_STATE, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioContext, GameAudioProvider, GameAudioToggle, GameCard, GameHud, GameIcon, GameMenu, GameShell, GameTemplate, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, GridPicker, HStack, Header, HealthBar, HeroOrganism, HeroSection, I18nProvider, IDENTITY_BOOK_FIELDS, Icon, IconPicker, InfiniteScrollSentinel, Input, InputGroup, InstallBox, InventoryGrid, ItemSlot, JazariStateMachine, JsonTreeEditor, Label, LandingPageTemplate, LawReferenceTooltip, LearningCanvas, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingFooter, MarketingStatCard, MasterDetail, MasterDetailLayout, MathCanvas, MatrixQuestion, MediaGallery, Menu, Meter, MiniMap, Modal, ModalSlot, ModuleCard, Navigation, NegotiatorBoard, NodeSlotEditor, NotifyListener, NumberStepper, ObjectRulePanel, OnboardingSpotlight, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, Pagination, PatternTile, PhysicsCanvas, Popover, PositionedCanvas, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PropertyInspector, PullQuote, PullToRefresh, QrScanner, QuizBlock, Radio, RangeSlider, ReflectionBlock, RelationSelect, RepeatableFormSection, ReplyTree, ResourceBar, ResourceCounter, RichBlockEditor, RuleEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreDisplay, SearchInput, Section, SectionHeader, SegmentRenderer, Select, SequenceBar, SequencerBoard, ServiceCatalog, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Sparkline, Spinner, Split, SplitPane, SplitSection, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateArchitectBoard, StateIndicator, StateJsonView, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StatusEffect, StepFlow, StepFlowOrganism, SubagentTracePanel, SvgBranch, SvgConnection, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, TableView, Tabs, TagCloud, TagInput, TeamCard, TeamOrganism, TerrainPalette, TextHighlight, Textarea, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TurnIndicator, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UploadDropZone, VStack, VariablePanel, VersionDiff, ViolationAlert, VoteStack, WaypointMarker, WizardContainer, WizardNavigation, WizardProgress, boardEntity, bool, calculateAttackTargets, calculateValidMoves, cn, createInitialGameState, createTranslate, createUnitAnimationState, drawSprite, getCurrentFrame, getTileDimensions, inferDirection, isoToScreen, makeAsset, makeAssetMap, mapBookData, num, objAvailableActions, objAvailableEvents, objCurrentState, objIcon, objId, objMaxRules, objName, objRules, objStates, parseEditFocus, parseLessonSegments, parseMarkdownWithCodeBlocks, parseQueryBinding, pendulum, projectileMotion, resolveFieldMap, resolveFrame, resolveSheetDirection, rows, screenToIso, springOscillator, str, tickAnimationState, toCodeLanguage, transitionAnimation, unitHealth, unitPosition, unitTeam, useAgentChat, useAnchorRect, useAuthContext, useCamera, useCanvasGestures, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGameAudio, useGameAudioContext, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useImageCache, useInfiniteScroll, useLongPress, useOrbitalHistory, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSwipeGesture, useTapReveal, useTraitListens, useTranslate127 as useTranslate, useUIEvents, useUISlotManager, useUnitSpriteAtlas, useValidation, vec2 };