automatick 0.0.1 → 0.0.3

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.
Files changed (44) hide show
  1. package/README.md +2 -0
  2. package/dist/{chunk-YNLOTPDY.js → chunk-A375T3UD.js} +39 -3
  3. package/dist/chunk-IKR53C2U.js +12 -0
  4. package/dist/chunk-LMHH7YPE.js +89 -0
  5. package/dist/chunk-VPS3ZXWI.js +132 -0
  6. package/dist/engine.cjs +42 -3
  7. package/dist/engine.d.cts +42 -18
  8. package/dist/engine.d.ts +42 -18
  9. package/dist/engine.js +2 -1
  10. package/dist/react/EngineContext.d.cts +4 -3
  11. package/dist/react/EngineContext.d.ts +4 -3
  12. package/dist/react/Simulation.cjs +341 -102
  13. package/dist/react/Simulation.d.cts +36 -16
  14. package/dist/react/Simulation.d.ts +36 -16
  15. package/dist/react/Simulation.js +93 -100
  16. package/dist/react/SimulationContext.d.cts +1 -2
  17. package/dist/react/SimulationContext.d.ts +1 -2
  18. package/dist/react/hooks.d.cts +1 -1
  19. package/dist/react/hooks.d.ts +1 -1
  20. package/dist/react/useSimulationCanvas.cjs +2 -10
  21. package/dist/react/useSimulationCanvas.d.cts +4 -7
  22. package/dist/react/useSimulationCanvas.d.ts +4 -7
  23. package/dist/react/useSimulationCanvas.js +2 -10
  24. package/dist/sim.cjs +7 -2
  25. package/dist/sim.d.cts +34 -14
  26. package/dist/sim.d.ts +34 -14
  27. package/dist/sim.js +6 -5
  28. package/dist/standalone/engine.js +242 -0
  29. package/dist/standalone/sim.js +11 -0
  30. package/dist/state.cjs +18 -0
  31. package/dist/state.d.cts +16 -0
  32. package/dist/state.d.ts +16 -0
  33. package/dist/state.js +0 -0
  34. package/dist/worker/createSimWorker.cjs +12 -3
  35. package/dist/worker/createSimWorker.d.cts +1 -2
  36. package/dist/worker/createSimWorker.d.ts +1 -2
  37. package/dist/worker/createSimWorker.js +3 -119
  38. package/dist/worker/protocol.d.cts +5 -5
  39. package/dist/worker/protocol.d.ts +5 -5
  40. package/dist/worker/workerRunner.cjs +21 -6
  41. package/dist/worker/workerRunner.d.cts +11 -3
  42. package/dist/worker/workerRunner.d.ts +11 -3
  43. package/dist/worker/workerRunner.js +3 -70
  44. package/package.json +2 -2
@@ -1,9 +1,16 @@
1
1
  import {
2
2
  useStableCallback
3
3
  } from "../chunk-SK5SHIWY.js";
4
+ import {
5
+ createSimWorker
6
+ } from "../chunk-VPS3ZXWI.js";
7
+ import {
8
+ createWorkerRunner
9
+ } from "../chunk-LMHH7YPE.js";
4
10
  import {
5
11
  createEngine
6
- } from "../chunk-YNLOTPDY.js";
12
+ } from "../chunk-A375T3UD.js";
13
+ import "../chunk-IKR53C2U.js";
7
14
  import {
8
15
  EngineContext
9
16
  } from "../chunk-OA6FGXTP.js";
@@ -15,18 +22,35 @@ import {
15
22
  import React from "react";
16
23
  import { jsx } from "react/jsx-runtime";
17
24
  function LocalSimulation(props) {
18
- const { sim, params: paramsProp, children, autoplay } = props;
25
+ const {
26
+ init,
27
+ step,
28
+ shouldStop,
29
+ defaultParams,
30
+ params: paramsProp,
31
+ children,
32
+ autoplay
33
+ } = props;
19
34
  const engineRef = React.useRef(null);
20
35
  if (!engineRef.current) {
21
- const initialParams = paramsProp ? { ...sim.defaultParams, ...paramsProp } : sim.defaultParams;
36
+ let initialParams;
37
+ if (defaultParams && paramsProp) {
38
+ initialParams = { ...defaultParams, ...paramsProp };
39
+ } else if (defaultParams) {
40
+ initialParams = defaultParams;
41
+ } else if (paramsProp) {
42
+ initialParams = paramsProp;
43
+ }
22
44
  engineRef.current = createEngine({
23
- init: sim.init,
24
- step: sim.step,
25
- shouldStop: sim.shouldStop,
45
+ init,
46
+ step,
47
+ shouldStop,
26
48
  initialParams,
27
49
  maxTime: props.maxTime,
28
50
  delayMs: props.delayMs,
29
- ticksPerFrame: props.ticksPerFrame
51
+ ticksPerFrame: props.ticksPerFrame,
52
+ // The React adapter drives its own rAF loop tied to component lifecycle.
53
+ autoFrame: false
30
54
  });
31
55
  }
32
56
  const engine = engineRef.current;
@@ -62,116 +86,70 @@ function LocalSimulation(props) {
62
86
  }, [engine]);
63
87
  return /* @__PURE__ */ jsx(SimulationProvider, { snapshot, backend: engine, children });
64
88
  }
