automatick 0.0.1
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/LICENSE +20 -0
- package/README.md +106 -0
- package/dist/chunk-66FUVAAG.js +7 -0
- package/dist/chunk-AIKB2FNR.js +17 -0
- package/dist/chunk-HTH6FQ7C.js +192 -0
- package/dist/chunk-OA6FGXTP.js +9 -0
- package/dist/chunk-SK5SHIWY.js +13 -0
- package/dist/chunk-YNLOTPDY.js +206 -0
- package/dist/engine.cjs +231 -0
- package/dist/engine.d.cts +72 -0
- package/dist/engine.d.ts +72 -0
- package/dist/engine.js +8 -0
- package/dist/react/EngineContext.cjs +43 -0
- package/dist/react/EngineContext.d.cts +18 -0
- package/dist/react/EngineContext.d.ts +18 -0
- package/dist/react/EngineContext.js +6 -0
- package/dist/react/PerformanceOverlay.cjs +341 -0
- package/dist/react/PerformanceOverlay.d.cts +9 -0
- package/dist/react/PerformanceOverlay.d.ts +9 -0
- package/dist/react/PerformanceOverlay.js +290 -0
- package/dist/react/Simulation.cjs +481 -0
- package/dist/react/Simulation.d.cts +31 -0
- package/dist/react/Simulation.d.ts +31 -0
- package/dist/react/Simulation.js +235 -0
- package/dist/react/SimulationContext.cjs +41 -0
- package/dist/react/SimulationContext.d.cts +25 -0
- package/dist/react/SimulationContext.d.ts +25 -0
- package/dist/react/SimulationContext.js +6 -0
- package/dist/react/SimulationControls.cjs +298 -0
- package/dist/react/SimulationControls.d.cts +33 -0
- package/dist/react/SimulationControls.d.ts +33 -0
- package/dist/react/SimulationControls.js +80 -0
- package/dist/react/controlPrimitives.cjs +247 -0
- package/dist/react/controlPrimitives.d.cts +45 -0
- package/dist/react/controlPrimitives.d.ts +45 -0
- package/dist/react/controlPrimitives.js +22 -0
- package/dist/react/hooks.cjs +53 -0
- package/dist/react/hooks.d.cts +26 -0
- package/dist/react/hooks.d.ts +26 -0
- package/dist/react/hooks.js +7 -0
- package/dist/react/stableCallback.cjs +47 -0
- package/dist/react/stableCallback.d.cts +3 -0
- package/dist/react/stableCallback.d.ts +3 -0
- package/dist/react/stableCallback.js +6 -0
- package/dist/react/useSimulationCanvas.cjs +92 -0
- package/dist/react/useSimulationCanvas.d.cts +38 -0
- package/dist/react/useSimulationCanvas.d.ts +38 -0
- package/dist/react/useSimulationCanvas.js +53 -0
- package/dist/sim.cjs +32 -0
- package/dist/sim.d.cts +40 -0
- package/dist/sim.d.ts +40 -0
- package/dist/sim.js +7 -0
- package/dist/worker/createSimWorker.cjs +147 -0
- package/dist/worker/createSimWorker.d.cts +19 -0
- package/dist/worker/createSimWorker.d.ts +19 -0
- package/dist/worker/createSimWorker.js +122 -0
- package/dist/worker/protocol.cjs +18 -0
- package/dist/worker/protocol.d.cts +59 -0
- package/dist/worker/protocol.d.ts +59 -0
- package/dist/worker/protocol.js +0 -0
- package/dist/worker/workerRunner.cjs +100 -0
- package/dist/worker/workerRunner.d.cts +30 -0
- package/dist/worker/workerRunner.d.ts +30 -0
- package/dist/worker/workerRunner.js +73 -0
- package/package.json +102 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/react/useSimulationCanvas.ts
|
|
31
|
+
var useSimulationCanvas_exports = {};
|
|
32
|
+
__export(useSimulationCanvas_exports, {
|
|
33
|
+
useSimulationCanvas: () => useSimulationCanvas
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(useSimulationCanvas_exports);
|
|
36
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
37
|
+
|
|
38
|
+
// src/react/EngineContext.tsx
|
|
39
|
+
var import_react = __toESM(require("react"), 1);
|
|
40
|
+
var EngineContext = import_react.default.createContext(
|
|
41
|
+
null
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
// src/react/useSimulationCanvas.ts
|
|
45
|
+
function useSimulationCanvas(draw) {
|
|
46
|
+
const engineCtx = import_react2.default.useContext(EngineContext);
|
|
47
|
+
if (!engineCtx) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
"useSimulationCanvas must be used within a <Simulation>"
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
const canvasRef = import_react2.default.useRef(null);
|
|
53
|
+
const drawRef = import_react2.default.useRef(draw);
|
|
54
|
+
drawRef.current = draw;
|
|
55
|
+
import_react2.default.useEffect(() => {
|
|
56
|
+
const canvas = canvasRef.current;
|
|
57
|
+
if (canvas) {
|
|
58
|
+
const ctx = canvas.getContext("2d");
|
|
59
|
+
if (ctx) {
|
|
60
|
+
const snap = engineCtx.getSnapshot();
|
|
61
|
+
const t0 = performance.now();
|
|
62
|
+
drawRef.current(ctx, {
|
|
63
|
+
data: snap.data,
|
|
64
|
+
params: snap.params,
|
|
65
|
+
tick: snap.tick
|
|
66
|
+
});
|
|
67
|
+
engineCtx.recordDrawTime(snap.tick, performance.now() - t0);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const unsubscribe = engineCtx.subscribe(
|
|
71
|
+
(snap) => {
|
|
72
|
+
const canvas2 = canvasRef.current;
|
|
73
|
+
if (!canvas2) return;
|
|
74
|
+
const ctx = canvas2.getContext("2d");
|
|
75
|
+
if (!ctx) return;
|
|
76
|
+
const t0 = performance.now();
|
|
77
|
+
drawRef.current(ctx, {
|
|
78
|
+
data: snap.data,
|
|
79
|
+
params: snap.params,
|
|
80
|
+
tick: snap.tick
|
|
81
|
+
});
|
|
82
|
+
engineCtx.recordDrawTime(snap.tick, performance.now() - t0);
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
return unsubscribe;
|
|
86
|
+
}, [engineCtx]);
|
|
87
|
+
return canvasRef;
|
|
88
|
+
}
|
|
89
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
90
|
+
0 && (module.exports = {
|
|
91
|
+
useSimulationCanvas
|
|
92
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { SimModule } from '../sim.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Draw callback signature for useSimulationCanvas.
|
|
6
|
+
* Called imperatively on every engine snapshot — no React re-render involved.
|
|
7
|
+
*/
|
|
8
|
+
type CanvasDrawFn<Data, Params> = (ctx: CanvasRenderingContext2D, snapshot: {
|
|
9
|
+
data: Data;
|
|
10
|
+
params: Params;
|
|
11
|
+
tick: number;
|
|
12
|
+
}) => void;
|
|
13
|
+
type InferDraw<T, FallbackParams> = T extends SimModule<infer D, infer P> ? CanvasDrawFn<D, P> : CanvasDrawFn<T, FallbackParams>;
|
|
14
|
+
/**
|
|
15
|
+
* Subscribe to simulation snapshots and draw to a canvas without React re-renders.
|
|
16
|
+
*
|
|
17
|
+
* Returns a ref to attach to a `<canvas>` element. The `draw` callback is called
|
|
18
|
+
* directly from the engine's subscription — it bypasses React's state/reconciliation
|
|
19
|
+
* entirely. Draw timing is recorded automatically to the engine's performance buffer.
|
|
20
|
+
*
|
|
21
|
+
* For DOM/React rendering, use `useSimulation()` instead.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* function BoidsCanvas() {
|
|
26
|
+
* const canvasRef = useSimulationCanvas<typeof boidsSim>((ctx, { data, params }) => {
|
|
27
|
+
* ctx.clearRect(0, 0, params.width, params.height);
|
|
28
|
+
* data.forEach(boid => {
|
|
29
|
+
* ctx.fillRect(boid.x, boid.y, 3, 3);
|
|
30
|
+
* });
|
|
31
|
+
* });
|
|
32
|
+
* return <canvas ref={canvasRef} width={400} height={400} />;
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
declare function useSimulationCanvas<T = unknown, FallbackParams = unknown>(draw: InferDraw<T, FallbackParams>): React.RefObject<HTMLCanvasElement>;
|
|
37
|
+
|
|
38
|
+
export { type CanvasDrawFn, useSimulationCanvas };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { SimModule } from '../sim.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Draw callback signature for useSimulationCanvas.
|
|
6
|
+
* Called imperatively on every engine snapshot — no React re-render involved.
|
|
7
|
+
*/
|
|
8
|
+
type CanvasDrawFn<Data, Params> = (ctx: CanvasRenderingContext2D, snapshot: {
|
|
9
|
+
data: Data;
|
|
10
|
+
params: Params;
|
|
11
|
+
tick: number;
|
|
12
|
+
}) => void;
|
|
13
|
+
type InferDraw<T, FallbackParams> = T extends SimModule<infer D, infer P> ? CanvasDrawFn<D, P> : CanvasDrawFn<T, FallbackParams>;
|
|
14
|
+
/**
|
|
15
|
+
* Subscribe to simulation snapshots and draw to a canvas without React re-renders.
|
|
16
|
+
*
|
|
17
|
+
* Returns a ref to attach to a `<canvas>` element. The `draw` callback is called
|
|
18
|
+
* directly from the engine's subscription — it bypasses React's state/reconciliation
|
|
19
|
+
* entirely. Draw timing is recorded automatically to the engine's performance buffer.
|
|
20
|
+
*
|
|
21
|
+
* For DOM/React rendering, use `useSimulation()` instead.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* function BoidsCanvas() {
|
|
26
|
+
* const canvasRef = useSimulationCanvas<typeof boidsSim>((ctx, { data, params }) => {
|
|
27
|
+
* ctx.clearRect(0, 0, params.width, params.height);
|
|
28
|
+
* data.forEach(boid => {
|
|
29
|
+
* ctx.fillRect(boid.x, boid.y, 3, 3);
|
|
30
|
+
* });
|
|
31
|
+
* });
|
|
32
|
+
* return <canvas ref={canvasRef} width={400} height={400} />;
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
declare function useSimulationCanvas<T = unknown, FallbackParams = unknown>(draw: InferDraw<T, FallbackParams>): React.RefObject<HTMLCanvasElement>;
|
|
37
|
+
|
|
38
|
+
export { type CanvasDrawFn, useSimulationCanvas };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EngineContext
|
|
3
|
+
} from "../chunk-OA6FGXTP.js";
|
|
4
|
+
|
|
5
|
+
// src/react/useSimulationCanvas.ts
|
|
6
|
+
import React from "react";
|
|
7
|
+
function useSimulationCanvas(draw) {
|
|
8
|
+
const engineCtx = React.useContext(EngineContext);
|
|
9
|
+
if (!engineCtx) {
|
|
10
|
+
throw new Error(
|
|
11
|
+
"useSimulationCanvas must be used within a <Simulation>"
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
const canvasRef = React.useRef(null);
|
|
15
|
+
const drawRef = React.useRef(draw);
|
|
16
|
+
drawRef.current = draw;
|
|
17
|
+
React.useEffect(() => {
|
|
18
|
+
const canvas = canvasRef.current;
|
|
19
|
+
if (canvas) {
|
|
20
|
+
const ctx = canvas.getContext("2d");
|
|
21
|
+
if (ctx) {
|
|
22
|
+
const snap = engineCtx.getSnapshot();
|
|
23
|
+
const t0 = performance.now();
|
|
24
|
+
drawRef.current(ctx, {
|
|
25
|
+
data: snap.data,
|
|
26
|
+
params: snap.params,
|
|
27
|
+
tick: snap.tick
|
|
28
|
+
});
|
|
29
|
+
engineCtx.recordDrawTime(snap.tick, performance.now() - t0);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const unsubscribe = engineCtx.subscribe(
|
|
33
|
+
(snap) => {
|
|
34
|
+
const canvas2 = canvasRef.current;
|
|
35
|
+
if (!canvas2) return;
|
|
36
|
+
const ctx = canvas2.getContext("2d");
|
|
37
|
+
if (!ctx) return;
|
|
38
|
+
const t0 = performance.now();
|
|
39
|
+
drawRef.current(ctx, {
|
|
40
|
+
data: snap.data,
|
|
41
|
+
params: snap.params,
|
|
42
|
+
tick: snap.tick
|
|
43
|
+
});
|
|
44
|
+
engineCtx.recordDrawTime(snap.tick, performance.now() - t0);
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
return unsubscribe;
|
|
48
|
+
}, [engineCtx]);
|
|
49
|
+
return canvasRef;
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
useSimulationCanvas
|
|
53
|
+
};
|
package/dist/sim.cjs
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/sim.ts
|
|
21
|
+
var sim_exports = {};
|
|
22
|
+
__export(sim_exports, {
|
|
23
|
+
defineSim: () => defineSim
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(sim_exports);
|
|
26
|
+
function defineSim(sim) {
|
|
27
|
+
return sim;
|
|
28
|
+
}
|
|
29
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
30
|
+
0 && (module.exports = {
|
|
31
|
+
defineSim
|
|
32
|
+
});
|
package/dist/sim.d.cts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Arguments passed to the `step` function on each tick. */
|
|
2
|
+
type StepArgs<Data, Params> = {
|
|
3
|
+
data: Data;
|
|
4
|
+
params: Params;
|
|
5
|
+
tick: number;
|
|
6
|
+
};
|
|
7
|
+
/** A simulation module: the pure business logic that automatick drives. */
|
|
8
|
+
type SimModule<Data, Params> = {
|
|
9
|
+
/** Create initial simulation state from params. Called on engine creation and on resetWith(). */
|
|
10
|
+
init: (params: Params) => Data;
|
|
11
|
+
/** Advance the simulation by one tick. Must be pure and synchronous. */
|
|
12
|
+
step: (args: StepArgs<Data, Params>) => Data;
|
|
13
|
+
/** Optional termination predicate. Checked after each step. If it returns true, the simulation stops. */
|
|
14
|
+
shouldStop?: (data: Data, params: Params) => boolean;
|
|
15
|
+
/** Default parameter values. Used at engine creation if no params override is provided. */
|
|
16
|
+
defaultParams: Params;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Define a simulation module with full type inference.
|
|
20
|
+
*
|
|
21
|
+
* This is an identity function — it returns its argument unchanged. Its purpose is to
|
|
22
|
+
* enable TypeScript to infer `Data` and `Params` from the `init` and `step` implementations,
|
|
23
|
+
* so the developer never needs to annotate types inside those functions.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* export default defineSim<{ count: number }, { increment: number }>({
|
|
28
|
+
* defaultParams: { increment: 1 },
|
|
29
|
+
* init: (params) => ({ count: 0 }),
|
|
30
|
+
* step: ({ data, params }) => ({ count: data.count + params.increment }),
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
declare function defineSim<Data, Params>(sim: SimModule<Data, Params>): SimModule<Data, Params>;
|
|
35
|
+
/** Extract the Data type from a SimModule. */
|
|
36
|
+
type SimData<M> = M extends SimModule<infer D, infer _P> ? D : never;
|
|
37
|
+
/** Extract the Params type from a SimModule. */
|
|
38
|
+
type SimParams<M> = M extends SimModule<infer _D, infer P> ? P : never;
|
|
39
|
+
|
|
40
|
+
export { type SimData, type SimModule, type SimParams, type StepArgs, defineSim };
|
package/dist/sim.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Arguments passed to the `step` function on each tick. */
|
|
2
|
+
type StepArgs<Data, Params> = {
|
|
3
|
+
data: Data;
|
|
4
|
+
params: Params;
|
|
5
|
+
tick: number;
|
|
6
|
+
};
|
|
7
|
+
/** A simulation module: the pure business logic that automatick drives. */
|
|
8
|
+
type SimModule<Data, Params> = {
|
|
9
|
+
/** Create initial simulation state from params. Called on engine creation and on resetWith(). */
|
|
10
|
+
init: (params: Params) => Data;
|
|
11
|
+
/** Advance the simulation by one tick. Must be pure and synchronous. */
|
|
12
|
+
step: (args: StepArgs<Data, Params>) => Data;
|
|
13
|
+
/** Optional termination predicate. Checked after each step. If it returns true, the simulation stops. */
|
|
14
|
+
shouldStop?: (data: Data, params: Params) => boolean;
|
|
15
|
+
/** Default parameter values. Used at engine creation if no params override is provided. */
|
|
16
|
+
defaultParams: Params;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Define a simulation module with full type inference.
|
|
20
|
+
*
|
|
21
|
+
* This is an identity function — it returns its argument unchanged. Its purpose is to
|
|
22
|
+
* enable TypeScript to infer `Data` and `Params` from the `init` and `step` implementations,
|
|
23
|
+
* so the developer never needs to annotate types inside those functions.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* export default defineSim<{ count: number }, { increment: number }>({
|
|
28
|
+
* defaultParams: { increment: 1 },
|
|
29
|
+
* init: (params) => ({ count: 0 }),
|
|
30
|
+
* step: ({ data, params }) => ({ count: data.count + params.increment }),
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
declare function defineSim<Data, Params>(sim: SimModule<Data, Params>): SimModule<Data, Params>;
|
|
35
|
+
/** Extract the Data type from a SimModule. */
|
|
36
|
+
type SimData<M> = M extends SimModule<infer D, infer _P> ? D : never;
|
|
37
|
+
/** Extract the Params type from a SimModule. */
|
|
38
|
+
type SimParams<M> = M extends SimModule<infer _D, infer P> ? P : never;
|
|
39
|
+
|
|
40
|
+
export { type SimData, type SimModule, type SimParams, type StepArgs, defineSim };
|
package/dist/sim.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/worker/createSimWorker.ts
|
|
21
|
+
var createSimWorker_exports = {};
|
|
22
|
+
__export(createSimWorker_exports, {
|
|
23
|
+
createSimWorker: () => createSimWorker
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(createSimWorker_exports);
|
|
26
|
+
var WORKER_SCRIPT = `
|
|
27
|
+
let engine = null;
|
|
28
|
+
let loopTimer = null;
|
|
29
|
+
let snapshotIntervalMs = 16;
|
|
30
|
+
let lastSnapshotMs = 0;
|
|
31
|
+
let ticksPerFrame = 1;
|
|
32
|
+
let delayMs = 0;
|
|
33
|
+
|
|
34
|
+
function emitSnapshot() {
|
|
35
|
+
if (!engine) return;
|
|
36
|
+
postMessage({ kind: 'snapshot', snapshot: engine.getSnapshot() });
|
|
37
|
+
lastSnapshotMs = performance.now();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function tickLoop() {
|
|
41
|
+
if (!engine || engine.getStatus() !== 'playing') return;
|
|
42
|
+
|
|
43
|
+
for (let i = 0; i < ticksPerFrame; i++) {
|
|
44
|
+
engine.advance(1);
|
|
45
|
+
const s = engine.getStatus();
|
|
46
|
+
if (s === 'stopped') { emitSnapshot(); return; }
|
|
47
|
+
if (s !== 'paused') break;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// advance() transitions to paused; resume playing for the next batch
|
|
51
|
+
if (engine.getStatus() === 'paused') engine.play();
|
|
52
|
+
|
|
53
|
+
if (performance.now() - lastSnapshotMs >= snapshotIntervalMs) emitSnapshot();
|
|
54
|
+
loopTimer = setTimeout(tickLoop, delayMs);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function stopLoop() {
|
|
58
|
+
if (loopTimer !== null) { clearTimeout(loopTimer); loopTimer = null; }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
self.onmessage = async (event) => {
|
|
62
|
+
const msg = event.data;
|
|
63
|
+
try {
|
|
64
|
+
switch (msg.kind) {
|
|
65
|
+
case 'init': {
|
|
66
|
+
delayMs = msg.config.delayMs || 0;
|
|
67
|
+
ticksPerFrame = msg.config.ticksPerFrame || 1;
|
|
68
|
+
snapshotIntervalMs = msg.config.snapshotIntervalMs || 16;
|
|
69
|
+
|
|
70
|
+
const [simMod, engineMod] = await Promise.all([
|
|
71
|
+
import(msg.moduleUrl),
|
|
72
|
+
import(msg.engineUrl),
|
|
73
|
+
]);
|
|
74
|
+
const sim = simMod.default;
|
|
75
|
+
engine = engineMod.createEngine({
|
|
76
|
+
init: sim.init,
|
|
77
|
+
step: sim.step,
|
|
78
|
+
shouldStop: sim.shouldStop,
|
|
79
|
+
initialParams: msg.params,
|
|
80
|
+
maxTime: msg.config.maxTime,
|
|
81
|
+
});
|
|
82
|
+
postMessage({ kind: 'ready' });
|
|
83
|
+
emitSnapshot();
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case 'play':
|
|
87
|
+
if (!engine) return;
|
|
88
|
+
engine.play(); emitSnapshot(); stopLoop(); loopTimer = setTimeout(tickLoop, 0);
|
|
89
|
+
break;
|
|
90
|
+
case 'pause':
|
|
91
|
+
if (!engine) return;
|
|
92
|
+
stopLoop(); engine.pause(); emitSnapshot();
|
|
93
|
+
break;
|
|
94
|
+
case 'stop':
|
|
95
|
+
if (!engine) return;
|
|
96
|
+
stopLoop(); engine.stop(); emitSnapshot();
|
|
97
|
+
break;
|
|
98
|
+
case 'seek':
|
|
99
|
+
if (!engine) return;
|
|
100
|
+
stopLoop(); engine.seek(msg.tick); emitSnapshot();
|
|
101
|
+
break;
|
|
102
|
+
case 'advance':
|
|
103
|
+
if (!engine) return;
|
|
104
|
+
engine.advance(msg.count); emitSnapshot();
|
|
105
|
+
break;
|
|
106
|
+
case 'setParams':
|
|
107
|
+
if (!engine) return;
|
|
108
|
+
engine.setParams(msg.patch); emitSnapshot();
|
|
109
|
+
break;
|
|
110
|
+
case 'resetWith':
|
|
111
|
+
if (!engine) return;
|
|
112
|
+
stopLoop(); engine.resetWith(msg.patch); emitSnapshot();
|
|
113
|
+
break;
|
|
114
|
+
case 'destroy':
|
|
115
|
+
stopLoop();
|
|
116
|
+
if (engine) { engine.destroy(); engine = null; }
|
|
117
|
+
self.close();
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
} catch (err) {
|
|
121
|
+
postMessage({ kind: 'error', error: { message: err.message, stack: err.stack } });
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
`;
|
|
125
|
+
function createSimWorker(options) {
|
|
126
|
+
const blob = new Blob([WORKER_SCRIPT], { type: "text/javascript" });
|
|
127
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
128
|
+
const worker = new Worker(blobUrl, { type: "module" });
|
|
129
|
+
worker.addEventListener("message", function cleanup(event) {
|
|
130
|
+
if (event.data?.kind === "ready" || event.data?.kind === "error") {
|
|
131
|
+
URL.revokeObjectURL(blobUrl);
|
|
132
|
+
worker.removeEventListener("message", cleanup);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
worker.postMessage({
|
|
136
|
+
kind: "init",
|
|
137
|
+
moduleUrl: options.moduleUrl,
|
|
138
|
+
engineUrl: options.engineUrl,
|
|
139
|
+
params: options.initialParams,
|
|
140
|
+
config: options.config
|
|
141
|
+
});
|
|
142
|
+
return worker;
|
|
143
|
+
}
|
|
144
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
145
|
+
0 && (module.exports = {
|
|
146
|
+
createSimWorker
|
|
147
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { WorkerConfig } from './protocol.cjs';
|
|
2
|
+
import '../engine.cjs';
|
|
3
|
+
import '../sim.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a Web Worker that loads a sim module and runs the engine.
|
|
7
|
+
*
|
|
8
|
+
* Uses a blob URL with dynamic import() — works in Vite dev (modules served
|
|
9
|
+
* over HTTP) and in production builds (bundled chunks).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
declare function createSimWorker<Params>(options: {
|
|
13
|
+
moduleUrl: string;
|
|
14
|
+
engineUrl: string;
|
|
15
|
+
initialParams: Params;
|
|
16
|
+
config: WorkerConfig;
|
|
17
|
+
}): Worker;
|
|
18
|
+
|
|
19
|
+
export { createSimWorker };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { WorkerConfig } from './protocol.js';
|
|
2
|
+
import '../engine.js';
|
|
3
|
+
import '../sim.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a Web Worker that loads a sim module and runs the engine.
|
|
7
|
+
*
|
|
8
|
+
* Uses a blob URL with dynamic import() — works in Vite dev (modules served
|
|
9
|
+
* over HTTP) and in production builds (bundled chunks).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
declare function createSimWorker<Params>(options: {
|
|
13
|
+
moduleUrl: string;
|
|
14
|
+
engineUrl: string;
|
|
15
|
+
initialParams: Params;
|
|
16
|
+
config: WorkerConfig;
|
|
17
|
+
}): Worker;
|
|
18
|
+
|
|
19
|
+
export { createSimWorker };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// src/worker/createSimWorker.ts
|
|
2
|
+
var WORKER_SCRIPT = `
|
|
3
|
+
let engine = null;
|
|
4
|
+
let loopTimer = null;
|
|
5
|
+
let snapshotIntervalMs = 16;
|
|
6
|
+
let lastSnapshotMs = 0;
|
|
7
|
+
let ticksPerFrame = 1;
|
|
8
|
+
let delayMs = 0;
|
|
9
|
+
|
|
10
|
+
function emitSnapshot() {
|
|
11
|
+
if (!engine) return;
|
|
12
|
+
postMessage({ kind: 'snapshot', snapshot: engine.getSnapshot() });
|
|
13
|
+
lastSnapshotMs = performance.now();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function tickLoop() {
|
|
17
|
+
if (!engine || engine.getStatus() !== 'playing') return;
|
|
18
|
+
|
|
19
|
+
for (let i = 0; i < ticksPerFrame; i++) {
|
|
20
|
+
engine.advance(1);
|
|
21
|
+
const s = engine.getStatus();
|
|
22
|
+
if (s === 'stopped') { emitSnapshot(); return; }
|
|
23
|
+
if (s !== 'paused') break;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// advance() transitions to paused; resume playing for the next batch
|
|
27
|
+
if (engine.getStatus() === 'paused') engine.play();
|
|
28
|
+
|
|
29
|
+
if (performance.now() - lastSnapshotMs >= snapshotIntervalMs) emitSnapshot();
|
|
30
|
+
loopTimer = setTimeout(tickLoop, delayMs);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function stopLoop() {
|
|
34
|
+
if (loopTimer !== null) { clearTimeout(loopTimer); loopTimer = null; }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
self.onmessage = async (event) => {
|
|
38
|
+
const msg = event.data;
|
|
39
|
+
try {
|
|
40
|
+
switch (msg.kind) {
|
|
41
|
+
case 'init': {
|
|
42
|
+
delayMs = msg.config.delayMs || 0;
|
|
43
|
+
ticksPerFrame = msg.config.ticksPerFrame || 1;
|
|
44
|
+
snapshotIntervalMs = msg.config.snapshotIntervalMs || 16;
|
|
45
|
+
|
|
46
|
+
const [simMod, engineMod] = await Promise.all([
|
|
47
|
+
import(msg.moduleUrl),
|
|
48
|
+
import(msg.engineUrl),
|
|
49
|
+
]);
|
|
50
|
+
const sim = simMod.default;
|
|
51
|
+
engine = engineMod.createEngine({
|
|
52
|
+
init: sim.init,
|
|
53
|
+
step: sim.step,
|
|
54
|
+
shouldStop: sim.shouldStop,
|
|
55
|
+
initialParams: msg.params,
|
|
56
|
+
maxTime: msg.config.maxTime,
|
|
57
|
+
});
|
|
58
|
+
postMessage({ kind: 'ready' });
|
|
59
|
+
emitSnapshot();
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
case 'play':
|
|
63
|
+
if (!engine) return;
|
|
64
|
+
engine.play(); emitSnapshot(); stopLoop(); loopTimer = setTimeout(tickLoop, 0);
|
|
65
|
+
break;
|
|
66
|
+
case 'pause':
|
|
67
|
+
if (!engine) return;
|
|
68
|
+
stopLoop(); engine.pause(); emitSnapshot();
|
|
69
|
+
break;
|
|
70
|
+
case 'stop':
|
|
71
|
+
if (!engine) return;
|
|
72
|
+
stopLoop(); engine.stop(); emitSnapshot();
|
|
73
|
+
break;
|
|
74
|
+
case 'seek':
|
|
75
|
+
if (!engine) return;
|
|
76
|
+
stopLoop(); engine.seek(msg.tick); emitSnapshot();
|
|
77
|
+
break;
|
|
78
|
+
case 'advance':
|
|
79
|
+
if (!engine) return;
|
|
80
|
+
engine.advance(msg.count); emitSnapshot();
|
|
81
|
+
break;
|
|
82
|
+
case 'setParams':
|
|
83
|
+
if (!engine) return;
|
|
84
|
+
engine.setParams(msg.patch); emitSnapshot();
|
|
85
|
+
break;
|
|
86
|
+
case 'resetWith':
|
|
87
|
+
if (!engine) return;
|
|
88
|
+
stopLoop(); engine.resetWith(msg.patch); emitSnapshot();
|
|
89
|
+
break;
|
|
90
|
+
case 'destroy':
|
|
91
|
+
stopLoop();
|
|
92
|
+
if (engine) { engine.destroy(); engine = null; }
|
|
93
|
+
self.close();
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
} catch (err) {
|
|
97
|
+
postMessage({ kind: 'error', error: { message: err.message, stack: err.stack } });
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
`;
|
|
101
|
+
function createSimWorker(options) {
|
|
102
|
+
const blob = new Blob([WORKER_SCRIPT], { type: "text/javascript" });
|
|
103
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
104
|
+
const worker = new Worker(blobUrl, { type: "module" });
|
|
105
|
+
worker.addEventListener("message", function cleanup(event) {
|
|
106
|
+
if (event.data?.kind === "ready" || event.data?.kind === "error") {
|
|
107
|
+
URL.revokeObjectURL(blobUrl);
|
|
108
|
+
worker.removeEventListener("message", cleanup);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
worker.postMessage({
|
|
112
|
+
kind: "init",
|
|
113
|
+
moduleUrl: options.moduleUrl,
|
|
114
|
+
engineUrl: options.engineUrl,
|
|
115
|
+
params: options.initialParams,
|
|
116
|
+
config: options.config
|
|
117
|
+
});
|
|
118
|
+
return worker;
|
|
119
|
+
}
|
|
120
|
+
export {
|
|
121
|
+
createSimWorker
|
|
122
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __copyProps = (to, from, except, desc) => {
|
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
+
for (let key of __getOwnPropNames(from))
|
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
+
}
|
|
12
|
+
return to;
|
|
13
|
+
};
|
|
14
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
|
+
|
|
16
|
+
// src/worker/protocol.ts
|
|
17
|
+
var protocol_exports = {};
|
|
18
|
+
module.exports = __toCommonJS(protocol_exports);
|