@almadar/ui 5.140.0 → 5.141.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.
@@ -15622,9 +15622,26 @@ var init_imageCache = __esm({
15622
15622
  });
15623
15623
 
15624
15624
  // lib/webPainter2d.ts
15625
+ function makeNoiseTile(alpha, color) {
15626
+ const tile = document.createElement("canvas");
15627
+ tile.width = NOISE_CELLS;
15628
+ tile.height = NOISE_CELLS;
15629
+ const t = tile.getContext("2d");
15630
+ if (t) {
15631
+ t.fillStyle = color;
15632
+ for (let y = 0; y < NOISE_CELLS; y++) {
15633
+ for (let x = 0; x < NOISE_CELLS; x++) {
15634
+ t.globalAlpha = noiseHash(x, y) * alpha;
15635
+ t.fillRect(x, y, 1, 1);
15636
+ }
15637
+ }
15638
+ }
15639
+ return tile;
15640
+ }
15625
15641
  function createWebPainter(ctx, onAssetLoad) {
15626
15642
  let vw = 0;
15627
15643
  let vh = 0;
15644
+ const patternCache = /* @__PURE__ */ new Map();
15628
15645
  const tracePoly = (points, closed) => {
15629
15646
  if (points.length === 0) return;
15630
15647
  ctx.beginPath();
@@ -15632,9 +15649,28 @@ function createWebPainter(ctx, onAssetLoad) {
15632
15649
  for (let i = 1; i < points.length; i++) ctx.lineTo(points[i].x, points[i].y);
15633
15650
  if (closed) ctx.closePath();
15634
15651
  };
15652
+ const toCanvasPattern = (style) => {
15653
+ const key = JSON.stringify(style);
15654
+ let pattern = patternCache.get(key);
15655
+ if (pattern === void 0) {
15656
+ if (style.kind === "noise") {
15657
+ pattern = ctx.createPattern(makeNoiseTile(style.alpha ?? 0.12, style.color ?? "#000000"), "repeat");
15658
+ } else {
15659
+ const img = getOrLoadImage(style.url, onAssetLoad);
15660
+ if (!img) return "rgba(0,0,0,0)";
15661
+ pattern = ctx.createPattern(img, "repeat");
15662
+ }
15663
+ if (pattern && style.scale !== void 0 && style.scale !== 1) {
15664
+ pattern.setTransform(new DOMMatrix().scale(style.scale));
15665
+ }
15666
+ patternCache.set(key, pattern);
15667
+ }
15668
+ return pattern ?? "rgba(0,0,0,0)";
15669
+ };
15635
15670
  const toCanvasStyle = (style) => {
15636
15671
  if (typeof style === "string") return style;
15637
- const g = style.kind === "linear" ? ctx.createLinearGradient(style.x1, style.y1, style.x2, style.y2) : ctx.createRadialGradient(style.cx, style.cy, 0, style.cx, style.cy, style.r);
15672
+ if (style.kind === "noise" || style.kind === "image") return toCanvasPattern(style);
15673
+ const g = style.kind === "linear" ? ctx.createLinearGradient(style.x1, style.y1, style.x2, style.y2) : style.kind === "conic" ? ctx.createConicGradient(style.angle, style.cx, style.cy) : ctx.createRadialGradient(style.cx, style.cy, 0, style.cx, style.cy, style.r);
15638
15674
  for (const stop of style.stops) g.addColorStop(stop.offset, stop.color);
15639
15675
  return g;
15640
15676
  };
@@ -15669,6 +15705,19 @@ function createWebPainter(ctx, onAssetLoad) {
15669
15705
  ctx.shadowColor = shadow ? shadow.color : "transparent";
15670
15706
  ctx.shadowBlur = shadow ? shadow.blur : 0;
15671
15707
  },
15708
+ setBlend(mode) {
15709
+ ctx.globalCompositeOperation = mode ?? "source-over";
15710
+ },
15711
+ setLineDash(pattern, offset = 0) {
15712
+ ctx.setLineDash(pattern ? [...pattern] : []);
15713
+ ctx.lineDashOffset = offset;
15714
+ },
15715
+ setBlur(px) {
15716
+ ctx.filter = px && px > 0 ? `blur(${px}px)` : "none";
15717
+ },
15718
+ clipPath(d) {
15719
+ ctx.clip(new Path2D(d));
15720
+ },
15672
15721
  resolveTexture(url) {
15673
15722
  const img = getOrLoadImage(url, onAssetLoad);
15674
15723
  if (!img) return null;
@@ -15744,13 +15793,18 @@ function createWebPainter(ctx, onAssetLoad) {
15744
15793
  }
15745
15794
  };
15746
15795
  }
15747
- var handleByImage, imageByHandle;
15796
+ var handleByImage, imageByHandle, noiseHash, NOISE_CELLS;
15748
15797
  var init_webPainter2d = __esm({
15749
15798
  "lib/webPainter2d.ts"() {
15750
15799
  "use client";
15751
15800
  init_imageCache();
15752
15801
  handleByImage = /* @__PURE__ */ new WeakMap();
15753
15802
  imageByHandle = /* @__PURE__ */ new WeakMap();
15803
+ noiseHash = (x, y) => {
15804
+ const s = Math.sin(x * 12.9898 + y * 78.233) * 43758.5453;
15805
+ return s - Math.floor(s);
15806
+ };
15807
+ NOISE_CELLS = 32;
15754
15808
  }
15755
15809
  });
15756
15810
 
@@ -16037,6 +16091,16 @@ function gradientStyle(g, ox, oy, scale) {
16037
16091
  stops: g.stops
16038
16092
  };
16039
16093
  }