89
+ function engineUrl() {
90
+ return new URL("../standalone/engine.js", import.meta.url).href;
91
+ }
65
92
  function WorkerSimulation(props) {
66
93
  const { children, autoplay } = props;
67
- const [backend, setBackend] = React.useState(
94
+ const [runner, setRunner] = React.useState(
95
+ null
96
+ );
97
+ const [snapshot, setSnapshot] = React.useState(
68
98
  null
69
99
  );
70
- const [snapshot, setSnapshot] = React.useState(null);
71
- const propsRef = React.useRef(props);
72
- propsRef.current = props;
73
100
  React.useEffect(() => {
74
- let cancelled = false;
75
- let runner = null;
76
- (async () => {
77
- const mod = await propsRef.current.worker();
78
- const simModule = mod.default;
79
- if (cancelled) return;
80
- const p = propsRef.current;
81
- const initialParams = p.params ? { ...simModule.defaultParams, ...p.params } : simModule.defaultParams;
82
- const engine = createEngine({
83
- init: simModule.init,
84
- step: simModule.step,
85
- shouldStop: simModule.shouldStop,
86
- initialParams,
87
- maxTime: p.maxTime
88
- });
89
- if (cancelled) {
90
- engine.destroy();
91
- return;
92
- }
93
- const delayMs = p.delayMs ?? 0;
94
- const ticksPerFrame = p.ticksPerFrame ?? 1;
95
- let loopTimer = null;
96
- function stopLoop() {
97
- if (loopTimer !== null) {
98
- clearTimeout(loopTimer);
99
- loopTimer = null;
100
- }
101
- }
102
- function tickLoop() {
103
- if (engine.getStatus() !== "playing") return;
104
- for (let i = 0; i < ticksPerFrame; i++) {
105
- engine.advance(1);
106
- const s = engine.getStatus();
107
- if (s === "stopped") return;
108
- if (s !== "paused") break;
109
- }
110
- if (engine.getStatus() === "paused") {
111
- engine.play();
112
- }
113
- loopTimer = setTimeout(tickLoop, delayMs);
101
+ const moduleUrl = props.worker.toString();
102
+ const initialParams = props.params ?? {};
103
+ const worker = createSimWorker({
104
+ moduleUrl,
105
+ engineUrl: engineUrl(),
106
+ initialParams,
107
+ config: {
108
+ maxTime: props.maxTime,
109
+ delayMs: props.delayMs,
110
+ ticksPerFrame: props.ticksPerFrame,
111
+ snapshotIntervalMs: props.snapshotIntervalMs
114
112
  }
115
- runner = {
116
- getSnapshot: () => engine.getSnapshot(),
117
- subscribe: (listener) => engine.subscribe(listener),
118
- play: () => {
119
- engine.play();
120
- stopLoop();
121
- loopTimer = setTimeout(tickLoop, 0);
122
- },
123
- pause: () => {
124
- stopLoop();
125
- engine.pause();
126
- },
127
- stop: () => {
128
- stopLoop();
129
- engine.stop();
130
- },
131
- seek: (tick) => {
132
- stopLoop();
133
- engine.seek(tick);
134
- },
135
- advance: (count) => engine.advance(count),
136
- setParams: (patch) => engine.setParams(patch),
137
- resetWith: (patch) => {
138
- stopLoop();
139
- engine.resetWith(patch);
140
- },
141
- destroy: () => {
142
- stopLoop();
143
- engine.destroy();
144
- },
145
- recordDrawTime: (tick, ms) => engine.recordDrawTime(tick, ms),
146
- getPerformance: () => engine.getPerformance()
147
- };
148
- if (!cancelled) {
149
- setBackend(runner);
150
- setSnapshot(engine.getSnapshot());
113
+ });
114
+ const r = createWorkerRunner(worker, {
115
+ initialParams,
116
+ config: {
117
+ maxTime: props.maxTime,
118
+ delayMs: props.delayMs,
119
+ ticksPerFrame: props.ticksPerFrame,
120
+ snapshotIntervalMs: props.snapshotIntervalMs
151
121
  }
152
- })();
122
+ });
123
+ const unsub = r.subscribe((next) => setSnapshot(next));
124
+ setRunner(r);
153
125
  return () => {
154
- cancelled = true;
155
- runner?.destroy();
126
+ unsub();
127
+ r.destroy();
156
128
  };
157
129
  }, []);
158
130
  React.useEffect(() => {
159
- if (!backend) return;
160
- return backend.subscribe((next) => setSnapshot(next));
161
- }, [backend]);
162
- React.useEffect(() => {
163
- if (autoplay && backend) backend.play();
164
- }, [backend, autoplay]);
131
+ if (autoplay && runner) runner.play();
132
+ }, [runner, autoplay]);
165
133
  const isFirstRender = React.useRef(true);
166
134
  React.useEffect(() => {
167
135
  if (isFirstRender.current) {
168
136
  isFirstRender.current = false;
169
137
  return;
170
138
  }
171
- if (props.params && backend) backend.setParams(props.params);
172
- }, [backend, props.params]);
173
- if (!snapshot || !backend) return null;
174
- return /* @__PURE__ */ jsx(SimulationProvider, { snapshot, backend, children });
139
+ if (props.params && runner) runner.setParams(props.params);
140
+ }, [runner, props.params]);
141
+ React.useEffect(() => {
142
+ if (!runner) return;
143
+ if (props.delayMs === void 0 && props.ticksPerFrame === void 0 && props.snapshotIntervalMs === void 0)
144
+ return;
145
+ runner.setConfig({
146
+ delayMs: props.delayMs,
147
+ ticksPerFrame: props.ticksPerFrame,
148
+ snapshotIntervalMs: props.snapshotIntervalMs
149
+ });
150
+ }, [runner, props.delayMs, props.ticksPerFrame, props.snapshotIntervalMs]);
151
+ if (!snapshot || !runner || snapshot.data === void 0) return null;
152
+ return /* @__PURE__ */ jsx(SimulationProvider, { snapshot, backend: runner, children });
175
153
  }
