murow 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.
Files changed (103) hide show
  1. package/README.md +61 -0
  2. package/dist/core/binary-codec/binary-codec.d.ts +159 -0
  3. package/dist/core/binary-codec/binary-codec.js +336 -0
  4. package/dist/core/binary-codec/index.d.ts +1 -0
  5. package/dist/core/binary-codec/index.js +1 -0
  6. package/dist/core/events/event-system.d.ts +71 -0
  7. package/dist/core/events/event-system.js +88 -0
  8. package/dist/core/events/index.d.ts +1 -0
  9. package/dist/core/events/index.js +1 -0
  10. package/dist/core/fixed-ticker/fixed-ticker.d.ts +105 -0
  11. package/dist/core/fixed-ticker/fixed-ticker.js +91 -0
  12. package/dist/core/fixed-ticker/index.d.ts +1 -0
  13. package/dist/core/fixed-ticker/index.js +1 -0
  14. package/dist/core/generate-id/generate-id.d.ts +21 -0
  15. package/dist/core/generate-id/generate-id.js +25 -0
  16. package/dist/core/generate-id/index.d.ts +1 -0
  17. package/dist/core/generate-id/index.js +1 -0
  18. package/dist/core/index.d.ts +8 -0
  19. package/dist/core/index.js +8 -0
  20. package/dist/core/lerp/index.d.ts +1 -0
  21. package/dist/core/lerp/index.js +1 -0
  22. package/dist/core/lerp/lerp.d.ts +40 -0
  23. package/dist/core/lerp/lerp.js +42 -0
  24. package/dist/core/navmesh/index.d.ts +1 -0
  25. package/dist/core/navmesh/index.js +1 -0
  26. package/dist/core/navmesh/navmesh.d.ts +116 -0
  27. package/dist/core/navmesh/navmesh.js +666 -0
  28. package/dist/core/pooled-codec/index.d.ts +1 -0
  29. package/dist/core/pooled-codec/index.js +1 -0
  30. package/dist/core/pooled-codec/pooled-codec.d.ts +140 -0
  31. package/dist/core/pooled-codec/pooled-codec.js +213 -0
  32. package/dist/core/prediction/index.d.ts +1 -0
  33. package/dist/core/prediction/index.js +1 -0
  34. package/dist/core/prediction/prediction.d.ts +64 -0
  35. package/dist/core/prediction/prediction.js +90 -0
  36. package/dist/core.esm.js +1 -0
  37. package/dist/core.js +1 -0
  38. package/dist/index.d.ts +16 -0
  39. package/dist/index.js +18 -0
  40. package/dist/protocol/index.d.ts +43 -0
  41. package/dist/protocol/index.js +43 -0
  42. package/dist/protocol/intent/index.d.ts +39 -0
  43. package/dist/protocol/intent/index.js +38 -0
  44. package/dist/protocol/intent/intent-registry.d.ts +54 -0
  45. package/dist/protocol/intent/intent-registry.js +73 -0
  46. package/dist/protocol/intent/intent.d.ts +12 -0
  47. package/dist/protocol/intent/intent.js +1 -0
  48. package/dist/protocol/snapshot/index.d.ts +44 -0
  49. package/dist/protocol/snapshot/index.js +43 -0
  50. package/dist/protocol/snapshot/snapshot-codec.d.ts +48 -0
  51. package/dist/protocol/snapshot/snapshot-codec.js +56 -0
  52. package/dist/protocol/snapshot/snapshot-registry.d.ts +100 -0
  53. package/dist/protocol/snapshot/snapshot-registry.js +136 -0
  54. package/dist/protocol/snapshot/snapshot.d.ts +19 -0
  55. package/dist/protocol/snapshot/snapshot.js +30 -0
  56. package/package.json +54 -0
  57. package/src/core/binary-codec/README.md +60 -0
  58. package/src/core/binary-codec/binary-codec.test.ts +300 -0
  59. package/src/core/binary-codec/binary-codec.ts +430 -0
  60. package/src/core/binary-codec/index.ts +1 -0
  61. package/src/core/events/README.md +47 -0
  62. package/src/core/events/event-system.test.ts +243 -0
  63. package/src/core/events/event-system.ts +140 -0
  64. package/src/core/events/index.ts +1 -0
  65. package/src/core/fixed-ticker/README.md +77 -0
  66. package/src/core/fixed-ticker/fixed-ticker.test.ts +151 -0
  67. package/src/core/fixed-ticker/fixed-ticker.ts +158 -0
  68. package/src/core/fixed-ticker/index.ts +1 -0
  69. package/src/core/generate-id/README.md +18 -0
  70. package/src/core/generate-id/generate-id.test.ts +79 -0
  71. package/src/core/generate-id/generate-id.ts +37 -0
  72. package/src/core/generate-id/index.ts +1 -0
  73. package/src/core/index.ts +8 -0
  74. package/src/core/lerp/README.md +79 -0
  75. package/src/core/lerp/index.ts +1 -0
  76. package/src/core/lerp/lerp.test.ts +90 -0
  77. package/src/core/lerp/lerp.ts +42 -0
  78. package/src/core/navmesh/README.md +124 -0
  79. package/src/core/navmesh/index.ts +1 -0
  80. package/src/core/navmesh/navmesh.test.ts +344 -0
  81. package/src/core/navmesh/navmesh.ts +850 -0
  82. package/src/core/pooled-codec/README.md +70 -0
  83. package/src/core/pooled-codec/index.ts +1 -0
  84. package/src/core/pooled-codec/pooled-codec.test.ts +349 -0
  85. package/src/core/pooled-codec/pooled-codec.ts +239 -0
  86. package/src/core/prediction/README.md +64 -0
  87. package/src/core/prediction/index.ts +1 -0
  88. package/src/core/prediction/prediction.test.ts +422 -0
  89. package/src/core/prediction/prediction.ts +101 -0
  90. package/src/index.ts +20 -0
  91. package/src/protocol/README.md +310 -0
  92. package/src/protocol/index.ts +44 -0
  93. package/src/protocol/intent/index.ts +40 -0
  94. package/src/protocol/intent/intent-registry.test.ts +237 -0
  95. package/src/protocol/intent/intent-registry.ts +88 -0
  96. package/src/protocol/intent/intent.ts +12 -0
  97. package/src/protocol/snapshot/index.ts +45 -0
  98. package/src/protocol/snapshot/snapshot-codec.test.ts +138 -0
  99. package/src/protocol/snapshot/snapshot-codec.ts +71 -0
  100. package/src/protocol/snapshot/snapshot-registry.test.ts +302 -0
  101. package/src/protocol/snapshot/snapshot-registry.ts +162 -0
  102. package/src/protocol/snapshot/snapshot.test.ts +76 -0
  103. package/src/protocol/snapshot/snapshot.ts +41 -0
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # Murow
2
+
3
+ A lightweight TypeScript game engine for server-authoritative multiplayer games.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install murow
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import {
15
+ FixedTicker,
16
+ EventSystem,
17
+ BinaryCodec,
18
+ generateId,
19
+ lerp,
20
+ NavMesh,
21
+ PooledCodec,
22
+ IntentTracker,
23
+ Reconciliator
24
+ } from 'murow';
25
+ // or
26
+ import { FixedTicker } from 'murow/core';
27
+ ```
28
+
29
+ ## Modules
30
+
31
+ ### Core Utilities
32
+ - `FixedTicker`: Deterministic fixed-rate update loop
33
+ - `EventSystem`: High-performance event handling
34
+ - `BinaryCodec`: Schema-driven binary serialization
35
+ - `generateId`: Cryptographically secure ID generation
36
+ - `lerp`: Linear interpolation utility
37
+ - `NavMesh`: Pathfinding with dynamic obstacles
38
+ - `PooledCodec`: Object-pooled binary codec
39
+ - `IntentTracker` & `Reconciliator`: Client-side prediction
40
+
41
+ ### Protocol Layer
42
+ Minimalist networking primitives:
43
+ - `IntentRegistry`: Type-safe intent codec registry
44
+ - `SnapshotCodec`: Binary encoding for state deltas
45
+ - `Snapshot<T>`: Delta-based state updates
46
+ - `applySnapshot()`: Deep merge snapshots into state
47
+
48
+ Works harmoniously with core utilities (`FixedTicker`, `IntentTracker`, `Reconciliator`).
49
+
50
+ See [Protocol Layer Documentation](./src/protocol/README.md) for usage.
51
+
52
+ ## Building
53
+
54
+ ```bash
55
+ npm install
56
+ npm run build
57
+ ```
58
+
59
+ ## License
60
+
61
+ MIT
@@ -0,0 +1,159 @@
1
+ /**
2
+ * A binary field descriptor.
3
+ * Defines how a single value is serialized/deserialized
4
+ * at a fixed byte size.
5
+ */
6
+ export type Field<T> = {
7
+ /** Size of the field in bytes */
8
+ size: number;
9
+ /**
10
+ * Writes a value into a DataView at the given offset.
11
+ * @param dv DataView to write into
12
+ * @param o Byte offset
13
+ * @param v Value to write
14
+ */
15
+ write(dv: DataView, o: number, v: T): void;
16
+ /**
17
+ * Reads a value from a DataView at the given offset.
18
+ * @param dv DataView to read from
19
+ * @param o Byte offset
20
+ */
21
+ read(dv: DataView, o: number): T;
22
+ /**
23
+ * Returns the nil value
24
+ */
25
+ toNil(): T;
26
+ };
27
+ /**
28
+ * A schema mapping object keys to binary fields.
29
+ * The order of iteration defines the binary layout.
30
+ *
31
+ * IMPORTANT:
32
+ * Property order is respected as insertion order.
33
+ * Do not rely on computed or dynamic keys.
34
+ */
35
+ export type Schema<T> = {
36
+ [K in keyof T]: Field<T[K]>;
37
+ };
38
+ /**
39
+ * Base codec implementation.
40
+ * Handles schema-driven encoding/decoding.
41
+ */
42
+ export declare class BaseBinaryCodec {
43
+ /**
44
+ * Encodes an object into a binary buffer using the given schema.
45
+ *
46
+ * Allocates a right-sized buffer per call.
47
+ * Safe for concurrent and re-entrant usage.
48
+ *
49
+ * @param schema Binary schema definition
50
+ * @param data Object to encode
51
+ * @returns A Uint8Array containing the encoded bytes
52
+ */
53
+ protected static encodeInto<T extends object>(schema: Schema<T>, data: T): Uint8Array;
54
+ /**
55
+ * Decodes a binary buffer into a target object using the given schema.
56
+ *
57
+ * Validates buffer size before reading.
58
+ * Does not mutate shared state.
59
+ *
60
+ * @param schema Binary schema definition
61
+ * @param buf Buffer containing encoded data
62
+ * @param target Target object to mutate
63
+ * @returns The mutated target object
64
+ */
65
+ static decodeInto<T extends object>(schema: Schema<T>, buf: Uint8Array, target: T): T;
66
+ }
67
+ /**
68
+ * Built-in binary primitive field definitions for multiplayer games.
69
+ */
70
+ export declare class BinaryPrimitives {
71
+ /** Unsigned 8-bit integer */
72
+ static readonly u8: Field<number>;
73
+ /** Unsigned 16-bit integer (big-endian) */
74
+ static readonly u16: Field<number>;
75
+ /** Unsigned 32-bit integer (big-endian) */
76
+ static readonly u32: Field<number>;
77
+ /** Signed 8-bit integer */
78
+ static readonly i8: Field<number>;
79
+ /** Signed 16-bit integer (big-endian) */
80
+ static readonly i16: Field<number>;
81
+ /** Signed 32-bit integer (big-endian) */
82
+ static readonly i32: Field<number>;
83
+ /** 32-bit floating point number (IEEE 754, big-endian) */
84
+ static readonly f32: Field<number>;
85
+ /** 64-bit floating point number (double, big-endian) */
86
+ static readonly f64: Field<number>;
87
+ /** Boolean stored as 1 byte (0 = false, 1 = true) */
88
+ static readonly bool: Field<boolean>;
89
+ /**
90
+ * String field with UTF-8 encoding and 2-byte length prefix.
91
+ * @param maxLength Maximum number of bytes allowed
92
+ */
93
+ static string(maxLength: number): Field<string>;
94
+ /** 2D vector of f32 (x, y) */
95
+ static readonly vec2: Field<{
96
+ x: number;
97
+ y: number;
98
+ }>;
99
+ /** 3D vector of f32 (x, y, z) */
100
+ static readonly vec3: Field<{
101
+ x: number;
102
+ y: number;
103
+ z: number;
104
+ }>;
105
+ /** RGBA color packed as 4 u8 bytes */
106
+ static readonly color: Field<{
107
+ r: number;
108
+ g: number;
109
+ b: number;
110
+ a: number;
111
+ }>;
112
+ /** 32-bit floating point number (IEEE 754, little-endian) */
113
+ static readonly f32_le: Field<number>;
114
+ /** 64-bit floating point number (double, little-endian) */
115
+ static readonly f64_le: Field<number>;
116
+ /** Unsigned 16-bit integer (little-endian) */
117
+ static readonly u16_le: Field<number>;
118
+ /** Unsigned 32-bit integer (little-endian) */
119
+ static readonly u32_le: Field<number>;
120
+ /** Signed 16-bit integer (little-endian) */
121
+ static readonly i16_le: Field<number>;
122
+ /** Signed 32-bit integer (little-endian) */
123
+ static readonly i32_le: Field<number>;
124
+ /**
125
+ * 2D vector of f32 stored as a tuple [x, y] (little-endian).
126
+ * Useful for compact math data or shader-friendly layouts.
127
+ */
128
+ static readonly vec2_le: Field<[number, number]>;
129
+ /**
130
+ * 3D vector of f32 stored as a tuple [x, y, z] (little-endian).
131
+ * Commonly used for positions, velocities, or directions.
132
+ */
133
+ static readonly vec3_le: Field<[number, number, number]>;
134
+ /**
135
+ * 4D vector of f32 stored as a tuple [x, y, z, w] (little-endian).
136
+ * Useful for quaternions, colors in shaders, or homogeneous coordinates.
137
+ */
138
+ static readonly vec4_le: Field<[number, number, number, number]>;
139
+ }
140
+ /**
141
+ * Public codec API.
142
+ * Re-exports primitives and exposes encode/decode helpers.
143
+ */
144
+ export declare class BinaryCodec extends BaseBinaryCodec {
145
+ /** Unsigned 8-bit integer field */
146
+ static readonly u8: Field<number>;
147
+ /** Unsigned 16-bit integer field */
148
+ static readonly u16: Field<number>;
149
+ /** 32-bit floating point field */
150
+ static readonly f32: Field<number>;
151
+ /**
152
+ * Encodes an object into a binary buffer.
153
+ */
154
+ static encode<T extends object>(schema: Schema<T>, data: T): Uint8Array;
155
+ /**
156
+ * Decodes a binary buffer into an existing object.
157
+ */
158
+ static decode<T extends object>(schema: Schema<T>, buf: Uint8Array, target: T): T;
159
+ }
@@ -0,0 +1,336 @@
1
+ /**
2
+ * Internal symbol used to cache computed schema byte size.
3
+ */
4
+ const SCHEMA_SIZE = Symbol("schemaSize");
5
+ /**
6
+ * Computes and caches the total byte size of a schema.
7
+ * @param schema Binary schema definition
8
+ */
9
+ function getSchemaSize(schema) {
10
+ const cached = schema[SCHEMA_SIZE];
11
+ if (cached !== undefined)
12
+ return cached;
13
+ let size = 0;
14
+ for (const k of Object.keys(schema)) {
15
+ size += schema[k].size;
16
+ }
17
+ schema[SCHEMA_SIZE] = size;
18
+ return size;
19
+ }
20
+ /**
21
+ * Base codec implementation.
22
+ * Handles schema-driven encoding/decoding.
23
+ */
24
+ export class BaseBinaryCodec {
25
+ /**
26
+ * Encodes an object into a binary buffer using the given schema.
27
+ *
28
+ * Allocates a right-sized buffer per call.
29
+ * Safe for concurrent and re-entrant usage.
30
+ *
31
+ * @param schema Binary schema definition
32
+ * @param data Object to encode
33
+ * @returns A Uint8Array containing the encoded bytes
34
+ */
35
+ static encodeInto(schema, data) {
36
+ const size = getSchemaSize(schema);
37
+ const buffer = new ArrayBuffer(size);
38
+ const view = new DataView(buffer);
39
+ let o = 0;
40
+ for (const k of Object.keys(schema)) {
41
+ const f = schema[k];
42
+ f.write(view, o, data[k]);
43
+ o += f.size;
44
+ }
45
+ return new Uint8Array(buffer);
46
+ }
47
+ /**
48
+ * Decodes a binary buffer into a target object using the given schema.
49
+ *
50
+ * Validates buffer size before reading.
51
+ * Does not mutate shared state.
52
+ *
53
+ * @param schema Binary schema definition
54
+ * @param buf Buffer containing encoded data
55
+ * @param target Target object to mutate
56
+ * @returns The mutated target object
57
+ */
58
+ static decodeInto(schema, buf, target) {
59
+ const expectedSize = getSchemaSize(schema);
60
+ if (buf.byteLength < expectedSize) {
61
+ throw new RangeError(`Buffer too small: expected ${expectedSize} bytes, got ${buf.byteLength}`);
62
+ }
63
+ const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
64
+ let o = 0;
65
+ for (const k of Object.keys(schema)) {
66
+ const f = schema[k];
67
+ target[k] = f.read(view, o);
68
+ o += f.size;
69
+ }
70
+ return target;
71
+ }
72
+ }
73
+ /**
74
+ * Built-in binary primitive field definitions for multiplayer games.
75
+ */
76
+ export class BinaryPrimitives {
77
+ /**
78
+ * String field with UTF-8 encoding and 2-byte length prefix.
79
+ * @param maxLength Maximum number of bytes allowed
80
+ */
81
+ static string(maxLength) {
82
+ return {
83
+ size: maxLength + 2,
84
+ write(dv, o, v) {
85
+ const encoder = new TextEncoder();
86
+ const bytes = encoder.encode(v);
87
+ if (bytes.length > maxLength)
88
+ throw new RangeError(`String too long, max ${maxLength} bytes`);
89
+ dv.setUint16(o, bytes.length, false);
90
+ for (let i = 0; i < bytes.length; i++)
91
+ dv.setUint8(o + 2 + i, bytes[i]);
92
+ for (let i = bytes.length; i < maxLength; i++)
93
+ dv.setUint8(o + 2 + i, 0);
94
+ },
95
+ read(dv, o) {
96
+ const length = dv.getUint16(o, false);
97
+ const bytes = new Uint8Array(length);
98
+ for (let i = 0; i < length; i++)
99
+ bytes[i] = dv.getUint8(o + 2 + i);
100
+ return new TextDecoder().decode(bytes);
101
+ },
102
+ toNil: () => "",
103
+ };
104
+ }
105
+ }
106
+ /** Unsigned 8-bit integer */
107
+ BinaryPrimitives.u8 = {
108
+ size: 1,
109
+ write: (dv, o, v) => dv.setUint8(o, v),
110
+ read: (dv, o) => dv.getUint8(o),
111
+ toNil: () => 0,
112
+ };
113
+ /** Unsigned 16-bit integer (big-endian) */
114
+ BinaryPrimitives.u16 = {
115
+ size: 2,
116
+ write: (dv, o, v) => dv.setUint16(o, v, false),
117
+ read: (dv, o) => dv.getUint16(o, false),
118
+ toNil: () => 0,
119
+ };
120
+ /** Unsigned 32-bit integer (big-endian) */
121
+ BinaryPrimitives.u32 = {
122
+ size: 4,
123
+ write: (dv, o, v) => dv.setUint32(o, v, false),
124
+ read: (dv, o) => dv.getUint32(o, false),
125
+ toNil: () => 0,
126
+ };
127
+ /** Signed 8-bit integer */
128
+ BinaryPrimitives.i8 = {
129
+ size: 1,
130
+ write: (dv, o, v) => dv.setInt8(o, v),
131
+ read: (dv, o) => dv.getInt8(o),
132
+ toNil: () => 0,
133
+ };
134
+ /** Signed 16-bit integer (big-endian) */
135
+ BinaryPrimitives.i16 = {
136
+ size: 2,
137
+ write: (dv, o, v) => dv.setInt16(o, v, false),
138
+ read: (dv, o) => dv.getInt16(o, false),
139
+ toNil: () => 0,
140
+ };
141
+ /** Signed 32-bit integer (big-endian) */
142
+ BinaryPrimitives.i32 = {
143
+ size: 4,
144
+ write: (dv, o, v) => dv.setInt32(o, v, false),
145
+ read: (dv, o) => dv.getInt32(o, false),
146
+ toNil: () => 0,
147
+ };
148
+ /** 32-bit floating point number (IEEE 754, big-endian) */
149
+ BinaryPrimitives.f32 = {
150
+ size: 4,
151
+ write: (dv, o, v) => dv.setFloat32(o, v, false),
152
+ read: (dv, o) => dv.getFloat32(o, false),
153
+ toNil: () => 0,
154
+ };
155
+ /** 64-bit floating point number (double, big-endian) */
156
+ BinaryPrimitives.f64 = {
157
+ size: 8,
158
+ write: (dv, o, v) => dv.setFloat64(o, v, false),
159
+ read: (dv, o) => dv.getFloat64(o, false),
160
+ toNil: () => 0,
161
+ };
162
+ /** Boolean stored as 1 byte (0 = false, 1 = true) */
163
+ BinaryPrimitives.bool = {
164
+ size: 1,
165
+ write: (dv, o, v) => dv.setUint8(o, v ? 1 : 0),
166
+ read: (dv, o) => dv.getUint8(o) !== 0,
167
+ toNil: () => false,
168
+ };
169
+ /** 2D vector of f32 (x, y) */
170
+ BinaryPrimitives.vec2 = {
171
+ size: 8,
172
+ write(dv, o, v) {
173
+ dv.setFloat32(o, v.x, false);
174
+ dv.setFloat32(o + 4, v.y, false);
175
+ },
176
+ read(dv, o) {
177
+ return { x: dv.getFloat32(o, false), y: dv.getFloat32(o + 4, false) };
178
+ },
179
+ toNil: () => ({ x: 0, y: 0 }),
180
+ };
181
+ /** 3D vector of f32 (x, y, z) */
182
+ BinaryPrimitives.vec3 = {
183
+ size: 12,
184
+ write(dv, o, v) {
185
+ dv.setFloat32(o, v.x, false);
186
+ dv.setFloat32(o + 4, v.y, false);
187
+ dv.setFloat32(o + 8, v.z, false);
188
+ },
189
+ read(dv, o) {
190
+ return {
191
+ x: dv.getFloat32(o, false),
192
+ y: dv.getFloat32(o + 4, false),
193
+ z: dv.getFloat32(o + 8, false),
194
+ };
195
+ },
196
+ toNil: () => ({ x: 0, y: 0, z: 0 }),
197
+ };
198
+ /** RGBA color packed as 4 u8 bytes */
199
+ BinaryPrimitives.color = {
200
+ size: 4,
201
+ write(dv, o, v) {
202
+ dv.setUint8(o, v.r);
203
+ dv.setUint8(o + 1, v.g);
204
+ dv.setUint8(o + 2, v.b);
205
+ dv.setUint8(o + 3, v.a);
206
+ },
207
+ read(dv, o) {
208
+ return {
209
+ r: dv.getUint8(o),
210
+ g: dv.getUint8(o + 1),
211
+ b: dv.getUint8(o + 2),
212
+ a: dv.getUint8(o + 3),
213
+ };
214
+ },
215
+ toNil: () => ({ r: 0, g: 0, b: 0, a: 0 }),
216
+ };
217
+ /** 32-bit floating point number (IEEE 754, little-endian) */
218
+ BinaryPrimitives.f32_le = {
219
+ size: 4,
220
+ write: (dv, o, v) => dv.setFloat32(o, v, true),
221
+ read: (dv, o) => dv.getFloat32(o, true),
222
+ toNil: () => 0,
223
+ };
224
+ /** 64-bit floating point number (double, little-endian) */
225
+ BinaryPrimitives.f64_le = {
226
+ size: 8,
227
+ write: (dv, o, v) => dv.setFloat64(o, v, true),
228
+ read: (dv, o) => dv.getFloat64(o, true),
229
+ toNil: () => 0,
230
+ };
231
+ /** Unsigned 16-bit integer (little-endian) */
232
+ BinaryPrimitives.u16_le = {
233
+ size: 2,
234
+ write: (dv, o, v) => dv.setUint16(o, v, true),
235
+ read: (dv, o) => dv.getUint16(o, true),
236
+ toNil: () => 0,
237
+ };
238
+ /** Unsigned 32-bit integer (little-endian) */
239
+ BinaryPrimitives.u32_le = {
240
+ size: 4,
241
+ write: (dv, o, v) => dv.setUint32(o, v, true),
242
+ read: (dv, o) => dv.getUint32(o, true),
243
+ toNil: () => 0,
244
+ };
245
+ /** Signed 16-bit integer (little-endian) */
246
+ BinaryPrimitives.i16_le = {
247
+ size: 2,
248
+ write: (dv, o, v) => dv.setInt16(o, v, true),
249
+ read: (dv, o) => dv.getInt16(o, true),
250
+ toNil: () => 0,
251
+ };
252
+ /** Signed 32-bit integer (little-endian) */
253
+ BinaryPrimitives.i32_le = {
254
+ size: 4,
255
+ write: (dv, o, v) => dv.setInt32(o, v, true),
256
+ read: (dv, o) => dv.getInt32(o, true),
257
+ toNil: () => 0,
258
+ };
259
+ /**
260
+ * 2D vector of f32 stored as a tuple [x, y] (little-endian).
261
+ * Useful for compact math data or shader-friendly layouts.
262
+ */
263
+ BinaryPrimitives.vec2_le = {
264
+ size: 8,
265
+ write: (dv, o, v) => {
266
+ dv.setFloat32(o, v[0], true);
267
+ dv.setFloat32(o + 4, v[1], true);
268
+ },
269
+ read: (dv, o) => [
270
+ dv.getFloat32(o, true),
271
+ dv.getFloat32(o + 4, true),
272
+ ],
273
+ toNil: () => [0, 0],
274
+ };
275
+ /**
276
+ * 3D vector of f32 stored as a tuple [x, y, z] (little-endian).
277
+ * Commonly used for positions, velocities, or directions.
278
+ */
279
+ BinaryPrimitives.vec3_le = {
280
+ size: 12,
281
+ write: (dv, o, v) => {
282
+ dv.setFloat32(o, v[0], true);
283
+ dv.setFloat32(o + 4, v[1], true);
284
+ dv.setFloat32(o + 8, v[2], true);
285
+ },
286
+ read: (dv, o) => [
287
+ dv.getFloat32(o, true),
288
+ dv.getFloat32(o + 4, true),
289
+ dv.getFloat32(o + 8, true),
290
+ ],
291
+ toNil: () => [0, 0, 0],
292
+ };
293
+ /**
294
+ * 4D vector of f32 stored as a tuple [x, y, z, w] (little-endian).
295
+ * Useful for quaternions, colors in shaders, or homogeneous coordinates.
296
+ */
297
+ BinaryPrimitives.vec4_le = {
298
+ size: 16,
299
+ write: (dv, o, v) => {
300
+ dv.setFloat32(o, v[0], true);
301
+ dv.setFloat32(o + 4, v[1], true);
302
+ dv.setFloat32(o + 8, v[2], true);
303
+ dv.setFloat32(o + 12, v[3], true);
304
+ },
305
+ read: (dv, o) => [
306
+ dv.getFloat32(o, true),
307
+ dv.getFloat32(o + 4, true),
308
+ dv.getFloat32(o + 8, true),
309
+ dv.getFloat32(o + 12, true),
310
+ ],
311
+ toNil: () => [0, 0, 0, 0],
312
+ };
313
+ /**
314
+ * Public codec API.
315
+ * Re-exports primitives and exposes encode/decode helpers.
316
+ */
317
+ export class BinaryCodec extends BaseBinaryCodec {
318
+ /**
319
+ * Encodes an object into a binary buffer.
320
+ */
321
+ static encode(schema, data) {
322
+ return this.encodeInto(schema, data);
323
+ }
324
+ /**
325
+ * Decodes a binary buffer into an existing object.
326
+ */
327
+ static decode(schema, buf, target) {
328
+ return this.decodeInto(schema, buf, target);
329
+ }
330
+ }
331
+ /** Unsigned 8-bit integer field */
332
+ BinaryCodec.u8 = BinaryPrimitives.u8;
333
+ /** Unsigned 16-bit integer field */
334
+ BinaryCodec.u16 = BinaryPrimitives.u16;
335
+ /** 32-bit floating point field */
336
+ BinaryCodec.f32 = BinaryPrimitives.f32;
@@ -0,0 +1 @@
1
+ export * from './binary-codec';
@@ -0,0 +1 @@
1
+ export * from './binary-codec';
@@ -0,0 +1,71 @@
1
+ type Callback<Props> = (props: Props) => void;
2
+ type EventMapFromTuple<T extends [string, unknown][]> = {
3
+ [K in T[number] as K[0]]: K[1];
4
+ };
5
+ interface EventSystemProps<EventNames extends string> {
6
+ /**
7
+ * @description
8
+ * The list of events to ever be registered.
9
+ */
10
+ events: EventNames[];
11
+ }
12
+ /**
13
+ * @description
14
+ * A callback-based event handling system designed to simplify
15
+ * event-driven programming.
16
+ */
17
+ export declare class EventSystem<EventTuple extends [string, unknown][]> {
18
+ /**
19
+ * @private
20
+ * @description
21
+ * The map of registered events and their callbacks.
22
+ */
23
+ private callbacks;
24
+ /**
25
+ * @private
26
+ * @description
27
+ * The list of events that were registered.
28
+ */
29
+ private events;
30
+ constructor({ events }: EventSystemProps<string>);
31
+ /**
32
+ * @description
33
+ * Registers a callback for an event.
34
+ *
35
+ * @param name Event name
36
+ * @param callback Callback to run when the event is emitted
37
+ */
38
+ on<EventName extends keyof EventMapFromTuple<EventTuple> & string>(name: EventName, callback: Callback<EventMapFromTuple<EventTuple>[EventName]>): void;
39
+ /**
40
+ * @description
41
+ * Registers a callback for an event that runs only once.
42
+ *
43
+ * @param name Event name
44
+ * @param callback Callback to run when the event is emitted
45
+ */
46
+ once<EventName extends keyof EventMapFromTuple<EventTuple> & string>(name: EventName, callback: Callback<EventMapFromTuple<EventTuple>[EventName]>): void;
47
+ /**
48
+ * @description
49
+ * Emits an event, running all registered callbacks.
50
+ *
51
+ * @param name Event name
52
+ * @param data Event data
53
+ */
54
+ emit<EventName extends keyof EventMapFromTuple<EventTuple> & string>(name: EventName, data: EventMapFromTuple<EventTuple>[EventName]): void;
55
+ /**
56
+ * @description
57
+ * Removes a callback from an event.
58
+ *
59
+ * @param name Event name
60
+ * @param callback Callback to remove
61
+ */
62
+ off<EventName extends keyof EventMapFromTuple<EventTuple> & string>(name: EventName, callback: Callback<EventMapFromTuple<EventTuple>[EventName]>): void;
63
+ /**
64
+ * @description
65
+ * Removes all callbacks.
66
+ *
67
+ * @param name Optional event name
68
+ */
69
+ clear<EventName extends keyof EventMapFromTuple<EventTuple> & string>(name?: EventName): void;
70
+ }
71
+ export {};