@series-inc/rundot-syncplay 5.26.0-beta.1 → 5.26.0-beta.2

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.
@@ -1,4 +1,8 @@
1
- export type KinetixInstalledProfileName = 'deterministic-f64' | 'fixed-1000-3d';
1
+ // Types-only entrypoint. The declarative `defineKinetixProject` lane it used to
2
+ // carry was removed with the engine-owned numeric profiles it validated; games
3
+ // build simulations with `createInstalledRuntimeAdapter` +
4
+ // `deriveCustomRuntimeIdentity` instead. Session-config schema types stay here
5
+ // because game runtimes declare their match configuration with them.
2
6
 
3
7
  export type KinetixSessionField =
4
8
  | { type: 'string'; maxBytes: number; required?: boolean }
@@ -12,19 +16,3 @@ export interface KinetixSessionConfigSchema {
12
16
  maxBytes: number;
13
17
  fields: Readonly<Record<string, KinetixSessionField>>;
14
18
  }
15
-
16
- export interface KinetixProjectDeclaration {
17
- id: string;
18
- installedProfile: KinetixInstalledProfileName;
19
- tickRate: 10 | 20 | 30 | 60;
20
- inputSchema: Readonly<Record<string, unknown>>;
21
- sessionConfigSchema: KinetixSessionConfigSchema;
22
- mechanics: readonly Readonly<Record<string, unknown>>[];
23
- components: readonly Readonly<Record<string, unknown>>[];
24
- systems: readonly Readonly<Record<string, unknown>>[];
25
- presentationBindings: readonly Readonly<Record<string, unknown>>[];
26
- }
27
-
28
- export function defineKinetixProject<const Project extends KinetixProjectDeclaration>(
29
- project: Project,
30
- ): Readonly<Project>;
@@ -84,19 +84,6 @@ export interface DeterministicMathApi {
84
84
  clamp(value: number, min: number, max: number): number;
85
85
  }
86
86
 
87
- export interface FixedTurnsMathApi {
88
- readonly ONE: number;
89
- F(value: number): number;
90
- mul(a: number, b: number): number;
91
- div(a: number, b: number): number;
92
- clamp(value: number, min: number, max: number): number;
93
- fabs(value: number): number;
94
- fsign(value: number): number;
95
- lerp(a: number, b: number, t: number): number;
96
- fsin(turns: number): number;
97
- fcos(turns: number): number;
98
- }
99
-
100
87
  export interface DeterministicRandomSnapshot {
101
88
  readonly state: number;
102
89
  }
@@ -107,8 +94,6 @@ export function createDeterministicMath(
107
94
  maxFixed?: number,
108
95
  ): DeterministicMathApi;
109
96
 
