@almadar/ui 5.141.0 → 5.142.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.
@@ -5,8 +5,10 @@ var providers = require('@almadar/ui/providers');
5
5
  var logger = require('@almadar/logger');
6
6
  var fiber = require('@react-three/fiber');
7
7
  var THREE10 = require('three');
8
+ var RoomEnvironment_js = require('three/examples/jsm/environments/RoomEnvironment.js');
8
9
  var drei = require('@react-three/drei');
9
10
  var jsxRuntime = require('react/jsx-runtime');
11
+ var postprocessing = require('@react-three/postprocessing');
10
12
  var GLTFLoader = require('three/examples/jsm/loaders/GLTFLoader');
11
13
  var SkeletonUtils = require('three/examples/jsm/utils/SkeletonUtils');
12
14
  var clsx = require('clsx');
@@ -14,7 +16,6 @@ var tailwindMerge = require('tailwind-merge');
14
16
  var OrbitControls_js = require('three/examples/jsm/controls/OrbitControls.js');
15
17
  var GLTFLoader_js = require('three/examples/jsm/loaders/GLTFLoader.js');
16
18
  var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
17
- var postprocessing = require('@react-three/postprocessing');
18
19
  var hooks = require('@almadar/ui/hooks');
19
20
 
20
21
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -474,6 +475,10 @@ function Lighting3D({
474
475
  directionalIntensity = 0.8,
475
476
  directionalColor = "#ffffff",
476
477
  directionalPosition = [10, 20, 10],
478
+ hemisphereIntensity = 0.3,
479
+ hemisphereColor = "#87ceeb",
480
+ hemisphereGroundColor = "#362d1d",
481
+ points,
477
482
  shadows = true,
478
483
  shadowMapSize = 2048,
479
484
  shadowCameraSize = 20,
@@ -506,11 +511,22 @@ function Lighting3D({
506
511
  /* @__PURE__ */ jsxRuntime.jsx(
507
512
  "hemisphereLight",
508
513
  {
509
- intensity: 0.3,
510
- color: "#87ceeb",
511
- groundColor: "#362d1d"
514
+ intensity: hemisphereIntensity,
515
+ color: hemisphereColor,
516
+ groundColor: hemisphereGroundColor
512
517
  }
513
518
  ),
519
+ points?.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx(
520
+ "pointLight",
521
+ {
522
+ position: p.position,
523
+ intensity: p.intensity,
524
+ color: p.color,
525
+ distance: p.distance,
526
+ decay: p.decay
527
+ },
528
+ i
529
+ )),
514
530
  showHelpers && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
515
531
  "directionalLightHelper",
516
532
  {
@@ -522,6 +538,36 @@ function Lighting3D({
522
538
  ) })
523
539
  ] });
524
540
  }
541
+ function Effects3D({ post }) {
542
+ if (!post || !post.bloom && !post.vignette) return null;
543
+ const passes = [];
544
+ if (post.bloom) {
545
+ passes.push(
546
+ /* @__PURE__ */ jsxRuntime.jsx(
547
+ postprocessing.Bloom,
548
+ {
549
+ intensity: post.bloom.intensity ?? 1,
550
+ luminanceThreshold: post.bloom.threshold ?? 0.9,
551
+ luminanceSmoothing: post.bloom.smoothing ?? 0.3
552
+ },
553
+ "bloom"
554
+ )
555
+ );
556
+ }
557
+ if (post.vignette) {
558
+ passes.push(
559
+ /* @__PURE__ */ jsxRuntime.jsx(
560
+ postprocessing.Vignette,
561
+ {
562
+ offset: post.vignette.offset ?? 0.3,
563
+ darkness: post.vignette.darkness ?? 0.6
564
+ },
565
+ "vignette"
566
+ )
567
+ );
568
+ }
569
+ return /* @__PURE__ */ jsxRuntime.jsx(postprocessing.EffectComposer, { children: passes });
570
+ }
525
571
  function CameraController3D({
526
572
  onCameraChange
527
573
  }) {
@@ -564,6 +610,77 @@ function create3DProjector(opts = {}) {
564
610
  toWorld: (pos) => [pos.x * cellSize + offsetX, pos.z ?? 0, pos.y * cellSize + offsetZ]
565
611
  };
566
612
  }