16094
+ if (g.kind === "conic") {
16095
+ if (!g.center) return void 0;
16096
+ return {
16097
+ kind: "conic",
16098
+ cx: ox + g.center.x * scale,
16099
+ cy: oy + g.center.y * scale,
16100
+ angle: g.angle ?? 0,
16101
+ stops: g.stops
16102
+ };
16103
+ }
16040
16104
  if (!g.center || g.radius === void 0) return void 0;
16041
16105
  return {
16042
16106
  kind: "radial",
@@ -16046,6 +16110,13 @@ function gradientStyle(g, ox, oy, scale) {
16046
16110
  stops: g.stops
16047
16111
  };
16048
16112
  }
16113
+ function patternStyle(p, unit) {
16114
+ if (p.kind === "image") {
16115
+ if (!p.url) return void 0;
16116
+ return { kind: "image", url: p.url, scale: (p.scale ?? 1) / unit };
16117
+ }
16118
+ return { kind: "noise", scale: (p.scale ?? 2) / unit, alpha: p.alpha, color: p.color };
16119
+ }
16049
16120
  function DrawShape(props) {
16050
16121
  const register = useContext(DrawableRegistryContext);
16051
16122
  if (register) {
@@ -16074,7 +16145,9 @@ var init_DrawShape = __esm({
16074
16145
  "radiusY",
16075
16146
  "width",
16076
16147
  "height",
16077
- "strokeWidth"
16148
+ "strokeWidth",
16149
+ "strokeDashOffset",
16150
+ "blur"
16078
16151
  ];
16079
16152
  lerp = (a, b, k) => a + (b - a) * k;
16080
16153
  paintShape = (painter, rawNode, dctx) => {
@@ -16084,6 +16157,16 @@ var init_DrawShape = __esm({
16084
16157
  if (node.opacity !== void 0 && node.opacity !== 1) painter.setAlpha(node.opacity);
16085
16158
  const origin = dctx.projector.project(node.position);
16086
16159
  const tileWidth = dctx.projector.tileWidth;
16160
+ const groupScale = dctx.groupScale ?? 1;
16161
+ const strokePx = (node.strokeWidth ?? 1) / groupScale;
16162
+ if (node.blendMode) painter.setBlend(node.blendMode);
16163
+ if (node.strokeDash && node.strokeDash.length > 0) {
16164
+ painter.setLineDash(
16165
+ node.strokeDash.map((v) => v / groupScale),
16166
+ (node.strokeDashOffset ?? 0) / groupScale
16167
+ );
16168
+ }
16169
+ if (node.blur !== void 0 && node.blur > 0) painter.setBlur(node.blur / groupScale);
16087
16170
  if (node.rotate) {
16088
16171
  const pivot = node.pivot ?? { x: 0.5, y: 0.5 };
16089
16172
  const px = origin.x + pivot.x * tileWidth;
@@ -16092,15 +16175,18 @@ var init_DrawShape = __esm({
16092
16175
  painter.rotate(node.rotate);
16093
16176
  painter.translate(-px, -py);
16094
16177
  }
16095
- if (node.shadow) painter.setShadow({ color: node.shadow.color, blur: node.shadow.blur * tileWidth });
16178
+ if (node.shadow) painter.setShadow({ color: node.shadow.color, blur: node.shadow.blur * tileWidth * groupScale });
16096
16179
  const fill = node.fill === "none" ? void 0 : node.fill;
16097
16180
  const stroke = node.stroke === "none" ? void 0 : node.stroke;
16098
16181
  const pxFill = node.gradient ? gradientStyle(node.gradient, origin.x, origin.y, tileWidth) ?? fill : fill;
16182
+ const pxStroke = node.strokeGradient ? gradientStyle(node.strokeGradient, origin.x, origin.y, tileWidth) ?? stroke : stroke;
16183
+ const patFill = node.fillPattern ? patternStyle(node.fillPattern, groupScale) : void 0;
16099
16184
  switch (node.shape) {
16100
16185
  case "cell": {
16101
16186
  const pts = dctx.projector.cellPath(node.position);
16102
16187
  if (pxFill) painter.fillPoly(pts, pxFill);
16103
- if (stroke) painter.strokePoly(pts, stroke, node.strokeWidth ?? 1, true);
16188
+ if (patFill) painter.fillPoly(pts, patFill);
16189
+ if (pxStroke) painter.strokePoly(pts, pxStroke, strokePx, true);
16104
16190
  break;
16105
16191
  }
16106
16192
  case "rect": {
@@ -16111,7 +16197,8 @@ var init_DrawShape = __esm({
16111
16197
  const w = (node.width ?? 0) * tw;
16112
16198
  const h = (node.height ?? 0) * tw;
16113
16199
  if (pxFill) painter.fillRect(x, y, w, h, pxFill);
16114
- if (stroke) painter.strokeRect(x, y, w, h, stroke, node.strokeWidth ?? 1);
16200
+ if (patFill) painter.fillRect(x, y, w, h, patFill);
16201
+ if (pxStroke) painter.strokeRect(x, y, w, h, pxStroke, strokePx);
16115
16202
  break;
16116
16203
  }
16117
16204
  case "ellipse": {
@@ -16122,7 +16209,8 @@ var init_DrawShape = __esm({
16122
16209
  const rx = (node.radiusX ?? 0) * tw;
16123
16210
  const ry = (node.radiusY ?? rx) * tw;
16124
16211
  if (pxFill) painter.fillEllipse(cx, cy, rx, ry, pxFill);
16125
- if (stroke) painter.strokeEllipse(cx, cy, rx, ry, stroke, node.strokeWidth ?? 1);
16212
+ if (patFill) painter.fillEllipse(cx, cy, rx, ry, patFill);
16213
+ if (pxStroke) painter.strokeEllipse(cx, cy, rx, ry, pxStroke, strokePx);
16126
16214
  break;
16127
16215
  }
16128
16216
  case "poly": {
@@ -16131,16 +16219,27 @@ var init_DrawShape = __esm({
16131
16219
  y: origin.y + ((node.offsetY ?? 0) + pt.y) * tileWidth
16132
16220
  }));
16133
16221
  if (pxFill) painter.fillPoly(pts, pxFill);
16134
- if (stroke) painter.strokePoly(pts, stroke, node.strokeWidth ?? 1, true);
16222
+ if (patFill) painter.fillPoly(pts, patFill);
16223
+ if (pxStroke) painter.strokePoly(pts, pxStroke, strokePx, true);
16135
16224
  break;
16136
16225
  }
16137
16226
  case "path": {
16138
16227
  if (!node.d) break;
16139
16228
  painter.translate(origin.x + (node.offsetX ?? 0) * tileWidth, origin.y + (node.offsetY ?? 0) * tileWidth);
16140
16229
  painter.scale(tileWidth, tileWidth);
16230
+ if (node.strokeDash && node.strokeDash.length > 0) {
16231
+ painter.setLineDash(
16232
+ node.strokeDash.map((v) => v / (groupScale * tileWidth)),
16233
+ (node.strokeDashOffset ?? 0) / (groupScale * tileWidth)
16234
+ );
16235
+ }
16236
+ if (node.blur !== void 0 && node.blur > 0) painter.setBlur(node.blur / (groupScale * tileWidth));
16141
16237
  const localFill = node.gradient ? gradientStyle(node.gradient, 0, 0, 1) ?? fill : fill;
16238
+ const localStroke = node.strokeGradient ? gradientStyle(node.strokeGradient, 0, 0, 1) ?? stroke : stroke;
16239
+ const localPat = node.fillPattern ? patternStyle(node.fillPattern, groupScale * tileWidth) : void 0;
16142
16240
  if (localFill) painter.fillPath(node.d, localFill);
16143
- if (stroke) painter.strokePath(node.d, stroke, (node.strokeWidth ?? 1) / tileWidth);
16241
+ if (localPat) painter.fillPath(node.d, localPat);
16242
+ if (localStroke) painter.strokePath(node.d, localStroke, strokePx / tileWidth);
16144
16243
  break;
16145
16244
  }
16146
16245
  }
@@ -16221,8 +16320,6 @@ var init_DrawTextLayer = __esm({
16221
16320
  };
16222
16321
  }
16223
16322
  });
16224
-
16225
- // lib/drawable/paintDispatch.ts
16226
16323
  function paintDrawable(painter, node, dctx) {
16227
16324
  switch (node.type) {
16228
16325
  case "draw-sprite":
@@ -16243,10 +16340,20 @@ function paintDrawable(painter, node, dctx) {
16243
16340
  if (node.scale !== void 0) painter.scale(node.scale, node.scale);
16244
16341
  if (node.rotate !== void 0) painter.rotate(node.rotate);
16245
16342
  if (node.opacity !== void 0 && node.opacity !== 1) painter.setAlpha(node.opacity);
16246
- for (const item of node.items) paintDrawable(painter, item, dctx);
16343
+ if (node.clip) {
16344
+ const tw = dctx.projector.tileWidth;
16345
+ painter.scale(tw, tw);
16346
+ painter.clipPath(node.clip);
16347
+ painter.scale(1 / tw, 1 / tw);
16348
+ }
16349
+ const childCtx = node.scale !== void 0 && node.scale !== 1 ? { ...dctx, groupScale: (dctx.groupScale ?? 1) * node.scale } : dctx;
16350
+ for (const item of node.items) paintDrawable(painter, item, childCtx);
16247
16351
  painter.restore();
16248
16352
  break;
16249
16353
  }
16354
+ case "draw-mesh":
16355
+ warnUnsupported2d("draw-mesh");
16356
+ break;
16250
16357
  case "draw-sprite-layer":
16251
16358
  paintSpriteLayer(painter, node, dctx);
16252
16359
  break;
@@ -16258,6 +16365,7 @@ function paintDrawable(painter, node, dctx) {
16258
16365
  break;
16259
16366
  }
16260
16367
  }
16368
+ var paint2dLog, warnedUnsupported2d, warnUnsupported2d;
16261
16369
  var init_paintDispatch = __esm({
16262
16370
  "lib/drawable/paintDispatch.ts"() {
16263
16371
  init_contract();
@@ -16267,6 +16375,13 @@ var init_paintDispatch = __esm({
16267
16375
  init_DrawSpriteLayer();
16268
16376
  init_DrawShapeLayer();
16269
16377
  init_DrawTextLayer();
16378
+ paint2dLog = createLogger("almadar:ui:drawable-2d");
16379
+ warnedUnsupported2d = /* @__PURE__ */ new Set();
16380
+ warnUnsupported2d = (kind) => {
16381
+ if (warnedUnsupported2d.has(kind)) return;
16382
+ warnedUnsupported2d.add(kind);
16383
+ paint2dLog.warn("unsupported drawable kind on the 2D painter \u2014 skipped", { kind });
16384
+ };
16270
16385
  }
16271
16386
  });
16272
16387
 
@@ -16281,6 +16396,7 @@ function collectDrawnItems(nodes) {
16281
16396
  case "draw-shape":
16282
16397
  case "draw-text":
16283
16398
  case "draw-group":
16399
+ case "draw-mesh":
16284
16400
  if (isValidScenePos(n.position)) out.push({ pos: n.position, id: n.id });
16285
16401
  break;
16286
16402
  case "draw-sprite-layer":
@@ -16898,6 +17014,7 @@ function Canvas({
16898
17014
  isLoading,
16899
17015
  cameraMode: to3DCameraMode(camera?.mode),
16900
17016
  ...zoom !== void 0 ? { scale: zoom } : {},
17017
+ ...camera?.fov !== void 0 ? { fov: camera.fov } : {},
16901
17018
  ...camera?.target !== void 0 ? { followTarget: camera.target } : {},
16902
17019
  unitScale,
16903
17020
  backgroundColor,
@@ -40134,14 +40251,26 @@ var init_DetailPanel = __esm({
40134
40251
  DetailPanel.displayName = "DetailPanel";
40135
40252
  }
40136
40253
  });
40137
-
40138
- // components/game/atoms/DrawGroup.tsx
40139
- function DrawGroup(_props) {
40254
+ function DrawGroup(props) {
40255
+ const register = useContext(DrawableRegistryContext);
40256
+ if (register) register({ ...props, type: "draw-group" });
40140
40257
  return null;
40141
40258
  }
40142
40259
  var init_DrawGroup = __esm({
40143
40260
  "components/game/atoms/DrawGroup.tsx"() {
40144
40261
  "use client";
40262
+ init_registry();
40263
+ }
40264
+ });
40265
+ function DrawMesh(props) {
40266
+ const register = useContext(DrawableRegistryContext);
40267
+ if (register) register({ ...props, type: "draw-mesh" });
40268
+ return null;
40269
+ }
40270
+ var init_DrawMesh = __esm({
40271
+ "components/game/atoms/DrawMesh.tsx"() {
40272
+ "use client";
40273
+ init_registry();
40145
40274
  }
40146
40275
  });
40147
40276
  function extractTitle(children) {
@@ -45848,6 +45977,7 @@ var init_component_registry_generated = __esm({
45848
45977
  init_DocTOC();
45849
45978
  init_DocumentViewer();
45850
45979
  init_DrawGroup();
45980
+ init_DrawMesh();
45851
45981
  init_DrawShape();
45852
45982
  init_DrawShapeLayer();
45853
45983
  init_DrawSprite();
@@ -46116,6 +46246,7 @@ var init_component_registry_generated = __esm({
46116
46246
  "DocTOC": DocTOC,
46117
46247
  "DocumentViewer": DocumentViewer,
46118
46248
  "DrawGroup": DrawGroup,
46249
+ "DrawMesh": DrawMesh,
46119
46250
  "DrawShape": DrawShape,
46120
46251
  "DrawShapeLayer": DrawShapeLayer,
46121
46252
  "DrawSprite": DrawSprite,