110
- export function createFixedTurnsMath(scale: number): FixedTurnsMathApi;
111
-
112
97
  export class DeterministicRandom {
113
98
  state: number;
114
99
  constructor(seed: number);
package/core/index.d.ts CHANGED
@@ -80,11 +80,9 @@ export type {
80
80
  KinetixPlatformerLevelErrorCode,
81
81
  KinetixRuntimeModuleManifestEntry,
82
82
  } from './runtime';
83
- export { defineKinetixProject } from './authoring';
84
- export type { KinetixProjectDeclaration, KinetixSessionConfigSchema } from './authoring';
83
+ export type { KinetixSessionConfigSchema } from './authoring';
85
84
  export {
86
85
  createDeterministicMath,
87
- createFixedTurnsMath,
88
86
  DeterministicRandom,
89
87
  } from './deterministic-stdlib';
90
88
  export {
@@ -145,15 +143,11 @@ export type {
145
143
  DeterministicRandomSnapshot,
146
144
  DeterministicVec2,
147
145
  DeterministicVec3,
148
- FixedTurnsMathApi,
149
146
  } from './deterministic-stdlib';
150
147
 
151
- export type KinetixTargetProfile = 'deterministic-f64' | 'fixed-1000-3d';
152
-
153
148
  export interface KinetixCompileInput {
154
149
  projectRoot: string;
155
150
  expectedCommit: string;
156
- targetProfile: KinetixTargetProfile;
157
151
  }
158
152
 
159
153
  export interface KinetixDiagnostic {
@@ -180,7 +174,7 @@ export interface KinetixCompiled {
180
174
 
181
175
  export interface KinetixRuntimeContract {
182
176
  readonly tickRate: 10 | 20 | 30 | 60;
183
- readonly targetProfile: KinetixTargetProfile;
177
+ readonly targetProfile: string;
184
178
  readonly numericProfile: string;
185
179
  readonly deterministicAbi: string;
186
180
  readonly deterministicVersion: string;
@@ -263,7 +257,6 @@ export function compileKinetixProject(input: KinetixCompileInput): KinetixCompil
263
257
  export function compileTrustedKinetixSource(input: {
264
258
  sourceRoot: string;
265
259
  expectedCommit: string;
266
- targetProfile: KinetixTargetProfile;
267
260
  classifyInstalledBranches?: boolean;
268
261
  }): KinetixCompiled;
269
262
  export function kinetixCanonicalSourceDigest(sourceRoot: string): string;
@@ -274,27 +267,6 @@ export function bakeKinetixEnvelope(
274
267
  ): KinetixBakeResult;
275
268
  export type KinetixRuntimeModuleDeclaration = import('./runtime').KinetixRuntimeModuleManifestEntry;
276
269
 
277
- export interface KinetixBakeOptions {
278
- /**
279
- * Canonical manifest of the installed runtime's implementation modules,
280
- * sorted by path. Folded into the simulation payload (and so into
281
- * engineIdentityHash), binding the custom step implementation to the signed
282
- * product. Build with kinetixRuntimeModuleManifest.
283
- */
284
- runtimeModules?: readonly KinetixRuntimeModuleDeclaration[];
285
- /** Emitted as manifest.auxiliaryAssets; bound into engineIdentityHash when non-empty. */
286
- auxiliaryAssets?: readonly { name: string; digest: string; byteLength: number }[];
287
- }
288
-
289
- export function bakeKinetixProjectDefinition(
290
- project: import('./authoring').KinetixProjectDeclaration,
291
- options?: KinetixBakeOptions,
292
- ): {
293
- products: KinetixProducts;
294
- runtimeIdentity: import('./runtime').KinetixRuntimeIdentity;
295
- contentDigest: string;
296
- };
297
-
298
270
  /** Node-only build-time helper: hashes module files into a sorted canonical manifest. */
299
271
  export function kinetixRuntimeModuleManifest(
300
272
  sourceRoot: string,
@@ -351,8 +323,8 @@ export interface CustomRuntimeIdentityOptions {
351
323
  * folding its `runtimeModules` manifest (and optional `auxiliaryAssets` /
352
324
  * `sessionConfigSchema` / `deterministicAbi`) into `engineIdentityHash` the same
353
325
  * canonical way `deriveKinetixRuntimeIdentity` does. The supported path for
354
- * custom `createInstalledRuntimeAdapter` runtimes, which cannot go through the
355
- * profile-locked `defineKinetixProject` baker.
326
+ * custom `createInstalledRuntimeAdapter` runtimes. It replaces the removed
327
+ * profile-locked declarative baker.
356
328
  */
357
329
  export function deriveCustomRuntimeIdentity(
358
330
  options: CustomRuntimeIdentityOptions,
@@ -383,7 +355,6 @@ export function compileStableKinetixProducts(input: KinetixCompileInput): Kineti
383
355
  export function compileStableKinetixProductsFromTrustedSource(input: {
384
356
  sourceRoot: string;
385
357
  expectedCommit: string;
386
- targetProfile: KinetixTargetProfile;
387
358
  }): KinetixCompilation;
388
359
 
389
360
  /** Builds the portable C++ core and returns the binary path. */
@@ -4,7 +4,7 @@
4
4
  // `rundot pack preflight` shells out to (the compiler is JS; the CLI is .NET).
5
5
  //
6
6
  // Usage:
7
- // node preflight.mjs --project-root <dir> --commit <sha> --profile <deterministic-f64|fixed-1000-3d>
7
+ // node preflight.mjs --project-root <dir> --commit <sha>
8
8
  //
9
9
  // Prints a JSON report to stdout and exits non-zero when the game does not
10
10
  // compile, so the CLI can format it and set the exit code without re-parsing.
@@ -22,30 +22,26 @@ function parseArgs(argv) {
22
22
  return args;
23
23
  }
24
24
 
25
- const PROFILES = new Set(['deterministic-f64', 'fixed-1000-3d']);
26
-
27
25
  function main() {
28
26
  const args = parseArgs(process.argv.slice(2));
29
27
  const projectRoot = args['project-root'];
30
28
  const commit = args.commit;
31
- const profile = args.profile;
32
- if (!projectRoot || !commit || !PROFILES.has(profile)) {
29
+ if (!projectRoot || !commit) {
33
30
  process.stderr.write(
34
- 'KINETIX_PREFLIGHT_USAGE --project-root <dir> --commit <sha> --profile <deterministic-f64|fixed-1000-3d>\n',
31
+ 'KINETIX_PREFLIGHT_USAGE --project-root <dir> --commit <sha>\n',
35
32
  );
36
33
  process.exit(2);
37
34
  }
38
35
 
39
36
  let result;
40
37
  try {
41
- result = compileKinetixProject({ projectRoot, expectedCommit: commit, targetProfile: profile });
38
+ result = compileKinetixProject({ projectRoot, expectedCommit: commit });
42
39
  } catch (err) {
43
40
  process.stdout.write(
44
41
  JSON.stringify({
45
42
  format: 'kinetix-preflight-v1',
46
43
  ok: false,
47
44
  commitSha: commit,
48
- numericProfile: profile,
49
45
  error: err instanceof Error ? err.message : String(err),
50
46
  diagnostics: [],
51
47
  unmatchedCount: 0,
@@ -66,7 +62,6 @@ function main() {
66
62
  format: 'kinetix-preflight-v1',
67
63
  ok,
68
64
  commitSha: commit,
69
- numericProfile: profile,
70
65
  diagnostics,
71
66
  unmatchedCount: diagnostics.length,
72
67
  }) + '\n');
@@ -6,7 +6,6 @@ export { compileKinetixProject, compileTrustedKinetixSource } from './kinetix-pr
6
6
  export { kinetixCanonicalSourceDigest, kinetixRuntimeModuleManifest } from './kinetix-source-snapshot.mjs';
7
7
  export {
8
8
  bakeKinetixEnvelope,
9
- bakeKinetixProjectDefinition,
10
9
  kinetixBakerVersion,
11
10
  kinetixPhases,
12
11
  scanKinetixPayloadTree,
@@ -14,13 +13,11 @@ export {
14
13
  stableKinetixSourceBytes,
15
14
  validateInstalledKinetixProfile,
16
15
  } from './kinetix-baker.mjs';
17
- export { defineKinetixProject } from './kinetix-authoring.mjs';
18
16
  export { createKinetixWorld } from './kinetix-world-kernel.mjs';
19
17
  export { createKinetixWorldRuntime } from './kinetix-world-runtime.mjs';
20
18
  export { createInstalledRuntimeAdapter } from './kinetix-runtime-adapter-utils.mjs';
21
19
  export {
22
20
  createDeterministicMath,
23
- createFixedTurnsMath,
24
21
  DeterministicRandom,
25
22
  } from './kinetix-deterministic-stdlib.mjs';
26
23
  export {
@@ -10,8 +10,6 @@ import {
10
10
  digestKinetixBytes,
11
11
  stableKinetixContractBytes,
12
12
  } from './kinetix-product-contract.mjs';
13
- import { kinetixRuntimeContractForProfile } from './kinetix-legacy-profile-contracts.mjs';
14
- import { normalizeKinetixRuntimeModuleManifest } from './kinetix-source-snapshot.mjs';
15
13
 
16
14
  export const kinetixBakerVersion = 'rundot.kinetix-baker.v1';
17
15
 
@@ -517,96 +515,6 @@ export function stableKinetixSourceBytes(envelope) {
517
515
  return stableKinetixEnvelopeBytes(envelope);
518
516
  }
519
517
 
520
- const bakeOptionKeys = new Set(['runtimeModules', 'auxiliaryAssets']);
521
-
522
- export function bakeKinetixProjectDefinition(project, options = {}) {
523
- if (typeof options !== 'object' || options === null || Array.isArray(options)
524
- || Object.keys(options).some((key) => !bakeOptionKeys.has(key))) {
525
- throw new Error('KINETIX_BAKE_OPTIONS_INVALID');
526
- }
527
- const runtimeModules = normalizeKinetixRuntimeModuleManifest(options.runtimeModules);
528
- // A present-but-non-array value would otherwise skip the manifest spread below
529
- // and bake a product that silently declares no assets. Element-level and
530
- // ordering validation stays in assertKinetixProductContract; empty stays
531
- // omitted for digest stability.
532
- if (options.auxiliaryAssets !== undefined && !Array.isArray(options.auxiliaryAssets)) {
533
- throw new Error('KINETIX_PRODUCT_AUX_ASSETS_INVALID');
534
- }
535
- const auxiliaryAssets = options.auxiliaryAssets === undefined ? [] : options.auxiliaryAssets;
536
- const baseRuntime = kinetixRuntimeContractForProfile(project.installedProfile);
537
- const sessionSchemaDigest = digestKinetixBytes(stableKinetixContractBytes(project.sessionConfigSchema));
538
- const runtime = {
539
- ...baseRuntime,
540
- tickRate: project.tickRate,
541
- inputSchema: structuredClone(project.inputSchema),
542
- };
543
- const simulation = {
544
- format: 'rundot.kinetix-authored-simulation.v1',
545
- installedProfile: project.installedProfile,
546
- mechanics: structuredClone(project.mechanics),
547
- components: structuredClone(project.components),
548
- systems: structuredClone(project.systems),
549
- // The installed runtime's implementation manifest lives in the simulation
550
- // payload so engineIdentityHash covers it through simulationPayloadDigest —
551
- // a changed step implementation is a different signed identity. Spread only
552
- // when non-empty so module-free products keep byte-identical digests.
553
- ...(runtimeModules.length > 0 ? { runtimeModules } : {}),
554
- };
555
- const presentation = {
556
- format: 'rundot.kinetix-authored-presentation.v1',
557
- bindings: structuredClone(project.presentationBindings),
558
- };
559
- const binding = {
560
- format: 'rundot.kinetix-authored-binding.v1',
561
- projectId: project.id,
562
- };
563
- const payloads = { simulation, presentation, binding };
564
- const payloadTable = ['simulation', 'presentation', 'binding'].map((name) => {
565
- const bytes = stableKinetixContractBytes(payloads[name]);
566
- return { name, digest: digestKinetixBytes(bytes), byteLength: bytes.length };
567
- });
568
- const sourceContract = {
569
- format: 'rundot.kinetix-authoring-source.v1',
570
- projectId: project.id,
571
- installedProfile: project.installedProfile,
572
- tickRate: project.tickRate,
573
- inputSchema: project.inputSchema,
574
- sessionConfigSchemaId: project.sessionConfigSchema.id,
575
- sessionConfigSchemaDigest: sessionSchemaDigest,
576
- mechanics: project.mechanics,
577
- components: project.components,
578
- systems: project.systems,
579
- presentationBindings: project.presentationBindings,
580
- ...(runtimeModules.length > 0 ? { runtimeModules } : {}),
581
- };
582
- const products = {
583
- sourceDigest: digestKinetixBytes(stableKinetixContractBytes(sourceContract)),
584
- manifest: {
585
- sceneId: project.id,
586
- runtime,
587
- sessionConfig: {
588
- schemaId: project.sessionConfigSchema.id,
589
- schemaDigest: sessionSchemaDigest,
590
- maxBytes: project.sessionConfigSchema.maxBytes,
591
- },
592
- payloads: payloadTable,
593
- // Content, not source: bound into engineIdentityHash by the product
594
- // contract, deliberately outside sourceDigest.
595
- ...(Array.isArray(auxiliaryAssets) && auxiliaryAssets.length > 0
596
- ? { auxiliaryAssets: structuredClone(auxiliaryAssets) }
597
- : {}),
598
- },
599
- ...payloads,
600
- };
601
- assertKinetixProductContract(products);
602
- const bytes = stableKinetixContractBytes(products);
603
- return {
604
- products,
605
- runtimeIdentity: deriveKinetixRuntimeIdentity(products, runtime),
606
- contentDigest: digestKinetixBytes(bytes),
607
- };
608
- }
609
-
610
518
  export {
611
519
  assertKinetixProductContract,
612
520
  assertKinetixRuntimeIdentityMatchesProducts,
@@ -631,39 +631,3 @@ function hashLabel(label) {
631
631
  }
632
632
  return hash;
633
633
  }
634
-
635
- export function createFixedTurnsMath(scale) {
636
- const ONE = scale;
637
- const mul = (a, b) => Math.trunc((a * b) / ONE);
638
- const div = (a, b) => (b === 0 ? 0 : Math.trunc((a * ONE) / b));
639
- const clamp = (v, min, max) => (v < min ? min : v > max ? max : v);
640
- const fabs = (v) => (v < 0 ? -v : v);
641
- const fsign = (v) => (v > 0 ? 1 : v < 0 ? -1 : 0);
642
- const lerp = (a, b, t) => a + mul(b - a, t);
643
-
644
- // 5th-order odd minimax fit of sin over the first quarter turn, evaluated in
645
- // fixed point. Angles are in TURNS (one revolution == ONE).
646
- function sinQuarter(x) {
647
- const u = div(x, ONE / 4);
648
- const u2 = mul(u, u);
649
- const u3 = mul(u2, u);
650
- const u5 = mul(u3, u2);
651
- const a1 = Math.round((1571 * ONE) / 1000);
652
- const a3 = Math.round((-646 * ONE) / 1000);
653
- const a5 = Math.round((80 * ONE) / 1000);
654
- return mul(a1, u) + mul(a3, u3) + mul(a5, u5);
655
- }
656
-
657
- function fsin(turns) {
658
- const t = ((turns % ONE) + ONE) % ONE;
659
- if (t < ONE / 4) return clamp(sinQuarter(t), -ONE, ONE);
660
- if (t < ONE / 2) return clamp(sinQuarter(ONE / 2 - t), -ONE, ONE);
661
- if (t < (3 * ONE) / 4) return clamp(-sinQuarter(t - ONE / 2), -ONE, ONE);
662
- return clamp(-sinQuarter(ONE - t), -ONE, ONE);
663
- }
664
-
665
- const fcos = (turns) => fsin(turns + ONE / 4);
666
- const F = (value) => Math.round(value * ONE);
667
-
668
- return { ONE, F, mul, div, clamp, fabs, fsign, lerp, fsin, fcos };
669
- }
@@ -3,7 +3,6 @@ import {
3
3
  scanKinetixPayloadTree,
4
4
  stableKinetixProductBytes,
5
5
  } from './kinetix-baker.mjs';
6
- import { createLegacyFrozenKinetixProfile } from './kinetix-legacy-profile-contracts.mjs';
7
6
  import { compileKinetixProject, compileTrustedKinetixSource } from './kinetix-project-compiler.mjs';
8
7
 
9
8
  function compileProducts(input, compile) {
@@ -11,8 +10,11 @@ function compileProducts(input, compile) {
11
10
  if (compiled.diagnostics.length > 0 || compiled.envelope === null) {
12
11
  throw new Error(`KINETIX_PROJECT_INELIGIBLE ${JSON.stringify(compiled.diagnostics)}`);
13
12
  }
14
- const profileId = compiled.envelope.profiles[0].id;
15
- const installedProfiles = new Map([[profileId, createLegacyFrozenKinetixProfile(input.targetProfile)]]);
13
+ // Unreachable while the trusted-source compiler is frozen: it always returns a
14
+ // diagnostic, so the throw above fires first. Kept so the shape stays honest
15
+ // for whoever reopens the signed path behind server-side product verification,
16
+ // which will supply real installed profiles here.
17
+ const installedProfiles = new Map();
16
18
  const baked = bakeKinetixEnvelope(compiled.envelope, installedProfiles);
17
19
  if (!baked.valid) throw new Error(`KINETIX_BAKE_FAILED ${JSON.stringify(baked.diagnostics)}`);
18
20
  return { compiled, products: baked.products, runtimeIdentity: baked.runtimeIdentity };
@@ -170,9 +170,10 @@ function normalizeCustomAuxiliaryAssets(auxiliaryAssets) {
170
170
  // Derives a source-bound KinetixRuntimeIdentity for a fully-custom installed
171
171
  // runtime (createInstalledRuntimeAdapter), folding its runtimeModules manifest
172
172
  // — and, when provided, auxiliaryAssets / sessionConfigSchema / deterministicAbi
173
- // — into engineIdentityHash the same canonical way the declarative baker does.
174
- // This is the supported alternative to the profile-locked defineKinetixProject
175
- // path, which rejects custom installedProfiles.
173
+ // — into engineIdentityHash the same canonical way the envelope baker does.
174
+ // This is the supported path for game-owned runtimes. It replaced the removed
175
+ // profile-locked declarative lane, which could only bake the two engine-owned
176
+ // numeric profiles that no longer exist.
176
177
  export function deriveCustomRuntimeIdentity(options) {
177
178
  if (!isPlainObject(options)
178
179
  || Object.keys(options).some((key) => !customRuntimeIdentityOptionKeys.has(key))
@@ -28,10 +28,9 @@ function treeFingerprint(projectRoot) {
28
28
  export function compileKinetixProject({
29
29
  projectRoot,
30
30
  expectedCommit,
31
- targetProfile,
32
31
  classifyInstalledBranches = true,
33
32
  }) {
34
- if (typeof projectRoot !== 'string' || typeof expectedCommit !== 'string' || typeof targetProfile !== 'string') {
33
+ if (typeof projectRoot !== 'string' || typeof expectedCommit !== 'string') {
35
34
  throw new Error('KINETIX_PROJECT_OPTIONS_INVALID');
36
35
  }
37
36
  const beforeFingerprint = treeFingerprint(projectRoot);
@@ -64,7 +63,6 @@ export function compileKinetixProject({
64
63
  const result = compileTrustedKinetixSource({
65
64
  sourceRoot: snapshotRoot,
66
65
  expectedCommit,
67
- targetProfile,
68
66
  classifyInstalledBranches,
69
67
  });
70
68
  if (treeFingerprint(projectRoot) !== beforeFingerprint) {
@@ -79,11 +77,8 @@ export function compileKinetixProject({
79
77
  export function compileTrustedKinetixSource({
80
78
  sourceRoot,
81
79
  expectedCommit,
82
- targetProfile,
83
80
  }) {
84
- if (typeof sourceRoot !== 'string'
85
- || typeof expectedCommit !== 'string'
86
- || typeof targetProfile !== 'string') {
81
+ if (typeof sourceRoot !== 'string' || typeof expectedCommit !== 'string') {
87
82
  throw new Error('KINETIX_TRUSTED_SOURCE_OPTIONS_INVALID');
88
83
  }
89
84
  const sourceDigest = kinetixCanonicalSourceDigest(sourceRoot);
@@ -1,5 +1,3 @@
1
- export { defineKinetixProject } from '@series-inc/rundot-syncplay/core/authoring';
2
- export type { KinetixProjectDeclaration } from '@series-inc/rundot-syncplay/core/authoring';
3
1
  export { checkDeterminism, checkSourceText, collectDeterminismSuppressions, type DeterminismCheckMode, type DeterminismCheckOptions, type DeterminismDiagnostic, type DeterminismParserKind, type DeterminismSeverity, type DeterminismSuppression, } from './static-checker.js';
4
2
  export { runSyncplaySynctest, type SyncplaySynctestConfig, type SyncplaySynctestDivergence, type SyncplaySynctestInputFuzz, type SyncplaySynctestPhase, type SyncplaySynctestResult, } from '../synctest.js';
5
3
  export { rundotSyncplayPlugin, createSyncplayViteConfig, withSyncplayViteConfig, formatDiagnostics, type SyncplayPluginOptions, type MinimalVitePlugin, type MinimalVitePluginApply, type MinimalVitePluginEnforce, type MinimalVitePluginEnvironment, type MinimalViteResolvedConfig, type MinimalViteConfig, } from './vite-plugin.js';
@@ -1,4 +1,3 @@
1
- export { defineKinetixProject } from '@series-inc/rundot-syncplay/core/authoring';
2
1
  export { checkDeterminism, checkSourceText, collectDeterminismSuppressions, } from './static-checker.js';
3
2
  export { runSyncplaySynctest, } from '../synctest.js';
4
3
  // Determinism-lint Vite plugin (relocated from the game SDK's syncplay/tools).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@series-inc/rundot-syncplay",
3
- "version": "5.26.0-beta.1",
3
+ "version": "5.26.0-beta.2",
4
4
  "description": "Kinetix orchestration, rollback, replay, late-join, and deterministic networking for RUN.game",
5
5
  "repository": {
6
6
  "type": "git",
@@ -51,8 +51,7 @@
51
51
  "default": "./core/src/runtime.mjs"
52
52
  },
53
53
  "./core/authoring": {
54
- "types": "./core/authoring.d.ts",
55
- "default": "./core/src/kinetix-authoring.mjs"
54
+ "types": "./core/authoring.d.ts"
56
55
  },
57
56
  "./core/compiler": "./core/src/kinetix-project-compiler.mjs",
58
57
  "./core/baker": "./core/src/kinetix-baker.mjs",
@@ -89,7 +88,7 @@
89
88
  "scripts": {
90
89
  "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json",
91
90
  "test": "npm run test:core",
92
- "test:core": "tsx --test tests/canonical.test.ts tests/runtime-session.test.ts tests/kinetix-runtime-session.test.ts tests/runtime-support.test.ts tests/runtime-guards.test.ts tests/r3f-render-adapter.test.ts tests/snapshot-cost.test.ts tests/sdkSession.test.ts tests/input-authority.test.ts tests/session-wire.test.ts tests/session-snapshot.test.ts tests/authority-room.test.ts tests/networked-client-snapshot.test.ts tests/runner.test.ts tests/testing.test.ts tests/browser-session.test.ts tests/secret-config.test.ts tests/secret-protocol.test.ts tests/secret-authority.test.ts tests/secret-client.test.ts tests/late-join-checksum.test.ts tests/late-join-input-backfill.test.ts tests/replay-scoring.test.ts tests/bot-backfill.test.ts tests/latency-simulation.test.ts tests/time-sync.test.ts tests/match-log.test.ts tests/spectator.test.ts tests/synctest.test.ts tests/instant-replay.test.ts tests/session-promotion.test.ts tests/physics3d-broadphase-stats.test.ts tests/entrypoints.test.ts tests/export-surface.test.ts tests/test-manifest.test.ts tests/coarse-region.test.ts tests/input-codec.test.ts tests/platformer-content.test.ts tests/command-ingress.test.ts tests/session-reconfigure.test.ts tests/prediction-mode.test.ts tests/ephemeral-channel.test.ts tests/runner-surface.test.ts tests/runner-harness.test.ts tests/effects-adapter-bounds.test.ts tests/simulated-match-secrets.test.ts tests/run-glue-surface.test.mjs core/tests/core-boundary.test.mjs",
91
+ "test:core": "tsx --test tests/canonical.test.ts tests/runtime-session.test.ts tests/kinetix-runtime-session.test.ts tests/runtime-support.test.ts tests/runtime-guards.test.ts tests/r3f-render-adapter.test.ts tests/snapshot-cost.test.ts tests/sdkSession.test.ts tests/input-authority.test.ts tests/session-wire.test.ts tests/session-snapshot.test.ts tests/authority-room.test.ts tests/networked-client-snapshot.test.ts tests/runner.test.ts tests/testing.test.ts tests/browser-session.test.ts tests/secret-config.test.ts tests/secret-protocol.test.ts tests/secret-authority.test.ts tests/secret-client.test.ts tests/late-join-checksum.test.ts tests/late-join-input-backfill.test.ts tests/replay-scoring.test.ts tests/bot-backfill.test.ts tests/latency-simulation.test.ts tests/time-sync.test.ts tests/match-log.test.ts tests/spectator.test.ts tests/synctest.test.ts tests/instant-replay.test.ts tests/session-promotion.test.ts tests/physics3d-broadphase-stats.test.ts tests/entrypoints.test.ts tests/export-surface.test.ts tests/test-manifest.test.ts tests/coarse-region.test.ts tests/input-codec.test.ts tests/platformer-content.test.ts tests/command-ingress.test.ts tests/session-reconfigure.test.ts tests/prediction-mode.test.ts tests/ephemeral-channel.test.ts tests/runner-surface.test.ts tests/runner-harness.test.ts tests/effects-adapter-bounds.test.ts tests/simulated-match-secrets.test.ts tests/run-glue-surface.test.mjs core/tests/core-boundary.test.mjs tests/math-core-parity.test.ts",
93
92
  "test:soak": "tsx --test tests/runtime-soak.test.ts",
94
93
  "test:extended": "tsx --test tests/animation.test.ts tests/asset-cooking.test.ts tests/backend-proof-checksum-vectors.test.ts tests/bot-documents.test.ts tests/bot-primitives.test.ts tests/collider-cooking.test.ts tests/collision.test.ts tests/command-timeline.test.ts tests/config-bundle.test.ts tests/cosmetic-physics3d.test.ts tests/deterministic-primitives.test.ts tests/ecs-lite.test.ts tests/effects-adapter.test.ts tests/engine-runtime.test.ts tests/errors.test.ts tests/events.test.ts tests/input-button.test.ts tests/load-128-players.test.ts tests/math.test.ts tests/movement.test.ts tests/movement3d.test.ts tests/multiclient-authority.test.ts tests/navigation.test.ts tests/noise.test.ts tests/physics-cert.test.ts tests/physics2d.test.ts tests/physics3d-ccd.test.ts tests/physics3d-coverage.test.ts tests/physics3d-destruction-cert.test.ts tests/physics3d-heightfield.test.ts tests/physics3d-hull.test.ts tests/physics3d-joints.test.ts tests/physics3d-kinematic-mesh.test.ts tests/physics3d-mass.test.ts tests/physics3d-materials.test.ts tests/physics3d-mesh-onesided.test.ts tests/physics3d-query-index.test.ts tests/physics3d-recipes.test.ts tests/physics3d-rotation-convention.test.ts tests/physics3d-shared.test.ts tests/physics3d-sleeping-manifold-reuse.test.ts tests/physics3d-solver.test.ts tests/physics3d-stacking.test.ts tests/physics3d-toi.test.ts tests/physics3d-vehicle.test.ts tests/physics3d-voxel.test.ts tests/physics3d-world-edit.test.ts tests/physics3d.test.ts tests/physics-vector-generator.test.ts tests/random.test.ts tests/rollback-history.test.ts tests/schema-artifacts.test.ts tests/schema-codegen.test.ts tests/schema-dsl-binary.test.ts tests/schema.test.ts tests/signals.test.ts tests/sparse-set.test.ts tests/static-checker.test.ts tests/system-lifecycle.test.ts tests/wire-canonical-sentinels.test.ts tests/ws-frame.test.ts",
95
94
  "test:ci": "npm run build && npm run test:core",
@@ -1,69 +0,0 @@
1
- import { normalizeKinetixSessionConfigSchema } from './kinetix-session-config.mjs';
2
-
3
- const projectKeys = new Set([
4
- 'id',
5
- 'installedProfile',
6
- 'tickRate',
7
- 'inputSchema',
8
- 'sessionConfigSchema',
9
- 'mechanics',
10
- 'components',
11
- 'systems',
12
- 'presentationBindings',
13
- ]);
14
-
15
- function fail(code) {
16
- throw new Error(code);
17
- }
18
-
19
- function isPlainObject(value) {
20
- return typeof value === 'object' && value !== null && !Array.isArray(value)
21
- && Object.getPrototypeOf(value) === Object.prototype;
22
- }
23
-
24
- function canonicalData(value) {
25
- if (Array.isArray(value)) return value.map(canonicalData);
26
- if (isPlainObject(value)) {
27
- return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonicalData(value[key])]));
28
- }
29
- if (value === null || typeof value === 'string' || typeof value === 'boolean'
30
- || (typeof value === 'number' && Number.isFinite(value) && Number.isSafeInteger(value))) {
31
- return value;
32
- }
33
- fail('KINETIX_AUTHORING_VALUE_INVALID');
34
- }
35
-
36
- function deepFreeze(value) {
37
- if (value && typeof value === 'object') {
38
- Object.freeze(value);
39
- Object.values(value).forEach(deepFreeze);
40
- }
41
- return value;
42
- }
43
-
44
- export function defineKinetixProject(input) {
45
- if (!isPlainObject(input)) fail('KINETIX_AUTHORING_INVALID');
46
- if (Object.keys(input).some((key) => !projectKeys.has(key))) fail('KINETIX_AUTHORING_FIELD_UNKNOWN');
47
- if (typeof input.id !== 'string' || input.id.length === 0
48
- || !['deterministic-f64', 'fixed-1000-3d'].includes(input.installedProfile)
49
- || ![10, 20, 30, 60].includes(input.tickRate)
50
- || !isPlainObject(input.inputSchema)
51
- || !Array.isArray(input.mechanics)
52
- || !Array.isArray(input.components)
53
- || !Array.isArray(input.systems)
54
- || !Array.isArray(input.presentationBindings)) {
55
- fail('KINETIX_AUTHORING_INVALID');
56
- }
57
- const project = canonicalData({
58
- id: input.id,
59
- installedProfile: input.installedProfile,
60
- tickRate: input.tickRate,
61
- inputSchema: input.inputSchema,
62
- sessionConfigSchema: normalizeKinetixSessionConfigSchema(input.sessionConfigSchema),
63
- mechanics: input.mechanics,
64
- components: input.components,
65
- systems: input.systems,
66
- presentationBindings: input.presentationBindings,
67
- });
68
- return deepFreeze(project);
69
- }
@@ -1,69 +0,0 @@
1
- const profileContracts = Object.freeze({
2
- 'fixed-1000-3d': Object.freeze({
3
- tickRate: 30,
4
- targetProfile: 'fixed-1000-3d',
5
- numericProfile: 'fixed-1000',
6
- deterministicAbi: 'fixed-1000-3d.v1',
7
- deterministicVersion: 'rundot.kinetix.fixed-1000-runtime.v1',
8
- inputSchema: Object.freeze({
9
- version: 'rundot.kinetix-input-schema.v1',
10
- slots: 'bounded-array',
11
- fields: Object.freeze([
12
- Object.freeze({ name: 'steerX', type: 'fixed-1000' }),
13
- Object.freeze({ name: 'throttle', type: 'fixed-1000' }),
14
- Object.freeze({ name: 'handbrake', type: 'boolean' }),
15
- ]),
16
- }),
17
- stateSchema: Object.freeze({
18
- version: 'rundot.kinetix-state-schema.v1',
19
- checkpoint: 'opaque-canonical-bytes',
20
- numericProfile: 'fixed-1000',
21
- componentRoot: 'KinetixRuntimeState',
22
- }),
23
- }),
24
- 'deterministic-f64': Object.freeze({
25
- tickRate: 30,
26
- targetProfile: 'deterministic-f64',
27
- numericProfile: 'deterministic-f64',
28
- deterministicAbi: 'deterministic-f64-2d.v1',
29
- deterministicVersion: 'rundot.kinetix.deterministic-f64-runtime.v1',
30
- inputSchema: Object.freeze({
31
- version: 'rundot.kinetix-input-schema.v1',
32
- slots: 'bounded-array',
33
- fields: Object.freeze([
34
- Object.freeze({ name: 'movementVector', type: 'f64x2' }),
35
- Object.freeze({ name: 'aimVector', type: 'f64x2' }),
36
- Object.freeze({ name: 'fireDown', type: 'boolean' }),
37
- Object.freeze({ name: 'bombPressed', type: 'boolean' }),
38
- ]),
39
- }),
40
- stateSchema: Object.freeze({
41
- version: 'rundot.kinetix-state-schema.v1',
42
- checkpoint: 'opaque-canonical-bytes',
43
- numericProfile: 'deterministic-f64',
44
- componentRoot: 'KinetixRuntimeState',
45
- }),
46
- }),
47
- });
48
-
49
- export function kinetixRuntimeContractForProfile(numericProfile) {
50
- const contract = profileContracts[numericProfile];
51
- if (contract === undefined) throw new Error('KINETIX_NUMERIC_PROFILE_UNSUPPORTED');
52
- return contract;
53
- }
54
-
55
- export function createLegacyFrozenKinetixProfile(numericProfile) {
56
- const runtimeContract = kinetixRuntimeContractForProfile(numericProfile);
57
- return {
58
- abi: runtimeContract.deterministicAbi,
59
- runtimeContract,
60
- componentSchemas: new Map([
61
- ['KinetixRuntimeState', { currentSchemaVersion: 1, domains: ['simulation'], validate: () => [] }],
62
- ['KinetixRenderRecord', { currentSchemaVersion: 1, domains: ['presentation'], validate: () => [] }],
63
- ['KinetixRenderBinding', { currentSchemaVersion: 1, domains: ['binding'], validate: () => [] }],
64
- ]),
65
- systems: [],
66
- bakeEntity: () => ({ simulation: [], presentation: [], binding: [] }),
67
- bakePrefab: () => ({ simulation: [], presentation: [], binding: [] }),
68
- };
69
- }