613
+ var NUMERIC_TRACKS = [
614
+ "offsetX",
615
+ "offsetY",
616
+ "rotate",
617
+ "opacity",
618
+ "radiusX",
619
+ "radiusY",
620
+ "width",
621
+ "height",
622
+ "strokeWidth",
623
+ "strokeDashOffset",
624
+ "blur"
625
+ ];
626
+ function isAnimatedShape(node) {
627
+ return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
628
+ }
629
+ var lerp = (a, b, k) => a + (b - a) * k;
630
+ function applyShapeAnimation(node, timeMs) {
631
+ const anim = node.animation;
632
+ if (!anim || !(anim.durationMs > 0) || anim.keyframes.length === 0) return node;
633
+ const frames = [...anim.keyframes].sort((a, b) => a.at - b.at);
634
+ const cycle = timeMs / anim.durationMs;
635
+ const t = anim.loop === false ? Math.min(cycle, 1) : cycle - Math.floor(cycle);
636
+ const out = { ...node };
637
+ const trackValue = (key) => {
638
+ const defined = frames.filter((f) => f[key] !== void 0);
639
+ if (defined.length === 0) return void 0;
640
+ let prev;
641
+ let next;
642
+ for (const f of defined) {
643
+ if (f.at <= t) prev = f;
644
+ else if (!next) next = f;
645
+ }
646
+ if (!prev) return defined[0][key];
647
+ if (!next) return prev[key];
648
+ const span = next.at - prev.at;
649
+ const k = span > 0 ? (t - prev.at) / span : 1;
650
+ const a = prev[key];
651
+ const b = next[key];
652
+ if (typeof a === "number" && typeof b === "number") return lerp(a, b, k);
653
+ return a;
654
+ };
655
+ for (const key of NUMERIC_TRACKS) {
656
+ const v = trackValue(key);
657
+ if (v !== void 0) out[key] = v;
658
+ }
659
+ const fill = trackValue("fill");
660
+ if (fill !== void 0) out.fill = fill;
661
+ const stroke = trackValue("stroke");
662
+ if (stroke !== void 0) out.stroke = stroke;
663
+ const shadowFrames = frames.filter((f) => f.shadow !== void 0);
664
+ if (shadowFrames.length > 0) {
665
+ const sh = trackValue("shadow");
666
+ if (sh !== void 0) {
667
+ let prevSh;
668
+ let nextSh;
669
+ for (const f of shadowFrames) {
670
+ if (f.at <= t) prevSh = f;
671
+ else if (!nextSh) nextSh = f;
672
+ }
673
+ if (prevSh?.shadow && nextSh?.shadow) {
674
+ const span = nextSh.at - prevSh.at;
675
+ const k = span > 0 ? (t - prevSh.at) / span : 1;
676
+ out.shadow = { color: prevSh.shadow.color, blur: lerp(prevSh.shadow.blur, nextSh.shadow.blur, k) };
677
+ } else {
678
+ out.shadow = sh;
679
+ }
680
+ }
681
+ }
682
+ return out;
683
+ }
567
684
 
568
685
  // lib/atlasSlice.ts
569
686
  var atlasCache = /* @__PURE__ */ new Map();
@@ -965,8 +1082,27 @@ function Sprite3D({ node, projector, groupOpacity = 1 }) {
965
1082
  return /* @__PURE__ */ jsxRuntime.jsx(SpriteBillboard, { node, world: projector.toWorld(node.position), cellSize: projector.cellSize, groupOpacity });
966
1083
  }
967
1084
  function Shape3D({ node, projector, groupOpacity = 1 }) {
968
- if (!isValidScenePos(node.position)) return null;
969
- const world = projector.toWorld(node.position);
1085
+ const groupRef = React3__default.default.useRef(null);
1086
+ const materialRef = React3__default.default.useRef(null);
1087
+ const animated = isAnimatedShape(node);
1088
+ const validPos = isValidScenePos(node.position);
1089
+ const world = validPos ? projector.toWorld(node.position) : [0, 0, 0];
1090
+ fiber.useFrame(({ clock }) => {
1091
+ if (!animated || !groupRef.current) return;
1092
+ const view = applyShapeAnimation(node, clock.elapsedTime * 1e3);
1093
+ groupRef.current.position.set(
1094
+ world[0] + (view.offsetX ?? 0) * projector.cellSize,
1095
+ world[1] + 0.02,
1096
+ world[2] + (view.offsetY ?? 0) * projector.cellSize
1097
+ );
1098
+ groupRef.current.rotation.y = -(view.rotate ?? 0);
1099
+ const mat = materialRef.current;
1100
+ if (mat) {
1101
+ mat.opacity = (view.opacity ?? node.opacity ?? 1) * groupOpacity;
1102
+ if (view.fill) mat.color.set(view.fill);
1103
+ }
1104
+ });
1105
+ if (!validPos) return null;
970
1106
  const color = node.fill ?? node.stroke ?? "#ffffff";
971
1107
  let geometry;
972
1108
  switch (node.shape) {
@@ -1000,12 +1136,12 @@ function Shape3D({ node, projector, groupOpacity = 1 }) {
1000
1136
  default:
1001
1137
  return null;
1002
1138
  }
1003
- return /* @__PURE__ */ jsxRuntime.jsxs("mesh", { rotation: [-Math.PI / 2, 0, 0], position: [world[0], world[1] + 0.02, world[2]], children: [
1139
+ return /* @__PURE__ */ jsxRuntime.jsx("group", { ref: groupRef, position: [world[0], world[1] + 0.02, world[2]], children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { rotation: [-Math.PI / 2, 0, 0], children: [
1004
1140
  geometry,
1005
- /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color, transparent: true, opacity: (node.opacity ?? 1) * groupOpacity, side: THREE10__namespace.DoubleSide })
1006
- ] });
1141
+ /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { ref: materialRef, color, transparent: true, opacity: (node.opacity ?? 1) * groupOpacity, side: THREE10__namespace.DoubleSide })
1142
+ ] }) });
1007
1143
  }