176
154
  function SimulationProvider({
177
155
  snapshot,
@@ -207,6 +185,8 @@ function SimulationProvider({
207
185
  );
208
186
  const engineValue = React.useMemo(
209
187
  () => ({
188
+ // TODO(#14): casts here bridge EngineContext's non-generic shape to
189
+ // the typed Backend<Data, Params>. Make EngineContext generic to drop them.
210
190
  subscribe: (listener) => backend.subscribe(
211
191
  listener
212
192
  ),
@@ -228,6 +208,19 @@ function Simulation(props) {
228
208
  if ("worker" in props && props.worker != null) {
229
209
  return /* @__PURE__ */ jsx(WorkerSimulation, { ...props });
230
210
  }
211
+ if ("sim" in props && props.sim != null) {
212
+ const { sim, ...rest } = props;
213
+ return /* @__PURE__ */ jsx(
214
+ LocalSimulation,
215
+ {
216
+ ...rest,
217
+ init: sim.init,
218
+ step: sim.step,
219
+ shouldStop: sim.shouldStop,
220
+ defaultParams: sim.defaultParams
221
+ }
222
+ );
223
+ }
231
224
  return /* @__PURE__ */ jsx(LocalSimulation, { ...props });
232
225
  }
233
226
  export {
@@ -1,6 +1,5 @@
1
1
  import React from 'react';
2
- import { SimulationStatus } from '../engine.cjs';
3
- import '../sim.cjs';
2
+ import { SimulationStatus } from '../state.cjs';
4
3
 
5
4
  type SimulationContextValue<Data, Params> = {
6
5
  data: Data;
@@ -1,6 +1,5 @@
1
1
  import React from 'react';
2
- import { SimulationStatus } from '../engine.js';
3
- import '../sim.js';
2
+ import { SimulationStatus } from '../state.js';
4
3
 
5
4
  type SimulationContextValue<Data, Params> = {
6
5
  data: Data;
@@ -1,7 +1,7 @@
1
1
  import { SimulationContextValue } from './SimulationContext.cjs';
2
2
  import { SimModule } from '../sim.cjs';
3
3
  import 'react';
4
- import '../engine.cjs';
4
+ import '../state.cjs';
5
5
 
6
6
  /**
7
7
  * Helper type: extract Data and Params from a SimModule type, or use them directly.
@@ -1,7 +1,7 @@
1
1
  import { SimulationContextValue } from './SimulationContext.js';
2
2
  import { SimModule } from '../sim.js';
3
3
  import 'react';
4
- import '../engine.js';
4
+ import '../state.js';
5
5
 
6
6
  /**
7
7
  * Helper type: extract Data and Params from a SimModule type, or use them directly.
@@ -59,11 +59,7 @@ function useSimulationCanvas(draw) {
59
59
  if (ctx) {
60
60
  const snap = engineCtx.getSnapshot();
61
61
  const t0 = performance.now();
62
- drawRef.current(ctx, {
63
- data: snap.data,
64
- params: snap.params,
65
- tick: snap.tick
66
- });
62
+ drawRef.current(ctx, snap);
67
63
  engineCtx.recordDrawTime(snap.tick, performance.now() - t0);
68
64
  }
69
65
  }
@@ -74,11 +70,7 @@ function useSimulationCanvas(draw) {
74
70
  const ctx = canvas2.getContext("2d");
75
71
  if (!ctx) return;
76
72
  const t0 = performance.now();
77
- drawRef.current(ctx, {
78
- data: snap.data,
79
- params: snap.params,
80
- tick: snap.tick
81
- });
73
+ drawRef.current(ctx, snap);
82
74
  engineCtx.recordDrawTime(snap.tick, performance.now() - t0);
83
75
  }
84
76
  );
@@ -1,18 +1,15 @@
1
1
  import React from 'react';
2
2
  import { SimModule } from '../sim.cjs';
3
+ import { State } from '../state.cjs';
3
4
 
4
5
  /**
5
6
  * Draw callback signature for useSimulationCanvas.
6
- * Called imperatively on every engine snapshot — no React re-render involved.
7
+ * Called imperatively on every engine state emit — no React re-render involved.
7
8
  */
8
- type CanvasDrawFn<Data, Params> = (ctx: CanvasRenderingContext2D, snapshot: {
9
- data: Data;
10
- params: Params;
11
- tick: number;
12
- }) => void;
9
+ type CanvasDrawFn<Data, Params> = (ctx: CanvasRenderingContext2D, snapshot: State<Data, Params>) => void;
13
10
  type InferDraw<T, FallbackParams> = T extends SimModule<infer D, infer P> ? CanvasDrawFn<D, P> : CanvasDrawFn<T, FallbackParams>;
14
11
  /**
15
- * Subscribe to simulation snapshots and draw to a canvas without React re-renders.
12
+ * Subscribe to simulation state and draw to a canvas without React re-renders.
16
13
  *
17
14
  * Returns a ref to attach to a `<canvas>` element. The `draw` callback is called
18
15
  * directly from the engine's subscription — it bypasses React's state/reconciliation
@@ -1,18 +1,15 @@
1
1
  import React from 'react';
2
2
  import { SimModule } from '../sim.js';
3
+ import { State } from '../state.js';
3
4
 
4
5
  /**
5
6
  * Draw callback signature for useSimulationCanvas.
6
- * Called imperatively on every engine snapshot — no React re-render involved.
7
+ * Called imperatively on every engine state emit — no React re-render involved.
7
8
  */
8
- type CanvasDrawFn<Data, Params> = (ctx: CanvasRenderingContext2D, snapshot: {
9
- data: Data;
10
- params: Params;
11
- tick: number;
12
- }) => void;
9
+ type CanvasDrawFn<Data, Params> = (ctx: CanvasRenderingContext2D, snapshot: State<Data, Params>) => void;
13
10
  type InferDraw<T, FallbackParams> = T extends SimModule<infer D, infer P> ? CanvasDrawFn<D, P> : CanvasDrawFn<T, FallbackParams>;
14
11
  /**
15
- * Subscribe to simulation snapshots and draw to a canvas without React re-renders.
12
+ * Subscribe to simulation state and draw to a canvas without React re-renders.
16
13
  *
17
14
  * Returns a ref to attach to a `<canvas>` element. The `draw` callback is called
18
15
  * directly from the engine's subscription — it bypasses React's state/reconciliation
@@ -21,11 +21,7 @@ function useSimulationCanvas(draw) {
21
21
  if (ctx) {
22
22
  const snap = engineCtx.getSnapshot();
23
23
  const t0 = performance.now();
24
- drawRef.current(ctx, {
25
- data: snap.data,
26
- params: snap.params,
27
- tick: snap.tick
28
- });
24
+ drawRef.current(ctx, snap);
29
25
  engineCtx.recordDrawTime(snap.tick, performance.now() - t0);
30
26
  }
31
27
  }
@@ -36,11 +32,7 @@ function useSimulationCanvas(draw) {
36
32
  const ctx = canvas2.getContext("2d");
37
33
  if (!ctx) return;
38
34
  const t0 = performance.now();
39
- drawRef.current(ctx, {
40
- data: snap.data,
41
- params: snap.params,
42
- tick: snap.tick
43
- });
35
+ drawRef.current(ctx, snap);
44
36
  engineCtx.recordDrawTime(snap.tick, performance.now() - t0);
45
37
  }
46
38
  );
package/dist/sim.cjs CHANGED
@@ -20,13 +20,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/sim.ts
21
21
  var sim_exports = {};
22
22
  __export(sim_exports, {
23
- defineSim: () => defineSim
23
+ defineSim: () => defineSim,
24
+ isInitFn: () => isInitFn
24
25
  });
25
26
  module.exports = __toCommonJS(sim_exports);
27
+ function isInitFn(init) {
28
+ return typeof init === "function";
29
+ }
26
30
  function defineSim(sim) {
27
31
  return sim;
28
32
  }
29
33
  // Annotate the CommonJS export names for ESM import in node:
30
34
  0 && (module.exports = {
31
- defineSim
35
+ defineSim,
36
+ isInitFn
32
37
  });
package/dist/sim.d.cts CHANGED
@@ -1,19 +1,39 @@
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
- };
1
+ import { State } from './state.cjs';
2
+
3
+ /**
4
+ * Initial state for a simulation. Either a value of type `Data`, or a function
5
+ * `(params) => Data`. The function form is required when the initial state
6
+ * depends on params; otherwise pass the value directly.
7
+ *
8
+ * `Data` itself must not be a function — it has to be structured-cloneable so
9
+ * it can cross the worker boundary and be safely re-emitted on resetWith.
10
+ * That's what makes this union unambiguous: a `function` value is always the
11
+ * `(params) => Data` branch.
12
+ */
13
+ type SimInit<Data, Params> = ((params: Params) => Data) | Data;
14
+ /**
15
+ * Type guard that narrows a `SimInit` to its function branch. Defined as a
16
+ * user-typed predicate so we can do the narrowing without an `as` cast.
17
+ */
18
+ declare function isInitFn<Data, Params>(init: SimInit<Data, Params>): init is (params: Params) => Data;
7
19
  /** 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;
20
+ type SimModule<Data, Params = Record<string, never>> = {
21
+ /**
22
+ * Initial simulation state — value or `(params) => Data`. When a value is
23
+ * passed, the engine takes a fresh `structuredClone` on every (re)init so
24
+ * mutations inside `step` never leak across resets.
25
+ */
26
+ init: SimInit<Data, Params>;
11
27
  /** Advance the simulation by one tick. Must be pure and synchronous. */
12
- step: (args: StepArgs<Data, Params>) => Data;
28
+ step: (state: State<Data, Params>) => Data;
13
29
  /** Optional termination predicate. Checked after each step. If it returns true, the simulation stops. */
14
30
  shouldStop?: (data: Data, params: Params) => boolean;
15
- /** Default parameter values. Used at engine creation if no params override is provided. */
16
- defaultParams: Params;
31
+ /**
32
+ * Default parameter values. Optional — sims without tweakable params can
33
+ * omit this. When omitted, `Params` defaults to `Record<string, never>` and
34
+ * the engine seeds an empty params object.
35
+ */
36
+ defaultParams?: Params;
17
37
  };
18
38
  /**
19
39
  * Define a simulation module with full type inference.
@@ -31,10 +51,10 @@ type SimModule<Data, Params> = {
31
51
  * });
32
52
  * ```
33
53
  */
34
- declare function defineSim<Data, Params>(sim: SimModule<Data, Params>): SimModule<Data, Params>;
54
+ declare function defineSim<Data, Params = Record<string, never>>(sim: SimModule<Data, Params>): SimModule<Data, Params>;
35
55
  /** Extract the Data type from a SimModule. */
36
56
  type SimData<M> = M extends SimModule<infer D, infer _P> ? D : never;
37
57
  /** Extract the Params type from a SimModule. */
38
58
  type SimParams<M> = M extends SimModule<infer _D, infer P> ? P : never;
39
59
 
40
- export { type SimData, type SimModule, type SimParams, type StepArgs, defineSim };
60
+ export { type SimData, type SimInit, type SimModule, type SimParams, defineSim, isInitFn };
package/dist/sim.d.ts CHANGED
@@ -1,19 +1,39 @@
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
- };
1
+ import { State } from './state.js';
2
+
3
+ /**
4
+ * Initial state for a simulation. Either a value of type `Data`, or a function
5
+ * `(params) => Data`. The function form is required when the initial state
6
+ * depends on params; otherwise pass the value directly.
7
+ *
8
+ * `Data` itself must not be a function — it has to be structured-cloneable so
9
+ * it can cross the worker boundary and be safely re-emitted on resetWith.
10
+ * That's what makes this union unambiguous: a `function` value is always the
11
+ * `(params) => Data` branch.
12
+ */
13
+ type SimInit<Data, Params> = ((params: Params) => Data) | Data;
14
+ /**
15
+ * Type guard that narrows a `SimInit` to its function branch. Defined as a
16
+ * user-typed predicate so we can do the narrowing without an `as` cast.
17
+ */
18
+ declare function isInitFn<Data, Params>(init: SimInit<Data, Params>): init is (params: Params) => Data;
7
19
  /** 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;
20
+ type SimModule<Data, Params = Record<string, never>> = {
21
+ /**
22
+ * Initial simulation state — value or `(params) => Data`. When a value is
23
+ * passed, the engine takes a fresh `structuredClone` on every (re)init so
24
+ * mutations inside `step` never leak across resets.
25
+ */
26
+ init: SimInit<Data, Params>;
11
27
  /** Advance the simulation by one tick. Must be pure and synchronous. */
12
- step: (args: StepArgs<Data, Params>) => Data;
28
+ step: (state: State<Data, Params>) => Data;
13
29
  /** Optional termination predicate. Checked after each step. If it returns true, the simulation stops. */
14
30
  shouldStop?: (data: Data, params: Params) => boolean;
15
- /** Default parameter values. Used at engine creation if no params override is provided. */
16
- defaultParams: Params;
31
+ /**
32
+ * Default parameter values. Optional — sims without tweakable params can
33
+ * omit this. When omitted, `Params` defaults to `Record<string, never>` and
34
+ * the engine seeds an empty params object.
35
+ */
36
+ defaultParams?: Params;
17
37
  };
18
38
  /**
19
39
  * Define a simulation module with full type inference.
@@ -31,10 +51,10 @@ type SimModule<Data, Params> = {
31
51
  * });
32
52
  * ```
33
53
  */
34
- declare function defineSim<Data, Params>(sim: SimModule<Data, Params>): SimModule<Data, Params>;
54
+ declare function defineSim<Data, Params = Record<string, never>>(sim: SimModule<Data, Params>): SimModule<Data, Params>;
35
55
  /** Extract the Data type from a SimModule. */
36
56
  type SimData<M> = M extends SimModule<infer D, infer _P> ? D : never;
37
57
  /** Extract the Params type from a SimModule. */
38
58
  type SimParams<M> = M extends SimModule<infer _D, infer P> ? P : never;
39
59
 
40
- export { type SimData, type SimModule, type SimParams, type StepArgs, defineSim };
60
+ export { type SimData, type SimInit, type SimModule, type SimParams, defineSim, isInitFn };
package/dist/sim.js CHANGED
@@ -1,7 +1,8 @@
1
- // src/sim.ts
2
- function defineSim(sim) {
3
- return sim;
4
- }
1
+ import {
2
+ defineSim,
3
+ isInitFn
4
+ } from "./chunk-IKR53C2U.js";
5
5
  export {
6
- defineSim
6
+ defineSim,
7
+ isInitFn
7
8
  };