@dreamboard-games/sdk 0.5.0-alpha.13 → 0.5.0-alpha.14

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.
package/README.md CHANGED
@@ -352,7 +352,9 @@ the application bundler resolves its supported React subscription dependencies.
352
352
  `dragFeature`, export `useCardGesture`, `useActiveCard`, `useDropArea` and `useDragOverlay` from the
353
353
  binding, and use the copied Hand and BoardTargets components or your own renderer.
354
354
  The SDK prescribes no layout. Headless `game.drag` remains browser-free and handles
355
- atomic domain routing. `fanLayout` computes arc positions for a hand, and
355
+ atomic domain routing. `fanLayout` computes arc positions for a hand,
356
+ `handFan` adds a focused, readable card with configurable presets and timing,
357
+ and
356
358
  `originsFeature` adds `card.getOrigin()` so a newly shown card can animate from
357
359
  the zone or player it came from.
358
360
 
package/dist/index.d.ts CHANGED
@@ -1500,6 +1500,122 @@ declare function fanLayout({ count, width, cardWidth, cardHeight, step, minStep,
1500
1500
  /** Moves a fanned card outward along its own tilt, as for a selected card. */
1501
1501
  declare function liftFanCard(card: FanCard, distance: number): FanCard;
1502
1502
 
1503
+ /**
1504
+ * How a hand rests and focuses one card. Lengths are shares of the resting
1505
+ * card, so one configuration fits every card size. Missing options come from
1506
+ * `handFanPresets.open`.
1507
+ */
1508
+ interface HandFanOptions extends Pick<FanOptions, "angle" | "maxSpread"> {
1509
+ /** Distance between neighbouring cards when there is room, in card widths. Default 0.6, as `fanLayout`. */
1510
+ readonly spacing?: number;
1511
+ /** Share of each resting card's height below the hand's bottom edge. 0 shows whole cards. */
1512
+ readonly tuck?: number;
1513
+ /** Focused face width as a multiple of the resting card. */
1514
+ readonly focusScale?: number;
1515
+ /** Tallest focused face, as a share of the window height. */
1516
+ readonly focusMaxHeight?: number;
1517
+ /**
1518
+ * Sideways shift of the first, second, third… neighbour, in card widths.
1519
+ * The focused face's extra width tapers over the same neighbours.
1520
+ */
1521
+ readonly push?: readonly number[];
1522
+ /** Narrowest strip of each neighbour kept visible, in card widths. */
1523
+ readonly exposed?: number;
1524
+ }
1525
+ /** Starting points for a hand; spread one and override what differs. */
1526
+ declare const handFanPresets: {
1527
+ /** Whole resting cards; focusing enlarges the card. */
1528
+ readonly open: {
1529
+ readonly tuck: 0;
1530
+ readonly focusScale: 2;
1531
+ readonly focusMaxHeight: 0.55;
1532
+ readonly push: readonly [0.29, 0.19, 0.1];
1533
+ readonly exposed: 0.35;
1534
+ };
1535
+ /**
1536
+ * Larger cards tucked below the bottom edge and spaced like a dealt hand;
1537
+ * focusing mostly reveals the card.
1538
+ */
1539
+ readonly tucked: {
1540
+ readonly spacing: 0.75;
1541
+ readonly tuck: 0.4;
1542
+ readonly focusScale: 1.4;
1543
+ readonly focusMaxHeight: 0.4;
1544
+ readonly push: readonly [0.29, 0.19, 0.1];
1545
+ readonly exposed: 0.35;
1546
+ };
1547
+ /** Coarse pointers: a shallower tuck and wider strips to tap. */
1548
+ readonly touch: {
1549
+ readonly spacing: 0.75;
1550
+ readonly tuck: 0.2;
1551
+ readonly focusScale: 1.6;
1552
+ readonly focusMaxHeight: 0.5;
1553
+ readonly push: readonly [0.35, 0.2, 0.1];
1554
+ readonly exposed: 0.45;
1555
+ };
1556
+ };
1557
+ /** A card's `fanLayout` pose with its scale and stacking order. */
1558
+ interface HandFanPose extends FanCard {
1559
+ readonly scale: number;
1560
+ /** Stacking order: fan order, with the focused card above the rest. */
1561
+ readonly layer: number;
1562
+ }
1563
+ interface HandFan {
1564
+ /** One pose per card, in the same coordinates as `fanLayout`. */
1565
+ readonly cards: readonly HandFanPose[];
1566
+ /** The fan's width, as `fanLayout` reports it. */
1567
+ readonly width: number;
1568
+ /** The visible band: the fan's height less the tucked part of its cards. */
1569
+ readonly height: number;
1570
+ /** Space above the band that a focused face can rise into. */
1571
+ readonly headroom: number;
1572
+ }
1573
+ interface HandFanInput extends Pick<FanOptions, "count" | "width" | "cardWidth" | "cardHeight"> {
1574
+ /** Index of the focused card, or -1 for none. */
1575
+ readonly focused?: number;
1576
+ /**
1577
+ * The part of the fan the viewer can see after scrolling, in fan
1578
+ * coordinates; a focused face stays inside it. Defaults to `width`,
1579
+ * centred on the fan.
1580
+ */
1581
+ readonly visible?: {
1582
+ readonly left: number;
1583
+ readonly width: number;
1584
+ };
1585
+ /** Window height in pixels; `focusMaxHeight` is a share of it. */
1586
+ readonly windowHeight?: number;
1587
+ /** Pixels above the band's bottom edge that a focused face may use. */
1588
+ readonly room?: number;
1589
+ readonly options?: HandFanOptions;
1590
+ }
1591
+ /**
1592
+ * Lays a hand on a `fanLayout` arc and focuses one card: upright on the
1593
+ * band's bottom edge at a readable size, with nearby cards pushed sideways.
1594
+ * Neighbours keep their order and at least their `exposed` strip.
1595
+ */
1596
+ declare function handFan({ count, width, cardWidth, cardHeight, focused, visible, windowHeight, room, options, }: HandFanInput): HandFan;
1597
+ /**
1598
+ * An exponential approach to the target. An animation restarted from the
1599
+ * current pose continues the same curve at full speed, so retargeting never
1600
+ * stalls a card or overshoots.
1601
+ */
1602
+ declare function exponentialOut(progress: number): number;
1603
+ /** Durations in seconds with an easing function, as Motion transitions take them. */
1604
+ declare const handFanTiming: {
1605
+ /** The focused face rises: 90% in about 45ms. */
1606
+ readonly focus: {
1607
+ readonly duration: 0.09;
1608
+ readonly ease: typeof exponentialOut;
1609
+ };
1610
+ /** Sideways travel, neighbours and returning cards: 90% in about 300ms. */
1611
+ readonly settle: {
1612
+ readonly duration: 0.6;
1613
+ readonly ease: typeof exponentialOut;
1614
+ };
1615
+ };
1616
+ /** An easing function as a CSS `linear()` easing, for CSS transitions and the Web Animations API. */
1617
+ declare function cssEasing(ease: (progress: number) => number, samples?: number): string;
1618
+
1503
1619
  declare function canonicalizePluginRuntimeJson(value: unknown): RuntimeJson;
1504
1620
  declare function encodeCanonicalPluginRuntimeJson(value: unknown): string;
1505
1621
  declare function digestPluginRuntimeJson(value: unknown): string;
@@ -4755,4 +4871,4 @@ declare function parsePluginGameplayFrame(value: unknown): PluginGameplayFrame;
4755
4871
  declare function parseHostToPluginEnvelope(value: unknown): PluginProtocolEnvelope<HostToPluginPayload>;
4756
4872
  declare function parsePluginToHostEnvelope(value: unknown): PluginProtocolEnvelope<PluginToHostPayload>;
4757
4873
 
4758
- export { ActionProps, type ActionSetVersionInput, AmbiguousTargetError, AuthAcceptedFrameSchema, AuthConnectFrameSchema, AuthRefreshFrameSchema, BoardBase, BoardCollection, BoardDataOf, BoardEdgeId, type BoardFeature, type BoardLayoutOptions, type BoardLayoutTile, BoardSpace, BoardSpaceCollection, BoardVertexId, type CancelInteractionCommand, CancelInteractionCommandSchema, Card, type CardOrigin, type ClientGameplayFrame, ClientGameplayFrameSchema, CommandSource, CoreInstance, DREAMBOARD_PLUGIN_PROTOCOL, DREAMBOARD_PLUGIN_PROTOCOL_VERSION, DREAMBOARD_SDK_PACKAGES, DREAMBOARD_SDK_PACKAGE_SET, DREAMBOARD_SDK_VERSION, type DragController, type DragState, type DreamboardSdkPackageName, type DreamboardSdkPackageSet, DropTarget, type FanCard, type FanLayout, type FanOptions, FeatureContext, Features, GESTURE_THRESHOLDS, GameEventDetailSchema, GameEventSchema, GameInstance, GameOutcomeSchema, GameSource, GameplayBackpressureFrameSchema, GameplayBackpressureOperationSchema, GameplayBackpressureReasonSchema, GameplayBasis, GameplayBasisSchema, GameplayCloseCode, type GameplayCredential, GameplayCredentialSchema, type GestureCallbacks, type GestureKind, type GestureOptions, type GesturePointer, type GestureRecognizer, type HandOptions, type HostToPluginEnvelope, HostToPluginEnvelopeSchema, type HostToPluginPayload, HostToPluginPayloadSchema, IdOf, InstanceOptions, InteractionDescriptor, type InteractionResult, InteractionResultSchema, type MaterializePluginGameplayFrameInput, type PanZoomOptions, PlayerId, PluginGameplayFrame, PluginGameplayFrameSchema, PluginPlayerSummarySchema, type PluginProtocolEnvelope, PluginSessionDescriptor, PluginSessionDescriptorSchema, type PluginToHostEnvelope, PluginToHostEnvelopeSchema, type PluginToHostPayload, PluginToHostPayloadSchema, ReducerSeatProjectionBundle, RuntimeJson, RuntimeTargetOptions, SeatBoardTopology, SeatCardId, SeatFrameSchema, SeatProjectionBundleSchema, SeatSpaceRef, SeatTileRef, type ServerGameplayFrame, ServerGameplayFrameSchema, SessionResumeFrameSchema, SessionSnapshotFrameSchema, SimultaneousPhaseSnapshotSchema, SourceSnapshot, type SubmitInteractionCommand, SubmitInteractionCommandSchema, SystemActionEventSchema, TargetOptions, type ViewportSurface, type ViewportTransform, type WheelInput, Zone, ZoneHandlesSnapshotSchema, ZoneHostId, boardFeature, canonicalizePluginRuntimeJson, computePluginActionSetVersion, createGameInstance, createGestureRecognizer, createPluginProtocolEnvelopeSchema, digestPluginCommandRequest, digestPluginGameplayFrame, digestPluginRuntimeJson, dragFeature, encodeCanonicalPluginRuntimeJson, fanLayout, handFeature, hostSource, iframeSource, liftFanCard, magneticDropPoint, materializePluginGameplayFrame, originsFeature, panZoomFeature, parseHostToPluginEnvelope, parsePluginGameplayFrame, parsePluginSessionDescriptor, parsePluginToHostEnvelope, staticSource };
4874
+ export { ActionProps, type ActionSetVersionInput, AmbiguousTargetError, AuthAcceptedFrameSchema, AuthConnectFrameSchema, AuthRefreshFrameSchema, BoardBase, BoardCollection, BoardDataOf, BoardEdgeId, type BoardFeature, type BoardLayoutOptions, type BoardLayoutTile, BoardSpace, BoardSpaceCollection, BoardVertexId, type CancelInteractionCommand, CancelInteractionCommandSchema, Card, type CardOrigin, type ClientGameplayFrame, ClientGameplayFrameSchema, CommandSource, CoreInstance, DREAMBOARD_PLUGIN_PROTOCOL, DREAMBOARD_PLUGIN_PROTOCOL_VERSION, DREAMBOARD_SDK_PACKAGES, DREAMBOARD_SDK_PACKAGE_SET, DREAMBOARD_SDK_VERSION, type DragController, type DragState, type DreamboardSdkPackageName, type DreamboardSdkPackageSet, DropTarget, type FanCard, type FanLayout, type FanOptions, FeatureContext, Features, GESTURE_THRESHOLDS, GameEventDetailSchema, GameEventSchema, GameInstance, GameOutcomeSchema, GameSource, GameplayBackpressureFrameSchema, GameplayBackpressureOperationSchema, GameplayBackpressureReasonSchema, GameplayBasis, GameplayBasisSchema, GameplayCloseCode, type GameplayCredential, GameplayCredentialSchema, type GestureCallbacks, type GestureKind, type GestureOptions, type GesturePointer, type GestureRecognizer, type HandFan, type HandFanInput, type HandFanOptions, type HandFanPose, type HandOptions, type HostToPluginEnvelope, HostToPluginEnvelopeSchema, type HostToPluginPayload, HostToPluginPayloadSchema, IdOf, InstanceOptions, InteractionDescriptor, type InteractionResult, InteractionResultSchema, type MaterializePluginGameplayFrameInput, type PanZoomOptions, PlayerId, PluginGameplayFrame, PluginGameplayFrameSchema, PluginPlayerSummarySchema, type PluginProtocolEnvelope, PluginSessionDescriptor, PluginSessionDescriptorSchema, type PluginToHostEnvelope, PluginToHostEnvelopeSchema, type PluginToHostPayload, PluginToHostPayloadSchema, ReducerSeatProjectionBundle, RuntimeJson, RuntimeTargetOptions, SeatBoardTopology, SeatCardId, SeatFrameSchema, SeatProjectionBundleSchema, SeatSpaceRef, SeatTileRef, type ServerGameplayFrame, ServerGameplayFrameSchema, SessionResumeFrameSchema, SessionSnapshotFrameSchema, SimultaneousPhaseSnapshotSchema, SourceSnapshot, type SubmitInteractionCommand, SubmitInteractionCommandSchema, SystemActionEventSchema, TargetOptions, type ViewportSurface, type ViewportTransform, type WheelInput, Zone, ZoneHandlesSnapshotSchema, ZoneHostId, boardFeature, canonicalizePluginRuntimeJson, computePluginActionSetVersion, createGameInstance, createGestureRecognizer, createPluginProtocolEnvelopeSchema, cssEasing, digestPluginCommandRequest, digestPluginGameplayFrame, digestPluginRuntimeJson, dragFeature, encodeCanonicalPluginRuntimeJson, exponentialOut, fanLayout, handFan, handFanPresets, handFanTiming, handFeature, hostSource, iframeSource, liftFanCard, magneticDropPoint, materializePluginGameplayFrame, originsFeature, panZoomFeature, parseHostToPluginEnvelope, parsePluginGameplayFrame, parsePluginSessionDescriptor, parsePluginToHostEnvelope, staticSource };
package/dist/index.js CHANGED
@@ -71,7 +71,7 @@ import {
71
71
  } from "./chunk-ES74C2IN.js";
72
72
 
73
73
  // src/package-set.ts
74
- var DREAMBOARD_SDK_VERSION = true ? "0.5.0-alpha.13" : "0.0.0-development";
74
+ var DREAMBOARD_SDK_VERSION = true ? "0.5.0-alpha.14" : "0.0.0-development";
75
75
  var DREAMBOARD_SDK_PACKAGES = {
76
76
  "@dreamboard-games/sdk": DREAMBOARD_SDK_VERSION
77
77
  };
@@ -1578,6 +1578,151 @@ function liftFanCard(card, distance) {
1578
1578
  rotate: card.rotate
1579
1579
  };
1580
1580
  }
1581
+
1582
+ // src/headless/hand-fan.ts
1583
+ var handFanPresets = {
1584
+ /** Whole resting cards; focusing enlarges the card. */
1585
+ open: {
1586
+ tuck: 0,
1587
+ focusScale: 2,
1588
+ focusMaxHeight: 0.55,
1589
+ push: [0.29, 0.19, 0.1],
1590
+ exposed: 0.35
1591
+ },
1592
+ /**
1593
+ * Larger cards tucked below the bottom edge and spaced like a dealt hand;
1594
+ * focusing mostly reveals the card.
1595
+ */
1596
+ tucked: {
1597
+ spacing: 0.75,
1598
+ tuck: 0.4,
1599
+ focusScale: 1.4,
1600
+ focusMaxHeight: 0.4,
1601
+ push: [0.29, 0.19, 0.1],
1602
+ exposed: 0.35
1603
+ },
1604
+ /** Coarse pointers: a shallower tuck and wider strips to tap. */
1605
+ touch: {
1606
+ spacing: 0.75,
1607
+ tuck: 0.2,
1608
+ focusScale: 1.6,
1609
+ focusMaxHeight: 0.5,
1610
+ push: [0.35, 0.2, 0.1],
1611
+ exposed: 0.45
1612
+ }
1613
+ };
1614
+ function handFan({
1615
+ count,
1616
+ width,
1617
+ cardWidth,
1618
+ cardHeight,
1619
+ focused = -1,
1620
+ visible,
1621
+ windowHeight = Infinity,
1622
+ room = Infinity,
1623
+ options
1624
+ }) {
1625
+ const o = { ...handFanPresets.open, ...options };
1626
+ const fan = fanLayout({
1627
+ count,
1628
+ width,
1629
+ cardWidth,
1630
+ cardHeight,
1631
+ angle: o.angle,
1632
+ maxSpread: o.maxSpread,
1633
+ step: o.spacing === void 0 ? void 0 : o.spacing * cardWidth
1634
+ });
1635
+ const band = Math.max(0, fan.height - o.tuck * cardHeight);
1636
+ const view = visible ?? {
1637
+ left: (fan.width - width) / 2,
1638
+ width
1639
+ };
1640
+ const exposed = cardWidth * o.exposed;
1641
+ const largest = Math.max(
1642
+ cardWidth,
1643
+ Math.min(
1644
+ cardWidth * o.focusScale,
1645
+ windowHeight * o.focusMaxHeight * cardWidth / cardHeight,
1646
+ room * cardWidth / cardHeight,
1647
+ view.width
1648
+ )
1649
+ );
1650
+ const headroom = Math.max(0, largest * cardHeight / cardWidth - band);
1651
+ const cards = fan.cards.map((card, index) => ({
1652
+ ...card,
1653
+ scale: 1,
1654
+ layer: index
1655
+ }));
1656
+ if (focused < 0 || focused >= count)
1657
+ return { cards, width: fan.width, height: band, headroom };
1658
+ const leftStrip = focused > 0 ? exposed : 0;
1659
+ const rightStrip = focused < count - 1 ? exposed : 0;
1660
+ const face = Math.max(
1661
+ cardWidth,
1662
+ Math.min(largest, view.width - leftStrip - rightStrip)
1663
+ );
1664
+ const scale = face / cardWidth;
1665
+ const half = face / 2;
1666
+ const centre = Math.max(
1667
+ view.left + leftStrip + half,
1668
+ Math.min(
1669
+ view.left + view.width - rightStrip - half,
1670
+ cards[focused].x + cardWidth / 2
1671
+ )
1672
+ );
1673
+ cards[focused] = {
1674
+ x: centre - cardWidth / 2,
1675
+ y: band - cardHeight * (scale + 1) / 2,
1676
+ rotate: 0,
1677
+ scale,
1678
+ layer: count
1679
+ };
1680
+ const extra = Math.max(0, half - cardWidth / 2);
1681
+ const reach = o.push.length;
1682
+ for (const direction of [-1, 1]) {
1683
+ let previous = centre;
1684
+ for (let distance = 1, index = focused + direction; index >= 0 && index < count; distance++, index += direction) {
1685
+ const card = cards[index];
1686
+ const shift = (o.push[distance - 1] ?? 0) * cardWidth + (reach ? extra * Math.max(0, 1 - (distance - 1) / reach) : 0);
1687
+ const desired = card.x + cardWidth / 2 + direction * shift;
1688
+ const angle = card.rotate * Math.PI / 180;
1689
+ const halfWidth = (cardWidth * Math.cos(angle) + cardHeight * Math.abs(Math.sin(angle))) / 2;
1690
+ const middleHalfWidth = cardWidth * Math.cos(angle) / 2;
1691
+ const clearance = distance === 1 ? Math.max(exposed, half - middleHalfWidth + exposed) : exposed;
1692
+ const boundary = direction === 1 && distance > 1 ? Math.max(previous + clearance, centre + half + exposed + halfWidth) : previous + direction * clearance;
1693
+ let next = direction === 1 ? Math.max(desired, boundary) : Math.min(desired, boundary);
1694
+ if (distance === 1)
1695
+ next = direction === 1 ? Math.min(
1696
+ next,
1697
+ view.left + view.width - middleHalfWidth,
1698
+ centre + half + middleHalfWidth
1699
+ ) : Math.max(
1700
+ next,
1701
+ view.left + middleHalfWidth,
1702
+ centre - half - middleHalfWidth
1703
+ );
1704
+ cards[index] = { ...card, x: next - cardWidth / 2 };
1705
+ previous = next;
1706
+ }
1707
+ }
1708
+ return { cards, width: fan.width, height: band, headroom };
1709
+ }
1710
+ function exponentialOut(progress) {
1711
+ return (1 - Math.exp(-4.5 * progress)) / (1 - Math.exp(-4.5));
1712
+ }
1713
+ var handFanTiming = {
1714
+ /** The focused face rises: 90% in about 45ms. */
1715
+ focus: { duration: 0.09, ease: exponentialOut },
1716
+ /** Sideways travel, neighbours and returning cards: 90% in about 300ms. */
1717
+ settle: { duration: 0.6, ease: exponentialOut }
1718
+ };
1719
+ function cssEasing(ease, samples = 24) {
1720
+ const points = Array.from(
1721
+ { length: samples + 1 },
1722
+ (_, index) => Number(ease(index / samples).toFixed(4))
1723
+ );
1724
+ return `linear(${points.join(", ")})`;
1725
+ }
1581
1726
  export {
1582
1727
  AmbiguousTargetError,
1583
1728
  AuthAcceptedFrameSchema,
@@ -1633,12 +1778,17 @@ export {
1633
1778
  createGameInstance,
1634
1779
  createGestureRecognizer,
1635
1780
  createPluginProtocolEnvelopeSchema,
1781
+ cssEasing,
1636
1782
  digestPluginCommandRequest,
1637
1783
  digestPluginGameplayFrame,
1638
1784
  digestPluginRuntimeJson,
1639
1785
  dragFeature,
1640
1786
  encodeCanonicalPluginRuntimeJson,
1787
+ exponentialOut,
1641
1788
  fanLayout,
1789
+ handFan,
1790
+ handFanPresets,
1791
+ handFanTiming,
1642
1792
  handFeature,
1643
1793
  hostSource,
1644
1794
  iframeSource,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/package-set.ts","../src/headless/sources/iframe.ts","../src/shared/protocol/gameplay-wire.ts","../src/headless/sources/host-websocket.ts","../src/headless/features/shortcuts.ts","../src/headless/features/hand.ts","../src/shared/tile-board-layout.ts","../src/shared/square-board-layout.ts","../src/headless/features/board.ts","../src/headless/features/drag.ts","../src/headless/features/pointer-session.ts","../src/headless/features/pan-zoom.ts","../src/headless/features/origins.ts","../src/headless/fan.ts"],"sourcesContent":["declare const __DREAMBOARD_SDK_VERSION__: string;\n\nexport const DREAMBOARD_SDK_VERSION =\n typeof __DREAMBOARD_SDK_VERSION__ === \"string\"\n ? __DREAMBOARD_SDK_VERSION__\n : \"0.0.0-development\";\n\nexport const DREAMBOARD_SDK_PACKAGES = {\n \"@dreamboard-games/sdk\": DREAMBOARD_SDK_VERSION,\n} as const;\n\nexport type DreamboardSdkPackageName = keyof typeof DREAMBOARD_SDK_PACKAGES;\n\nexport type DreamboardSdkPackageSet = {\n version: 1;\n sdkVersion: string;\n packages: Record<DreamboardSdkPackageName, string>;\n};\n\nexport const DREAMBOARD_SDK_PACKAGE_SET: DreamboardSdkPackageSet = {\n version: 1,\n sdkVersion: DREAMBOARD_SDK_VERSION,\n packages: DREAMBOARD_SDK_PACKAGES,\n};\n","import {\n DREAMBOARD_PLUGIN_PROTOCOL,\n DREAMBOARD_PLUGIN_PROTOCOL_VERSION,\n} from \"../../shared/protocol/protocol.js\";\nimport { HostToPluginEnvelopeSchema } from \"../../shared/protocol/schema.js\";\nimport type { PluginToHostPayload } from \"../../shared/protocol/protocol.js\";\nimport { createSourceLifecycle } from \"./lifecycle.js\";\nimport type { CommandSource } from \"./types.js\";\n\n/** Pins its parent window, origin and channel at the first valid initialization. */\nexport function iframeSource(\n options: {\n timeoutMs?: number;\n /** Trusted pass-and-play hosts may change seats without replacing the iframe. */\n followHostSeat?: boolean;\n } = {},\n): CommandSource {\n const target = window;\n const parent = target.parent;\n let channel: { id: string; origin: string } | null = null;\n let sequence = 0;\n let receivedSequence = -1;\n const send = (payload: PluginToHostPayload) => {\n if (!channel) throw new Error(\"Iframe source is not initialized.\");\n parent.postMessage(\n {\n protocol: DREAMBOARD_PLUGIN_PROTOCOL,\n version: DREAMBOARD_PLUGIN_PROTOCOL_VERSION,\n channelId: channel.id,\n sequence: ++sequence,\n payload,\n },\n channel.origin,\n );\n };\n const lifecycle = createSourceLifecycle({\n timeoutMs: options.timeoutMs,\n followHostSeat: options.followHostSeat,\n send,\n recover: () => send({ type: \"runtime.resume\" }),\n close: () => target.removeEventListener(\"message\", receive),\n });\n const isOpen = () => {\n const { connection } = lifecycle.source.store.get();\n return connection !== \"closed\" && connection !== \"failed\";\n };\n function receive(event: MessageEvent) {\n if (event.source !== parent) return;\n const parsed = HostToPluginEnvelopeSchema.safeParse(event.data);\n if (!parsed.success) {\n const data: unknown = event.data;\n if (\n channel &&\n event.origin === channel.origin &&\n typeof data === \"object\" &&\n data !== null &&\n \"channelId\" in data &&\n data.channelId === channel.id\n ) {\n try {\n send({\n type: \"runtime.error\",\n code: \"host-runtime-protocol-mismatch\",\n message: \"Iframe source received an invalid host envelope.\",\n });\n } finally {\n lifecycle.fail(new Error(\"Invalid iframe host envelope.\"));\n }\n }\n return;\n }\n const envelope = parsed.data;\n if (!channel) {\n if (envelope.payload.type !== \"runtime.init\") return;\n channel = { id: envelope.channelId, origin: event.origin };\n }\n if (\n channel.id !== envelope.channelId ||\n channel.origin !== event.origin ||\n envelope.sequence <= receivedSequence\n )\n return;\n receivedSequence = envelope.sequence;\n const payload = envelope.payload;\n if (payload.type === \"runtime.init\") {\n lifecycle.session(payload.session);\n if (isOpen()) send({ type: \"runtime.ready\" });\n } else if (payload.type === \"gameplay.frame\")\n lifecycle.frame(payload.frame);\n else lifecycle.result(payload);\n if (isOpen()) send({ type: \"runtime.ack\", sequence: envelope.sequence });\n }\n target.addEventListener(\"message\", receive);\n return lifecycle.source;\n}\n","import * as z from \"zod\";\nimport {\n InteractionResultSchema,\n PluginGameplayFrameSchema,\n SubmitInteractionCommandSchema,\n CancelInteractionCommandSchema,\n} from \"./schema.js\";\nexport const GameplayCloseCode = {\n GoingAway: 1001,\n CredentialExpired: 4000,\n CredentialInvalid: 4001,\n RefreshContextMismatch: 4002,\n PermissionDenied: 4100,\n ProtocolViolation: 4200,\n FrameBeforeAuth: 4201,\n SlowConsumer: 4300,\n TooManyRequests: 4301,\n} as const;\n\nexport const GameplayCredentialSchema = z.discriminatedUnion(\"kind\", [\n z\n .object({ kind: z.literal(\"user\"), token: z.string().min(1).max(16384) })\n .strict(),\n z\n .object({ kind: z.literal(\"demo\"), secret: z.string().min(1).max(1024) })\n .strict(),\n]);\nexport const AuthConnectFrameSchema = z\n .object({\n type: z.literal(\"auth.connect\"),\n credential: GameplayCredentialSchema,\n sessionId: z.string().uuid(),\n playerId: z.string().min(1).max(128),\n })\n .strict();\nexport const AuthRefreshFrameSchema = z\n .object({\n type: z.literal(\"auth.refresh\"),\n credential: GameplayCredentialSchema,\n })\n .strict();\n\nexport const SessionResumeFrameSchema = z.object({\n type: z.literal(\"session.resume\"),\n lastSeenLogCursor: z.number().int().nonnegative().nullable(),\n unacknowledgedClientActionIds: z.array(z.string().min(1)).max(32),\n});\n\nexport const AuthAcceptedFrameSchema = z.object({\n type: z.literal(\"auth.accepted\"),\n expiresAt: z.string().datetime(),\n});\n\nexport const GameplayBackpressureReasonSchema = z.enum([\n \"queue_full\",\n \"capacity_full\",\n]);\n\nexport const GameplayBackpressureOperationSchema = z.enum([\n \"session.resume\",\n \"interaction.submit\",\n \"interaction.cancel\",\n]);\nexport const GameplayBackpressureFrameSchema = z.object({\n type: z.literal(\"gameplay.backpressure\"),\n reason: GameplayBackpressureReasonSchema,\n retryAfterMs: z.number().int().positive(),\n message: z.string().min(1),\n operation: GameplayBackpressureOperationSchema,\n clientActionId: z.string().min(1).optional(),\n});\nexport const SessionSnapshotFrameSchema = z.object({\n type: z.literal(\"session.snapshot\"),\n frame: PluginGameplayFrameSchema,\n});\nexport const ClientGameplayFrameSchema = z.discriminatedUnion(\"type\", [\n AuthConnectFrameSchema,\n AuthRefreshFrameSchema,\n SessionResumeFrameSchema,\n SubmitInteractionCommandSchema,\n CancelInteractionCommandSchema,\n]);\nexport const ServerGameplayFrameSchema = z.discriminatedUnion(\"type\", [\n AuthAcceptedFrameSchema,\n GameplayBackpressureFrameSchema,\n SessionSnapshotFrameSchema,\n InteractionResultSchema,\n]);\nexport type GameplayCredential = z.infer<typeof GameplayCredentialSchema>;\nexport type ClientGameplayFrame = z.infer<typeof ClientGameplayFrameSchema>;\nexport type ServerGameplayFrame = z.infer<typeof ServerGameplayFrameSchema>;\n","import type { PluginSessionDescriptor } from \"../../shared/protocol/frame.js\";\nimport {\n ClientGameplayFrameSchema,\n ServerGameplayFrameSchema,\n GameplayCloseCode,\n type ClientGameplayFrame,\n type GameplayCredential,\n} from \"../../shared/protocol/gameplay-wire.js\";\nimport { createSourceLifecycle } from \"./lifecycle.js\";\nimport type { CommandSource, SourceCommand } from \"./types.js\";\n\nexport function hostSource(options: {\n url: string;\n session: PluginSessionDescriptor;\n playerId: string;\n getCredential(): Promise<GameplayCredential>;\n timeoutMs?: number;\n}): CommandSource {\n const { url, playerId, getCredential } = options;\n const sessionId = options.session.sessionId;\n let socket: WebSocket | null = null;\n let generation = 0;\n let disposed = false;\n let authenticated = false;\n let queued: SourceCommand | null = null;\n let reconnects = 0;\n let refreshTimer: ReturnType<typeof setTimeout> | undefined;\n let snapshotTimer: ReturnType<typeof setTimeout> | undefined;\n let openTimer: ReturnType<typeof setTimeout> | undefined;\n let cleanup = () => {};\n const timeoutMs = options.timeoutMs ?? 10_000;\n const send = (frame: ClientGameplayFrame) => {\n if (!socket || socket.readyState !== WebSocket.OPEN)\n throw new Error(\"Gameplay socket is not open.\");\n socket.send(JSON.stringify(ClientGameplayFrameSchema.parse(frame)));\n };\n const resume = () =>\n send({\n type: \"session.resume\",\n lastSeenLogCursor: null,\n unacknowledgedClientActionIds: queued ? [queued.clientActionId] : [],\n });\n const lifecycle = createSourceLifecycle({\n context: {\n sessionId,\n playerId,\n },\n timeoutMs,\n send(command) {\n if (!authenticated) {\n queued = command;\n return;\n }\n send(command);\n },\n recover() {\n if (authenticated) resume();\n else if (!openTimer) void connect();\n },\n close() {\n disposed = true;\n generation++;\n clearTimeout(refreshTimer);\n clearTimeout(openTimer);\n clearTimeout(snapshotTimer);\n cleanup();\n socket?.close();\n socket = null;\n queued = null;\n },\n });\n lifecycle.session(options.session);\n async function connect() {\n if (disposed) return;\n const current = ++generation;\n authenticated = false;\n clearTimeout(refreshTimer);\n clearTimeout(openTimer);\n clearTimeout(snapshotTimer);\n cleanup();\n socket?.close();\n socket = null;\n openTimer = setTimeout(\n () =>\n lifecycle.fail(new Error(\"Gameplay socket authentication timed out.\")),\n timeoutMs,\n );\n try {\n const credential = await getCredential();\n if (disposed || current !== generation) return;\n const next = new WebSocket(url);\n socket = next;\n const active = () => !disposed && current === generation;\n const onOpen = () => {\n if (!active()) return;\n try {\n send({\n type: \"auth.connect\",\n credential,\n sessionId,\n playerId,\n });\n } catch (error) {\n lifecycle.fail(asError(error));\n }\n };\n const onMessage = (event: MessageEvent) => {\n if (!active()) return;\n try {\n const value: unknown = JSON.parse(String(event.data));\n if (typeof value !== \"object\" || value === null || !(\"type\" in value))\n throw new Error(\"Invalid gameplay frame.\");\n if (\n ![\n \"auth.accepted\",\n \"session.snapshot\",\n \"interaction.result\",\n \"gameplay.backpressure\",\n ].includes(String(value.type))\n )\n return;\n const frame = ServerGameplayFrameSchema.parse(value);\n if (frame.type === \"auth.accepted\") {\n clearTimeout(openTimer);\n openTimer = undefined;\n const first = !authenticated;\n authenticated = true;\n if (first) {\n snapshotTimer = setTimeout(\n () => lifecycle.fail(new Error(\"Gameplay snapshot timed out.\")),\n timeoutMs,\n );\n resume();\n if (queued) {\n send(queued);\n queued = null;\n }\n }\n clearTimeout(refreshTimer);\n if (credential.kind === \"user\") {\n const ttl = Date.parse(frame.expiresAt) - Date.now();\n if (ttl <= 0)\n throw new Error(\"Gameplay credential is already expired.\");\n refreshTimer = setTimeout(\n () => {\n openTimer = setTimeout(\n () =>\n lifecycle.fail(\n new Error(\"Gameplay credential refresh timed out.\"),\n ),\n timeoutMs,\n );\n void getCredential()\n .then((updated) => {\n if (active())\n send({ type: \"auth.refresh\", credential: updated });\n })\n .catch((error) => {\n if (active()) lifecycle.fail(asError(error));\n });\n },\n Math.max(0, ttl - Math.min(60_000, ttl * 0.2)),\n );\n }\n } else if (!authenticated)\n throw new Error(\"Gameplay frame arrived before authentication.\");\n else if (frame.type === \"session.snapshot\") {\n clearTimeout(snapshotTimer);\n snapshotTimer = undefined;\n reconnects = 0;\n lifecycle.frame(frame.frame);\n } else if (frame.type === \"interaction.result\")\n lifecycle.result(frame);\n else lifecycle.fail(new Error(frame.message));\n } catch (error) {\n lifecycle.fail(asError(error));\n }\n };\n const onClose = (event: CloseEvent) => {\n if (!active()) return;\n authenticated = false;\n lifecycle.recovering();\n if (\n new Set<number>([\n GameplayCloseCode.CredentialInvalid,\n GameplayCloseCode.RefreshContextMismatch,\n GameplayCloseCode.PermissionDenied,\n GameplayCloseCode.ProtocolViolation,\n GameplayCloseCode.FrameBeforeAuth,\n ]).has(event.code) ||\n reconnects++ > 0\n ) {\n lifecycle.fail(new Error(`Gameplay socket closed (${event.code}).`));\n return;\n }\n void connect();\n lifecycle.retry();\n };\n const onError = () => {\n if (active()) next.close();\n };\n next.addEventListener(\"open\", onOpen);\n next.addEventListener(\"message\", onMessage);\n next.addEventListener(\"close\", onClose);\n next.addEventListener(\"error\", onError);\n cleanup = () => {\n next.removeEventListener(\"open\", onOpen);\n next.removeEventListener(\"message\", onMessage);\n next.removeEventListener(\"close\", onClose);\n next.removeEventListener(\"error\", onError);\n };\n } catch (error) {\n if (!disposed && current === generation) lifecycle.fail(asError(error));\n }\n }\n void connect();\n return lifecycle.source;\n}\nfunction asError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n","import { createStore, type Store } from \"@tanstack/store\";\nimport type {\n CoreInstance,\n FeatureContext,\n IdOf,\n InputKey,\n InputKind,\n InputTarget,\n InteractionKey,\n InteractionParams,\n SelectionTarget,\n SubmitResult,\n ZoneHostId,\n} from \"../model.js\";\nimport { runtimeFeatures } from \"../runtime-features.js\";\nimport type { RuntimeSelectionTarget } from \"../targets.js\";\nimport type { RuntimeJson } from \"../../shared/runtime-json.js\";\n\n/** A zone control carries the actual admitted attachment, including its host. */\nexport type ShortcutZoneTarget<G> = {\n [Z in IdOf<G, \"zoneId\">]: {\n readonly kind: \"zone\";\n readonly zoneId: Z;\n readonly hostId: ZoneHostId<G, Z>;\n };\n}[IdOf<G, \"zoneId\">];\nexport type ShortcutTarget<G> = SelectionTarget<G> | ShortcutZoneTarget<G>;\ntype TargetKind = SelectionTarget<unknown>[\"kind\"];\ntype CollectorKind<Kind extends TargetKind> = Kind extends \"space\"\n ? \"board-space\"\n : Kind extends \"edge\"\n ? \"board-edge\"\n : Kind extends \"vertex\"\n ? \"board-vertex\"\n : Kind;\ntype TargetFor<\n G,\n K extends InteractionKey<G>,\n N extends InputKey<G, K>,\n Kind extends TargetKind,\n> = Extract<SelectionTarget<G>, { readonly kind: Kind }> & {\n readonly value: InputTarget<G, K, N>;\n};\ntype Binding<G, K extends InteractionKey<G>, Target, Filter> = Filter & {\n /** Exact browser event.key values; modifiers and held repeats are ignored. */\n readonly keys: readonly string[];\n readonly label: string;\n readonly interaction: K;\n readonly inputs: (context: {\n readonly key: string;\n readonly target: Target;\n }) => InteractionParams<G, K>;\n};\ntype SelectionBinding<G, K extends InteractionKey<G>> = {\n [N in InputKey<G, K>]: {\n [Kind in TargetKind]: [\n Extract<InputKind<G, K, N>, CollectorKind<Kind>>,\n ] extends [never]\n ? never\n : Binding<\n G,\n K,\n TargetFor<G, K, N, Kind>,\n { readonly target: Kind; readonly input: N }\n >;\n }[TargetKind];\n}[InputKey<G, K>];\n/** Correlated by interaction, input kind, and the selected target's value. */\nexport type ShortcutBinding<G> = {\n [K in InteractionKey<G>]:\n | SelectionBinding<G, K>\n | {\n [Z in IdOf<G, \"zoneId\">]: Binding<\n G,\n K,\n Extract<ShortcutZoneTarget<G>, { readonly zoneId: Z }>,\n { readonly target: \"zone\"; readonly zoneId: Z }\n >;\n }[IdOf<G, \"zoneId\">];\n}[InteractionKey<G>];\nexport interface ShortcutOptions<G> {\n readonly bindings: readonly ShortcutBinding<G>[];\n}\nexport interface ShortcutHint<G = unknown> {\n readonly keys: readonly string[];\n readonly label: string;\n readonly interaction: InteractionKey<G>;\n}\nexport interface ShortcutsController<G> {\n /** UI binding configuration has its own subscription, independent of reducer frames. */\n readonly configuration: Pick<\n Store<ShortcutOptions<G> | null>,\n \"get\" | \"subscribe\"\n >;\n /** Registers one mounted adapter. Cleanup removes both behavior and hints. */\n register(options: ShortcutOptions<G>): {\n update(options: ShortcutOptions<G>): void;\n dispose(): void;\n };\n /** null means unhandled; a handled key submits exactly once. */\n handle(\n key: string,\n target: ShortcutTarget<G> | null,\n ): Promise<SubmitResult> | null;\n getHints(target: ShortcutTarget<G> | null): readonly ShortcutHint<G>[];\n}\nexport type RuntimeShortcutTarget =\n | RuntimeSelectionTarget\n | {\n readonly kind: \"zone\";\n readonly zoneId: string;\n readonly hostId: string;\n };\ntype RuntimeBinding = {\n readonly keys: readonly string[];\n readonly label: string;\n readonly interaction: string;\n readonly target: RuntimeShortcutTarget[\"kind\"];\n readonly input?: string;\n readonly zoneId?: string;\n readonly inputs: (context: {\n readonly key: string;\n readonly target: RuntimeShortcutTarget;\n }) => Readonly<Record<string, RuntimeJson>>;\n};\n\n/** Headless and opt-in: no names, bindings or browser listeners are installed by default. */\nexport function shortcutsFeature<G>(\n _game: CoreInstance<G>,\n context: FeatureContext<G>,\n) {\n const game = context[runtimeFeatures].game;\n const configuration = createStore<ShortcutOptions<G> | null>(null);\n let registration: object | null = null;\n function bindings(): readonly RuntimeBinding[] {\n // eslint-disable-next-line no-restricted-syntax -- Instance composition owns the typed bindings; resolve validates the admitted projected domain before invoking each factory.\n return (configuration.get()?.bindings ??\n []) as unknown as readonly RuntimeBinding[];\n }\n let disposed = false;\n function resolve(\n binding: RuntimeBinding,\n key: string,\n target: RuntimeShortcutTarget | null,\n ) {\n if (\n disposed ||\n !target ||\n game.connection !== \"ready\" ||\n game.request ||\n target.kind !== binding.target\n )\n return null;\n const routes =\n target.kind === \"card\"\n ? (game.cards.find(target.value)?.getInteractions() ?? [])\n : game.interactions.list();\n const interaction = routes.find((item) => item.key === binding.interaction);\n if (!interaction || interaction.getStatus() !== \"open\") return null;\n if (target.kind === \"zone\") {\n if (\n target.zoneId !== binding.zoneId ||\n !game.zones.find(target.zoneId, target.hostId)\n )\n return null;\n } else {\n const input = interaction\n .getInputs()\n .find((item) => item.key === binding.input);\n if (!input || !input.getIsEligible(target.value)) return null;\n const domain = input.getDomain();\n if (target.kind === \"card\" && input.kind !== \"card\") return null;\n if (target.kind === \"tile\" && input.kind !== \"tile\") return null;\n if (\n target.kind === \"space\" ||\n target.kind === \"edge\" ||\n target.kind === \"vertex\"\n ) {\n if (\n domain.type !== \"boardTarget\" ||\n domain.targetKind !== target.kind ||\n domain.valueKind !== target.valueKind\n )\n return null;\n if (\n domain.valueKind === \"board-id\" &&\n target.valueKind === \"board-id\" &&\n domain.boardId !== target.boardId\n )\n return null;\n }\n }\n const params = binding.inputs({ key, target });\n return interaction.getIsAvailable(params) && interaction.getIsReady(params)\n ? { interaction, params }\n : null;\n }\n const controller: ShortcutsController<G> = {\n configuration,\n register(options) {\n if (registration)\n throw new Error(\"Mount useGameShortcuts once per GameProvider.\");\n const owned = {};\n registration = owned;\n configuration.setState(() => options);\n return {\n update(options) {\n if (registration !== owned) return;\n configuration.setState(() => options);\n },\n dispose() {\n if (registration !== owned) return;\n registration = null;\n configuration.setState(() => null);\n },\n };\n },\n handle(key, target) {\n const candidates = bindings()\n .filter((binding) => binding.keys.includes(key))\n .flatMap((binding) => {\n const resolved = resolve(binding, key, target);\n return resolved ? [resolved] : [];\n });\n // Ambiguous authored routes do not guess which action to run.\n return candidates.length === 1\n ? candidates[0].interaction.submit(candidates[0].params)\n : null;\n },\n getHints(target) {\n const eligible = bindings().map((binding) => ({\n binding,\n keys: binding.keys.filter((key) => resolve(binding, key, target)),\n }));\n const counts = new Map<string, number>();\n for (const { keys } of eligible)\n for (const key of new Set(keys))\n counts.set(key, (counts.get(key) ?? 0) + 1);\n return eligible.flatMap(({ binding, keys }) => {\n const unique = [...new Set(keys)].filter(\n (key) => counts.get(key) === 1,\n );\n return unique.length\n ? [\n {\n keys: unique,\n label: binding.label,\n interaction: binding.interaction,\n },\n ]\n : [];\n }) as readonly ShortcutHint<G>[];\n },\n };\n return {\n root: { shortcuts: controller },\n dispose() {\n disposed = true;\n registration = null;\n configuration.setState(() => null);\n },\n };\n}\n","import type { Card, CoreInstance, SeatCardId, Zone } from \"../model.js\";\n\nexport interface HandOptions<G> {\n /** Compare projected card data only; hidden cards never expose private fields. */\n readonly sort?: (\n left: Card<G, Record<never, never>>,\n right: Card<G, Record<never, never>>,\n ) => number;\n}\n\n// Generic G defers the card visibility union, so ids widen to string here.\nconst seatCardId = <G>(card: { readonly id: string }) =>\n card.id as SeatCardId<G>;\n\n/** Optional hand helpers reuse the zone order and the core selection router. */\nexport function handFeature<G>(\n _game: CoreInstance<G>,\n options: HandOptions<G> = {},\n) {\n return {\n zone: {\n getSortedCardIds(\n this: Zone<G, Record<never, never>>,\n ): readonly SeatCardId<G>[] {\n return this.getCards({ sort: options.sort }).map(seatCardId<G>);\n },\n getSelectedCardIds(\n this: Zone<G, Record<never, never>>,\n ): readonly SeatCardId<G>[] {\n return this.getCards()\n .filter((card) => card.getIsSelected())\n .map(seatCardId<G>);\n },\n getSelectableCardIds(\n this: Zone<G, Record<never, never>>,\n ): readonly SeatCardId<G>[] {\n return this.getCards()\n .filter((card) => card.getCanSelect())\n .map(seatCardId<G>);\n },\n },\n };\n}\n","import { immutableCopy } from \"./immutable.js\";\nimport { createHexTopology } from \"./hex-board.js\";\nimport { getPublicTileFootprint } from \"./tile-appearance.js\";\nimport {\n SeatBoardTopologySchema,\n type SeatBoardTopology,\n} from \"./seat-topology-schema.js\";\nimport type { SeatSpaceRef, SeatTileRef } from \"./domain/seat-reference.js\";\n\nexport type TileLayoutPoint = { readonly x: number; readonly y: number };\ntype PlacedTile = Exclude<\n SeatBoardTopology,\n { layout: \"generic\" }\n>[\"tiles\"][number];\n/** Rendering geometry is separate from inventory and spatial target handles. */\nexport type TileLayoutGeometry<Data extends PlacedTile = PlacedTile> = {\n readonly ref: SeatTileRef;\n readonly data: Data;\n readonly spaceIds: readonly SeatSpaceRef[];\n readonly outlines: readonly (readonly TileLayoutPoint[])[];\n readonly center: TileLayoutPoint;\n readonly anchor: TileLayoutPoint;\n readonly rotationDegrees: number;\n};\ntype Corner = { readonly key: string; readonly point: TileLayoutPoint };\ntype Side = { readonly from: Corner; readonly to: Corner };\ntype Cell = {\n readonly center: TileLayoutPoint;\n readonly corners: readonly Corner[];\n};\nfunction assertFinite(values: readonly number[]): void {\n if (!values.every(Number.isFinite))\n throw new Error(\"Derived tile layout geometry must be finite.\");\n}\nconst frozenPoint = (point: TileLayoutPoint) => {\n assertFinite([point.x, point.y]);\n return Object.freeze({ ...point });\n};\n\n/** Cancel internal sides using exact lattice identities, then walk every oriented boundary. */\nfunction outlines(\n cells: readonly Cell[],\n): readonly (readonly TileLayoutPoint[])[] {\n const sides = new Map<string, Side>();\n for (const cell of cells) {\n for (const [index, from] of cell.corners.entries()) {\n const to = cell.corners[(index + 1) % cell.corners.length];\n const key = [from.key, to.key].sort().join(\"|\");\n if (sides.has(key)) sides.delete(key);\n else sides.set(key, { from, to });\n }\n }\n const outgoing = new Map<string, Side[]>();\n for (const side of sides.values()) {\n const next = outgoing.get(side.from.key) ?? [];\n next.push(side);\n outgoing.set(side.from.key, next);\n }\n const loops: (readonly TileLayoutPoint[])[] = [];\n while (sides.size) {\n const first = sides.values().next().value!;\n const start = first.from.key;\n let side = first;\n const loop: TileLayoutPoint[] = [];\n while (true) {\n loop.push(frozenPoint(side.from.point));\n sides.delete([side.from.key, side.to.key].sort().join(\"|\"));\n const remaining = outgoing.get(side.from.key)!;\n remaining.splice(remaining.indexOf(side), 1);\n if (side.to.key === start) break;\n const candidates = [...(outgoing.get(side.to.key) ?? [])];\n if (!candidates.length)\n throw new Error(\"Tile footprint boundary is not closed.\");\n // At corner-touching islands, preserve the clockwise contour instead of joining islands.\n const angle = Math.atan2(\n side.to.point.y - side.from.point.y,\n side.to.point.x - side.from.point.x,\n );\n const turn = (next: typeof side) => {\n const delta =\n Math.atan2(\n next.to.point.y - next.from.point.y,\n next.to.point.x - next.from.point.x,\n ) - angle;\n return Math.atan2(Math.sin(delta), Math.cos(delta));\n };\n candidates.sort(\n (a, b) =>\n turn(b) - turn(a) ||\n (a.to.key < b.to.key ? -1 : a.to.key > b.to.key ? 1 : 0),\n );\n side = candidates[0];\n }\n loops.push(Object.freeze(loop));\n }\n return Object.freeze(loops);\n}\n\nfunction hexCells(\n boardId: string,\n orientation: \"pointy\" | \"flat\",\n coordinates: readonly { q: number; r: number }[],\n size: number,\n origin: TileLayoutPoint,\n): Cell[] {\n const topology = createHexTopology({\n id: boardId,\n orientation,\n spaces: coordinates.map((coordinate, index) => ({\n ...coordinate,\n id: String(index),\n })),\n });\n const layout = topology.getLayout({ hexSize: size, origin });\n const vertices = new Map(\n layout.vertices.map((vertex) => [vertex.id, vertex.center]),\n );\n return layout.spaces.map((space) => ({\n center: space.center,\n corners: topology\n .verticesOf(space.id)\n .map((key) => ({ key, point: vertices.get(key)! }))\n .sort(\n (a, b) =>\n Math.atan2(a.point.y - space.center.y, a.point.x - space.center.x) -\n Math.atan2(b.point.y - space.center.y, b.point.x - space.center.x),\n ),\n }));\n}\nfunction squareCells(\n coordinates: readonly { col: number; row: number }[],\n size: number,\n origin: TileLayoutPoint,\n): Cell[] {\n return coordinates.map(({ col, row }) => ({\n center: {\n x: origin.x + (col + 0.5) * size,\n y: origin.y + (row + 0.5) * size,\n },\n corners: [\n [col, row],\n [col + 1, row],\n [col + 1, row + 1],\n [col, row + 1],\n ].map(([x, y]) => ({\n key: `${x},${y}`,\n point: { x: origin.x + x * size, y: origin.y + y * size },\n })),\n }));\n}\n\nfunction build(\n board: SeatBoardTopology,\n size: number,\n origin: TileLayoutPoint,\n) {\n if (board.layout === \"generic\")\n throw new Error(\"Generic boards have no tile layout.\");\n const visibleByTile = new Map<\n SeatTileRef,\n { cells: Cell[]; ids: SeatSpaceRef[] }\n >();\n const group = (\n spaces: readonly { tileRef: SeatTileRef; id: SeatSpaceRef }[],\n cells: readonly Cell[],\n ) => {\n spaces.forEach((space, index) => {\n const grouped = visibleByTile.get(space.tileRef) ?? {\n cells: [],\n ids: [],\n };\n grouped.cells.push(cells[index]);\n grouped.ids.push(space.id);\n visibleByTile.set(space.tileRef, grouped);\n });\n };\n if (board.layout === \"hex\") {\n const spaces = Object.values(board.spaces);\n group(spaces, hexCells(board.id, board.orientation, spaces, size, origin));\n } else {\n const spaces = Object.values(board.spaces);\n group(spaces, squareCells(spaces, size, origin));\n }\n const tiles = board.tiles.map((tile): TileLayoutGeometry => {\n const visible = visibleByTile.get(tile.ref);\n const footprint =\n tile.disclosure === \"concealed\"\n ? getPublicTileFootprint(tile.appearance, tile.placement)\n : null;\n let cells: Cell[];\n let anchor: TileLayoutPoint;\n if (board.layout === \"hex\" && tile.placement.layout === \"hex\") {\n const placement = tile.placement;\n cells =\n tile.disclosure === \"visible\"\n ? (visible?.cells ?? [])\n : footprint?.layout === \"hex\"\n ? hexCells(\n board.id,\n board.orientation,\n footprint.cells,\n size,\n origin,\n )\n : [];\n anchor = hexCells(\n board.id,\n board.orientation,\n [{ q: placement.q, r: placement.r }],\n size,\n origin,\n )[0].center;\n } else if (\n board.layout === \"square\" &&\n tile.placement.layout === \"square\"\n ) {\n const placement = tile.placement;\n cells =\n tile.disclosure === \"visible\"\n ? (visible?.cells ?? [])\n : footprint?.layout === \"square\"\n ? squareCells(footprint.cells, size, origin)\n : [];\n anchor = squareCells(\n [{ col: placement.col, row: placement.row }],\n size,\n origin,\n )[0].center;\n } else throw new Error(\"Tile placement layout does not match board.\");\n if (!cells.length)\n throw new Error(\"A projected tile requires a nonempty footprint.\");\n const center = {\n x: cells.reduce((sum, cell) => sum + cell.center.x, 0) / cells.length,\n y: cells.reduce((sum, cell) => sum + cell.center.y, 0) / cells.length,\n };\n return Object.freeze({\n ref: tile.ref,\n data: tile,\n spaceIds: Object.freeze(visible?.ids ?? []),\n outlines: outlines(cells),\n center: frozenPoint(center),\n anchor: frozenPoint(anchor),\n rotationDegrees:\n tile.placement.rotation * (board.layout === \"hex\" ? 60 : 90),\n });\n });\n let minX = Infinity,\n minY = Infinity,\n maxX = -Infinity,\n maxY = -Infinity;\n for (const tile of tiles)\n for (const loop of tile.outlines)\n for (const point of loop) {\n minX = Math.min(minX, point.x);\n minY = Math.min(minY, point.y);\n maxX = Math.max(maxX, point.x);\n maxY = Math.max(maxY, point.y);\n }\n const viewBox = {\n x: tiles.length ? minX : 0,\n y: tiles.length ? minY : 0,\n width: tiles.length ? maxX - minX : 0,\n height: tiles.length ? maxY - minY : 0,\n };\n assertFinite([viewBox.x, viewBox.y, viewBox.width, viewBox.height]);\n return Object.freeze({\n tiles: Object.freeze(tiles),\n viewBox: Object.freeze(viewBox),\n });\n}\nconst cache = new WeakMap<\n SeatBoardTopology,\n { key: string; value: ReturnType<typeof build> }\n>();\n/** Admit projected topology and layout options before caching derived rendering geometry. */\nexport function createTileBoardLayout(\n board: SeatBoardTopology,\n size: number,\n suppliedOrigin: TileLayoutPoint = { x: 0, y: 0 },\n) {\n if (!Number.isFinite(size) || size <= 0)\n throw new Error(\"Tile cell size must be positive and finite.\");\n if (![suppliedOrigin.x, suppliedOrigin.y].every(Number.isFinite))\n throw new Error(\"Tile layout origin must be finite.\");\n const key = JSON.stringify([size, suppliedOrigin.x, suppliedOrigin.y]);\n const cached = cache.get(board);\n if (cached?.key === key) return cached.value;\n const value = build(\n immutableCopy(SeatBoardTopologySchema.parse(board)),\n size,\n {\n ...suppliedOrigin,\n },\n );\n cache.set(board, { key, value });\n return value;\n}\n","import type { SquareBoardTopology } from \"./board-topology.js\";\nimport { parseBoardElementId } from \"./domain/board-element.js\";\n\ntype Point = { readonly x: number; readonly y: number };\n\n/** Render admitted square topology without inferring boundary incidence from cells. */\nexport function createSquareBoardLayout(\n board: {\n readonly id: string;\n readonly spaces: Readonly<\n Record<\n string,\n { readonly id: string; readonly col: number; readonly row: number }\n >\n >;\n readonly vertices: SquareBoardTopology[\"vertices\"];\n readonly edges: SquareBoardTopology[\"edges\"];\n },\n size: number,\n origin: Point,\n) {\n if (!Number.isFinite(size) || size <= 0)\n throw new Error(\"Square cell size must be positive and finite.\");\n if (![origin.x, origin.y].every(Number.isFinite))\n throw new Error(\"Layout origin must be finite.\");\n const spaces = Object.values(board.spaces).map((space) => {\n const x = origin.x + space.col * size;\n const y = origin.y + space.row * size;\n return {\n id: space.id,\n center: { x: x + size / 2, y: y + size / 2 },\n corners: [\n { x, y },\n { x: x + size, y },\n { x: x + size, y: y + size },\n { x, y: y + size },\n ],\n };\n });\n const vertices = board.vertices.map((vertex) => {\n const identity = parseBoardElementId(vertex.id);\n if (\n !identity ||\n identity.kind !== \"vertex\" ||\n identity.layout !== \"square\" ||\n identity.boardId !== board.id\n )\n throw new Error(\n `Square vertex '${vertex.id}' does not belong to board '${board.id}'.`,\n );\n const [col, row] = identity.latticeId.split(\",\").map(Number);\n return {\n id: vertex.id,\n center: { x: origin.x + col * size, y: origin.y + row * size },\n };\n });\n const vertexPoints = new Map(\n vertices.map((vertex) => [vertex.id, vertex.center]),\n );\n const edges = board.edges.map((edge) => {\n const from = vertexPoints.get(edge.vertexIds[0]);\n const to = vertexPoints.get(edge.vertexIds[1]);\n if (!from || !to)\n throw new Error(`Square edge '${edge.id}' references a missing vertex.`);\n return { id: edge.id, from, to };\n });\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const space of spaces) {\n for (const point of space.corners) {\n minX = Math.min(minX, point.x);\n minY = Math.min(minY, point.y);\n maxX = Math.max(maxX, point.x);\n maxY = Math.max(maxY, point.y);\n }\n }\n const x = spaces.length ? minX : 0;\n const y = spaces.length ? minY : 0;\n return {\n viewBox: {\n x,\n y,\n width: spaces.length ? maxX - x : 0,\n height: spaces.length ? maxY - y : 0,\n },\n spaces,\n edges,\n vertices,\n pointToSpace(point: Point): string | undefined {\n const col = Math.floor((point.x - origin.x) / size);\n const row = Math.floor((point.y - origin.y) / size);\n return Object.values(board.spaces).find(\n (space) => space.col === col && space.row === row,\n )?.id;\n },\n };\n}\n","import {\n createTileBoardLayout,\n type TileLayoutGeometry,\n} from \"../../shared/tile-board-layout.js\";\nimport type { SeatBoardTopology } from \"../../shared/seat-topology-schema.js\";\ntype ProjectedBoardSpace = SeatBoardTopology[\"spaces\"][string];\nimport { createSquareBoardLayout } from \"../../shared/square-board-layout.js\";\nimport {\n runtimeFeatures,\n type RuntimeBoard,\n type RuntimeFeatureContext,\n type RuntimeFeatureSnapshot,\n type RuntimeCollection,\n} from \"../runtime-features.js\";\nimport type { RuntimeTargetOptions } from \"../targets.js\";\nimport type {\n BoardBase,\n BoardDataOf,\n IdOf,\n BoardCollection,\n BoardSpaceCollection,\n BoardSpace,\n CoreInstance,\n FeatureContext,\n TargetOptions,\n ActionProps,\n} from \"../model.js\";\nimport type { BoardEdge, BoardVertex } from \"../../shared/board-topology.js\";\nimport { requireLookup } from \"../../shared/lookup.js\";\nimport { AmbiguousTargetError } from \"../instance.js\";\nimport {\n createHexTopology,\n createHexTopologyCache,\n} from \"../../shared/hex-board.js\";\nimport type { Point } from \"./pointer-session.js\";\nimport type { ViewportTransform } from \"./pan-zoom.js\";\n\ninterface RuntimeSpace {\n readonly id: string;\n readonly data: ProjectedBoardSpace;\n readonly board: RuntimeBoard;\n getIsEligible(): boolean;\n getIsSelectable(): boolean;\n getIsSelected(): boolean;\n getSelectHandler(options?: RuntimeTargetOptions): () => void;\n getTargetProps(options?: RuntimeTargetOptions): ActionProps;\n}\ninterface RuntimeLayoutTarget {\n readonly id: string;\n getIsEligible(): boolean;\n getIsSelectable(): boolean;\n getIsSelected(): boolean;\n getSelectHandler(options?: RuntimeTargetOptions): () => void;\n getTargetProps(options?: RuntimeTargetOptions): ActionProps;\n}\ninterface RuntimeLayout {\n readonly viewBox: {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n };\n getSpaces(): readonly (RuntimeSpace & {\n readonly center: Point;\n points(): readonly Point[];\n readonly transform: string;\n })[];\n getEdges(): readonly (RuntimeLayoutTarget & {\n readonly data: BoardEdge | undefined;\n readonly center: Point;\n readonly line: readonly [Point, Point];\n })[];\n getVertices(): readonly (RuntimeLayoutTarget & {\n readonly data: BoardVertex | undefined;\n readonly center: Point;\n })[];\n getTiles(): readonly TileLayoutGeometry[];\n pointToSpace(x: number, y: number): string | undefined;\n}\ntype TargetKind = \"space\" | \"edge\" | \"vertex\";\nexport interface BoardLayoutOptions {\n /** Hex radius, or square cell width and height. */\n readonly hexSize: number;\n readonly origin?: Point;\n readonly viewport?: ViewportTransform;\n}\ninterface Geometry {\n readonly viewBox: { x: number; y: number; width: number; height: number };\n readonly spaces: readonly {\n id: string;\n center: Point;\n corners: readonly Point[];\n }[];\n readonly edges: readonly { id: string; from: Point; to: Point }[];\n readonly vertices: readonly { id: string; center: Point }[];\n pointToSpace(point: Point): string | undefined;\n}\n\n/** Semantic board spaces and captured selection, with optional spatial geometry. */\nfunction createRuntimeBoardFeature(context: RuntimeFeatureContext) {\n const game = context.game;\n const captures = new WeakMap<\n object,\n {\n model: RuntimeFeatureSnapshot;\n source: ReturnType<typeof game.getOptions>[\"source\"];\n geometry?: ReturnType<typeof createHexTopology>;\n }\n >();\n const cachedHexTopology = createHexTopologyCache();\n let cached:\n | {\n view: unknown;\n boards: ReturnType<RuntimeFeatureContext[\"getBoards\"]>;\n interactions: RuntimeFeatureSnapshot[\"interactions\"];\n source: ReturnType<typeof game.getOptions>[\"source\"];\n collection: RuntimeCollection<RuntimeBoard>;\n }\n | undefined;\n function collection(): RuntimeCollection<RuntimeBoard> {\n const model = game.getSnapshot();\n const source = game.getOptions().source;\n const projectedBoards = context.getBoards();\n if (\n cached &&\n cached.view === model.view &&\n cached.boards === projectedBoards &&\n cached.interactions === model.interactions &&\n cached.source === source\n )\n return cached.collection;\n const boards = Object.values(projectedBoards).map((data) => {\n const board = context.createBoard(data);\n const geometry =\n data.layout === \"hex\"\n ? cachedHexTopology({\n id: data.id,\n orientation: data.orientation,\n spaces: Object.values(data.spaces),\n })\n : undefined;\n captures.set(board, { model, source, geometry });\n return board;\n });\n const byId = new Map(boards.map((board) => [board.id, board]));\n const result: RuntimeCollection<RuntimeBoard> = Object.freeze({\n get: (id: string) => requireLookup(byId.get(id), \"Board\", id),\n find: (id: string) => byId.get(id),\n getAll: () => Object.freeze(boards),\n });\n cached = {\n view: model.view,\n boards: projectedBoards,\n interactions: model.interactions,\n source,\n collection: result,\n };\n return result;\n }\n function targetsFor(owner: RuntimeBoard) {\n const board = owner.data;\n const captured = captures.get(owner)!;\n function matchingTargets(\n model: RuntimeFeatureSnapshot,\n kind: TargetKind,\n id: string,\n ) {\n return model.interactions.list().flatMap((interaction) =>\n interaction\n .getInputs()\n .filter((input) => {\n const domain = input.getDomain();\n return (\n domain.type === \"boardTarget\" &&\n domain.targetKind === kind &&\n (domain.valueKind === \"board-space\"\n ? board.scope === \"perPlayer\" &&\n domain.boardBaseId === board.baseId\n : domain.boardId === board.id)\n );\n })\n .map((input) => {\n const domain = input.getDomain();\n return {\n interaction,\n input,\n value:\n domain.type === \"boardTarget\" &&\n domain.valueKind === \"board-space\"\n ? Object.freeze({\n boardId: board.id,\n spaceId: id,\n })\n : id,\n };\n }),\n );\n }\n function target(kind: TargetKind, id: string) {\n const matches = matchingTargets(captured.model, kind, id);\n const eligible = matches.some(({ input, value }) =>\n input.getIsEligible(value),\n );\n const selected = matches.some(({ input, value }) =>\n input.getIsSelected(value),\n );\n const selectable = matches.some(\n ({ input, value }) => !input.getTargetProps(value).disabled,\n );\n function select(options?: RuntimeTargetOptions) {\n if (\n game.getOptions().source !== captured.source ||\n game.snapshot?.me !== captured.model.snapshot?.me\n )\n return;\n const matching = matchingTargets(game.getSnapshot(), kind, id).filter(\n ({ interaction, input, value }) =>\n (!options?.interaction ||\n options.interaction === interaction.key) &&\n (!options?.input || options.input === input.key) &&\n !input.getTargetProps(value).disabled,\n );\n if (!matching.length) return;\n if (matching.length > 1) throw new AmbiguousTargetError(id);\n const domain = matching[0].input.getDomain();\n if (domain.type !== \"boardTarget\") return;\n const value = matching[0].value;\n const target =\n domain.valueKind === \"board-space\" && typeof value !== \"string\"\n ? { kind: \"space\" as const, valueKind: domain.valueKind, value }\n : {\n kind,\n valueKind: \"board-id\" as const,\n value: id,\n boardId: board.id,\n };\n context.routeTarget(target, {\n interaction: matching[0].interaction.key,\n input: matching[0].input.key,\n });\n }\n return {\n id,\n getIsEligible: () => eligible,\n getIsSelectable: () => selectable,\n getIsSelected: () => selected,\n getSelectHandler: (options?: RuntimeTargetOptions) => () =>\n select(options),\n getTargetProps(options?: RuntimeTargetOptions) {\n const candidates = matches.filter(\n ({ interaction, input, value }) =>\n (!options?.interaction ||\n interaction.key === options.interaction) &&\n (!options?.input || options.input === input.key) &&\n !input.getTargetProps(value).disabled,\n );\n const only = candidates.length === 1 ? candidates[0] : undefined;\n return {\n type: \"button\" as const,\n disabled: candidates.length === 0,\n \"data-action\": \"select\",\n \"data-value\":\n only && typeof only.value !== \"string\"\n ? JSON.stringify(only.value)\n : id,\n \"data-board\": board.id,\n \"data-interaction\": options?.interaction ?? only?.interaction.key,\n \"data-input\": only?.input.key,\n \"data-eligible\": eligible,\n \"data-selected\": selected,\n \"data-disabled\": candidates.length === 0,\n onClick: () => select(options),\n };\n },\n };\n }\n return target;\n }\n const spaceCollections = new WeakMap<\n object,\n RuntimeCollection<RuntimeSpace>\n >();\n function spacesFor(owner: RuntimeBoard): RuntimeCollection<RuntimeSpace> {\n const cached = spaceCollections.get(owner);\n if (cached) return cached;\n const target = targetsFor(owner);\n const data = owner.data;\n const values = Object.freeze(\n Object.values(data.spaces).map((space) =>\n Object.freeze({\n ...target(\"space\", space.id),\n data: space,\n board: owner,\n }),\n ),\n );\n const byId = new Map(values.map((space) => [space.id, space]));\n const spaces = Object.freeze({\n get: (id: string) =>\n requireLookup(byId.get(id), `Space on board ${owner.id}`, id),\n find: (id: string) => byId.get(id),\n getAll: () => values,\n });\n spaceCollections.set(owner, spaces);\n return spaces;\n }\n return {\n root: {\n get boards() {\n return collection();\n },\n },\n board: {\n get spaces(): RuntimeCollection<RuntimeSpace> {\n return spacesFor(this);\n },\n getLayout(\n this: RuntimeBoard,\n options: BoardLayoutOptions,\n ): RuntimeLayout {\n const board = this.data;\n if (board.layout === \"generic\")\n throw new Error(\n `Board '${board.id}' has no spatial geometry; use board.spaces for semantic selection.`,\n );\n const {\n hexSize,\n origin: suppliedOrigin = { x: 0, y: 0 },\n viewport: suppliedViewport = { x: 0, y: 0, scale: 1 },\n } = options;\n const origin = { ...suppliedOrigin };\n const viewport = { ...suppliedViewport };\n if (!Number.isFinite(hexSize) || hexSize <= 0)\n throw new Error(\"hexSize must be positive and finite.\");\n if (\n ![origin.x, origin.y, viewport.x, viewport.y, viewport.scale].every(\n Number.isFinite,\n ) ||\n viewport.scale <= 0\n )\n throw new Error(\n \"Layout transform must be finite with positive scale.\",\n );\n const captured = captures.get(this)!;\n const geometry: Geometry =\n board.layout === \"hex\"\n ? captured.geometry!.getLayout({ hexSize, origin })\n : createSquareBoardLayout(board, hexSize, origin);\n const point = (value: Point): Point => {\n const transformed = {\n x: value.x * viewport.scale + viewport.x,\n y: value.y * viewport.scale + viewport.y,\n };\n if (![transformed.x, transformed.y].every(Number.isFinite))\n throw new Error(\"Derived layout transform must be finite.\");\n return Object.freeze(transformed);\n };\n const tileGeometry = createTileBoardLayout(board, hexSize, origin);\n const tiles = Object.freeze(\n tileGeometry.tiles.map((tile) =>\n Object.freeze({\n ...tile,\n center: point(tile.center),\n anchor: point(tile.anchor),\n outlines: Object.freeze(\n tile.outlines.map((loop) => Object.freeze(loop.map(point))),\n ),\n }),\n ),\n );\n const target = targetsFor(this);\n const semanticSpaces = spacesFor(this);\n const spaces = Object.freeze(\n geometry.spaces.map((space) => {\n const corners = Object.freeze(space.corners.map(point));\n const center = point(space.center);\n return Object.freeze({\n ...semanticSpaces.get(space.id),\n center,\n points: () => corners,\n transform: `translate(${center.x} ${center.y})`,\n });\n }),\n );\n const edges = Object.freeze(\n geometry.edges.map((edge) =>\n Object.freeze({\n ...target(\"edge\", edge.id),\n data: board.edges.find((data) => data.id === edge.id),\n center: point({\n x: (edge.from.x + edge.to.x) / 2,\n y: (edge.from.y + edge.to.y) / 2,\n }),\n line: Object.freeze([point(edge.from), point(edge.to)] as const),\n }),\n ),\n );\n const vertices = Object.freeze(\n geometry.vertices.map((vertex) =>\n Object.freeze({\n ...target(\"vertex\", vertex.id),\n data: board.vertices.find((data) => data.id === vertex.id),\n center: point(vertex.center),\n }),\n ),\n );\n return Object.freeze({\n viewBox: tileGeometry.viewBox,\n getTiles: () => tiles,\n getSpaces: () => spaces,\n getEdges: () => edges,\n getVertices: () => vertices,\n pointToSpace(x: number, y: number) {\n return geometry.pointToSpace({\n x: (x - viewport.x) / viewport.scale,\n y: (y - viewport.y) / viewport.scale,\n });\n },\n });\n },\n } satisfies ThisType<RuntimeBoard>,\n };\n}\n\ntype LayoutTarget<G, Value> = Omit<\n Value,\n \"getSelectHandler\" | \"getTargetProps\"\n> & {\n getSelectHandler(options?: TargetOptions<G>): () => void;\n getTargetProps(options?: TargetOptions<G>): ActionProps;\n};\ntype LayoutElementData<G, Kind extends \"edges\" | \"vertices\"> =\n BoardDataOf<G, IdOf<G, \"boardId\">> extends infer Topology\n ? Topology extends Record<Kind, readonly (infer Element)[]>\n ? Element\n : never\n : never;\ntype LayoutElement<G, Kind extends \"edges\" | \"vertices\", Value> = LayoutTarget<\n G,\n Omit<Value, \"data\" | \"id\">\n> & {\n readonly id: LayoutElementData<G, Kind> extends { readonly id: infer Id }\n ? Id\n : never;\n readonly data: LayoutElementData<G, Kind> | undefined;\n};\n/** Seat tile presentation retains its visible/concealed data union without another discriminator. */\nexport type BoardLayoutTile<G> =\n BoardDataOf<G, IdOf<G, \"boardId\">> extends infer Board\n ? Board extends { readonly tiles: readonly (infer Tile)[] }\n ? Omit<TileLayoutGeometry, \"data\"> & { readonly data: Tile }\n : never\n : never;\n\ntype BoardLayout<G> = Omit<\n RuntimeLayout,\n \"getSpaces\" | \"getEdges\" | \"getVertices\" | \"getTiles\"\n> & {\n getTiles(): readonly BoardLayoutTile<G>[];\n getSpaces(): readonly (BoardSpace<G> & {\n readonly center: Point;\n points(): readonly Point[];\n readonly transform: string;\n })[];\n getEdges(): readonly LayoutElement<\n G,\n \"edges\",\n ReturnType<RuntimeLayout[\"getEdges\"]>[number]\n >[];\n getVertices(): readonly LayoutElement<\n G,\n \"vertices\",\n ReturnType<RuntimeLayout[\"getVertices\"]>[number]\n >[];\n};\nexport interface BoardFeature<G> {\n readonly root: { readonly boards: BoardCollection<G> };\n readonly board: {\n readonly spaces: BoardSpaceCollection<G>;\n getLayout(this: BoardBase<G>, options: BoardLayoutOptions): BoardLayout<G>;\n };\n}\n/** Bind one runtime implementation to the same game/source contract as the instance. */\nexport function boardFeature<G>(\n _game: CoreInstance<G>,\n context: FeatureContext<G>,\n): BoardFeature<G> {\n // Game-binding boundary: source identities and installed hooks belong to G.\n // Proven by headless-features/inline-boards type tests and board behavior tests.\n // eslint-disable-next-line no-restricted-syntax -- Instance composition binds these runtime source identities and feature hooks to the same game G.\n return createRuntimeBoardFeature(\n context[runtimeFeatures],\n ) as unknown as BoardFeature<G>;\n}\n","import {\n runtimeFeatures,\n type RuntimeFeatureContext,\n} from \"../runtime-features.js\";\nimport type { RuntimeDropTarget, RuntimeTargetOptions } from \"../targets.js\";\nimport type { DropTarget, TargetOptions } from \"../targets.js\";\nexport type { DropTarget } from \"../targets.js\";\nimport { isSameDropTarget } from \"../drop-targets.js\";\nimport type { CoreInstance, FeatureContext, SeatCardId } from \"../model.js\";\nexport interface DragState<G> {\n readonly cardId: SeatCardId<G>;\n readonly target: DropTarget<G> | null;\n}\n\nexport interface DragController<G> {\n readonly active: DragState<G> | null;\n getCanDrag(cardId: SeatCardId<G>, options?: TargetOptions<G>): boolean;\n begin(cardId: SeatCardId<G>, options?: TargetOptions<G>): boolean;\n getDropTargets(): readonly DropTarget<G>[];\n setDropTarget(target: DropTarget<G> | null): void;\n drop(): void;\n cancel(): void;\n}\n\ninterface RuntimeDragState {\n readonly cardId: string;\n readonly target: RuntimeDropTarget | null;\n}\ninterface RuntimeDragController {\n readonly active: RuntimeDragState | null;\n getCanDrag(cardId: string, options?: RuntimeTargetOptions): boolean;\n begin(cardId: string, options?: RuntimeTargetOptions): boolean;\n getDropTargets(): readonly RuntimeDropTarget[];\n setDropTarget(target: RuntimeDropTarget | null): void;\n drop(): void;\n cancel(): void;\n}\nfunction createRuntimeDragFeature(context: RuntimeFeatureContext) {\n const game = context.game;\n let active: RuntimeDragState | null = null;\n let selection: RuntimeTargetOptions | undefined;\n let source = game.getOptions().source;\n let seat = game.snapshot?.me;\n let disposed = false;\n let version = game.snapshot?.version;\n let lastInteractions = game.interactions;\n let lastCards = game.cards;\n let branch = snapshot();\n function update(next: RuntimeDragState | null) {\n if (disposed) return;\n active = next === null ? null : Object.freeze(next);\n branch = snapshot();\n context.invalidate();\n }\n function targets(\n cardId = active?.cardId,\n selected = selection,\n ): readonly RuntimeDropTarget[] {\n if (!cardId || game.connection !== \"ready\") return [];\n const options = selected;\n const resolved = (game.cards.find(cardId)?.getInteractions() ?? []).flatMap(\n (candidate) => {\n if (\n !candidate.getIsAvailable() ||\n (options?.interaction && candidate.key !== options.interaction)\n )\n return [];\n const inputs = candidate.getInputs();\n const cardInputs = inputs.filter(\n (input) =>\n input.getDomain().type === \"cardTarget\" &&\n (!options?.input || input.key === options.input) &&\n input.getIsEligible(cardId),\n );\n // Without a board input, the card lands on an area that runs the interaction.\n if (!inputs.some((input) => input.getDomain().type === \"boardTarget\"))\n return cardInputs.map((cardInput): RuntimeDropTarget =>\n Object.freeze({\n kind: \"interaction\",\n interactionKey: candidate.key,\n cardInputKey: cardInput.key,\n }),\n );\n return cardInputs.flatMap((cardInput) =>\n inputs.flatMap((input): RuntimeDropTarget[] => {\n const domain = input.getDomain();\n if (domain.type !== \"boardTarget\") return [];\n const route = {\n interactionKey: candidate.key,\n cardInputKey: cardInput.key,\n inputKey: input.key,\n };\n if (domain.valueKind === \"board-space\")\n return domain.eligibleTargets\n .filter((value) => !input.getTargetProps(value).disabled)\n .map((value) =>\n Object.freeze({\n kind: \"space\",\n valueKind: domain.valueKind,\n value,\n ...route,\n }),\n );\n return domain.eligibleTargets\n .filter((value) => !input.getTargetProps(value).disabled)\n .map((value) =>\n Object.freeze({\n kind: domain.targetKind,\n valueKind: domain.valueKind,\n value,\n boardId: domain.boardId,\n ...route,\n }),\n );\n }),\n );\n },\n );\n return resolved;\n }\n function cancel() {\n if (active) update(null);\n }\n function snapshot(): RuntimeDragController {\n const captured = active;\n const dropTargets = Object.freeze(targets());\n return Object.freeze<RuntimeDragController>({\n active: captured,\n getCanDrag: (cardId, options) =>\n !disposed && targets(cardId, options).length > 0,\n begin(cardId, options) {\n if (disposed || !targets(cardId, options).length) return false;\n selection = options;\n update({ cardId, target: null });\n return true;\n },\n getDropTargets: () => dropTargets,\n setDropTarget(target: RuntimeDropTarget | null) {\n if (!active || disposed) return;\n if (\n target &&\n !targets().some((candidate) => isSameDropTarget(candidate, target))\n ) {\n update({ ...active, target: null });\n return;\n }\n update({ ...active, target });\n },\n drop() {\n const finished = active;\n const eligible =\n finished?.target &&\n targets().some((target) =>\n isSameDropTarget(target, finished.target!),\n );\n cancel();\n if (!disposed && finished?.target && eligible)\n context.routeCardDrop(finished.cardId, finished.target);\n },\n cancel,\n });\n }\n const unsubscribe = game.subscribe(() => {\n const nextSource = game.getOptions().source;\n const nextSeat = game.snapshot?.me;\n const nextVersion = game.snapshot?.version;\n if (\n nextSource !== source ||\n nextSeat !== seat ||\n nextVersion !== version ||\n game.connection !== \"ready\"\n ) {\n source = nextSource;\n seat = nextSeat;\n version = nextVersion;\n cancel();\n }\n });\n return {\n root: {\n get drag() {\n if (\n lastInteractions !== game.interactions ||\n lastCards !== game.cards\n ) {\n lastInteractions = game.interactions;\n lastCards = game.cards;\n branch = snapshot();\n }\n return branch;\n },\n },\n dispose() {\n unsubscribe();\n cancel();\n disposed = true;\n },\n };\n}\n\n/**\n * Semantic card/drop routing. A card lands on a board destination when its\n * interaction has a board input, otherwise on an area that runs the\n * interaction. Gestures, hit-testing and feedback belong to /react.\n */\nexport function dragFeature<G>(\n _game: CoreInstance<G>,\n context: FeatureContext<G>,\n): { readonly root: { readonly drag: DragController<G> }; dispose(): void } {\n // Game-binding boundary: routes come from this instance's admitted descriptors.\n // The runtime implementation revalidates both inputs atomically on drop.\n return createRuntimeDragFeature(context[runtimeFeatures]) as {\n readonly root: { readonly drag: DragController<G> };\n dispose(): void;\n };\n}\n","/** Native pointer surface; importing a feature never requires browser globals. */\nexport interface PointerSurface {\n setPointerCapture(pointerId: number): void;\n hasPointerCapture(pointerId: number): boolean;\n releasePointerCapture(pointerId: number): void;\n}\n\nexport interface PointerInput {\n readonly pointerId: number;\n readonly button: number;\n readonly clientX: number;\n readonly clientY: number;\n readonly currentTarget: PointerSurface;\n preventDefault(): void;\n}\n\nexport interface Point {\n readonly x: number;\n readonly y: number;\n}\n\nexport interface PointerMove {\n readonly origin: Point;\n readonly point: Point;\n readonly delta: Point;\n}\n\n/** One captured gesture. Pointer cancellation and disposal never commit a drop. */\nexport function createPointerSession(callbacks: {\n move(value: PointerMove): void;\n end(value: PointerMove): void;\n cancel(): void;\n}) {\n let disposed = false;\n let active:\n | { id: number; surface: PointerSurface; origin: Point; point: Point }\n | undefined;\n\n function value(): PointerMove {\n const { origin, point } = active!;\n return {\n origin,\n point,\n delta: { x: point.x - origin.x, y: point.y - origin.y },\n };\n }\n\n function release() {\n const previous = active;\n active = undefined;\n if (previous?.surface.hasPointerCapture(previous.id)) {\n previous.surface.releasePointerCapture(previous.id);\n }\n }\n\n function cancel() {\n if (!active) return;\n release();\n callbacks.cancel();\n }\n\n return {\n start(event: PointerInput): boolean {\n if (disposed || active || event.button !== 0) return false;\n event.currentTarget.setPointerCapture(event.pointerId);\n const point = { x: event.clientX, y: event.clientY };\n active = {\n id: event.pointerId,\n surface: event.currentTarget,\n origin: point,\n point,\n };\n event.preventDefault();\n return true;\n },\n move(event: PointerInput) {\n if (event.pointerId !== active?.id) return;\n active.point = { x: event.clientX, y: event.clientY };\n event.preventDefault();\n callbacks.move(value());\n },\n end(event: PointerInput) {\n if (event.pointerId !== active?.id) return;\n active.point = { x: event.clientX, y: event.clientY };\n const result = value();\n release();\n callbacks.end(result);\n },\n cancel(event?: Pick<PointerInput, \"pointerId\">) {\n if (event && event.pointerId !== active?.id) return;\n cancel();\n },\n dispose() {\n disposed = true;\n cancel();\n },\n };\n}\n","import type { CoreInstance, FeatureContext } from \"../model.js\";\nimport {\n createPointerSession,\n type PointerInput,\n type PointerSurface,\n} from \"./pointer-session.js\";\n\nexport interface ViewportTransform {\n readonly x: number;\n readonly y: number;\n readonly scale: number;\n}\nexport interface ViewportSurface extends PointerSurface {\n getBoundingClientRect(): {\n readonly left: number;\n readonly top: number;\n readonly height: number;\n };\n}\nexport interface WheelInput {\n readonly clientX: number;\n readonly clientY: number;\n readonly deltaY: number;\n readonly deltaMode: number;\n readonly currentTarget: ViewportSurface;\n preventDefault(): void;\n}\nexport interface PanZoomOptions {\n readonly initial?: ViewportTransform;\n readonly minScale?: number;\n readonly maxScale?: number;\n}\n\n/** Native pointer panning and wheel zoom around the cursor. No document listeners. */\nexport function panZoomFeature<G>(\n game: CoreInstance<G>,\n context: FeatureContext<G>,\n options: PanZoomOptions = {},\n) {\n const minScale = options.minScale ?? 0.25;\n const maxScale = options.maxScale ?? 4;\n if (\n !Number.isFinite(minScale) ||\n !Number.isFinite(maxScale) ||\n minScale <= 0 ||\n maxScale < minScale\n ) {\n throw new Error(\n \"Viewport scale limits must be positive, finite, and ordered.\",\n );\n }\n const initial = options.initial ?? { x: 0, y: 0, scale: 1 };\n let disposed = false;\n let source = game.getOptions().source;\n let seat = game.snapshot?.me;\n let dragOrigin = initial;\n let transform = admit(initial);\n let branch = snapshot();\n\n function admit(value: ViewportTransform): ViewportTransform {\n if (\n ![value.x, value.y, value.scale].every(Number.isFinite) ||\n value.scale <= 0\n ) {\n throw new Error(\n \"Viewport transform must have finite coordinates and positive scale.\",\n );\n }\n return Object.freeze({\n x: value.x,\n y: value.y,\n scale: Math.min(maxScale, Math.max(minScale, value.scale)),\n });\n }\n function update(value: ViewportTransform) {\n if (disposed) return;\n const next = admit(value);\n if (\n next.x === transform.x &&\n next.y === transform.y &&\n next.scale === transform.scale\n )\n return;\n transform = next;\n branch = snapshot();\n context.invalidate();\n }\n const pointer = createPointerSession({\n move: ({ delta }) =>\n update({\n ...dragOrigin,\n x: dragOrigin.x + delta.x,\n y: dragOrigin.y + delta.y,\n }),\n end: ({ delta }) =>\n update({\n ...dragOrigin,\n x: dragOrigin.x + delta.x,\n y: dragOrigin.y + delta.y,\n }),\n cancel() {},\n });\n function props() {\n return {\n style: { touchAction: \"none\" as const },\n onPointerDown(event: PointerInput) {\n if (pointer.start(event)) dragOrigin = transform;\n },\n onPointerMove: pointer.move,\n onPointerUp: pointer.end,\n onPointerCancel: pointer.cancel,\n onLostPointerCapture: pointer.cancel,\n onWheel(event: WheelInput) {\n if (disposed) return;\n event.preventDefault();\n const rect = event.currentTarget.getBoundingClientRect();\n const unit =\n event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? rect.height : 1;\n const scale = Math.min(\n maxScale,\n Math.max(\n minScale,\n transform.scale * Math.exp(-event.deltaY * unit * 0.002),\n ),\n );\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n const ratio = scale / transform.scale;\n update({\n x: x - (x - transform.x) * ratio,\n y: y - (y - transform.y) * ratio,\n scale,\n });\n },\n };\n }\n function snapshot() {\n const captured = transform;\n return Object.freeze({\n transform: captured,\n getTransform: () => captured,\n getProps: props,\n setTransform: update,\n reset: () => {\n pointer.cancel();\n update(initial);\n },\n });\n }\n const unsubscribe = game.subscribe(() => {\n const nextSource = game.getOptions().source;\n const nextSeat = game.snapshot?.me;\n if (nextSource !== source || nextSeat !== seat) {\n source = nextSource;\n seat = nextSeat;\n pointer.cancel();\n update(initial);\n }\n });\n return {\n root: {\n get viewport() {\n return branch;\n },\n },\n dispose() {\n disposed = true;\n unsubscribe();\n pointer.dispose();\n },\n };\n}\n","import { isHiddenCardId as isHidden } from \"../../shared/domain/cards.js\";\nimport type { CoreInstance, IdOf, SeatCardId, ZoneHostId } from \"../model.js\";\nimport type { SourceSnapshot } from \"../sources/types.js\";\n\n/**\n * Where a card that arrived in its zone with the current frame was on the\n * previous one: another zone, or the private zones of the player who moved.\n * `hidden` says whether the seat saw only the card's back there.\n */\nexport type CardOrigin<G> =\n | {\n readonly zone: IdOf<G, \"zoneId\">;\n readonly hostId: ZoneHostId<G>;\n readonly hidden: boolean;\n }\n | { readonly player: IdOf<G, \"playerId\">; readonly hidden: true };\n\ntype RuntimeOrigin =\n | {\n readonly zone: string;\n readonly hostId?: string;\n readonly hidden: boolean;\n }\n | { readonly player: string; readonly hidden: true };\ntype NestedZones = SourceSnapshot[\"frame\"][\"zones\"];\ntype Zones = Record<\n string,\n import(\"../../shared/protocol/frame\").ZoneHandlesSnapshot\n>;\nconst flatten = (zones: NestedZones): Zones =>\n Object.fromEntries(\n Object.entries(zones).flatMap(([zoneId, hosts]) =>\n Object.entries(hosts).map(([hostId, zone]) => [\n JSON.stringify([zoneId, hostId]),\n zone,\n ]),\n ),\n );\n\nconst hiddenCount = (zones: Zones, zone: string) =>\n zones[zone]?.cardIds.filter(isHidden).length ?? 0;\n\nfunction singleOrigin(\n departures: readonly {\n readonly zone: string;\n readonly hostId?: string;\n readonly hidden: boolean;\n }[],\n count: number,\n) {\n const origin = departures[0];\n return origin &&\n departures.length >= count &&\n departures.every(\n (card) => card.zone === origin.zone && card.hidden === origin.hidden,\n )\n ? Object.freeze(origin)\n : null;\n}\n\n/**\n * Visible ids are card identities, so a visible card is followed between\n * zones. Hidden ids are positions, so only their net counts are compared.\n * An inferred origin requires one compatible source with enough departures;\n * existing hidden cards make the arriving positions ambiguous. Unexplained\n * arrivals can come from the sole mover's private zones, which the seat's\n * frame does not list. Ambiguous origins are omitted.\n */\nexport function findCardOrigins(\n previousNested: NestedZones,\n nextNested: NestedZones,\n mover: string | null,\n): ReadonlyMap<string, RuntimeOrigin> {\n const previous = flatten(previousNested);\n const next = flatten(nextNested);\n const shownBefore = new Map<string, string>();\n for (const [zone, { cardIds }] of Object.entries(previous))\n for (const cardId of cardIds)\n if (!isHidden(cardId)) shownBefore.set(cardId, zone);\n const shownNow = new Set(\n Object.values(next).flatMap(({ cardIds }) =>\n cardIds.filter((cardId) => !isHidden(cardId)),\n ),\n );\n let left = Object.entries(previous).flatMap(([zone, { cardIds }]) => [\n ...cardIds\n .filter((cardId) => !isHidden(cardId) && !shownNow.has(cardId))\n .map(() => ({ zone, hidden: false })),\n ...Array.from(\n {\n length: Math.max(\n 0,\n hiddenCount(previous, zone) - hiddenCount(next, zone),\n ),\n },\n () => ({ zone, hidden: true }),\n ),\n ]);\n const origins = new Map<string, RuntimeOrigin>();\n const shownArrivals: string[] = [];\n const hiddenArrivals: (string | null)[] = [];\n for (const [zone, { cardIds }] of Object.entries(next)) {\n for (const cardId of cardIds) {\n if (isHidden(cardId)) continue;\n const from = shownBefore.get(cardId);\n if (from === undefined) shownArrivals.push(cardId);\n else if (from !== zone)\n origins.set(cardId, Object.freeze({ zone: from, hidden: false }));\n }\n const hidden = cardIds.filter(isHidden);\n const before = hiddenCount(previous, zone);\n // Count ambiguous arrivals too, so another destination cannot claim their source.\n hiddenArrivals.push(\n ...Array.from(\n { length: Math.max(0, hidden.length - before) },\n (_, index) => (before === 0 ? hidden[index] : null),\n ),\n );\n }\n // Concealing a visible card can replace a hidden departure without changing\n // the hidden count. Net counts cannot resolve those simultaneous movements.\n if (\n left.some(\n (card) =>\n !card.hidden &&\n hiddenCount(previous, card.zone) > 0 &&\n hiddenCount(next, card.zone) > 0,\n )\n )\n return decodedOrigins(origins);\n const hiddenLeft = left.filter((card) => card.hidden);\n if (shownArrivals.length) {\n const origin = singleOrigin(hiddenLeft, shownArrivals.length);\n if (origin) {\n for (const cardId of shownArrivals) origins.set(cardId, origin);\n left = [\n ...left.filter((card) => !card.hidden),\n ...hiddenLeft.slice(shownArrivals.length),\n ];\n } else if (hiddenLeft.length) {\n // Which departures the shown cards consumed is also ambiguous.\n return decodedOrigins(origins);\n } else if (mover !== null) {\n const origin = Object.freeze({ player: mover, hidden: true as const });\n for (const cardId of shownArrivals) origins.set(cardId, origin);\n }\n }\n const hiddenOrigin =\n singleOrigin(left, hiddenArrivals.length) ??\n (left.length === 0 && mover !== null\n ? Object.freeze({ player: mover, hidden: true as const })\n : null);\n if (hiddenOrigin) {\n for (const cardId of hiddenArrivals)\n if (cardId !== null) origins.set(cardId, hiddenOrigin);\n }\n return decodedOrigins(origins);\n}\n\n/** The sole active player, when it is another seat. */\nfunction moverOf(snapshot: SourceSnapshot) {\n const active = snapshot.frame.flow.activePlayers;\n return active.length === 1 && active[0] !== snapshot.me ? active[0] : null;\n}\n\n/**\n * Adds `card.getOrigin()`: where a card that arrived in its zone with the\n * current frame came from, or null. Origins last until the next frame and\n * reset when the seat or source changes. Hidden origins are inferred from\n * net counts; ambiguous sources and arriving positions return null.\n */\nexport function originsFeature<G>(game: CoreInstance<G>) {\n type Origins = ReadonlyMap<SeatCardId<G>, CardOrigin<G>>;\n let frame = game.snapshot;\n let source = game.getOptions().source;\n let origins: Origins = new Map();\n function sync() {\n const next = game.snapshot;\n const nextSource = game.getOptions().source;\n if (\n next?.version === frame?.version &&\n next?.me === frame?.me &&\n nextSource === source\n )\n return;\n // Game-binding boundary: card, zone and player ids come from this instance's frames.\n origins =\n frame &&\n next &&\n next.me === frame.me &&\n nextSource === source &&\n next.version === frame.version + 1\n ? (findCardOrigins(\n frame.frame.zones,\n next.frame.zones,\n moverOf(frame),\n ) as Origins)\n : new Map();\n frame = next;\n source = nextSource;\n }\n // Also read lazily, so a reader notified before this listener sees the new frame's origins.\n const unsubscribe = game.subscribe(sync);\n return {\n card: {\n getOrigin(this: { readonly id: SeatCardId<G> }): CardOrigin<G> | null {\n sync();\n return origins.get(this.id) ?? null;\n },\n },\n dispose: unsubscribe,\n };\n}\n\nfunction decodedOrigins(\n origins: ReadonlyMap<string, RuntimeOrigin>,\n): ReadonlyMap<string, RuntimeOrigin> {\n return new Map<string, RuntimeOrigin>(\n [...origins].map(([id, origin]) => {\n if (!(\"zone\" in origin)) return [id, origin];\n const [zone, hostId] = JSON.parse(origin.zone) as [string, string];\n return [id, Object.freeze({ ...origin, zone, hostId })];\n }),\n );\n}\n","const RADIANS = Math.PI / 180;\n\nexport interface FanOptions {\n readonly count: number;\n /** The width available to the fan, in pixels. */\n readonly width: number;\n readonly cardWidth: number;\n readonly cardHeight: number;\n /** Distance between neighbouring cards along the arc when there is room. Default: 60% of the card width. */\n readonly step?: number;\n /** The smallest visible slice of a covered card. Default: 25% of the card width. */\n readonly minStep?: number;\n /** Degrees between neighbouring cards. Default 5; 0 lays a straight row. */\n readonly angle?: number;\n /** The most degrees between the two end cards. Default 30. */\n readonly maxSpread?: number;\n}\n\n/** A card's CSS `translate` from the fan's top-left corner, and its `rotate` about its own centre. */\nexport interface FanCard {\n readonly x: number;\n readonly y: number;\n /** Degrees clockwise. */\n readonly rotate: number;\n}\n\nexport interface FanLayout {\n readonly cards: readonly FanCard[];\n /** The fan's bounding box. It is wider than the available width only when the cards are at `minStep`. */\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * Lays cards on a circular arc. The spread grows with the card count up to\n * `maxSpread`; the step shrinks continuously to fit the width, down to\n * `minStep`, past which the fan overflows and the hand should scroll.\n */\nexport function fanLayout({\n count,\n width,\n cardWidth,\n cardHeight,\n step = cardWidth * 0.6,\n minStep = cardWidth * 0.25,\n angle = 5,\n maxSpread = 30,\n}: FanOptions): FanLayout {\n if (count < 1) return { cards: [], width: 0, height: 0 };\n const gaps = count - 1;\n const delta = gaps ? Math.min(angle, maxSpread / gaps) * RADIANS : 0;\n const edge = (gaps * delta) / 2;\n // The horizontal distance between the end cards' centres is `spacing * span`.\n const span = delta ? (2 * Math.sin(edge)) / delta : gaps;\n // The end cards' outer halves, tilted by the edge angle.\n const ends = cardWidth * Math.cos(edge) + cardHeight * Math.sin(edge);\n const spacing = span\n ? Math.max(minStep, Math.min(step, (width - ends) / span))\n : 0;\n const radius = delta ? spacing / delta : 0;\n const centres = Array.from({ length: count }, (_, index) => {\n if (!delta) return { theta: 0, x: (index - gaps / 2) * spacing, y: 0 };\n const theta = (index - gaps / 2) * delta;\n return {\n theta,\n x: radius * Math.sin(theta),\n y: radius * (1 - Math.cos(theta)),\n };\n });\n const halfHeight = (theta: number) =>\n (cardHeight / 2) * Math.cos(theta) +\n (cardWidth / 2) * Math.abs(Math.sin(theta));\n const top = Math.min(\n ...centres.map((card) => card.y - halfHeight(card.theta)),\n );\n const bottom = Math.max(\n ...centres.map((card) => card.y + halfHeight(card.theta)),\n );\n const fanWidth = spacing * span + ends;\n return {\n cards: centres.map((card) => ({\n x: card.x + (fanWidth - cardWidth) / 2,\n y: card.y - top - cardHeight / 2,\n rotate: card.theta / RADIANS,\n })),\n width: fanWidth,\n height: bottom - top,\n };\n}\n\n/** Moves a fanned card outward along its own tilt, as for a selected card. */\nexport function liftFanCard(card: FanCard, distance: number): FanCard {\n const theta = card.rotate * RADIANS;\n return {\n x: card.x + distance * Math.sin(theta),\n y: card.y - distance * Math.cos(theta),\n rotate: card.rotate,\n };\n}\n"],"mappings":"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","names":["options","x","y","value","target","cached","origin"]}
1
+ {"version":3,"sources":["../src/package-set.ts","../src/headless/sources/iframe.ts","../src/shared/protocol/gameplay-wire.ts","../src/headless/sources/host-websocket.ts","../src/headless/features/shortcuts.ts","../src/headless/features/hand.ts","../src/shared/tile-board-layout.ts","../src/shared/square-board-layout.ts","../src/headless/features/board.ts","../src/headless/features/drag.ts","../src/headless/features/pointer-session.ts","../src/headless/features/pan-zoom.ts","../src/headless/features/origins.ts","../src/headless/fan.ts","../src/headless/hand-fan.ts"],"sourcesContent":["declare const __DREAMBOARD_SDK_VERSION__: string;\n\nexport const DREAMBOARD_SDK_VERSION =\n typeof __DREAMBOARD_SDK_VERSION__ === \"string\"\n ? __DREAMBOARD_SDK_VERSION__\n : \"0.0.0-development\";\n\nexport const DREAMBOARD_SDK_PACKAGES = {\n \"@dreamboard-games/sdk\": DREAMBOARD_SDK_VERSION,\n} as const;\n\nexport type DreamboardSdkPackageName = keyof typeof DREAMBOARD_SDK_PACKAGES;\n\nexport type DreamboardSdkPackageSet = {\n version: 1;\n sdkVersion: string;\n packages: Record<DreamboardSdkPackageName, string>;\n};\n\nexport const DREAMBOARD_SDK_PACKAGE_SET: DreamboardSdkPackageSet = {\n version: 1,\n sdkVersion: DREAMBOARD_SDK_VERSION,\n packages: DREAMBOARD_SDK_PACKAGES,\n};\n","import {\n DREAMBOARD_PLUGIN_PROTOCOL,\n DREAMBOARD_PLUGIN_PROTOCOL_VERSION,\n} from \"../../shared/protocol/protocol.js\";\nimport { HostToPluginEnvelopeSchema } from \"../../shared/protocol/schema.js\";\nimport type { PluginToHostPayload } from \"../../shared/protocol/protocol.js\";\nimport { createSourceLifecycle } from \"./lifecycle.js\";\nimport type { CommandSource } from \"./types.js\";\n\n/** Pins its parent window, origin and channel at the first valid initialization. */\nexport function iframeSource(\n options: {\n timeoutMs?: number;\n /** Trusted pass-and-play hosts may change seats without replacing the iframe. */\n followHostSeat?: boolean;\n } = {},\n): CommandSource {\n const target = window;\n const parent = target.parent;\n let channel: { id: string; origin: string } | null = null;\n let sequence = 0;\n let receivedSequence = -1;\n const send = (payload: PluginToHostPayload) => {\n if (!channel) throw new Error(\"Iframe source is not initialized.\");\n parent.postMessage(\n {\n protocol: DREAMBOARD_PLUGIN_PROTOCOL,\n version: DREAMBOARD_PLUGIN_PROTOCOL_VERSION,\n channelId: channel.id,\n sequence: ++sequence,\n payload,\n },\n channel.origin,\n );\n };\n const lifecycle = createSourceLifecycle({\n timeoutMs: options.timeoutMs,\n followHostSeat: options.followHostSeat,\n send,\n recover: () => send({ type: \"runtime.resume\" }),\n close: () => target.removeEventListener(\"message\", receive),\n });\n const isOpen = () => {\n const { connection } = lifecycle.source.store.get();\n return connection !== \"closed\" && connection !== \"failed\";\n };\n function receive(event: MessageEvent) {\n if (event.source !== parent) return;\n const parsed = HostToPluginEnvelopeSchema.safeParse(event.data);\n if (!parsed.success) {\n const data: unknown = event.data;\n if (\n channel &&\n event.origin === channel.origin &&\n typeof data === \"object\" &&\n data !== null &&\n \"channelId\" in data &&\n data.channelId === channel.id\n ) {\n try {\n send({\n type: \"runtime.error\",\n code: \"host-runtime-protocol-mismatch\",\n message: \"Iframe source received an invalid host envelope.\",\n });\n } finally {\n lifecycle.fail(new Error(\"Invalid iframe host envelope.\"));\n }\n }\n return;\n }\n const envelope = parsed.data;\n if (!channel) {\n if (envelope.payload.type !== \"runtime.init\") return;\n channel = { id: envelope.channelId, origin: event.origin };\n }\n if (\n channel.id !== envelope.channelId ||\n channel.origin !== event.origin ||\n envelope.sequence <= receivedSequence\n )\n return;\n receivedSequence = envelope.sequence;\n const payload = envelope.payload;\n if (payload.type === \"runtime.init\") {\n lifecycle.session(payload.session);\n if (isOpen()) send({ type: \"runtime.ready\" });\n } else if (payload.type === \"gameplay.frame\")\n lifecycle.frame(payload.frame);\n else lifecycle.result(payload);\n if (isOpen()) send({ type: \"runtime.ack\", sequence: envelope.sequence });\n }\n target.addEventListener(\"message\", receive);\n return lifecycle.source;\n}\n","import * as z from \"zod\";\nimport {\n InteractionResultSchema,\n PluginGameplayFrameSchema,\n SubmitInteractionCommandSchema,\n CancelInteractionCommandSchema,\n} from \"./schema.js\";\nexport const GameplayCloseCode = {\n GoingAway: 1001,\n CredentialExpired: 4000,\n CredentialInvalid: 4001,\n RefreshContextMismatch: 4002,\n PermissionDenied: 4100,\n ProtocolViolation: 4200,\n FrameBeforeAuth: 4201,\n SlowConsumer: 4300,\n TooManyRequests: 4301,\n} as const;\n\nexport const GameplayCredentialSchema = z.discriminatedUnion(\"kind\", [\n z\n .object({ kind: z.literal(\"user\"), token: z.string().min(1).max(16384) })\n .strict(),\n z\n .object({ kind: z.literal(\"demo\"), secret: z.string().min(1).max(1024) })\n .strict(),\n]);\nexport const AuthConnectFrameSchema = z\n .object({\n type: z.literal(\"auth.connect\"),\n credential: GameplayCredentialSchema,\n sessionId: z.string().uuid(),\n playerId: z.string().min(1).max(128),\n })\n .strict();\nexport const AuthRefreshFrameSchema = z\n .object({\n type: z.literal(\"auth.refresh\"),\n credential: GameplayCredentialSchema,\n })\n .strict();\n\nexport const SessionResumeFrameSchema = z.object({\n type: z.literal(\"session.resume\"),\n lastSeenLogCursor: z.number().int().nonnegative().nullable(),\n unacknowledgedClientActionIds: z.array(z.string().min(1)).max(32),\n});\n\nexport const AuthAcceptedFrameSchema = z.object({\n type: z.literal(\"auth.accepted\"),\n expiresAt: z.string().datetime(),\n});\n\nexport const GameplayBackpressureReasonSchema = z.enum([\n \"queue_full\",\n \"capacity_full\",\n]);\n\nexport const GameplayBackpressureOperationSchema = z.enum([\n \"session.resume\",\n \"interaction.submit\",\n \"interaction.cancel\",\n]);\nexport const GameplayBackpressureFrameSchema = z.object({\n type: z.literal(\"gameplay.backpressure\"),\n reason: GameplayBackpressureReasonSchema,\n retryAfterMs: z.number().int().positive(),\n message: z.string().min(1),\n operation: GameplayBackpressureOperationSchema,\n clientActionId: z.string().min(1).optional(),\n});\nexport const SessionSnapshotFrameSchema = z.object({\n type: z.literal(\"session.snapshot\"),\n frame: PluginGameplayFrameSchema,\n});\nexport const ClientGameplayFrameSchema = z.discriminatedUnion(\"type\", [\n AuthConnectFrameSchema,\n AuthRefreshFrameSchema,\n SessionResumeFrameSchema,\n SubmitInteractionCommandSchema,\n CancelInteractionCommandSchema,\n]);\nexport const ServerGameplayFrameSchema = z.discriminatedUnion(\"type\", [\n AuthAcceptedFrameSchema,\n GameplayBackpressureFrameSchema,\n SessionSnapshotFrameSchema,\n InteractionResultSchema,\n]);\nexport type GameplayCredential = z.infer<typeof GameplayCredentialSchema>;\nexport type ClientGameplayFrame = z.infer<typeof ClientGameplayFrameSchema>;\nexport type ServerGameplayFrame = z.infer<typeof ServerGameplayFrameSchema>;\n","import type { PluginSessionDescriptor } from \"../../shared/protocol/frame.js\";\nimport {\n ClientGameplayFrameSchema,\n ServerGameplayFrameSchema,\n GameplayCloseCode,\n type ClientGameplayFrame,\n type GameplayCredential,\n} from \"../../shared/protocol/gameplay-wire.js\";\nimport { createSourceLifecycle } from \"./lifecycle.js\";\nimport type { CommandSource, SourceCommand } from \"./types.js\";\n\nexport function hostSource(options: {\n url: string;\n session: PluginSessionDescriptor;\n playerId: string;\n getCredential(): Promise<GameplayCredential>;\n timeoutMs?: number;\n}): CommandSource {\n const { url, playerId, getCredential } = options;\n const sessionId = options.session.sessionId;\n let socket: WebSocket | null = null;\n let generation = 0;\n let disposed = false;\n let authenticated = false;\n let queued: SourceCommand | null = null;\n let reconnects = 0;\n let refreshTimer: ReturnType<typeof setTimeout> | undefined;\n let snapshotTimer: ReturnType<typeof setTimeout> | undefined;\n let openTimer: ReturnType<typeof setTimeout> | undefined;\n let cleanup = () => {};\n const timeoutMs = options.timeoutMs ?? 10_000;\n const send = (frame: ClientGameplayFrame) => {\n if (!socket || socket.readyState !== WebSocket.OPEN)\n throw new Error(\"Gameplay socket is not open.\");\n socket.send(JSON.stringify(ClientGameplayFrameSchema.parse(frame)));\n };\n const resume = () =>\n send({\n type: \"session.resume\",\n lastSeenLogCursor: null,\n unacknowledgedClientActionIds: queued ? [queued.clientActionId] : [],\n });\n const lifecycle = createSourceLifecycle({\n context: {\n sessionId,\n playerId,\n },\n timeoutMs,\n send(command) {\n if (!authenticated) {\n queued = command;\n return;\n }\n send(command);\n },\n recover() {\n if (authenticated) resume();\n else if (!openTimer) void connect();\n },\n close() {\n disposed = true;\n generation++;\n clearTimeout(refreshTimer);\n clearTimeout(openTimer);\n clearTimeout(snapshotTimer);\n cleanup();\n socket?.close();\n socket = null;\n queued = null;\n },\n });\n lifecycle.session(options.session);\n async function connect() {\n if (disposed) return;\n const current = ++generation;\n authenticated = false;\n clearTimeout(refreshTimer);\n clearTimeout(openTimer);\n clearTimeout(snapshotTimer);\n cleanup();\n socket?.close();\n socket = null;\n openTimer = setTimeout(\n () =>\n lifecycle.fail(new Error(\"Gameplay socket authentication timed out.\")),\n timeoutMs,\n );\n try {\n const credential = await getCredential();\n if (disposed || current !== generation) return;\n const next = new WebSocket(url);\n socket = next;\n const active = () => !disposed && current === generation;\n const onOpen = () => {\n if (!active()) return;\n try {\n send({\n type: \"auth.connect\",\n credential,\n sessionId,\n playerId,\n });\n } catch (error) {\n lifecycle.fail(asError(error));\n }\n };\n const onMessage = (event: MessageEvent) => {\n if (!active()) return;\n try {\n const value: unknown = JSON.parse(String(event.data));\n if (typeof value !== \"object\" || value === null || !(\"type\" in value))\n throw new Error(\"Invalid gameplay frame.\");\n if (\n ![\n \"auth.accepted\",\n \"session.snapshot\",\n \"interaction.result\",\n \"gameplay.backpressure\",\n ].includes(String(value.type))\n )\n return;\n const frame = ServerGameplayFrameSchema.parse(value);\n if (frame.type === \"auth.accepted\") {\n clearTimeout(openTimer);\n openTimer = undefined;\n const first = !authenticated;\n authenticated = true;\n if (first) {\n snapshotTimer = setTimeout(\n () => lifecycle.fail(new Error(\"Gameplay snapshot timed out.\")),\n timeoutMs,\n );\n resume();\n if (queued) {\n send(queued);\n queued = null;\n }\n }\n clearTimeout(refreshTimer);\n if (credential.kind === \"user\") {\n const ttl = Date.parse(frame.expiresAt) - Date.now();\n if (ttl <= 0)\n throw new Error(\"Gameplay credential is already expired.\");\n refreshTimer = setTimeout(\n () => {\n openTimer = setTimeout(\n () =>\n lifecycle.fail(\n new Error(\"Gameplay credential refresh timed out.\"),\n ),\n timeoutMs,\n );\n void getCredential()\n .then((updated) => {\n if (active())\n send({ type: \"auth.refresh\", credential: updated });\n })\n .catch((error) => {\n if (active()) lifecycle.fail(asError(error));\n });\n },\n Math.max(0, ttl - Math.min(60_000, ttl * 0.2)),\n );\n }\n } else if (!authenticated)\n throw new Error(\"Gameplay frame arrived before authentication.\");\n else if (frame.type === \"session.snapshot\") {\n clearTimeout(snapshotTimer);\n snapshotTimer = undefined;\n reconnects = 0;\n lifecycle.frame(frame.frame);\n } else if (frame.type === \"interaction.result\")\n lifecycle.result(frame);\n else lifecycle.fail(new Error(frame.message));\n } catch (error) {\n lifecycle.fail(asError(error));\n }\n };\n const onClose = (event: CloseEvent) => {\n if (!active()) return;\n authenticated = false;\n lifecycle.recovering();\n if (\n new Set<number>([\n GameplayCloseCode.CredentialInvalid,\n GameplayCloseCode.RefreshContextMismatch,\n GameplayCloseCode.PermissionDenied,\n GameplayCloseCode.ProtocolViolation,\n GameplayCloseCode.FrameBeforeAuth,\n ]).has(event.code) ||\n reconnects++ > 0\n ) {\n lifecycle.fail(new Error(`Gameplay socket closed (${event.code}).`));\n return;\n }\n void connect();\n lifecycle.retry();\n };\n const onError = () => {\n if (active()) next.close();\n };\n next.addEventListener(\"open\", onOpen);\n next.addEventListener(\"message\", onMessage);\n next.addEventListener(\"close\", onClose);\n next.addEventListener(\"error\", onError);\n cleanup = () => {\n next.removeEventListener(\"open\", onOpen);\n next.removeEventListener(\"message\", onMessage);\n next.removeEventListener(\"close\", onClose);\n next.removeEventListener(\"error\", onError);\n };\n } catch (error) {\n if (!disposed && current === generation) lifecycle.fail(asError(error));\n }\n }\n void connect();\n return lifecycle.source;\n}\nfunction asError(error: unknown): Error {\n return error instanceof Error ? error : new Error(String(error));\n}\n","import { createStore, type Store } from \"@tanstack/store\";\nimport type {\n CoreInstance,\n FeatureContext,\n IdOf,\n InputKey,\n InputKind,\n InputTarget,\n InteractionKey,\n InteractionParams,\n SelectionTarget,\n SubmitResult,\n ZoneHostId,\n} from \"../model.js\";\nimport { runtimeFeatures } from \"../runtime-features.js\";\nimport type { RuntimeSelectionTarget } from \"../targets.js\";\nimport type { RuntimeJson } from \"../../shared/runtime-json.js\";\n\n/** A zone control carries the actual admitted attachment, including its host. */\nexport type ShortcutZoneTarget<G> = {\n [Z in IdOf<G, \"zoneId\">]: {\n readonly kind: \"zone\";\n readonly zoneId: Z;\n readonly hostId: ZoneHostId<G, Z>;\n };\n}[IdOf<G, \"zoneId\">];\nexport type ShortcutTarget<G> = SelectionTarget<G> | ShortcutZoneTarget<G>;\ntype TargetKind = SelectionTarget<unknown>[\"kind\"];\ntype CollectorKind<Kind extends TargetKind> = Kind extends \"space\"\n ? \"board-space\"\n : Kind extends \"edge\"\n ? \"board-edge\"\n : Kind extends \"vertex\"\n ? \"board-vertex\"\n : Kind;\ntype TargetFor<\n G,\n K extends InteractionKey<G>,\n N extends InputKey<G, K>,\n Kind extends TargetKind,\n> = Extract<SelectionTarget<G>, { readonly kind: Kind }> & {\n readonly value: InputTarget<G, K, N>;\n};\ntype Binding<G, K extends InteractionKey<G>, Target, Filter> = Filter & {\n /** Exact browser event.key values; modifiers and held repeats are ignored. */\n readonly keys: readonly string[];\n readonly label: string;\n readonly interaction: K;\n readonly inputs: (context: {\n readonly key: string;\n readonly target: Target;\n }) => InteractionParams<G, K>;\n};\ntype SelectionBinding<G, K extends InteractionKey<G>> = {\n [N in InputKey<G, K>]: {\n [Kind in TargetKind]: [\n Extract<InputKind<G, K, N>, CollectorKind<Kind>>,\n ] extends [never]\n ? never\n : Binding<\n G,\n K,\n TargetFor<G, K, N, Kind>,\n { readonly target: Kind; readonly input: N }\n >;\n }[TargetKind];\n}[InputKey<G, K>];\n/** Correlated by interaction, input kind, and the selected target's value. */\nexport type ShortcutBinding<G> = {\n [K in InteractionKey<G>]:\n | SelectionBinding<G, K>\n | {\n [Z in IdOf<G, \"zoneId\">]: Binding<\n G,\n K,\n Extract<ShortcutZoneTarget<G>, { readonly zoneId: Z }>,\n { readonly target: \"zone\"; readonly zoneId: Z }\n >;\n }[IdOf<G, \"zoneId\">];\n}[InteractionKey<G>];\nexport interface ShortcutOptions<G> {\n readonly bindings: readonly ShortcutBinding<G>[];\n}\nexport interface ShortcutHint<G = unknown> {\n readonly keys: readonly string[];\n readonly label: string;\n readonly interaction: InteractionKey<G>;\n}\nexport interface ShortcutsController<G> {\n /** UI binding configuration has its own subscription, independent of reducer frames. */\n readonly configuration: Pick<\n Store<ShortcutOptions<G> | null>,\n \"get\" | \"subscribe\"\n >;\n /** Registers one mounted adapter. Cleanup removes both behavior and hints. */\n register(options: ShortcutOptions<G>): {\n update(options: ShortcutOptions<G>): void;\n dispose(): void;\n };\n /** null means unhandled; a handled key submits exactly once. */\n handle(\n key: string,\n target: ShortcutTarget<G> | null,\n ): Promise<SubmitResult> | null;\n getHints(target: ShortcutTarget<G> | null): readonly ShortcutHint<G>[];\n}\nexport type RuntimeShortcutTarget =\n | RuntimeSelectionTarget\n | {\n readonly kind: \"zone\";\n readonly zoneId: string;\n readonly hostId: string;\n };\ntype RuntimeBinding = {\n readonly keys: readonly string[];\n readonly label: string;\n readonly interaction: string;\n readonly target: RuntimeShortcutTarget[\"kind\"];\n readonly input?: string;\n readonly zoneId?: string;\n readonly inputs: (context: {\n readonly key: string;\n readonly target: RuntimeShortcutTarget;\n }) => Readonly<Record<string, RuntimeJson>>;\n};\n\n/** Headless and opt-in: no names, bindings or browser listeners are installed by default. */\nexport function shortcutsFeature<G>(\n _game: CoreInstance<G>,\n context: FeatureContext<G>,\n) {\n const game = context[runtimeFeatures].game;\n const configuration = createStore<ShortcutOptions<G> | null>(null);\n let registration: object | null = null;\n function bindings(): readonly RuntimeBinding[] {\n // eslint-disable-next-line no-restricted-syntax -- Instance composition owns the typed bindings; resolve validates the admitted projected domain before invoking each factory.\n return (configuration.get()?.bindings ??\n []) as unknown as readonly RuntimeBinding[];\n }\n let disposed = false;\n function resolve(\n binding: RuntimeBinding,\n key: string,\n target: RuntimeShortcutTarget | null,\n ) {\n if (\n disposed ||\n !target ||\n game.connection !== \"ready\" ||\n game.request ||\n target.kind !== binding.target\n )\n return null;\n const routes =\n target.kind === \"card\"\n ? (game.cards.find(target.value)?.getInteractions() ?? [])\n : game.interactions.list();\n const interaction = routes.find((item) => item.key === binding.interaction);\n if (!interaction || interaction.getStatus() !== \"open\") return null;\n if (target.kind === \"zone\") {\n if (\n target.zoneId !== binding.zoneId ||\n !game.zones.find(target.zoneId, target.hostId)\n )\n return null;\n } else {\n const input = interaction\n .getInputs()\n .find((item) => item.key === binding.input);\n if (!input || !input.getIsEligible(target.value)) return null;\n const domain = input.getDomain();\n if (target.kind === \"card\" && input.kind !== \"card\") return null;\n if (target.kind === \"tile\" && input.kind !== \"tile\") return null;\n if (\n target.kind === \"space\" ||\n target.kind === \"edge\" ||\n target.kind === \"vertex\"\n ) {\n if (\n domain.type !== \"boardTarget\" ||\n domain.targetKind !== target.kind ||\n domain.valueKind !== target.valueKind\n )\n return null;\n if (\n domain.valueKind === \"board-id\" &&\n target.valueKind === \"board-id\" &&\n domain.boardId !== target.boardId\n )\n return null;\n }\n }\n const params = binding.inputs({ key, target });\n return interaction.getIsAvailable(params) && interaction.getIsReady(params)\n ? { interaction, params }\n : null;\n }\n const controller: ShortcutsController<G> = {\n configuration,\n register(options) {\n if (registration)\n throw new Error(\"Mount useGameShortcuts once per GameProvider.\");\n const owned = {};\n registration = owned;\n configuration.setState(() => options);\n return {\n update(options) {\n if (registration !== owned) return;\n configuration.setState(() => options);\n },\n dispose() {\n if (registration !== owned) return;\n registration = null;\n configuration.setState(() => null);\n },\n };\n },\n handle(key, target) {\n const candidates = bindings()\n .filter((binding) => binding.keys.includes(key))\n .flatMap((binding) => {\n const resolved = resolve(binding, key, target);\n return resolved ? [resolved] : [];\n });\n // Ambiguous authored routes do not guess which action to run.\n return candidates.length === 1\n ? candidates[0].interaction.submit(candidates[0].params)\n : null;\n },\n getHints(target) {\n const eligible = bindings().map((binding) => ({\n binding,\n keys: binding.keys.filter((key) => resolve(binding, key, target)),\n }));\n const counts = new Map<string, number>();\n for (const { keys } of eligible)\n for (const key of new Set(keys))\n counts.set(key, (counts.get(key) ?? 0) + 1);\n return eligible.flatMap(({ binding, keys }) => {\n const unique = [...new Set(keys)].filter(\n (key) => counts.get(key) === 1,\n );\n return unique.length\n ? [\n {\n keys: unique,\n label: binding.label,\n interaction: binding.interaction,\n },\n ]\n : [];\n }) as readonly ShortcutHint<G>[];\n },\n };\n return {\n root: { shortcuts: controller },\n dispose() {\n disposed = true;\n registration = null;\n configuration.setState(() => null);\n },\n };\n}\n","import type { Card, CoreInstance, SeatCardId, Zone } from \"../model.js\";\n\nexport interface HandOptions<G> {\n /** Compare projected card data only; hidden cards never expose private fields. */\n readonly sort?: (\n left: Card<G, Record<never, never>>,\n right: Card<G, Record<never, never>>,\n ) => number;\n}\n\n// Generic G defers the card visibility union, so ids widen to string here.\nconst seatCardId = <G>(card: { readonly id: string }) =>\n card.id as SeatCardId<G>;\n\n/** Optional hand helpers reuse the zone order and the core selection router. */\nexport function handFeature<G>(\n _game: CoreInstance<G>,\n options: HandOptions<G> = {},\n) {\n return {\n zone: {\n getSortedCardIds(\n this: Zone<G, Record<never, never>>,\n ): readonly SeatCardId<G>[] {\n return this.getCards({ sort: options.sort }).map(seatCardId<G>);\n },\n getSelectedCardIds(\n this: Zone<G, Record<never, never>>,\n ): readonly SeatCardId<G>[] {\n return this.getCards()\n .filter((card) => card.getIsSelected())\n .map(seatCardId<G>);\n },\n getSelectableCardIds(\n this: Zone<G, Record<never, never>>,\n ): readonly SeatCardId<G>[] {\n return this.getCards()\n .filter((card) => card.getCanSelect())\n .map(seatCardId<G>);\n },\n },\n };\n}\n","import { immutableCopy } from \"./immutable.js\";\nimport { createHexTopology } from \"./hex-board.js\";\nimport { getPublicTileFootprint } from \"./tile-appearance.js\";\nimport {\n SeatBoardTopologySchema,\n type SeatBoardTopology,\n} from \"./seat-topology-schema.js\";\nimport type { SeatSpaceRef, SeatTileRef } from \"./domain/seat-reference.js\";\n\nexport type TileLayoutPoint = { readonly x: number; readonly y: number };\ntype PlacedTile = Exclude<\n SeatBoardTopology,\n { layout: \"generic\" }\n>[\"tiles\"][number];\n/** Rendering geometry is separate from inventory and spatial target handles. */\nexport type TileLayoutGeometry<Data extends PlacedTile = PlacedTile> = {\n readonly ref: SeatTileRef;\n readonly data: Data;\n readonly spaceIds: readonly SeatSpaceRef[];\n readonly outlines: readonly (readonly TileLayoutPoint[])[];\n readonly center: TileLayoutPoint;\n readonly anchor: TileLayoutPoint;\n readonly rotationDegrees: number;\n};\ntype Corner = { readonly key: string; readonly point: TileLayoutPoint };\ntype Side = { readonly from: Corner; readonly to: Corner };\ntype Cell = {\n readonly center: TileLayoutPoint;\n readonly corners: readonly Corner[];\n};\nfunction assertFinite(values: readonly number[]): void {\n if (!values.every(Number.isFinite))\n throw new Error(\"Derived tile layout geometry must be finite.\");\n}\nconst frozenPoint = (point: TileLayoutPoint) => {\n assertFinite([point.x, point.y]);\n return Object.freeze({ ...point });\n};\n\n/** Cancel internal sides using exact lattice identities, then walk every oriented boundary. */\nfunction outlines(\n cells: readonly Cell[],\n): readonly (readonly TileLayoutPoint[])[] {\n const sides = new Map<string, Side>();\n for (const cell of cells) {\n for (const [index, from] of cell.corners.entries()) {\n const to = cell.corners[(index + 1) % cell.corners.length];\n const key = [from.key, to.key].sort().join(\"|\");\n if (sides.has(key)) sides.delete(key);\n else sides.set(key, { from, to });\n }\n }\n const outgoing = new Map<string, Side[]>();\n for (const side of sides.values()) {\n const next = outgoing.get(side.from.key) ?? [];\n next.push(side);\n outgoing.set(side.from.key, next);\n }\n const loops: (readonly TileLayoutPoint[])[] = [];\n while (sides.size) {\n const first = sides.values().next().value!;\n const start = first.from.key;\n let side = first;\n const loop: TileLayoutPoint[] = [];\n while (true) {\n loop.push(frozenPoint(side.from.point));\n sides.delete([side.from.key, side.to.key].sort().join(\"|\"));\n const remaining = outgoing.get(side.from.key)!;\n remaining.splice(remaining.indexOf(side), 1);\n if (side.to.key === start) break;\n const candidates = [...(outgoing.get(side.to.key) ?? [])];\n if (!candidates.length)\n throw new Error(\"Tile footprint boundary is not closed.\");\n // At corner-touching islands, preserve the clockwise contour instead of joining islands.\n const angle = Math.atan2(\n side.to.point.y - side.from.point.y,\n side.to.point.x - side.from.point.x,\n );\n const turn = (next: typeof side) => {\n const delta =\n Math.atan2(\n next.to.point.y - next.from.point.y,\n next.to.point.x - next.from.point.x,\n ) - angle;\n return Math.atan2(Math.sin(delta), Math.cos(delta));\n };\n candidates.sort(\n (a, b) =>\n turn(b) - turn(a) ||\n (a.to.key < b.to.key ? -1 : a.to.key > b.to.key ? 1 : 0),\n );\n side = candidates[0];\n }\n loops.push(Object.freeze(loop));\n }\n return Object.freeze(loops);\n}\n\nfunction hexCells(\n boardId: string,\n orientation: \"pointy\" | \"flat\",\n coordinates: readonly { q: number; r: number }[],\n size: number,\n origin: TileLayoutPoint,\n): Cell[] {\n const topology = createHexTopology({\n id: boardId,\n orientation,\n spaces: coordinates.map((coordinate, index) => ({\n ...coordinate,\n id: String(index),\n })),\n });\n const layout = topology.getLayout({ hexSize: size, origin });\n const vertices = new Map(\n layout.vertices.map((vertex) => [vertex.id, vertex.center]),\n );\n return layout.spaces.map((space) => ({\n center: space.center,\n corners: topology\n .verticesOf(space.id)\n .map((key) => ({ key, point: vertices.get(key)! }))\n .sort(\n (a, b) =>\n Math.atan2(a.point.y - space.center.y, a.point.x - space.center.x) -\n Math.atan2(b.point.y - space.center.y, b.point.x - space.center.x),\n ),\n }));\n}\nfunction squareCells(\n coordinates: readonly { col: number; row: number }[],\n size: number,\n origin: TileLayoutPoint,\n): Cell[] {\n return coordinates.map(({ col, row }) => ({\n center: {\n x: origin.x + (col + 0.5) * size,\n y: origin.y + (row + 0.5) * size,\n },\n corners: [\n [col, row],\n [col + 1, row],\n [col + 1, row + 1],\n [col, row + 1],\n ].map(([x, y]) => ({\n key: `${x},${y}`,\n point: { x: origin.x + x * size, y: origin.y + y * size },\n })),\n }));\n}\n\nfunction build(\n board: SeatBoardTopology,\n size: number,\n origin: TileLayoutPoint,\n) {\n if (board.layout === \"generic\")\n throw new Error(\"Generic boards have no tile layout.\");\n const visibleByTile = new Map<\n SeatTileRef,\n { cells: Cell[]; ids: SeatSpaceRef[] }\n >();\n const group = (\n spaces: readonly { tileRef: SeatTileRef; id: SeatSpaceRef }[],\n cells: readonly Cell[],\n ) => {\n spaces.forEach((space, index) => {\n const grouped = visibleByTile.get(space.tileRef) ?? {\n cells: [],\n ids: [],\n };\n grouped.cells.push(cells[index]);\n grouped.ids.push(space.id);\n visibleByTile.set(space.tileRef, grouped);\n });\n };\n if (board.layout === \"hex\") {\n const spaces = Object.values(board.spaces);\n group(spaces, hexCells(board.id, board.orientation, spaces, size, origin));\n } else {\n const spaces = Object.values(board.spaces);\n group(spaces, squareCells(spaces, size, origin));\n }\n const tiles = board.tiles.map((tile): TileLayoutGeometry => {\n const visible = visibleByTile.get(tile.ref);\n const footprint =\n tile.disclosure === \"concealed\"\n ? getPublicTileFootprint(tile.appearance, tile.placement)\n : null;\n let cells: Cell[];\n let anchor: TileLayoutPoint;\n if (board.layout === \"hex\" && tile.placement.layout === \"hex\") {\n const placement = tile.placement;\n cells =\n tile.disclosure === \"visible\"\n ? (visible?.cells ?? [])\n : footprint?.layout === \"hex\"\n ? hexCells(\n board.id,\n board.orientation,\n footprint.cells,\n size,\n origin,\n )\n : [];\n anchor = hexCells(\n board.id,\n board.orientation,\n [{ q: placement.q, r: placement.r }],\n size,\n origin,\n )[0].center;\n } else if (\n board.layout === \"square\" &&\n tile.placement.layout === \"square\"\n ) {\n const placement = tile.placement;\n cells =\n tile.disclosure === \"visible\"\n ? (visible?.cells ?? [])\n : footprint?.layout === \"square\"\n ? squareCells(footprint.cells, size, origin)\n : [];\n anchor = squareCells(\n [{ col: placement.col, row: placement.row }],\n size,\n origin,\n )[0].center;\n } else throw new Error(\"Tile placement layout does not match board.\");\n if (!cells.length)\n throw new Error(\"A projected tile requires a nonempty footprint.\");\n const center = {\n x: cells.reduce((sum, cell) => sum + cell.center.x, 0) / cells.length,\n y: cells.reduce((sum, cell) => sum + cell.center.y, 0) / cells.length,\n };\n return Object.freeze({\n ref: tile.ref,\n data: tile,\n spaceIds: Object.freeze(visible?.ids ?? []),\n outlines: outlines(cells),\n center: frozenPoint(center),\n anchor: frozenPoint(anchor),\n rotationDegrees:\n tile.placement.rotation * (board.layout === \"hex\" ? 60 : 90),\n });\n });\n let minX = Infinity,\n minY = Infinity,\n maxX = -Infinity,\n maxY = -Infinity;\n for (const tile of tiles)\n for (const loop of tile.outlines)\n for (const point of loop) {\n minX = Math.min(minX, point.x);\n minY = Math.min(minY, point.y);\n maxX = Math.max(maxX, point.x);\n maxY = Math.max(maxY, point.y);\n }\n const viewBox = {\n x: tiles.length ? minX : 0,\n y: tiles.length ? minY : 0,\n width: tiles.length ? maxX - minX : 0,\n height: tiles.length ? maxY - minY : 0,\n };\n assertFinite([viewBox.x, viewBox.y, viewBox.width, viewBox.height]);\n return Object.freeze({\n tiles: Object.freeze(tiles),\n viewBox: Object.freeze(viewBox),\n });\n}\nconst cache = new WeakMap<\n SeatBoardTopology,\n { key: string; value: ReturnType<typeof build> }\n>();\n/** Admit projected topology and layout options before caching derived rendering geometry. */\nexport function createTileBoardLayout(\n board: SeatBoardTopology,\n size: number,\n suppliedOrigin: TileLayoutPoint = { x: 0, y: 0 },\n) {\n if (!Number.isFinite(size) || size <= 0)\n throw new Error(\"Tile cell size must be positive and finite.\");\n if (![suppliedOrigin.x, suppliedOrigin.y].every(Number.isFinite))\n throw new Error(\"Tile layout origin must be finite.\");\n const key = JSON.stringify([size, suppliedOrigin.x, suppliedOrigin.y]);\n const cached = cache.get(board);\n if (cached?.key === key) return cached.value;\n const value = build(\n immutableCopy(SeatBoardTopologySchema.parse(board)),\n size,\n {\n ...suppliedOrigin,\n },\n );\n cache.set(board, { key, value });\n return value;\n}\n","import type { SquareBoardTopology } from \"./board-topology.js\";\nimport { parseBoardElementId } from \"./domain/board-element.js\";\n\ntype Point = { readonly x: number; readonly y: number };\n\n/** Render admitted square topology without inferring boundary incidence from cells. */\nexport function createSquareBoardLayout(\n board: {\n readonly id: string;\n readonly spaces: Readonly<\n Record<\n string,\n { readonly id: string; readonly col: number; readonly row: number }\n >\n >;\n readonly vertices: SquareBoardTopology[\"vertices\"];\n readonly edges: SquareBoardTopology[\"edges\"];\n },\n size: number,\n origin: Point,\n) {\n if (!Number.isFinite(size) || size <= 0)\n throw new Error(\"Square cell size must be positive and finite.\");\n if (![origin.x, origin.y].every(Number.isFinite))\n throw new Error(\"Layout origin must be finite.\");\n const spaces = Object.values(board.spaces).map((space) => {\n const x = origin.x + space.col * size;\n const y = origin.y + space.row * size;\n return {\n id: space.id,\n center: { x: x + size / 2, y: y + size / 2 },\n corners: [\n { x, y },\n { x: x + size, y },\n { x: x + size, y: y + size },\n { x, y: y + size },\n ],\n };\n });\n const vertices = board.vertices.map((vertex) => {\n const identity = parseBoardElementId(vertex.id);\n if (\n !identity ||\n identity.kind !== \"vertex\" ||\n identity.layout !== \"square\" ||\n identity.boardId !== board.id\n )\n throw new Error(\n `Square vertex '${vertex.id}' does not belong to board '${board.id}'.`,\n );\n const [col, row] = identity.latticeId.split(\",\").map(Number);\n return {\n id: vertex.id,\n center: { x: origin.x + col * size, y: origin.y + row * size },\n };\n });\n const vertexPoints = new Map(\n vertices.map((vertex) => [vertex.id, vertex.center]),\n );\n const edges = board.edges.map((edge) => {\n const from = vertexPoints.get(edge.vertexIds[0]);\n const to = vertexPoints.get(edge.vertexIds[1]);\n if (!from || !to)\n throw new Error(`Square edge '${edge.id}' references a missing vertex.`);\n return { id: edge.id, from, to };\n });\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const space of spaces) {\n for (const point of space.corners) {\n minX = Math.min(minX, point.x);\n minY = Math.min(minY, point.y);\n maxX = Math.max(maxX, point.x);\n maxY = Math.max(maxY, point.y);\n }\n }\n const x = spaces.length ? minX : 0;\n const y = spaces.length ? minY : 0;\n return {\n viewBox: {\n x,\n y,\n width: spaces.length ? maxX - x : 0,\n height: spaces.length ? maxY - y : 0,\n },\n spaces,\n edges,\n vertices,\n pointToSpace(point: Point): string | undefined {\n const col = Math.floor((point.x - origin.x) / size);\n const row = Math.floor((point.y - origin.y) / size);\n return Object.values(board.spaces).find(\n (space) => space.col === col && space.row === row,\n )?.id;\n },\n };\n}\n","import {\n createTileBoardLayout,\n type TileLayoutGeometry,\n} from \"../../shared/tile-board-layout.js\";\nimport type { SeatBoardTopology } from \"../../shared/seat-topology-schema.js\";\ntype ProjectedBoardSpace = SeatBoardTopology[\"spaces\"][string];\nimport { createSquareBoardLayout } from \"../../shared/square-board-layout.js\";\nimport {\n runtimeFeatures,\n type RuntimeBoard,\n type RuntimeFeatureContext,\n type RuntimeFeatureSnapshot,\n type RuntimeCollection,\n} from \"../runtime-features.js\";\nimport type { RuntimeTargetOptions } from \"../targets.js\";\nimport type {\n BoardBase,\n BoardDataOf,\n IdOf,\n BoardCollection,\n BoardSpaceCollection,\n BoardSpace,\n CoreInstance,\n FeatureContext,\n TargetOptions,\n ActionProps,\n} from \"../model.js\";\nimport type { BoardEdge, BoardVertex } from \"../../shared/board-topology.js\";\nimport { requireLookup } from \"../../shared/lookup.js\";\nimport { AmbiguousTargetError } from \"../instance.js\";\nimport {\n createHexTopology,\n createHexTopologyCache,\n} from \"../../shared/hex-board.js\";\nimport type { Point } from \"./pointer-session.js\";\nimport type { ViewportTransform } from \"./pan-zoom.js\";\n\ninterface RuntimeSpace {\n readonly id: string;\n readonly data: ProjectedBoardSpace;\n readonly board: RuntimeBoard;\n getIsEligible(): boolean;\n getIsSelectable(): boolean;\n getIsSelected(): boolean;\n getSelectHandler(options?: RuntimeTargetOptions): () => void;\n getTargetProps(options?: RuntimeTargetOptions): ActionProps;\n}\ninterface RuntimeLayoutTarget {\n readonly id: string;\n getIsEligible(): boolean;\n getIsSelectable(): boolean;\n getIsSelected(): boolean;\n getSelectHandler(options?: RuntimeTargetOptions): () => void;\n getTargetProps(options?: RuntimeTargetOptions): ActionProps;\n}\ninterface RuntimeLayout {\n readonly viewBox: {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n };\n getSpaces(): readonly (RuntimeSpace & {\n readonly center: Point;\n points(): readonly Point[];\n readonly transform: string;\n })[];\n getEdges(): readonly (RuntimeLayoutTarget & {\n readonly data: BoardEdge | undefined;\n readonly center: Point;\n readonly line: readonly [Point, Point];\n })[];\n getVertices(): readonly (RuntimeLayoutTarget & {\n readonly data: BoardVertex | undefined;\n readonly center: Point;\n })[];\n getTiles(): readonly TileLayoutGeometry[];\n pointToSpace(x: number, y: number): string | undefined;\n}\ntype TargetKind = \"space\" | \"edge\" | \"vertex\";\nexport interface BoardLayoutOptions {\n /** Hex radius, or square cell width and height. */\n readonly hexSize: number;\n readonly origin?: Point;\n readonly viewport?: ViewportTransform;\n}\ninterface Geometry {\n readonly viewBox: { x: number; y: number; width: number; height: number };\n readonly spaces: readonly {\n id: string;\n center: Point;\n corners: readonly Point[];\n }[];\n readonly edges: readonly { id: string; from: Point; to: Point }[];\n readonly vertices: readonly { id: string; center: Point }[];\n pointToSpace(point: Point): string | undefined;\n}\n\n/** Semantic board spaces and captured selection, with optional spatial geometry. */\nfunction createRuntimeBoardFeature(context: RuntimeFeatureContext) {\n const game = context.game;\n const captures = new WeakMap<\n object,\n {\n model: RuntimeFeatureSnapshot;\n source: ReturnType<typeof game.getOptions>[\"source\"];\n geometry?: ReturnType<typeof createHexTopology>;\n }\n >();\n const cachedHexTopology = createHexTopologyCache();\n let cached:\n | {\n view: unknown;\n boards: ReturnType<RuntimeFeatureContext[\"getBoards\"]>;\n interactions: RuntimeFeatureSnapshot[\"interactions\"];\n source: ReturnType<typeof game.getOptions>[\"source\"];\n collection: RuntimeCollection<RuntimeBoard>;\n }\n | undefined;\n function collection(): RuntimeCollection<RuntimeBoard> {\n const model = game.getSnapshot();\n const source = game.getOptions().source;\n const projectedBoards = context.getBoards();\n if (\n cached &&\n cached.view === model.view &&\n cached.boards === projectedBoards &&\n cached.interactions === model.interactions &&\n cached.source === source\n )\n return cached.collection;\n const boards = Object.values(projectedBoards).map((data) => {\n const board = context.createBoard(data);\n const geometry =\n data.layout === \"hex\"\n ? cachedHexTopology({\n id: data.id,\n orientation: data.orientation,\n spaces: Object.values(data.spaces),\n })\n : undefined;\n captures.set(board, { model, source, geometry });\n return board;\n });\n const byId = new Map(boards.map((board) => [board.id, board]));\n const result: RuntimeCollection<RuntimeBoard> = Object.freeze({\n get: (id: string) => requireLookup(byId.get(id), \"Board\", id),\n find: (id: string) => byId.get(id),\n getAll: () => Object.freeze(boards),\n });\n cached = {\n view: model.view,\n boards: projectedBoards,\n interactions: model.interactions,\n source,\n collection: result,\n };\n return result;\n }\n function targetsFor(owner: RuntimeBoard) {\n const board = owner.data;\n const captured = captures.get(owner)!;\n function matchingTargets(\n model: RuntimeFeatureSnapshot,\n kind: TargetKind,\n id: string,\n ) {\n return model.interactions.list().flatMap((interaction) =>\n interaction\n .getInputs()\n .filter((input) => {\n const domain = input.getDomain();\n return (\n domain.type === \"boardTarget\" &&\n domain.targetKind === kind &&\n (domain.valueKind === \"board-space\"\n ? board.scope === \"perPlayer\" &&\n domain.boardBaseId === board.baseId\n : domain.boardId === board.id)\n );\n })\n .map((input) => {\n const domain = input.getDomain();\n return {\n interaction,\n input,\n value:\n domain.type === \"boardTarget\" &&\n domain.valueKind === \"board-space\"\n ? Object.freeze({\n boardId: board.id,\n spaceId: id,\n })\n : id,\n };\n }),\n );\n }\n function target(kind: TargetKind, id: string) {\n const matches = matchingTargets(captured.model, kind, id);\n const eligible = matches.some(({ input, value }) =>\n input.getIsEligible(value),\n );\n const selected = matches.some(({ input, value }) =>\n input.getIsSelected(value),\n );\n const selectable = matches.some(\n ({ input, value }) => !input.getTargetProps(value).disabled,\n );\n function select(options?: RuntimeTargetOptions) {\n if (\n game.getOptions().source !== captured.source ||\n game.snapshot?.me !== captured.model.snapshot?.me\n )\n return;\n const matching = matchingTargets(game.getSnapshot(), kind, id).filter(\n ({ interaction, input, value }) =>\n (!options?.interaction ||\n options.interaction === interaction.key) &&\n (!options?.input || options.input === input.key) &&\n !input.getTargetProps(value).disabled,\n );\n if (!matching.length) return;\n if (matching.length > 1) throw new AmbiguousTargetError(id);\n const domain = matching[0].input.getDomain();\n if (domain.type !== \"boardTarget\") return;\n const value = matching[0].value;\n const target =\n domain.valueKind === \"board-space\" && typeof value !== \"string\"\n ? { kind: \"space\" as const, valueKind: domain.valueKind, value }\n : {\n kind,\n valueKind: \"board-id\" as const,\n value: id,\n boardId: board.id,\n };\n context.routeTarget(target, {\n interaction: matching[0].interaction.key,\n input: matching[0].input.key,\n });\n }\n return {\n id,\n getIsEligible: () => eligible,\n getIsSelectable: () => selectable,\n getIsSelected: () => selected,\n getSelectHandler: (options?: RuntimeTargetOptions) => () =>\n select(options),\n getTargetProps(options?: RuntimeTargetOptions) {\n const candidates = matches.filter(\n ({ interaction, input, value }) =>\n (!options?.interaction ||\n interaction.key === options.interaction) &&\n (!options?.input || options.input === input.key) &&\n !input.getTargetProps(value).disabled,\n );\n const only = candidates.length === 1 ? candidates[0] : undefined;\n return {\n type: \"button\" as const,\n disabled: candidates.length === 0,\n \"data-action\": \"select\",\n \"data-value\":\n only && typeof only.value !== \"string\"\n ? JSON.stringify(only.value)\n : id,\n \"data-board\": board.id,\n \"data-interaction\": options?.interaction ?? only?.interaction.key,\n \"data-input\": only?.input.key,\n \"data-eligible\": eligible,\n \"data-selected\": selected,\n \"data-disabled\": candidates.length === 0,\n onClick: () => select(options),\n };\n },\n };\n }\n return target;\n }\n const spaceCollections = new WeakMap<\n object,\n RuntimeCollection<RuntimeSpace>\n >();\n function spacesFor(owner: RuntimeBoard): RuntimeCollection<RuntimeSpace> {\n const cached = spaceCollections.get(owner);\n if (cached) return cached;\n const target = targetsFor(owner);\n const data = owner.data;\n const values = Object.freeze(\n Object.values(data.spaces).map((space) =>\n Object.freeze({\n ...target(\"space\", space.id),\n data: space,\n board: owner,\n }),\n ),\n );\n const byId = new Map(values.map((space) => [space.id, space]));\n const spaces = Object.freeze({\n get: (id: string) =>\n requireLookup(byId.get(id), `Space on board ${owner.id}`, id),\n find: (id: string) => byId.get(id),\n getAll: () => values,\n });\n spaceCollections.set(owner, spaces);\n return spaces;\n }\n return {\n root: {\n get boards() {\n return collection();\n },\n },\n board: {\n get spaces(): RuntimeCollection<RuntimeSpace> {\n return spacesFor(this);\n },\n getLayout(\n this: RuntimeBoard,\n options: BoardLayoutOptions,\n ): RuntimeLayout {\n const board = this.data;\n if (board.layout === \"generic\")\n throw new Error(\n `Board '${board.id}' has no spatial geometry; use board.spaces for semantic selection.`,\n );\n const {\n hexSize,\n origin: suppliedOrigin = { x: 0, y: 0 },\n viewport: suppliedViewport = { x: 0, y: 0, scale: 1 },\n } = options;\n const origin = { ...suppliedOrigin };\n const viewport = { ...suppliedViewport };\n if (!Number.isFinite(hexSize) || hexSize <= 0)\n throw new Error(\"hexSize must be positive and finite.\");\n if (\n ![origin.x, origin.y, viewport.x, viewport.y, viewport.scale].every(\n Number.isFinite,\n ) ||\n viewport.scale <= 0\n )\n throw new Error(\n \"Layout transform must be finite with positive scale.\",\n );\n const captured = captures.get(this)!;\n const geometry: Geometry =\n board.layout === \"hex\"\n ? captured.geometry!.getLayout({ hexSize, origin })\n : createSquareBoardLayout(board, hexSize, origin);\n const point = (value: Point): Point => {\n const transformed = {\n x: value.x * viewport.scale + viewport.x,\n y: value.y * viewport.scale + viewport.y,\n };\n if (![transformed.x, transformed.y].every(Number.isFinite))\n throw new Error(\"Derived layout transform must be finite.\");\n return Object.freeze(transformed);\n };\n const tileGeometry = createTileBoardLayout(board, hexSize, origin);\n const tiles = Object.freeze(\n tileGeometry.tiles.map((tile) =>\n Object.freeze({\n ...tile,\n center: point(tile.center),\n anchor: point(tile.anchor),\n outlines: Object.freeze(\n tile.outlines.map((loop) => Object.freeze(loop.map(point))),\n ),\n }),\n ),\n );\n const target = targetsFor(this);\n const semanticSpaces = spacesFor(this);\n const spaces = Object.freeze(\n geometry.spaces.map((space) => {\n const corners = Object.freeze(space.corners.map(point));\n const center = point(space.center);\n return Object.freeze({\n ...semanticSpaces.get(space.id),\n center,\n points: () => corners,\n transform: `translate(${center.x} ${center.y})`,\n });\n }),\n );\n const edges = Object.freeze(\n geometry.edges.map((edge) =>\n Object.freeze({\n ...target(\"edge\", edge.id),\n data: board.edges.find((data) => data.id === edge.id),\n center: point({\n x: (edge.from.x + edge.to.x) / 2,\n y: (edge.from.y + edge.to.y) / 2,\n }),\n line: Object.freeze([point(edge.from), point(edge.to)] as const),\n }),\n ),\n );\n const vertices = Object.freeze(\n geometry.vertices.map((vertex) =>\n Object.freeze({\n ...target(\"vertex\", vertex.id),\n data: board.vertices.find((data) => data.id === vertex.id),\n center: point(vertex.center),\n }),\n ),\n );\n return Object.freeze({\n viewBox: tileGeometry.viewBox,\n getTiles: () => tiles,\n getSpaces: () => spaces,\n getEdges: () => edges,\n getVertices: () => vertices,\n pointToSpace(x: number, y: number) {\n return geometry.pointToSpace({\n x: (x - viewport.x) / viewport.scale,\n y: (y - viewport.y) / viewport.scale,\n });\n },\n });\n },\n } satisfies ThisType<RuntimeBoard>,\n };\n}\n\ntype LayoutTarget<G, Value> = Omit<\n Value,\n \"getSelectHandler\" | \"getTargetProps\"\n> & {\n getSelectHandler(options?: TargetOptions<G>): () => void;\n getTargetProps(options?: TargetOptions<G>): ActionProps;\n};\ntype LayoutElementData<G, Kind extends \"edges\" | \"vertices\"> =\n BoardDataOf<G, IdOf<G, \"boardId\">> extends infer Topology\n ? Topology extends Record<Kind, readonly (infer Element)[]>\n ? Element\n : never\n : never;\ntype LayoutElement<G, Kind extends \"edges\" | \"vertices\", Value> = LayoutTarget<\n G,\n Omit<Value, \"data\" | \"id\">\n> & {\n readonly id: LayoutElementData<G, Kind> extends { readonly id: infer Id }\n ? Id\n : never;\n readonly data: LayoutElementData<G, Kind> | undefined;\n};\n/** Seat tile presentation retains its visible/concealed data union without another discriminator. */\nexport type BoardLayoutTile<G> =\n BoardDataOf<G, IdOf<G, \"boardId\">> extends infer Board\n ? Board extends { readonly tiles: readonly (infer Tile)[] }\n ? Omit<TileLayoutGeometry, \"data\"> & { readonly data: Tile }\n : never\n : never;\n\ntype BoardLayout<G> = Omit<\n RuntimeLayout,\n \"getSpaces\" | \"getEdges\" | \"getVertices\" | \"getTiles\"\n> & {\n getTiles(): readonly BoardLayoutTile<G>[];\n getSpaces(): readonly (BoardSpace<G> & {\n readonly center: Point;\n points(): readonly Point[];\n readonly transform: string;\n })[];\n getEdges(): readonly LayoutElement<\n G,\n \"edges\",\n ReturnType<RuntimeLayout[\"getEdges\"]>[number]\n >[];\n getVertices(): readonly LayoutElement<\n G,\n \"vertices\",\n ReturnType<RuntimeLayout[\"getVertices\"]>[number]\n >[];\n};\nexport interface BoardFeature<G> {\n readonly root: { readonly boards: BoardCollection<G> };\n readonly board: {\n readonly spaces: BoardSpaceCollection<G>;\n getLayout(this: BoardBase<G>, options: BoardLayoutOptions): BoardLayout<G>;\n };\n}\n/** Bind one runtime implementation to the same game/source contract as the instance. */\nexport function boardFeature<G>(\n _game: CoreInstance<G>,\n context: FeatureContext<G>,\n): BoardFeature<G> {\n // Game-binding boundary: source identities and installed hooks belong to G.\n // Proven by headless-features/inline-boards type tests and board behavior tests.\n // eslint-disable-next-line no-restricted-syntax -- Instance composition binds these runtime source identities and feature hooks to the same game G.\n return createRuntimeBoardFeature(\n context[runtimeFeatures],\n ) as unknown as BoardFeature<G>;\n}\n","import {\n runtimeFeatures,\n type RuntimeFeatureContext,\n} from \"../runtime-features.js\";\nimport type { RuntimeDropTarget, RuntimeTargetOptions } from \"../targets.js\";\nimport type { DropTarget, TargetOptions } from \"../targets.js\";\nexport type { DropTarget } from \"../targets.js\";\nimport { isSameDropTarget } from \"../drop-targets.js\";\nimport type { CoreInstance, FeatureContext, SeatCardId } from \"../model.js\";\nexport interface DragState<G> {\n readonly cardId: SeatCardId<G>;\n readonly target: DropTarget<G> | null;\n}\n\nexport interface DragController<G> {\n readonly active: DragState<G> | null;\n getCanDrag(cardId: SeatCardId<G>, options?: TargetOptions<G>): boolean;\n begin(cardId: SeatCardId<G>, options?: TargetOptions<G>): boolean;\n getDropTargets(): readonly DropTarget<G>[];\n setDropTarget(target: DropTarget<G> | null): void;\n drop(): void;\n cancel(): void;\n}\n\ninterface RuntimeDragState {\n readonly cardId: string;\n readonly target: RuntimeDropTarget | null;\n}\ninterface RuntimeDragController {\n readonly active: RuntimeDragState | null;\n getCanDrag(cardId: string, options?: RuntimeTargetOptions): boolean;\n begin(cardId: string, options?: RuntimeTargetOptions): boolean;\n getDropTargets(): readonly RuntimeDropTarget[];\n setDropTarget(target: RuntimeDropTarget | null): void;\n drop(): void;\n cancel(): void;\n}\nfunction createRuntimeDragFeature(context: RuntimeFeatureContext) {\n const game = context.game;\n let active: RuntimeDragState | null = null;\n let selection: RuntimeTargetOptions | undefined;\n let source = game.getOptions().source;\n let seat = game.snapshot?.me;\n let disposed = false;\n let version = game.snapshot?.version;\n let lastInteractions = game.interactions;\n let lastCards = game.cards;\n let branch = snapshot();\n function update(next: RuntimeDragState | null) {\n if (disposed) return;\n active = next === null ? null : Object.freeze(next);\n branch = snapshot();\n context.invalidate();\n }\n function targets(\n cardId = active?.cardId,\n selected = selection,\n ): readonly RuntimeDropTarget[] {\n if (!cardId || game.connection !== \"ready\") return [];\n const options = selected;\n const resolved = (game.cards.find(cardId)?.getInteractions() ?? []).flatMap(\n (candidate) => {\n if (\n !candidate.getIsAvailable() ||\n (options?.interaction && candidate.key !== options.interaction)\n )\n return [];\n const inputs = candidate.getInputs();\n const cardInputs = inputs.filter(\n (input) =>\n input.getDomain().type === \"cardTarget\" &&\n (!options?.input || input.key === options.input) &&\n input.getIsEligible(cardId),\n );\n // Without a board input, the card lands on an area that runs the interaction.\n if (!inputs.some((input) => input.getDomain().type === \"boardTarget\"))\n return cardInputs.map((cardInput): RuntimeDropTarget =>\n Object.freeze({\n kind: \"interaction\",\n interactionKey: candidate.key,\n cardInputKey: cardInput.key,\n }),\n );\n return cardInputs.flatMap((cardInput) =>\n inputs.flatMap((input): RuntimeDropTarget[] => {\n const domain = input.getDomain();\n if (domain.type !== \"boardTarget\") return [];\n const route = {\n interactionKey: candidate.key,\n cardInputKey: cardInput.key,\n inputKey: input.key,\n };\n if (domain.valueKind === \"board-space\")\n return domain.eligibleTargets\n .filter((value) => !input.getTargetProps(value).disabled)\n .map((value) =>\n Object.freeze({\n kind: \"space\",\n valueKind: domain.valueKind,\n value,\n ...route,\n }),\n );\n return domain.eligibleTargets\n .filter((value) => !input.getTargetProps(value).disabled)\n .map((value) =>\n Object.freeze({\n kind: domain.targetKind,\n valueKind: domain.valueKind,\n value,\n boardId: domain.boardId,\n ...route,\n }),\n );\n }),\n );\n },\n );\n return resolved;\n }\n function cancel() {\n if (active) update(null);\n }\n function snapshot(): RuntimeDragController {\n const captured = active;\n const dropTargets = Object.freeze(targets());\n return Object.freeze<RuntimeDragController>({\n active: captured,\n getCanDrag: (cardId, options) =>\n !disposed && targets(cardId, options).length > 0,\n begin(cardId, options) {\n if (disposed || !targets(cardId, options).length) return false;\n selection = options;\n update({ cardId, target: null });\n return true;\n },\n getDropTargets: () => dropTargets,\n setDropTarget(target: RuntimeDropTarget | null) {\n if (!active || disposed) return;\n if (\n target &&\n !targets().some((candidate) => isSameDropTarget(candidate, target))\n ) {\n update({ ...active, target: null });\n return;\n }\n update({ ...active, target });\n },\n drop() {\n const finished = active;\n const eligible =\n finished?.target &&\n targets().some((target) =>\n isSameDropTarget(target, finished.target!),\n );\n cancel();\n if (!disposed && finished?.target && eligible)\n context.routeCardDrop(finished.cardId, finished.target);\n },\n cancel,\n });\n }\n const unsubscribe = game.subscribe(() => {\n const nextSource = game.getOptions().source;\n const nextSeat = game.snapshot?.me;\n const nextVersion = game.snapshot?.version;\n if (\n nextSource !== source ||\n nextSeat !== seat ||\n nextVersion !== version ||\n game.connection !== \"ready\"\n ) {\n source = nextSource;\n seat = nextSeat;\n version = nextVersion;\n cancel();\n }\n });\n return {\n root: {\n get drag() {\n if (\n lastInteractions !== game.interactions ||\n lastCards !== game.cards\n ) {\n lastInteractions = game.interactions;\n lastCards = game.cards;\n branch = snapshot();\n }\n return branch;\n },\n },\n dispose() {\n unsubscribe();\n cancel();\n disposed = true;\n },\n };\n}\n\n/**\n * Semantic card/drop routing. A card lands on a board destination when its\n * interaction has a board input, otherwise on an area that runs the\n * interaction. Gestures, hit-testing and feedback belong to /react.\n */\nexport function dragFeature<G>(\n _game: CoreInstance<G>,\n context: FeatureContext<G>,\n): { readonly root: { readonly drag: DragController<G> }; dispose(): void } {\n // Game-binding boundary: routes come from this instance's admitted descriptors.\n // The runtime implementation revalidates both inputs atomically on drop.\n return createRuntimeDragFeature(context[runtimeFeatures]) as {\n readonly root: { readonly drag: DragController<G> };\n dispose(): void;\n };\n}\n","/** Native pointer surface; importing a feature never requires browser globals. */\nexport interface PointerSurface {\n setPointerCapture(pointerId: number): void;\n hasPointerCapture(pointerId: number): boolean;\n releasePointerCapture(pointerId: number): void;\n}\n\nexport interface PointerInput {\n readonly pointerId: number;\n readonly button: number;\n readonly clientX: number;\n readonly clientY: number;\n readonly currentTarget: PointerSurface;\n preventDefault(): void;\n}\n\nexport interface Point {\n readonly x: number;\n readonly y: number;\n}\n\nexport interface PointerMove {\n readonly origin: Point;\n readonly point: Point;\n readonly delta: Point;\n}\n\n/** One captured gesture. Pointer cancellation and disposal never commit a drop. */\nexport function createPointerSession(callbacks: {\n move(value: PointerMove): void;\n end(value: PointerMove): void;\n cancel(): void;\n}) {\n let disposed = false;\n let active:\n | { id: number; surface: PointerSurface; origin: Point; point: Point }\n | undefined;\n\n function value(): PointerMove {\n const { origin, point } = active!;\n return {\n origin,\n point,\n delta: { x: point.x - origin.x, y: point.y - origin.y },\n };\n }\n\n function release() {\n const previous = active;\n active = undefined;\n if (previous?.surface.hasPointerCapture(previous.id)) {\n previous.surface.releasePointerCapture(previous.id);\n }\n }\n\n function cancel() {\n if (!active) return;\n release();\n callbacks.cancel();\n }\n\n return {\n start(event: PointerInput): boolean {\n if (disposed || active || event.button !== 0) return false;\n event.currentTarget.setPointerCapture(event.pointerId);\n const point = { x: event.clientX, y: event.clientY };\n active = {\n id: event.pointerId,\n surface: event.currentTarget,\n origin: point,\n point,\n };\n event.preventDefault();\n return true;\n },\n move(event: PointerInput) {\n if (event.pointerId !== active?.id) return;\n active.point = { x: event.clientX, y: event.clientY };\n event.preventDefault();\n callbacks.move(value());\n },\n end(event: PointerInput) {\n if (event.pointerId !== active?.id) return;\n active.point = { x: event.clientX, y: event.clientY };\n const result = value();\n release();\n callbacks.end(result);\n },\n cancel(event?: Pick<PointerInput, \"pointerId\">) {\n if (event && event.pointerId !== active?.id) return;\n cancel();\n },\n dispose() {\n disposed = true;\n cancel();\n },\n };\n}\n","import type { CoreInstance, FeatureContext } from \"../model.js\";\nimport {\n createPointerSession,\n type PointerInput,\n type PointerSurface,\n} from \"./pointer-session.js\";\n\nexport interface ViewportTransform {\n readonly x: number;\n readonly y: number;\n readonly scale: number;\n}\nexport interface ViewportSurface extends PointerSurface {\n getBoundingClientRect(): {\n readonly left: number;\n readonly top: number;\n readonly height: number;\n };\n}\nexport interface WheelInput {\n readonly clientX: number;\n readonly clientY: number;\n readonly deltaY: number;\n readonly deltaMode: number;\n readonly currentTarget: ViewportSurface;\n preventDefault(): void;\n}\nexport interface PanZoomOptions {\n readonly initial?: ViewportTransform;\n readonly minScale?: number;\n readonly maxScale?: number;\n}\n\n/** Native pointer panning and wheel zoom around the cursor. No document listeners. */\nexport function panZoomFeature<G>(\n game: CoreInstance<G>,\n context: FeatureContext<G>,\n options: PanZoomOptions = {},\n) {\n const minScale = options.minScale ?? 0.25;\n const maxScale = options.maxScale ?? 4;\n if (\n !Number.isFinite(minScale) ||\n !Number.isFinite(maxScale) ||\n minScale <= 0 ||\n maxScale < minScale\n ) {\n throw new Error(\n \"Viewport scale limits must be positive, finite, and ordered.\",\n );\n }\n const initial = options.initial ?? { x: 0, y: 0, scale: 1 };\n let disposed = false;\n let source = game.getOptions().source;\n let seat = game.snapshot?.me;\n let dragOrigin = initial;\n let transform = admit(initial);\n let branch = snapshot();\n\n function admit(value: ViewportTransform): ViewportTransform {\n if (\n ![value.x, value.y, value.scale].every(Number.isFinite) ||\n value.scale <= 0\n ) {\n throw new Error(\n \"Viewport transform must have finite coordinates and positive scale.\",\n );\n }\n return Object.freeze({\n x: value.x,\n y: value.y,\n scale: Math.min(maxScale, Math.max(minScale, value.scale)),\n });\n }\n function update(value: ViewportTransform) {\n if (disposed) return;\n const next = admit(value);\n if (\n next.x === transform.x &&\n next.y === transform.y &&\n next.scale === transform.scale\n )\n return;\n transform = next;\n branch = snapshot();\n context.invalidate();\n }\n const pointer = createPointerSession({\n move: ({ delta }) =>\n update({\n ...dragOrigin,\n x: dragOrigin.x + delta.x,\n y: dragOrigin.y + delta.y,\n }),\n end: ({ delta }) =>\n update({\n ...dragOrigin,\n x: dragOrigin.x + delta.x,\n y: dragOrigin.y + delta.y,\n }),\n cancel() {},\n });\n function props() {\n return {\n style: { touchAction: \"none\" as const },\n onPointerDown(event: PointerInput) {\n if (pointer.start(event)) dragOrigin = transform;\n },\n onPointerMove: pointer.move,\n onPointerUp: pointer.end,\n onPointerCancel: pointer.cancel,\n onLostPointerCapture: pointer.cancel,\n onWheel(event: WheelInput) {\n if (disposed) return;\n event.preventDefault();\n const rect = event.currentTarget.getBoundingClientRect();\n const unit =\n event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? rect.height : 1;\n const scale = Math.min(\n maxScale,\n Math.max(\n minScale,\n transform.scale * Math.exp(-event.deltaY * unit * 0.002),\n ),\n );\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n const ratio = scale / transform.scale;\n update({\n x: x - (x - transform.x) * ratio,\n y: y - (y - transform.y) * ratio,\n scale,\n });\n },\n };\n }\n function snapshot() {\n const captured = transform;\n return Object.freeze({\n transform: captured,\n getTransform: () => captured,\n getProps: props,\n setTransform: update,\n reset: () => {\n pointer.cancel();\n update(initial);\n },\n });\n }\n const unsubscribe = game.subscribe(() => {\n const nextSource = game.getOptions().source;\n const nextSeat = game.snapshot?.me;\n if (nextSource !== source || nextSeat !== seat) {\n source = nextSource;\n seat = nextSeat;\n pointer.cancel();\n update(initial);\n }\n });\n return {\n root: {\n get viewport() {\n return branch;\n },\n },\n dispose() {\n disposed = true;\n unsubscribe();\n pointer.dispose();\n },\n };\n}\n","import { isHiddenCardId as isHidden } from \"../../shared/domain/cards.js\";\nimport type { CoreInstance, IdOf, SeatCardId, ZoneHostId } from \"../model.js\";\nimport type { SourceSnapshot } from \"../sources/types.js\";\n\n/**\n * Where a card that arrived in its zone with the current frame was on the\n * previous one: another zone, or the private zones of the player who moved.\n * `hidden` says whether the seat saw only the card's back there.\n */\nexport type CardOrigin<G> =\n | {\n readonly zone: IdOf<G, \"zoneId\">;\n readonly hostId: ZoneHostId<G>;\n readonly hidden: boolean;\n }\n | { readonly player: IdOf<G, \"playerId\">; readonly hidden: true };\n\ntype RuntimeOrigin =\n | {\n readonly zone: string;\n readonly hostId?: string;\n readonly hidden: boolean;\n }\n | { readonly player: string; readonly hidden: true };\ntype NestedZones = SourceSnapshot[\"frame\"][\"zones\"];\ntype Zones = Record<\n string,\n import(\"../../shared/protocol/frame\").ZoneHandlesSnapshot\n>;\nconst flatten = (zones: NestedZones): Zones =>\n Object.fromEntries(\n Object.entries(zones).flatMap(([zoneId, hosts]) =>\n Object.entries(hosts).map(([hostId, zone]) => [\n JSON.stringify([zoneId, hostId]),\n zone,\n ]),\n ),\n );\n\nconst hiddenCount = (zones: Zones, zone: string) =>\n zones[zone]?.cardIds.filter(isHidden).length ?? 0;\n\nfunction singleOrigin(\n departures: readonly {\n readonly zone: string;\n readonly hostId?: string;\n readonly hidden: boolean;\n }[],\n count: number,\n) {\n const origin = departures[0];\n return origin &&\n departures.length >= count &&\n departures.every(\n (card) => card.zone === origin.zone && card.hidden === origin.hidden,\n )\n ? Object.freeze(origin)\n : null;\n}\n\n/**\n * Visible ids are card identities, so a visible card is followed between\n * zones. Hidden ids are positions, so only their net counts are compared.\n * An inferred origin requires one compatible source with enough departures;\n * existing hidden cards make the arriving positions ambiguous. Unexplained\n * arrivals can come from the sole mover's private zones, which the seat's\n * frame does not list. Ambiguous origins are omitted.\n */\nexport function findCardOrigins(\n previousNested: NestedZones,\n nextNested: NestedZones,\n mover: string | null,\n): ReadonlyMap<string, RuntimeOrigin> {\n const previous = flatten(previousNested);\n const next = flatten(nextNested);\n const shownBefore = new Map<string, string>();\n for (const [zone, { cardIds }] of Object.entries(previous))\n for (const cardId of cardIds)\n if (!isHidden(cardId)) shownBefore.set(cardId, zone);\n const shownNow = new Set(\n Object.values(next).flatMap(({ cardIds }) =>\n cardIds.filter((cardId) => !isHidden(cardId)),\n ),\n );\n let left = Object.entries(previous).flatMap(([zone, { cardIds }]) => [\n ...cardIds\n .filter((cardId) => !isHidden(cardId) && !shownNow.has(cardId))\n .map(() => ({ zone, hidden: false })),\n ...Array.from(\n {\n length: Math.max(\n 0,\n hiddenCount(previous, zone) - hiddenCount(next, zone),\n ),\n },\n () => ({ zone, hidden: true }),\n ),\n ]);\n const origins = new Map<string, RuntimeOrigin>();\n const shownArrivals: string[] = [];\n const hiddenArrivals: (string | null)[] = [];\n for (const [zone, { cardIds }] of Object.entries(next)) {\n for (const cardId of cardIds) {\n if (isHidden(cardId)) continue;\n const from = shownBefore.get(cardId);\n if (from === undefined) shownArrivals.push(cardId);\n else if (from !== zone)\n origins.set(cardId, Object.freeze({ zone: from, hidden: false }));\n }\n const hidden = cardIds.filter(isHidden);\n const before = hiddenCount(previous, zone);\n // Count ambiguous arrivals too, so another destination cannot claim their source.\n hiddenArrivals.push(\n ...Array.from(\n { length: Math.max(0, hidden.length - before) },\n (_, index) => (before === 0 ? hidden[index] : null),\n ),\n );\n }\n // Concealing a visible card can replace a hidden departure without changing\n // the hidden count. Net counts cannot resolve those simultaneous movements.\n if (\n left.some(\n (card) =>\n !card.hidden &&\n hiddenCount(previous, card.zone) > 0 &&\n hiddenCount(next, card.zone) > 0,\n )\n )\n return decodedOrigins(origins);\n const hiddenLeft = left.filter((card) => card.hidden);\n if (shownArrivals.length) {\n const origin = singleOrigin(hiddenLeft, shownArrivals.length);\n if (origin) {\n for (const cardId of shownArrivals) origins.set(cardId, origin);\n left = [\n ...left.filter((card) => !card.hidden),\n ...hiddenLeft.slice(shownArrivals.length),\n ];\n } else if (hiddenLeft.length) {\n // Which departures the shown cards consumed is also ambiguous.\n return decodedOrigins(origins);\n } else if (mover !== null) {\n const origin = Object.freeze({ player: mover, hidden: true as const });\n for (const cardId of shownArrivals) origins.set(cardId, origin);\n }\n }\n const hiddenOrigin =\n singleOrigin(left, hiddenArrivals.length) ??\n (left.length === 0 && mover !== null\n ? Object.freeze({ player: mover, hidden: true as const })\n : null);\n if (hiddenOrigin) {\n for (const cardId of hiddenArrivals)\n if (cardId !== null) origins.set(cardId, hiddenOrigin);\n }\n return decodedOrigins(origins);\n}\n\n/** The sole active player, when it is another seat. */\nfunction moverOf(snapshot: SourceSnapshot) {\n const active = snapshot.frame.flow.activePlayers;\n return active.length === 1 && active[0] !== snapshot.me ? active[0] : null;\n}\n\n/**\n * Adds `card.getOrigin()`: where a card that arrived in its zone with the\n * current frame came from, or null. Origins last until the next frame and\n * reset when the seat or source changes. Hidden origins are inferred from\n * net counts; ambiguous sources and arriving positions return null.\n */\nexport function originsFeature<G>(game: CoreInstance<G>) {\n type Origins = ReadonlyMap<SeatCardId<G>, CardOrigin<G>>;\n let frame = game.snapshot;\n let source = game.getOptions().source;\n let origins: Origins = new Map();\n function sync() {\n const next = game.snapshot;\n const nextSource = game.getOptions().source;\n if (\n next?.version === frame?.version &&\n next?.me === frame?.me &&\n nextSource === source\n )\n return;\n // Game-binding boundary: card, zone and player ids come from this instance's frames.\n origins =\n frame &&\n next &&\n next.me === frame.me &&\n nextSource === source &&\n next.version === frame.version + 1\n ? (findCardOrigins(\n frame.frame.zones,\n next.frame.zones,\n moverOf(frame),\n ) as Origins)\n : new Map();\n frame = next;\n source = nextSource;\n }\n // Also read lazily, so a reader notified before this listener sees the new frame's origins.\n const unsubscribe = game.subscribe(sync);\n return {\n card: {\n getOrigin(this: { readonly id: SeatCardId<G> }): CardOrigin<G> | null {\n sync();\n return origins.get(this.id) ?? null;\n },\n },\n dispose: unsubscribe,\n };\n}\n\nfunction decodedOrigins(\n origins: ReadonlyMap<string, RuntimeOrigin>,\n): ReadonlyMap<string, RuntimeOrigin> {\n return new Map<string, RuntimeOrigin>(\n [...origins].map(([id, origin]) => {\n if (!(\"zone\" in origin)) return [id, origin];\n const [zone, hostId] = JSON.parse(origin.zone) as [string, string];\n return [id, Object.freeze({ ...origin, zone, hostId })];\n }),\n );\n}\n","const RADIANS = Math.PI / 180;\n\nexport interface FanOptions {\n readonly count: number;\n /** The width available to the fan, in pixels. */\n readonly width: number;\n readonly cardWidth: number;\n readonly cardHeight: number;\n /** Distance between neighbouring cards along the arc when there is room. Default: 60% of the card width. */\n readonly step?: number;\n /** The smallest visible slice of a covered card. Default: 25% of the card width. */\n readonly minStep?: number;\n /** Degrees between neighbouring cards. Default 5; 0 lays a straight row. */\n readonly angle?: number;\n /** The most degrees between the two end cards. Default 30. */\n readonly maxSpread?: number;\n}\n\n/** A card's CSS `translate` from the fan's top-left corner, and its `rotate` about its own centre. */\nexport interface FanCard {\n readonly x: number;\n readonly y: number;\n /** Degrees clockwise. */\n readonly rotate: number;\n}\n\nexport interface FanLayout {\n readonly cards: readonly FanCard[];\n /** The fan's bounding box. It is wider than the available width only when the cards are at `minStep`. */\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * Lays cards on a circular arc. The spread grows with the card count up to\n * `maxSpread`; the step shrinks continuously to fit the width, down to\n * `minStep`, past which the fan overflows and the hand should scroll.\n */\nexport function fanLayout({\n count,\n width,\n cardWidth,\n cardHeight,\n step = cardWidth * 0.6,\n minStep = cardWidth * 0.25,\n angle = 5,\n maxSpread = 30,\n}: FanOptions): FanLayout {\n if (count < 1) return { cards: [], width: 0, height: 0 };\n const gaps = count - 1;\n const delta = gaps ? Math.min(angle, maxSpread / gaps) * RADIANS : 0;\n const edge = (gaps * delta) / 2;\n // The horizontal distance between the end cards' centres is `spacing * span`.\n const span = delta ? (2 * Math.sin(edge)) / delta : gaps;\n // The end cards' outer halves, tilted by the edge angle.\n const ends = cardWidth * Math.cos(edge) + cardHeight * Math.sin(edge);\n const spacing = span\n ? Math.max(minStep, Math.min(step, (width - ends) / span))\n : 0;\n const radius = delta ? spacing / delta : 0;\n const centres = Array.from({ length: count }, (_, index) => {\n if (!delta) return { theta: 0, x: (index - gaps / 2) * spacing, y: 0 };\n const theta = (index - gaps / 2) * delta;\n return {\n theta,\n x: radius * Math.sin(theta),\n y: radius * (1 - Math.cos(theta)),\n };\n });\n const halfHeight = (theta: number) =>\n (cardHeight / 2) * Math.cos(theta) +\n (cardWidth / 2) * Math.abs(Math.sin(theta));\n const top = Math.min(\n ...centres.map((card) => card.y - halfHeight(card.theta)),\n );\n const bottom = Math.max(\n ...centres.map((card) => card.y + halfHeight(card.theta)),\n );\n const fanWidth = spacing * span + ends;\n return {\n cards: centres.map((card) => ({\n x: card.x + (fanWidth - cardWidth) / 2,\n y: card.y - top - cardHeight / 2,\n rotate: card.theta / RADIANS,\n })),\n width: fanWidth,\n height: bottom - top,\n };\n}\n\n/** Moves a fanned card outward along its own tilt, as for a selected card. */\nexport function liftFanCard(card: FanCard, distance: number): FanCard {\n const theta = card.rotate * RADIANS;\n return {\n x: card.x + distance * Math.sin(theta),\n y: card.y - distance * Math.cos(theta),\n rotate: card.rotate,\n };\n}\n","import { fanLayout, type FanCard, type FanOptions } from \"./fan.js\";\n\n/**\n * How a hand rests and focuses one card. Lengths are shares of the resting\n * card, so one configuration fits every card size. Missing options come from\n * `handFanPresets.open`.\n */\nexport interface HandFanOptions extends Pick<\n FanOptions,\n \"angle\" | \"maxSpread\"\n> {\n /** Distance between neighbouring cards when there is room, in card widths. Default 0.6, as `fanLayout`. */\n readonly spacing?: number;\n /** Share of each resting card's height below the hand's bottom edge. 0 shows whole cards. */\n readonly tuck?: number;\n /** Focused face width as a multiple of the resting card. */\n readonly focusScale?: number;\n /** Tallest focused face, as a share of the window height. */\n readonly focusMaxHeight?: number;\n /**\n * Sideways shift of the first, second, third… neighbour, in card widths.\n * The focused face's extra width tapers over the same neighbours.\n */\n readonly push?: readonly number[];\n /** Narrowest strip of each neighbour kept visible, in card widths. */\n readonly exposed?: number;\n}\n\n/** Starting points for a hand; spread one and override what differs. */\nexport const handFanPresets = {\n /** Whole resting cards; focusing enlarges the card. */\n open: {\n tuck: 0,\n focusScale: 2,\n focusMaxHeight: 0.55,\n push: [0.29, 0.19, 0.1],\n exposed: 0.35,\n },\n /**\n * Larger cards tucked below the bottom edge and spaced like a dealt hand;\n * focusing mostly reveals the card.\n */\n tucked: {\n spacing: 0.75,\n tuck: 0.4,\n focusScale: 1.4,\n focusMaxHeight: 0.4,\n push: [0.29, 0.19, 0.1],\n exposed: 0.35,\n },\n /** Coarse pointers: a shallower tuck and wider strips to tap. */\n touch: {\n spacing: 0.75,\n tuck: 0.2,\n focusScale: 1.6,\n focusMaxHeight: 0.5,\n push: [0.35, 0.2, 0.1],\n exposed: 0.45,\n },\n} as const satisfies Record<string, HandFanOptions>;\n\n/** A card's `fanLayout` pose with its scale and stacking order. */\nexport interface HandFanPose extends FanCard {\n readonly scale: number;\n /** Stacking order: fan order, with the focused card above the rest. */\n readonly layer: number;\n}\n\nexport interface HandFan {\n /** One pose per card, in the same coordinates as `fanLayout`. */\n readonly cards: readonly HandFanPose[];\n /** The fan's width, as `fanLayout` reports it. */\n readonly width: number;\n /** The visible band: the fan's height less the tucked part of its cards. */\n readonly height: number;\n /** Space above the band that a focused face can rise into. */\n readonly headroom: number;\n}\n\nexport interface HandFanInput extends Pick<\n FanOptions,\n \"count\" | \"width\" | \"cardWidth\" | \"cardHeight\"\n> {\n /** Index of the focused card, or -1 for none. */\n readonly focused?: number;\n /**\n * The part of the fan the viewer can see after scrolling, in fan\n * coordinates; a focused face stays inside it. Defaults to `width`,\n * centred on the fan.\n */\n readonly visible?: { readonly left: number; readonly width: number };\n /** Window height in pixels; `focusMaxHeight` is a share of it. */\n readonly windowHeight?: number;\n /** Pixels above the band's bottom edge that a focused face may use. */\n readonly room?: number;\n readonly options?: HandFanOptions;\n}\n\n/**\n * Lays a hand on a `fanLayout` arc and focuses one card: upright on the\n * band's bottom edge at a readable size, with nearby cards pushed sideways.\n * Neighbours keep their order and at least their `exposed` strip.\n */\nexport function handFan({\n count,\n width,\n cardWidth,\n cardHeight,\n focused = -1,\n visible,\n windowHeight = Infinity,\n room = Infinity,\n options,\n}: HandFanInput): HandFan {\n const o = { ...handFanPresets.open, ...options };\n const fan = fanLayout({\n count,\n width,\n cardWidth,\n cardHeight,\n angle: o.angle,\n maxSpread: o.maxSpread,\n step: o.spacing === undefined ? undefined : o.spacing * cardWidth,\n });\n const band = Math.max(0, fan.height - o.tuck * cardHeight);\n const view = visible ?? {\n left: (fan.width - width) / 2,\n width,\n };\n const exposed = cardWidth * o.exposed;\n // The widest face this hand shows, before an end card's missing strip.\n const largest = Math.max(\n cardWidth,\n Math.min(\n cardWidth * o.focusScale,\n (windowHeight * o.focusMaxHeight * cardWidth) / cardHeight,\n (room * cardWidth) / cardHeight,\n view.width,\n ),\n );\n const headroom = Math.max(0, (largest * cardHeight) / cardWidth - band);\n const cards: HandFanPose[] = fan.cards.map((card, index) => ({\n ...card,\n scale: 1,\n layer: index,\n }));\n if (focused < 0 || focused >= count)\n return { cards, width: fan.width, height: band, headroom };\n const leftStrip = focused > 0 ? exposed : 0;\n const rightStrip = focused < count - 1 ? exposed : 0;\n const face = Math.max(\n cardWidth,\n Math.min(largest, view.width - leftStrip - rightStrip),\n );\n const scale = face / cardWidth;\n const half = face / 2;\n const centre = Math.max(\n view.left + leftStrip + half,\n Math.min(\n view.left + view.width - rightStrip - half,\n cards[focused].x + cardWidth / 2,\n ),\n );\n cards[focused] = {\n x: centre - cardWidth / 2,\n y: band - (cardHeight * (scale + 1)) / 2,\n rotate: 0,\n scale,\n layer: count,\n };\n // The listed pushes taper over their neighbours. A crowded fan needs a\n // longer tail: never reverse card order or erase the next exposed strip.\n const extra = Math.max(0, half - cardWidth / 2);\n const reach = o.push.length;\n for (const direction of [-1, 1] as const) {\n let previous = centre;\n for (\n let distance = 1, index = focused + direction;\n index >= 0 && index < count;\n distance++, index += direction\n ) {\n const card = cards[index];\n const shift =\n (o.push[distance - 1] ?? 0) * cardWidth +\n (reach ? extra * Math.max(0, 1 - (distance - 1) / reach) : 0);\n const desired = card.x + cardWidth / 2 + direction * shift;\n const angle = (card.rotate * Math.PI) / 180;\n const halfWidth =\n (cardWidth * Math.cos(angle) + cardHeight * Math.abs(Math.sin(angle))) /\n 2;\n // The rotated bounding corner alone is not a useful pointer target.\n // Use the horizontal projection of the vertical edge's midpoint, a\n // conservative extent within the card's centre row.\n const middleHalfWidth = (cardWidth * Math.cos(angle)) / 2;\n const clearance =\n distance === 1\n ? Math.max(exposed, half - middleHalfWidth + exposed)\n : exposed;\n // Cards farther right stack higher. Keep their left edges beyond the\n // next card's exposed strip rather than covering it entirely.\n const boundary =\n direction === 1 && distance > 1\n ? Math.max(previous + clearance, centre + half + exposed + halfWidth)\n : previous + direction * clearance;\n let next =\n direction === 1\n ? Math.max(desired, boundary)\n : Math.min(desired, boundary);\n // Keep an immediate neighbour inside the visible part of the fan and\n // touching the face: a gap would drop focus between the two cards.\n if (distance === 1)\n next =\n direction === 1\n ? Math.min(\n next,\n view.left + view.width - middleHalfWidth,\n centre + half + middleHalfWidth,\n )\n : Math.max(\n next,\n view.left + middleHalfWidth,\n centre - half - middleHalfWidth,\n );\n cards[index] = { ...card, x: next - cardWidth / 2 };\n previous = next;\n }\n }\n return { cards, width: fan.width, height: band, headroom };\n}\n\n/**\n * An exponential approach to the target. An animation restarted from the\n * current pose continues the same curve at full speed, so retargeting never\n * stalls a card or overshoots.\n */\nexport function exponentialOut(progress: number): number {\n return (1 - Math.exp(-4.5 * progress)) / (1 - Math.exp(-4.5));\n}\n\n/** Durations in seconds with an easing function, as Motion transitions take them. */\nexport const handFanTiming = {\n /** The focused face rises: 90% in about 45ms. */\n focus: { duration: 0.09, ease: exponentialOut },\n /** Sideways travel, neighbours and returning cards: 90% in about 300ms. */\n settle: { duration: 0.6, ease: exponentialOut },\n} as const;\n\n/** An easing function as a CSS `linear()` easing, for CSS transitions and the Web Animations API. */\nexport function cssEasing(\n ease: (progress: number) => number,\n samples = 24,\n): string {\n const points = Array.from({ length: samples + 1 }, (_, index) =>\n Number(ease(index / samples).toFixed(4)),\n );\n return `linear(${points.join(\", \")})`;\n}\n"],"mappings":"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","names":["options","x","y","value","target","cached","origin"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dreamboard-games/sdk",
3
- "version": "0.5.0-alpha.13",
3
+ "version": "0.5.0-alpha.14",
4
4
  "description": "Typed headless game instances, reducer authoring, React integration and testing",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",