1008
- function Text3D({ node, projector }) {
1144
+ function Text3D({ node, projector, groupOpacity = 1 }) {
1009
1145
  if (!isValidScenePos(node.position)) return null;
1010
1146
  const world = projector.toWorld(node.position);
1011
1147
  return /* @__PURE__ */ jsxRuntime.jsx(drei.Billboard, { position: [world[0], world[1] + 1.2, world[2]], children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -1017,6 +1153,8 @@ function Text3D({ node, projector }) {
1017
1153
  anchorY: "middle",
1018
1154
  outlineWidth: 0.02,
1019
1155
  outlineColor: "#000000",
1156
+ fillOpacity: groupOpacity,
1157
+ outlineOpacity: groupOpacity,
1020
1158
  children: node.text
1021
1159
  }
1022
1160
  ) });
@@ -1029,8 +1167,8 @@ function clampSegments(segments) {
1029
1167
  function isAnimatedMesh(node) {
1030
1168
  return Boolean(node.animation && node.animation.durationMs > 0 && node.animation.keyframes.length > 0);
1031
1169
  }
1032
- var lerp = (a, b, k) => a + (b - a) * k;
1033
- var NUMERIC_TRACKS = [
1170
+ var lerp2 = (a, b, k) => a + (b - a) * k;
1171
+ var NUMERIC_TRACKS2 = [
1034
1172
  "offsetX",
1035
1173
  "offsetY",
1036
1174
  "offsetZ",
@@ -1062,11 +1200,11 @@ function applyMeshAnimation(node, timeMs) {
1062
1200
  const k = span > 0 ? (t - prev.at) / span : 1;
1063
1201
  const a = prev[key];
1064
1202
  const b = next[key];
1065
- if (typeof a === "number" && typeof b === "number") return lerp(a, b, k);
1203
+ if (typeof a === "number" && typeof b === "number") return lerp2(a, b, k);
1066
1204
  return a;
1067
1205
  };
1068
1206
  const num = {};
1069
- for (const key of NUMERIC_TRACKS) {
1207
+ for (const key of NUMERIC_TRACKS2) {
1070
1208
  const v = trackValue(key);
1071
1209
  if (v !== void 0) num[key] = v;
1072
1210
  }
@@ -1240,7 +1378,7 @@ function Drawable3D({ node, projector, groupOpacity = 1 }) {
1240
1378
  case "draw-shape":
1241
1379
  return /* @__PURE__ */ jsxRuntime.jsx(Shape3D, { node, projector, groupOpacity });
1242
1380
  case "draw-text":
1243
- return /* @__PURE__ */ jsxRuntime.jsx(Text3D, { node, projector });
1381
+ return /* @__PURE__ */ jsxRuntime.jsx(Text3D, { node, projector, groupOpacity });
1244
1382
  case "draw-mesh":
1245
1383
  return /* @__PURE__ */ jsxRuntime.jsx(Mesh3D, { node, projector, groupOpacity });
1246
1384
  case "draw-sprite-layer":
@@ -1248,7 +1386,7 @@ function Drawable3D({ node, projector, groupOpacity = 1 }) {
1248
1386
  case "draw-shape-layer":
1249
1387
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: node.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(Shape3D, { node: item, projector, groupOpacity }, i)) });
1250
1388
  case "draw-text-layer":
1251
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: node.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(Text3D, { node: item, projector }, i)) });
1389
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: node.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(Text3D, { node: item, projector, groupOpacity }, i)) });
1252
1390
  case "draw-group": {
1253
1391
  if (!isValidScenePos(node.position) || !Array.isArray(node.items)) return null;
1254
1392
  if (node.clip) warnUnsupported3d("draw-group:clip");
@@ -1272,6 +1410,20 @@ function cn(...inputs) {
1272
1410
  }
1273
1411
  var DEFAULT_GRID_CONFIG = {
1274
1412
  cellSize: 1};
1413
+ function RoomEnvironment3D() {
1414
+ const { gl, scene } = fiber.useThree(({ gl: gl2, scene: scene2 }) => ({ gl: gl2, scene: scene2 }));
1415
+ React3.useEffect(() => {
1416
+ const pmremGenerator = new THREE10__namespace.PMREMGenerator(gl);
1417
+ const envTexture = pmremGenerator.fromScene(new RoomEnvironment_js.RoomEnvironment(), 0.04).texture;
1418
+ scene.environment = envTexture;
1419
+ return () => {
1420
+ scene.environment = null;
1421
+ envTexture.dispose();
1422
+ pmremGenerator.dispose();
1423
+ };
1424
+ }, [gl, scene]);
1425
+ return null;
1426
+ }
1275
1427
  var Canvas3DHost = React3.forwardRef(
1276
1428
  ({
1277
1429
  cameraMode = "isometric",
@@ -1297,6 +1449,8 @@ var Canvas3DHost = React3.forwardRef(
1297
1449
  keyUpMap,
1298
1450
  pixelsPerUnit,
1299
1451
  fov,
1452
+ lighting,
1453
+ post,
1300
1454
  children,
1301
1455
  drawables
1302
1456
  }, ref) => {
@@ -1305,6 +1459,7 @@ var Canvas3DHost = React3.forwardRef(
1305
1459
  const [internalError, setInternalError] = React3.useState(null);
1306
1460
  const eventBus = useEventBus();
1307
1461
  const keysRef = React3.useRef(/* @__PURE__ */ new Set());
1462
+ const allDrawables = React3.useMemo(() => drawables ?? [], [drawables]);
1308
1463
  React3.useEffect(() => {
1309
1464
  if (!keyMap && !keyUpMap) return;
1310
1465
  const down = (e) => {
@@ -1338,7 +1493,7 @@ var Canvas3DHost = React3.forwardRef(
1338
1493
  unitAnimationEvent,
1339
1494
  cameraChangeEvent
1340
1495
  });
1341
- const drawnItems = React3.useMemo(() => collectDrawnItems(drawables ?? []), [drawables]);
1496
+ const drawnItems = React3.useMemo(() => collectDrawnItems(allDrawables), [allDrawables]);
1342
1497
  const scenePositions = React3.useMemo(() => drawnItems.map((i) => i.pos), [drawnItems]);
1343
1498
  const hitIndex = React3.useMemo(() => buildHitIndex(drawnItems), [drawnItems]);
1344
1499
  const gridBounds = React3.useMemo(() => {
@@ -1520,9 +1675,19 @@ var Canvas3DHost = React3.forwardRef(
1520
1675
  shadowNormalBias: 0.04,
1521
1676
  shadowCameraSize: 5,
1522
1677
  shadowCameraNear: 0.5,
1523
- shadowCameraFar: 500
1678
+ shadowCameraFar: 500,
1679
+ ambientIntensity: lighting?.ambient?.intensity,
1680
+ ambientColor: lighting?.ambient?.color,
1681
+ directionalIntensity: lighting?.directional?.intensity,
1682
+ directionalColor: lighting?.directional?.color,
1683
+ directionalPosition: lighting?.directional?.position,
1684
+ hemisphereIntensity: lighting?.hemisphere?.intensity,
1685
+ hemisphereColor: lighting?.hemisphere?.color,
1686
+ hemisphereGroundColor: lighting?.hemisphere?.groundColor,
1687
+ points: lighting?.points
1524
1688
  }
1525
1689
  ),
1690
+ lighting?.environment === "room" && /* @__PURE__ */ jsxRuntime.jsx(RoomEnvironment3D, {}),
1526
1691
  showGrid && /* @__PURE__ */ jsxRuntime.jsx(
1527
1692
  drei.Grid,
1528
1693
  {
@@ -1545,7 +1710,7 @@ var Canvas3DHost = React3.forwardRef(
1545
1710
  fadeStrength: 1
1546
1711
  }
1547
1712
  ),
1548
- drawables && drawables.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("group", { children: drawables.map((node, i) => /* @__PURE__ */ jsxRuntime.jsx(Drawable3D, { node, projector: drawableProjector }, i)) }),
1713
+ allDrawables.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("group", { children: allDrawables.map((node, i) => /* @__PURE__ */ jsxRuntime.jsx(Drawable3D, { node, projector: drawableProjector }, i)) }),
1549
1714
  (tileClickEvent || unitClickEvent) && /* @__PURE__ */ jsxRuntime.jsxs(
1550
1715
  "mesh",
1551
1716
  {
@@ -1570,7 +1735,7 @@ var Canvas3DHost = React3.forwardRef(
1570
1735
  ]
1571
1736
  }
1572
1737
  ),
1573
- children,
1738
+ post && (post.bloom || post.vignette) ? /* @__PURE__ */ jsxRuntime.jsx(Effects3D, { post }) : null,
1574
1739
  /* @__PURE__ */ jsxRuntime.jsx(
1575
1740
  drei.OrbitControls,
1576
1741
  {
@@ -1920,7 +2085,7 @@ var DEFAULT_OPTIONS = {
1920
2085
  gridSize: 20,
1921
2086
  assetLoader: new AssetLoader()
1922
2087
  };
1923
- function useThree4(options = {}) {
2088
+ function useThree5(options = {}) {
1924
2089
  const opts = { ...DEFAULT_OPTIONS, ...options };
1925
2090
  const containerRef = React3.useRef(null);
1926
2091
  const canvasRef = React3.useRef(null);
@@ -5781,5 +5946,5 @@ exports.useAvl3DConfig = useAvl3DConfig;
5781
5946
  exports.useGameCanvas3DEvents = useGameCanvas3DEvents;
5782
5947
  exports.useRaycaster = useRaycaster;
5783
5948
  exports.useSceneGraph = useSceneGraph;
5784
- exports.useThree = useThree4;
5949
+ exports.useThree = useThree5;
5785
5950
  exports.worldToGrid = worldToGrid;
@@ -1,179 +1,12 @@
1
+ import { C as CanvasPointLightConfig, I as IsometricTile, a as IsometricUnit, b as IsometricFeature, A as ApplicationLevelData, O as OrbitalLevelData, T as TraitLevelData, c as TransitionLevelData } from '../../../avl-schema-parser-wOkfbwAh.cjs';
2
+ export { d as Canvas3DHost, e as Canvas3DHostHandle, f as Canvas3DHostProps, d as GameCanvas3D, U as UnitAnimationState } from '../../../avl-schema-parser-wOkfbwAh.cjs';
1
3
  import * as React$1 from 'react';
2
4
  import React__default, { Component, ReactNode, ErrorInfo } from 'react';
3
- import { ScenePos, EventEmit, JsonObject, OrbitalSchema } from '@almadar/core';
4
5
  import * as THREE from 'three';
5
6
  import { QuadraticBezierCurve3 } from 'three';
6
- import { D as DrawableNode } from '../../../paintDispatch-BQn5Lyx1.cjs';
7
7
  import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
8
- import { I as IsometricTile, a as IsometricUnit, b as IsometricFeature, A as ApplicationLevelData, O as OrbitalLevelData, T as TraitLevelData, c as TransitionLevelData } from '../../../avl-schema-parser-B8Onmfsu.cjs';
9
- export { U as UnitAnimationState } from '../../../avl-schema-parser-B8Onmfsu.cjs';
10
-
11
- /**
12
- * Canvas3DHost — the thin 3D draw-host: the `canvas` host's 3D painter backend
13
- * (the R3F "vessel" behind the neutral drawables), the exact 3D analogue of the
14
- * 2D `Painter2D` seam. Reached only via the lazy `@almadar/ui/.../game/three`
15
- * subpath so three.js never enters a 2D bundle.
16
- *
17
- * The 3D twin of Canvas2D: the board authors a `drawables` list (the neutral
18
- * `draw-*` children) and this host maps each descriptor through `Drawable3D` to a
19
- * three.js mesh (a raw descriptor NEVER reaches `<group>{children}` — R3F throws).
20
- * It owns NO game data — tiles, units, features, selection, health bars and labels
21
- * are all `draw-*` children composed in `.lolo`, not props here. Only view state
22
- * (camera, error boundary) is local.
23
- *
24
- * Camera: `isometric`/`perspective`/`top-down` frame the scene bounds (derived from
25
- * the drawn descriptors); `follow`/`chase` track the neutral core `Camera.target`
26
- * (forwarded as `followTarget`), falling back to the scene centre.
27
- *
28
- * Interaction: keyboard maps to semantic events (device-agnostic input). Pointer
29
- * click/hover on neutral drawables needs a per-entity id + a scene-space raycast
30
- * the descriptors don't yet carry — that hit-test is a tracked fork
31
- * (docs/Almadar_Std_Game_V2_PLAN.md); the click/hover event props are accepted but
32
- * not yet emitted from a raycast.
33
- *
34
- * @packageDocumentation
35
- */
36
-
37
- /** Camera mode for 3D view.
38
- * - `follow` tracks `followTarget` (the neutral `Camera.target`) from a fixed offset.
39
- * - `chase` sits behind + above the target. */
40
- type CameraMode$2 = 'isometric' | 'perspective' | 'top-down' | 'follow' | 'chase';
41
- /** Map orientation */
42
- type MapOrientation = 'standard' | 'rotated';
43
- /** Overlay control */
44
- type OverlayControl = 'default' | 'hidden' | 'minimap';
45
- /** Props for GameCanvas3D component */
46
- interface Canvas3DHostProps {
47
- /** Additional CSS classes */
48
- className?: string;
49
- /** Children to render inside the 3D canvas (e.g., physics objects, custom meshes) */
50
- children?: React__default.ReactNode;
51
- /** Neutral drawable descriptors — the same `children` vocabulary as Canvas2D. The
52
- * host maps each through `Drawable3D` to a mesh. */
53
- drawables?: DrawableNode[];
54
- /** Loading state indicator */
55
- isLoading?: boolean;
56
- /** Error state */
57
- error?: string | null;
58
- /** Fog of war data (accepted for API parity; presentation-only). */
59
- fogOfWar?: boolean[][];
60
- /** Map orientation (data attribute). */
61
- orientation?: MapOrientation;
62
- /** Camera mode */
63
- cameraMode?: CameraMode$2;
64
- /** Follow-camera target in scene space (the neutral core `Camera.target`). */
65
- followTarget?: ScenePos;
66
- /** Show grid */
67
- showGrid?: boolean;
68
- /** Show coordinates overlay (accepted for API parity). */
69
- showCoordinates?: boolean;
70
- /** Show tile information (accepted for API parity). */
71
- showTileInfo?: boolean;
72
- /** Overlay control mode (data attribute). */
73
- overlay?: OverlayControl;
74
- /** Enable shadows */
75
- shadows?: boolean;
76
- /** Background color */
77
- backgroundColor?: string;
78
- /** Declarative event: tile click. Emitted from a ground-plane raycast → scene cell
79
- * `{ x, z }` (the FSM validates the cell). `tileId` is optional — the neutral host
80
- * has no per-tile id, and the board FSMs key off the coordinate. */
81
- tileClickEvent?: EventEmit<{
82
- x: number;
83
- z: number;
84
- tileId?: string;
85
- type?: string;
86
- terrain?: string;
87
- elevation?: number;
88
- }>;
89
- /** Declarative event: unit click. Emitted `{ unitId, x, z }` when the raycast lands on a
90
- * cell whose descriptor carries an `id` (a tagged unit sprite). */
91
- unitClickEvent?: EventEmit<{
92
- unitId: string;
93
- x: number;
94
- z: number;
95
- unitType?: string;
96
- name?: string;
97
- team?: string;
98
- faction?: string;
99
- health?: number;
100
- maxHealth?: number;
101
- }>;
102
- /** Declarative event: feature click. Accepted; not yet emitted (see `tileClickEvent`). */
103
- featureClickEvent?: EventEmit<{
104
- featureId: string;
105
- x: number;
106
- z: number;
107
- type?: string;
108
- elevation?: number;
109
- }>;
110
- /** Declarative event: canvas (background) click. */
111
- canvasClickEvent?: EventEmit<{
112
- clientX: number;
113
- clientY: number;
114
- button: number;
115
- }>;
116
- /** Declarative event: tile hover. Accepted; not yet emitted (see `tileClickEvent`). */
117
- tileHoverEvent?: EventEmit<{
118
- tileId: string;
119
- x: number;
120
- z: number;
121
- type?: string;
122
- }>;
123
- /** Declarative event: tile leave. */
124
- tileLeaveEvent?: EventEmit<Record<string, never>>;
125
- /** Declarative event: unit animation. */
126
- unitAnimationEvent?: EventEmit<{
127
- unitId: string;
128
- state: string;
129
- timestamp: number;
130
- }>;
131
- /** Declarative event: camera change. */
132
- cameraChangeEvent?: EventEmit<{
133
- position: {
134
- x: number;
135
- y: number;
136
- z: number;
137
- };
138
- timestamp: number;
139
- }>;
140
- /** Loading message */
141
- loadingMessage?: string;
142
- /** Unit draw-size multiplier (accepted for API parity; sizing is drawable-authored). */
143
- unitScale?: number;
144
- /** Board zoom (accepted for API parity; 3D zoom is camera-driven, not group-scaled). */
145
- scale?: number;
146
- /** Maps a keydown `e.code` → the board's SEMANTIC event (device-agnostic input). */
147
- keyMap?: Record<string, string>;
148
- /** Maps a keyup `e.code` → the board's SEMANTIC event. */
149
- keyUpMap?: Record<string, string>;
150
- /** Side-view world size in pixels (accepted for API parity). */
151
- worldWidth?: number;
152
- /** Side-view world size in pixels (accepted for API parity). */
153
- worldHeight?: number;
154
- /** Pixel→world-unit divisor for pixel-authored (side-view) scenes: world size =
155
- * scene size ÷ `pixelsPerUnit`. Omitted → 1 world unit per scene unit (grid boards). */
156
- pixelsPerUnit?: number;
157
- /** Perspective field of view in degrees — the neutral `Camera.fov`. Default 45. */
158
- fov?: number;
159
- }
160
- /** Imperative handle for GameCanvas3D */
161
- interface Canvas3DHostHandle {
162
- /** Get current camera position */
163
- getCameraPosition: () => THREE.Vector3 | null;
164
- /** Set camera position */
165
- setCameraPosition: (x: number, y: number, z: number) => void;
166
- /** Look at a specific point */
167
- lookAt: (x: number, y: number, z: number) => void;
168
- /** Reset camera to default position */
169
- resetCamera: () => void;
170
- /** Take a screenshot */
171
- screenshot: () => string | null;
172
- }
173
- /**
174
- * Canvas3DHost — thin 3D draw-host. Walks `drawables` through `Drawable3D`.
175
- */
176
- declare const Canvas3DHost: React__default.ForwardRefExoticComponent<Canvas3DHostProps & React__default.RefAttributes<Canvas3DHostHandle>>;
8
+ import { JsonObject, EventEmit, OrbitalSchema } from '@almadar/core';
9
+ import '../../../paintDispatch-BQn5Lyx1.cjs';
177
10
 
178
11
  /**
179
12
  * Scene3D
@@ -291,6 +124,14 @@ interface Lighting3DProps {
291
124
  directionalColor?: string;
292
125
  /** Directional light position */
293
126
  directionalPosition?: [number, number, number];
127
+ /** Hemisphere (sky/ground) light intensity */
128
+ hemisphereIntensity?: number;
129
+ /** Hemisphere sky color */
130
+ hemisphereColor?: string;
131
+ /** Hemisphere ground color */
132
+ hemisphereGroundColor?: string;
133
+ /** Additional point lights, authored as data */
134
+ points?: CanvasPointLightConfig[];
294
135
  /** Enable shadows */
295
136
  shadows?: boolean;
296
137
  /** Shadow map size */
@@ -324,7 +165,7 @@ interface Lighting3DProps {
324
165
  * </Canvas>
325
166
  * ```
326
167
  */
327
- declare function Lighting3D({ ambientIntensity, ambientColor, directionalIntensity, directionalColor, directionalPosition, shadows, shadowMapSize, shadowCameraSize, shadowBias, shadowNormalBias, shadowCameraNear, shadowCameraFar, showHelpers, }: Lighting3DProps): React__default.JSX.Element;
168
+ declare function Lighting3D({ ambientIntensity, ambientColor, directionalIntensity, directionalColor, directionalPosition, hemisphereIntensity, hemisphereColor, hemisphereGroundColor, points, shadows, shadowMapSize, shadowCameraSize, shadowBias, shadowNormalBias, shadowCameraNear, shadowCameraFar, showHelpers, }: Lighting3DProps): React__default.JSX.Element;
328
169
 
329
170
  /**
330
171
  * Canvas3DLoadingState
@@ -1485,4 +1326,4 @@ declare const CAMERA_POSITIONS: {
1485
1326
  };
1486
1327
  };
1487
1328
 
1488
- export { AVL_3D_COLORS, AssetLoader, type AssetLoadingState, Avl3DApplicationScene, type Avl3DApplicationSceneProps, type Avl3DConfig, Avl3DContext, Avl3DEffects, type Avl3DEffectsProps, type Avl3DModelOverrides, Avl3DOrbitalScene, type Avl3DOrbitalSceneProps, Avl3DTraitScene, type Avl3DTraitSceneProps, Avl3DTransitionScene, type Avl3DTransitionSceneProps, Avl3DViewer, type Avl3DViewerProps, CAMERA_POSITIONS, Camera3D, type Camera3DHandle, type Camera3DProps, type CameraMode$1 as CameraMode, Canvas3DErrorBoundary, type Canvas3DErrorBoundaryProps, type Canvas3DErrorBoundaryState, Canvas3DHost, type Canvas3DHostHandle, type Canvas3DHostProps, Canvas3DLoadingState, type Canvas3DLoadingStateProps, type CullingOptions, Canvas3DHost as GameCanvas3D, type GameCanvas3DEventConfig, type Grid3DConfig, type GridCoordinate, type GridHit, type LODConfig, type LODLevel, Lighting3D, type Lighting3DProps, type LoadedModel, ModelLoader, type ModelLoaderProps, type NodeType, type Position3D, type RaycastHit, Scene3D, type Scene3DProps, type SceneGraphNode, SpatialHashGrid, type UseAssetLoaderOptions, type UseAssetLoaderReturn, type UseGameCanvas3DEventsOptions, type UseGameCanvas3DEventsReturn, type UseRaycasterOptions, type UseRaycasterReturn, type UseSceneGraphReturn, type UseThreeOptions, type UseThreeReturn, arcCurve3D, assetLoader, calculateLODLevel, createGridHighlight, cullInstancedMesh, fibonacciSpherePositions, filterByFrustum, getCellsInRadius, getNeighbors, getVisibleIndices, goldenSpiralPositions, gridDistance, gridManhattanDistance, gridToWorld, isInBounds, isInFrustum, normalizeMouseCoordinates, orbitRingPositions, raycastToObjects, raycastToPlane, selfLoopCurve3D, treeLayout3D, updateInstanceLOD, useAssetLoader, useAvl3DConfig, useGameCanvas3DEvents, useRaycaster, useSceneGraph, useThree, worldToGrid };
1329
+ export { AVL_3D_COLORS, AssetLoader, type AssetLoadingState, Avl3DApplicationScene, type Avl3DApplicationSceneProps, type Avl3DConfig, Avl3DContext, Avl3DEffects, type Avl3DEffectsProps, type Avl3DModelOverrides, Avl3DOrbitalScene, type Avl3DOrbitalSceneProps, Avl3DTraitScene, type Avl3DTraitSceneProps, Avl3DTransitionScene, type Avl3DTransitionSceneProps, Avl3DViewer, type Avl3DViewerProps, CAMERA_POSITIONS, Camera3D, type Camera3DHandle, type Camera3DProps, type CameraMode$1 as CameraMode, Canvas3DErrorBoundary, type Canvas3DErrorBoundaryProps, type Canvas3DErrorBoundaryState, Canvas3DLoadingState, type Canvas3DLoadingStateProps, type CullingOptions, type GameCanvas3DEventConfig, type Grid3DConfig, type GridCoordinate, type GridHit, type LODConfig, type LODLevel, Lighting3D, type Lighting3DProps, type LoadedModel, ModelLoader, type ModelLoaderProps, type NodeType, type Position3D, type RaycastHit, Scene3D, type Scene3DProps, type SceneGraphNode, SpatialHashGrid, type UseAssetLoaderOptions, type UseAssetLoaderReturn, type UseGameCanvas3DEventsOptions, type UseGameCanvas3DEventsReturn, type UseRaycasterOptions, type UseRaycasterReturn, type UseSceneGraphReturn, type UseThreeOptions, type UseThreeReturn, arcCurve3D, assetLoader, calculateLODLevel, createGridHighlight, cullInstancedMesh, fibonacciSpherePositions, filterByFrustum, getCellsInRadius, getNeighbors, getVisibleIndices, goldenSpiralPositions, gridDistance, gridManhattanDistance, gridToWorld, isInBounds, isInFrustum, normalizeMouseCoordinates, orbitRingPositions, raycastToObjects, raycastToPlane, selfLoopCurve3D, treeLayout3D, updateInstanceLOD, useAssetLoader, useAvl3DConfig, useGameCanvas3DEvents, useRaycaster, useSceneGraph, useThree, worldToGrid };