@zvk/game-bridge 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/LICENSE.md +21 -0
- package/README.md +38 -0
- package/dist/core/channel.d.ts +67 -0
- package/dist/core/channel.js +153 -0
- package/dist/core/coalesced-publisher.d.ts +35 -0
- package/dist/core/coalesced-publisher.js +127 -0
- package/dist/core/game-bridge.d.ts +60 -0
- package/dist/core/game-bridge.js +118 -0
- package/dist/core/intents.d.ts +33 -0
- package/dist/core/intents.js +43 -0
- package/dist/core/serializable.d.ts +3 -0
- package/dist/core/serializable.js +71 -0
- package/dist/core/types.d.ts +17 -0
- package/dist/core/types.js +1 -0
- package/dist/dom/index.d.ts +68 -0
- package/dist/dom/index.js +244 -0
- package/dist/geometry/anchors.d.ts +48 -0
- package/dist/geometry/anchors.js +96 -0
- package/dist/geometry/index.d.ts +6 -0
- package/dist/geometry/index.js +6 -0
- package/dist/geometry/matrix.d.ts +45 -0
- package/dist/geometry/matrix.js +77 -0
- package/dist/geometry/placement.d.ts +24 -0
- package/dist/geometry/placement.js +49 -0
- package/dist/geometry/projection.d.ts +118 -0
- package/dist/geometry/projection.js +194 -0
- package/dist/geometry/types.d.ts +62 -0
- package/dist/geometry/types.js +79 -0
- package/dist/geometry/visibility.d.ts +30 -0
- package/dist/geometry/visibility.js +128 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +5 -0
- package/dist/phaser/index.d.ts +187 -0
- package/dist/phaser/index.js +347 -0
- package/dist/react/index.d.ts +20 -0
- package/dist/react/index.js +47 -0
- package/dist/test-utils/assertions.d.ts +2 -0
- package/dist/test-utils/assertions.js +9 -0
- package/dist/test-utils/fixtures.d.ts +7 -0
- package/dist/test-utils/fixtures.js +9 -0
- package/dist/test-utils/index.d.ts +3 -0
- package/dist/test-utils/index.js +3 -0
- package/dist/test-utils/manual-scheduler.d.ts +10 -0
- package/dist/test-utils/manual-scheduler.js +43 -0
- package/docs/content/core-contracts.md +5 -0
- package/docs/content/dom.md +5 -0
- package/docs/content/errors-and-performance.md +5 -0
- package/docs/content/geometry.md +5 -0
- package/docs/content/index.md +5 -0
- package/docs/content/migration.md +5 -0
- package/docs/content/phaser.md +5 -0
- package/docs/content/react.md +5 -0
- package/docs/examples/react-phaser-overlay.tsx +14 -0
- package/package.json +109 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ComponentType, type ReactNode } from "react";
|
|
2
|
+
import type { BridgeEquality, BridgeReader, GameBridge, GameBridgeFrame, JsonValue } from "../index.js";
|
|
3
|
+
import type { ProjectedWorldAnchor } from "../geometry/index.js";
|
|
4
|
+
export declare function useBridgeSnapshot<TSnapshot>(reader: BridgeReader<TSnapshot>): TSnapshot;
|
|
5
|
+
export declare function useBridgeSelector<TSnapshot, TSelected>(reader: BridgeReader<TSnapshot>, selector: (snapshot: TSnapshot) => TSelected, equals?: BridgeEquality<TSelected>): TSelected;
|
|
6
|
+
export interface GameBridgeReactBindings<TState, TIntent extends JsonValue, TAnchorMetadata extends JsonValue> {
|
|
7
|
+
readonly Provider: ComponentType<{
|
|
8
|
+
readonly bridge: GameBridge<TState, TIntent, TAnchorMetadata>;
|
|
9
|
+
readonly children?: ReactNode;
|
|
10
|
+
}>;
|
|
11
|
+
readonly useBridge: () => GameBridge<TState, TIntent, TAnchorMetadata>;
|
|
12
|
+
readonly useStateSnapshot: () => TState;
|
|
13
|
+
readonly useFrameSnapshot: () => GameBridgeFrame<TAnchorMetadata>;
|
|
14
|
+
readonly useStateSelector: <TSelected>(selector: (snapshot: TState) => TSelected, equals?: BridgeEquality<TSelected>) => TSelected;
|
|
15
|
+
readonly useFrameSelector: <TSelected>(selector: (snapshot: GameBridgeFrame<TAnchorMetadata>) => TSelected, equals?: BridgeEquality<TSelected>) => TSelected;
|
|
16
|
+
readonly useProjectedAnchor: (id: string) => ProjectedWorldAnchor<TAnchorMetadata> | null;
|
|
17
|
+
}
|
|
18
|
+
export declare function createGameBridgeReactBindings<TState, TIntent extends JsonValue, TAnchorMetadata extends JsonValue = JsonValue>(options?: {
|
|
19
|
+
readonly displayName?: string;
|
|
20
|
+
}): GameBridgeReactBindings<TState, TIntent, TAnchorMetadata>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { createContext, createElement, useCallback, useContext, useRef, useSyncExternalStore, } from "react";
|
|
3
|
+
export function useBridgeSnapshot(reader) {
|
|
4
|
+
return useSyncExternalStore(reader.subscribe, reader.getSnapshot, reader.getServerSnapshot);
|
|
5
|
+
}
|
|
6
|
+
export function useBridgeSelector(reader, selector, equals = Object.is) {
|
|
7
|
+
const selectorRef = useRef(selector);
|
|
8
|
+
const equalsRef = useRef(equals);
|
|
9
|
+
selectorRef.current = selector;
|
|
10
|
+
equalsRef.current = equals;
|
|
11
|
+
const cacheRef = useRef(undefined);
|
|
12
|
+
const getSelected = useCallback((getSnapshot) => {
|
|
13
|
+
const source = getSnapshot();
|
|
14
|
+
const selected = selectorRef.current(source);
|
|
15
|
+
const cached = cacheRef.current;
|
|
16
|
+
if (cached && cached.source === source && selectorRef.current === selector)
|
|
17
|
+
return cached.selected;
|
|
18
|
+
if (cached && equalsRef.current(cached.selected, selected)) {
|
|
19
|
+
cacheRef.current = { source, selected: cached.selected };
|
|
20
|
+
return cached.selected;
|
|
21
|
+
}
|
|
22
|
+
cacheRef.current = { source, selected };
|
|
23
|
+
return selected;
|
|
24
|
+
}, [reader, selector]);
|
|
25
|
+
const getSnapshot = useCallback(() => getSelected(reader.getSnapshot), [getSelected, reader]);
|
|
26
|
+
const getServerSnapshot = useCallback(() => getSelected(reader.getServerSnapshot), [getSelected, reader]);
|
|
27
|
+
return useSyncExternalStore(reader.subscribe, getSnapshot, getServerSnapshot);
|
|
28
|
+
}
|
|
29
|
+
export function createGameBridgeReactBindings(options) {
|
|
30
|
+
const displayName = options?.displayName?.trim() || "GameBridge";
|
|
31
|
+
const Context = createContext(null);
|
|
32
|
+
Context.displayName = `${displayName}Context`;
|
|
33
|
+
const Provider = ({ bridge, children }) => createElement(Context.Provider, { value: bridge }, children);
|
|
34
|
+
Provider.displayName = `${displayName}Provider`;
|
|
35
|
+
const useBridge = () => {
|
|
36
|
+
const bridge = useContext(Context);
|
|
37
|
+
if (!bridge)
|
|
38
|
+
throw new Error(`${displayName} context is missing; render ${displayName}Provider above this hook`);
|
|
39
|
+
return bridge;
|
|
40
|
+
};
|
|
41
|
+
const useStateSnapshot = () => useBridgeSnapshot(useBridge().state);
|
|
42
|
+
const useFrameSnapshot = () => useBridgeSnapshot(useBridge().frame);
|
|
43
|
+
const useStateSelector = (selector, equals) => useBridgeSelector(useBridge().state, selector, equals);
|
|
44
|
+
const useFrameSelector = (selector, equals) => useBridgeSelector(useBridge().frame, selector, equals);
|
|
45
|
+
const useProjectedAnchor = (id) => useFrameSelector((frame) => frame.anchors.find((anchor) => anchor.id === id) ?? null, Object.is);
|
|
46
|
+
return { Provider, useBridge, useStateSnapshot, useFrameSnapshot, useStateSelector, useFrameSelector, useProjectedAnchor };
|
|
47
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { assertJsonValue, isJsonValue } from "../core/serializable.js";
|
|
2
|
+
export function assertApproximatelyEqual(actual, expected, epsilon = 1e-9) {
|
|
3
|
+
if (!Number.isFinite(epsilon) || epsilon < 0) {
|
|
4
|
+
throw new RangeError("epsilon must be finite and non-negative");
|
|
5
|
+
}
|
|
6
|
+
if (!Number.isFinite(actual) || !Number.isFinite(expected) || Math.abs(actual - expected) > epsilon) {
|
|
7
|
+
throw new Error(`Expected finite numbers to be within ${epsilon}`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BridgeReader } from "../core/channel.js";
|
|
2
|
+
export interface BridgeNotificationRecorder<TSnapshot> {
|
|
3
|
+
readonly snapshots: readonly TSnapshot[];
|
|
4
|
+
readonly revisions: readonly number[];
|
|
5
|
+
readonly unsubscribe: () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function recordBridgeNotifications<TSnapshot>(reader: BridgeReader<TSnapshot>): BridgeNotificationRecorder<TSnapshot>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function recordBridgeNotifications(reader) {
|
|
2
|
+
const snapshots = [];
|
|
3
|
+
const revisions = [];
|
|
4
|
+
const unsubscribe = reader.subscribe(() => {
|
|
5
|
+
snapshots.push(reader.getSnapshot());
|
|
6
|
+
revisions.push(reader.getRevision());
|
|
7
|
+
});
|
|
8
|
+
return { snapshots, revisions, unsubscribe };
|
|
9
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { BridgeScheduler } from "../core/coalesced-publisher.js";
|
|
2
|
+
export interface ManualBridgeScheduler extends BridgeScheduler<number> {
|
|
3
|
+
readonly flushNext: () => boolean;
|
|
4
|
+
readonly flushAll: () => number;
|
|
5
|
+
readonly getPendingCount: () => number;
|
|
6
|
+
readonly getRequestedCount: () => number;
|
|
7
|
+
readonly getCancelledCount: () => number;
|
|
8
|
+
readonly capture: (handle: number) => (() => void) | undefined;
|
|
9
|
+
}
|
|
10
|
+
export declare function createManualBridgeScheduler(): ManualBridgeScheduler;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export function createManualBridgeScheduler() {
|
|
2
|
+
let nextHandle = 1;
|
|
3
|
+
let requestedCount = 0;
|
|
4
|
+
let cancelledCount = 0;
|
|
5
|
+
const callbacks = new Map();
|
|
6
|
+
const captured = new Map();
|
|
7
|
+
return {
|
|
8
|
+
request: (callback) => {
|
|
9
|
+
const handle = nextHandle;
|
|
10
|
+
nextHandle += 1;
|
|
11
|
+
requestedCount += 1;
|
|
12
|
+
callbacks.set(handle, callback);
|
|
13
|
+
captured.set(handle, callback);
|
|
14
|
+
return handle;
|
|
15
|
+
},
|
|
16
|
+
cancel: (handle) => {
|
|
17
|
+
if (callbacks.delete(handle))
|
|
18
|
+
cancelledCount += 1;
|
|
19
|
+
},
|
|
20
|
+
flushNext: () => {
|
|
21
|
+
const entry = callbacks.entries().next().value;
|
|
22
|
+
if (entry === undefined)
|
|
23
|
+
return false;
|
|
24
|
+
callbacks.delete(entry[0]);
|
|
25
|
+
entry[1]();
|
|
26
|
+
return true;
|
|
27
|
+
},
|
|
28
|
+
flushAll: () => {
|
|
29
|
+
let count = 0;
|
|
30
|
+
while (callbacks.size > 0) {
|
|
31
|
+
const entry = callbacks.entries().next().value;
|
|
32
|
+
callbacks.delete(entry[0]);
|
|
33
|
+
entry[1]();
|
|
34
|
+
count += 1;
|
|
35
|
+
}
|
|
36
|
+
return count;
|
|
37
|
+
},
|
|
38
|
+
getPendingCount: () => callbacks.size,
|
|
39
|
+
getRequestedCount: () => requestedCount,
|
|
40
|
+
getCancelledCount: () => cancelledCount,
|
|
41
|
+
capture: (handle) => captured.get(handle),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Core Contracts
|
|
2
|
+
|
|
3
|
+
A channel separates a read-only `BridgeReader` from a write-only `BridgePublisher`. Snapshots keep reference identity until an accepted publication, server snapshots stay fixed, listeners use stable iteration, reentrant publications drain FIFO, and close is idempotent.
|
|
4
|
+
|
|
5
|
+
`createGameBridge` composes independent app-state and atomic frame channels with a synchronous typed intent sink. Destroy clears anchors through a terminal frame before closing channels. Production paths do not clone or stringify snapshots; use test utilities to assert JSON compatibility.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# DOM Adapter
|
|
2
|
+
|
|
3
|
+
`measureGameSurface` reads canvas backing size, the bitmap content box, and a selected overlay reference box. It returns typed failures for missing DOM, disconnected or zero-sized surfaces, invalid measurements, and unsupported transforms.
|
|
4
|
+
|
|
5
|
+
`observeGameSurface` coalesces resize, scroll, visual viewport, and fullscreen changes. Disconnect removes observers, listeners, and scheduled work. Importing the module performs no measurement.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Errors and Performance
|
|
2
|
+
|
|
3
|
+
Expected runtime failures are discriminated results and bounded diagnostics; package code never logs implicitly. Invalid points and anchors are isolated where safe, while duplicate IDs or invalid transforms reject the current frame.
|
|
4
|
+
|
|
5
|
+
Projection is constant time per point after compilation and linear per selected batch. Frame staging is latest-value-wins with one notification per scheduling boundary. Avoid deep equality, cloning, stringification, and unbounded diagnostic history in frame producers. Keep DOM-selected anchors small; treat batches above 128 as an application review threshold rather than a package error.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Geometry
|
|
2
|
+
|
|
3
|
+
Coordinate brands distinguish world, camera, logical game, canvas backing, canvas CSS, client, overlay, and normalized values. The forward affine chain is compiled once and inverted once, then reused for point and anchor projection.
|
|
4
|
+
|
|
5
|
+
Visibility uses half-open bounds and reports camera, canvas, and overlay membership separately. Canvas backing-to-CSS scale comes from measured dimensions rather than global DPR. Inverse projection supports reject, allow, and camera-clamp policies. Placement ranks overflow, exclusion overlap, and fallback order deterministically.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Game Bridge
|
|
2
|
+
|
|
3
|
+
Choose the root for immutable channels, the state/frame bridge, intents, and diagnostics. Choose `geometry` for pure affine math; `dom`, `react`, and `phaser` only at those runtime boundaries; and `test-utils` only in tests. Applications own gameplay and presentation.
|
|
4
|
+
|
|
5
|
+
Public imports are `@zvk/game-bridge`, `/geometry`, `/dom`, `/react`, `/phaser`, and `/test-utils`.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Migration
|
|
2
|
+
|
|
3
|
+
Create one bridge at the application boundary, preserve app-owned selectors and action types, and migrate one selected overlay. Compare old and new projection in tests, then replace the adopted local external-store hook and transform math with public subpaths.
|
|
4
|
+
|
|
5
|
+
Verify pan, zoom, rotation, viewport offset, CSS scale, resize, pointer mapping, and scene restart. Remove the old adopted path only after parity. Rollback restores that narrow seam; no save or simulation schema must change.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# Phaser Adapter
|
|
2
|
+
|
|
3
|
+
The Phaser subpath accepts a small structural camera, scale, scene, and emitter surface and performs no runtime Phaser import. Version 0.1 proves Phaser `^3.90.0`; other major lines are not claimed until the same real-browser contract passes.
|
|
4
|
+
|
|
5
|
+
Select one camera explicitly. Capture at the render boundary, sample only app-selected anchors, and publish transform plus anchors atomically. Temporary capture failures clear anchors with `not-ready`; shutdown publishes `disconnected`; stale generation callbacks cannot publish after cleanup.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# React Adapter
|
|
2
|
+
|
|
3
|
+
`useBridgeSnapshot` delegates to `useSyncExternalStore` with the reader's fixed server snapshot. `useBridgeSelector` preserves selected reference identity when equality succeeds. `createGameBridgeReactBindings` creates an explicit app-typed provider and hooks without a package singleton.
|
|
4
|
+
|
|
5
|
+
Create matching server/client initial snapshots, begin runtime capture after mount, and destroy runtime connectors before destroying the bridge. Strict Mode must settle to one subscription.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createGameBridge } from "@zvk/game-bridge";
|
|
2
|
+
import { createGameBridgeReactBindings } from "@zvk/game-bridge/react";
|
|
3
|
+
|
|
4
|
+
type State = { readonly labelById: Readonly<Record<string, string>> };
|
|
5
|
+
type Intent = { readonly type: "marker.select"; readonly id: string };
|
|
6
|
+
|
|
7
|
+
export const created = createGameBridge<State, Intent>({ initialState: { labelById: {} } });
|
|
8
|
+
export const bindings = createGameBridgeReactBindings<State, Intent>({ displayName: "ExampleBridge" });
|
|
9
|
+
|
|
10
|
+
export function MarkerList() {
|
|
11
|
+
const frame = bindings.useFrameSnapshot();
|
|
12
|
+
const labels = bindings.useStateSelector((state) => state.labelById);
|
|
13
|
+
return <>{frame.anchors.map((anchor) => <span key={anchor.id}>{labels[anchor.id]}</span>)}</>;
|
|
14
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zvk/game-bridge",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Typed snapshots, coordinate transforms, and optional React and Phaser adapters for browser-game UI bridges.",
|
|
5
|
+
"private": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/brandon-schabel/zvk.git"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"docs",
|
|
19
|
+
"CHANGELOG.md",
|
|
20
|
+
"LICENSE.md",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"import": "./dist/index.js",
|
|
28
|
+
"default": "./dist/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./geometry": {
|
|
31
|
+
"types": "./dist/geometry/index.d.ts",
|
|
32
|
+
"import": "./dist/geometry/index.js",
|
|
33
|
+
"default": "./dist/geometry/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./dom": {
|
|
36
|
+
"types": "./dist/dom/index.d.ts",
|
|
37
|
+
"import": "./dist/dom/index.js",
|
|
38
|
+
"default": "./dist/dom/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./react": {
|
|
41
|
+
"types": "./dist/react/index.d.ts",
|
|
42
|
+
"import": "./dist/react/index.js",
|
|
43
|
+
"default": "./dist/react/index.js"
|
|
44
|
+
},
|
|
45
|
+
"./phaser": {
|
|
46
|
+
"types": "./dist/phaser/index.d.ts",
|
|
47
|
+
"import": "./dist/phaser/index.js",
|
|
48
|
+
"default": "./dist/phaser/index.js"
|
|
49
|
+
},
|
|
50
|
+
"./test-utils": {
|
|
51
|
+
"types": "./dist/test-utils/index.d.ts",
|
|
52
|
+
"import": "./dist/test-utils/index.js",
|
|
53
|
+
"default": "./dist/test-utils/index.js"
|
|
54
|
+
},
|
|
55
|
+
"./package.json": "./package.json"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"clean": "bun run scripts/clean.mjs",
|
|
59
|
+
"build:types": "tsc -p tsconfig.build.json",
|
|
60
|
+
"build": "bun run clean && bun run build:types",
|
|
61
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
62
|
+
"test": "vitest run src --maxWorkers=2",
|
|
63
|
+
"test:ssr": "vitest run tests/ssr --environment node",
|
|
64
|
+
"test:exports": "vitest run tests/exports --environment node",
|
|
65
|
+
"test:types": "tsd",
|
|
66
|
+
"test:docs-examples": "bun run build && vitest run tests/docs-examples --environment jsdom",
|
|
67
|
+
"test:browser": "bun run build && playwright test --config playwright.config.ts",
|
|
68
|
+
"test:packed-consumer": "bun run build && bun run scripts/check-packed-consumer.mjs",
|
|
69
|
+
"benchmark:geometry": "bun run build && bun run scripts/benchmark-geometry.mjs",
|
|
70
|
+
"docs:lint": "bun run scripts/lint-docs.mjs",
|
|
71
|
+
"validate:exports": "bun run scripts/validate-exports.mjs",
|
|
72
|
+
"validate:source-policy": "bun run scripts/validate-source-policy.mjs",
|
|
73
|
+
"tarball:inspect": "bun run scripts/check-tarball.mjs",
|
|
74
|
+
"pack:dry": "bun pm pack --dry-run",
|
|
75
|
+
"preflight": "bun run build && bun run typecheck && bun run test && bun run test:ssr && bun run test:types && bun run test:exports && bun run test:docs-examples && bun run test:browser && bun run test:packed-consumer && bun run docs:lint && bun run validate:exports && bun run validate:source-policy && bun run tarball:inspect && bun run pack:dry",
|
|
76
|
+
"preflight:ci": "bun run build && bun run typecheck && bun run test && bun run test:ssr && bun run test:types && bun run test:exports && bun run test:docs-examples && bun run test:browser && bun run test:packed-consumer && bun run docs:lint && bun run validate:exports && bun run validate:source-policy && bun run tarball:inspect && bun run pack:dry"
|
|
77
|
+
},
|
|
78
|
+
"dependencies": {},
|
|
79
|
+
"peerDependencies": {
|
|
80
|
+
"phaser": "^3.90.0",
|
|
81
|
+
"react": "^19.0.0"
|
|
82
|
+
},
|
|
83
|
+
"peerDependenciesMeta": {
|
|
84
|
+
"phaser": {
|
|
85
|
+
"optional": true
|
|
86
|
+
},
|
|
87
|
+
"react": {
|
|
88
|
+
"optional": true
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"devDependencies": {
|
|
92
|
+
"@playwright/test": "^1.60.0",
|
|
93
|
+
"@testing-library/react": "^16.3.2",
|
|
94
|
+
"@types/node": "^25.9.1",
|
|
95
|
+
"@types/react": "^19.2.16",
|
|
96
|
+
"@types/react-dom": "^19.2.3",
|
|
97
|
+
"jsdom": "^28.1.0",
|
|
98
|
+
"phaser": "^3.90.0",
|
|
99
|
+
"react": "^19.2.3",
|
|
100
|
+
"react-dom": "^19.2.3",
|
|
101
|
+
"tsd": "^0.33.0",
|
|
102
|
+
"typescript": "^6.0.3",
|
|
103
|
+
"vite": "^8.0.16",
|
|
104
|
+
"vitest": "^4.1.8"
|
|
105
|
+
},
|
|
106
|
+
"tsd": {
|
|
107
|
+
"directory": "tests/types"
|
|
108
|
+
}
|
|
109
|
+
}
|