@certe/atmos-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/LICENCE +674 -0
  2. package/README.md +171 -0
  3. package/dist/component-registry.d.ts +60 -0
  4. package/dist/component-registry.d.ts.map +1 -0
  5. package/dist/component-registry.js +14 -0
  6. package/dist/component-registry.js.map +1 -0
  7. package/dist/component.d.ts +19 -0
  8. package/dist/component.d.ts.map +1 -0
  9. package/dist/component.js +23 -0
  10. package/dist/component.js.map +1 -0
  11. package/dist/engine.d.ts +32 -0
  12. package/dist/engine.d.ts.map +1 -0
  13. package/dist/engine.js +75 -0
  14. package/dist/engine.js.map +1 -0
  15. package/dist/game-object.d.ts +23 -0
  16. package/dist/game-object.d.ts.map +1 -0
  17. package/dist/game-object.js +65 -0
  18. package/dist/game-object.js.map +1 -0
  19. package/dist/index.d.ts +15 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +11 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/input.d.ts +48 -0
  24. package/dist/input.d.ts.map +1 -0
  25. package/dist/input.js +102 -0
  26. package/dist/input.js.map +1 -0
  27. package/dist/register-builtins.d.ts +2 -0
  28. package/dist/register-builtins.d.ts.map +1 -0
  29. package/dist/register-builtins.js +13 -0
  30. package/dist/register-builtins.js.map +1 -0
  31. package/dist/scene-serializer.d.ts +46 -0
  32. package/dist/scene-serializer.d.ts.map +1 -0
  33. package/dist/scene-serializer.js +197 -0
  34. package/dist/scene-serializer.js.map +1 -0
  35. package/dist/scene.d.ts +38 -0
  36. package/dist/scene.d.ts.map +1 -0
  37. package/dist/scene.js +142 -0
  38. package/dist/scene.js.map +1 -0
  39. package/dist/time.d.ts +9 -0
  40. package/dist/time.d.ts.map +1 -0
  41. package/dist/time.js +24 -0
  42. package/dist/time.js.map +1 -0
  43. package/dist/transform.d.ts +27 -0
  44. package/dist/transform.d.ts.map +1 -0
  45. package/dist/transform.js +121 -0
  46. package/dist/transform.js.map +1 -0
  47. package/package.json +27 -0
  48. package/src/index.ts +33 -0
package/dist/input.js ADDED
@@ -0,0 +1,102 @@
1
+ export class Input {
2
+ /** The currently active Input instance, set automatically by Engine. */
3
+ static current = null;
4
+ _keysDown = new Set();
5
+ _keysJustDown = new Set();
6
+ _keysJustUp = new Set();
7
+ _mouseButtons = 0;
8
+ _detach = null;
9
+ /** Canvas-relative mouse position in CSS pixels. Updated on mousemove. */
10
+ mousePosition = { x: 0, y: 0 };
11
+ /** Accumulated mouse movement since last endFrame(). */
12
+ mouseDelta = { x: 0, y: 0 };
13
+ /** Bind keyboard + mouse listeners to a target (e.g., window). Optionally bind mouse position to a canvas. */
14
+ attach(target, canvas) {
15
+ this.detach();
16
+ const onKeyDown = (e) => {
17
+ const key = e.code;
18
+ if (!this._keysDown.has(key)) {
19
+ this._keysJustDown.add(key);
20
+ }
21
+ this._keysDown.add(key);
22
+ };
23
+ const onKeyUp = (e) => {
24
+ const key = e.code;
25
+ this._keysDown.delete(key);
26
+ this._keysJustUp.add(key);
27
+ };
28
+ const onMouseMove = (e) => {
29
+ const me = e;
30
+ this.mouseDelta.x += me.movementX;
31
+ this.mouseDelta.y += me.movementY;
32
+ this._mouseButtons = me.buttons;
33
+ };
34
+ const onMouseDown = (e) => {
35
+ this._mouseButtons = e.buttons;
36
+ };
37
+ const onMouseUp = (e) => {
38
+ this._mouseButtons = e.buttons;
39
+ };
40
+ // Use capture phase so events are received before any focused element
41
+ // (e.g. <select>) can consume or stop propagation of keyboard events.
42
+ target.addEventListener('keydown', onKeyDown, true);
43
+ target.addEventListener('keyup', onKeyUp, true);
44
+ target.addEventListener('mousemove', onMouseMove);
45
+ target.addEventListener('mousedown', onMouseDown);
46
+ target.addEventListener('mouseup', onMouseUp);
47
+ let onCanvasMouseMove = null;
48
+ if (canvas) {
49
+ onCanvasMouseMove = (e) => {
50
+ const me = e;
51
+ const rect = canvas.getBoundingClientRect();
52
+ this.mousePosition.x = me.clientX - rect.left;
53
+ this.mousePosition.y = me.clientY - rect.top;
54
+ };
55
+ canvas.addEventListener('mousemove', onCanvasMouseMove);
56
+ }
57
+ this._detach = () => {
58
+ target.removeEventListener('keydown', onKeyDown, true);
59
+ target.removeEventListener('keyup', onKeyUp, true);
60
+ target.removeEventListener('mousemove', onMouseMove);
61
+ target.removeEventListener('mousedown', onMouseDown);
62
+ target.removeEventListener('mouseup', onMouseUp);
63
+ if (canvas && onCanvasMouseMove) {
64
+ canvas.removeEventListener('mousemove', onCanvasMouseMove);
65
+ }
66
+ this._detach = null;
67
+ };
68
+ return this._detach;
69
+ }
70
+ /** Remove previously attached listeners */
71
+ detach() {
72
+ this._detach?.();
73
+ }
74
+ /** True while key is held */
75
+ getKey(code) {
76
+ return this._keysDown.has(code);
77
+ }
78
+ /** True only on the frame the key was first pressed */
79
+ getKeyDown(code) {
80
+ return this._keysJustDown.has(code);
81
+ }
82
+ /** True only on the frame the key was first pressed (alias for getKeyDown). */
83
+ getKeyPressed(code) {
84
+ return this._keysJustDown.has(code);
85
+ }
86
+ /** True only on the frame the key was released */
87
+ getKeyUp(code) {
88
+ return this._keysJustUp.has(code);
89
+ }
90
+ /** True while mouse button is held (0=left, 1=middle, 2=right). */
91
+ getMouseButton(button) {
92
+ return (this._mouseButtons & (1 << button)) !== 0;
93
+ }
94
+ /** Call at the end of each frame to reset per-frame state */
95
+ endFrame() {
96
+ this._keysJustDown.clear();
97
+ this._keysJustUp.clear();
98
+ this.mouseDelta.x = 0;
99
+ this.mouseDelta.y = 0;
100
+ }
101
+ }
102
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../src/input.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,KAAK;IAChB,wEAAwE;IACxE,MAAM,CAAC,OAAO,GAAiB,IAAI,CAAC;IAEnB,SAAS,GAAgB,IAAI,GAAG,EAAE,CAAC;IACnC,aAAa,GAAgB,IAAI,GAAG,EAAE,CAAC;IACvC,WAAW,GAAgB,IAAI,GAAG,EAAE,CAAC;IAC9C,aAAa,GAAG,CAAC,CAAC;IAClB,OAAO,GAAwB,IAAI,CAAC;IAE5C,0EAA0E;IACjE,aAAa,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAExC,wDAAwD;IAC/C,UAAU,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAErC,8GAA8G;IAC9G,MAAM,CAAC,MAAmB,EAAE,MAAmB;QAC7C,IAAI,CAAC,MAAM,EAAE,CAAC;QAEd,MAAM,SAAS,GAAG,CAAC,CAAU,EAAE,EAAE;YAC/B,MAAM,GAAG,GAAI,CAAmB,CAAC,IAAI,CAAC;YACtC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC9B,CAAC;YACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,CAAC,CAAU,EAAE,EAAE;YAC7B,MAAM,GAAG,GAAI,CAAmB,CAAC,IAAI,CAAC;YACtC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC,CAAC;QAEF,MAAM,WAAW,GAAG,CAAC,CAAU,EAAE,EAAE;YACjC,MAAM,EAAE,GAAG,CAAe,CAAC;YAC3B,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;YAClC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC;YAClC,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC,OAAO,CAAC;QAClC,CAAC,CAAC;QAEF,MAAM,WAAW,GAAG,CAAC,CAAU,EAAE,EAAE;YACjC,IAAI,CAAC,aAAa,GAAI,CAAgB,CAAC,OAAO,CAAC;QACjD,CAAC,CAAC;QACF,MAAM,SAAS,GAAG,CAAC,CAAU,EAAE,EAAE;YAC/B,IAAI,CAAC,aAAa,GAAI,CAAgB,CAAC,OAAO,CAAC;QACjD,CAAC,CAAC;QAEF,sEAAsE;QACtE,sEAAsE;QACtE,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;QACpD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QAClD,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QAClD,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAE9C,IAAI,iBAAiB,GAAkC,IAAI,CAAC;QAC5D,IAAI,MAAM,EAAE,CAAC;YACX,iBAAiB,GAAG,CAAC,CAAU,EAAE,EAAE;gBACjC,MAAM,EAAE,GAAG,CAAe,CAAC;gBAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,qBAAqB,EAAE,CAAC;gBAC5C,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC;gBAC9C,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC;YAC/C,CAAC,CAAC;YACF,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,GAAG,EAAE;YAClB,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;YACvD,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;YACnD,MAAM,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;YACrD,MAAM,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;YACrD,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YACjD,IAAI,MAAM,IAAI,iBAAiB,EAAE,CAAC;gBAChC,MAAM,CAAC,mBAAmB,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;YAC7D,CAAC;YACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC,CAAC;QACF,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,2CAA2C;IAC3C,MAAM;QACJ,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;IACnB,CAAC;IAED,6BAA6B;IAC7B,MAAM,CAAC,IAAY;QACjB,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,uDAAuD;IACvD,UAAU,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,+EAA+E;IAC/E,aAAa,CAAC,IAAY;QACxB,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,kDAAkD;IAClD,QAAQ,CAAC,IAAY;QACnB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,mEAAmE;IACnE,cAAc,CAAC,MAAc;QAC3B,OAAO,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC;IACpD,CAAC;IAED,6DAA6D;IAC7D,QAAQ;QACN,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function registerCoreBuiltins(): void;
2
+ //# sourceMappingURL=register-builtins.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-builtins.d.ts","sourceRoot":"","sources":["../src/register-builtins.ts"],"names":[],"mappings":"AAGA,wBAAgB,oBAAoB,IAAI,IAAI,CAS3C"}
@@ -0,0 +1,13 @@
1
+ import { registerComponent } from './component-registry.js';
2
+ import { Transform } from './transform.js';
3
+ export function registerCoreBuiltins() {
4
+ registerComponent(Transform, {
5
+ name: 'Transform',
6
+ properties: [
7
+ { key: 'position', type: 'vec3' },
8
+ { key: 'rotation', type: 'quat' },
9
+ { key: 'scale', type: 'vec3' },
10
+ ],
11
+ });
12
+ }
13
+ //# sourceMappingURL=register-builtins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-builtins.js","sourceRoot":"","sources":["../src/register-builtins.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,UAAU,oBAAoB;IAClC,iBAAiB,CAAC,SAAS,EAAE;QAC3B,IAAI,EAAE,WAAW;QACjB,UAAU,EAAE;YACV,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE;YACjC,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE;YACjC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE;SAC/B;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { Scene } from './scene.js';
2
+ import { GameObject } from './game-object.js';
3
+ export interface ComponentData {
4
+ type: string;
5
+ data: Record<string, unknown>;
6
+ }
7
+ export interface GameObjectData {
8
+ name: string;
9
+ id: number;
10
+ parentId: number | null;
11
+ /** @deprecated Use parentId instead */
12
+ parentName?: string | null;
13
+ components: ComponentData[];
14
+ }
15
+ export interface PostProcessData {
16
+ bloomIntensity?: number;
17
+ bloomThreshold?: number;
18
+ bloomRadius?: number;
19
+ ssaoEnabled?: boolean;
20
+ ssaoRadius?: number;
21
+ ssaoBias?: number;
22
+ ssaoIntensity?: number;
23
+ exposure?: number;
24
+ vignetteIntensity?: number;
25
+ vignetteRadius?: number;
26
+ fogEnabled?: boolean;
27
+ fogMode?: 'linear' | 'exponential';
28
+ fogDensity?: number;
29
+ fogStart?: number;
30
+ fogEnd?: number;
31
+ fogColor?: number[];
32
+ }
33
+ export interface SceneData {
34
+ gameObjects: GameObjectData[];
35
+ postProcess?: PostProcessData;
36
+ }
37
+ export interface DeserializeContext {
38
+ onComponent?(gameObject: GameObject, type: string, data: Record<string, unknown>): void;
39
+ onComplete?(): void;
40
+ }
41
+ export declare function serializeScene(scene: Scene): SceneData;
42
+ export declare function applyComponentData(target: unknown, data: Record<string, unknown>): void;
43
+ export declare function deserializeScene(data: SceneData, context?: DeserializeContext): Scene;
44
+ export declare function serializePostProcess(source: Record<string, unknown>): PostProcessData;
45
+ export declare function applyPostProcess(target: Record<string, unknown>, data: PostProcessData): void;
46
+ //# sourceMappingURL=scene-serializer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene-serializer.d.ts","sourceRoot":"","sources":["../src/scene-serializer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAO9C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,QAAQ,GAAG,aAAa,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxF,UAAU,CAAC,IAAI,IAAI,CAAC;CACrB;AAsBD,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CA4CtD;AAwBD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAIvF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,KAAK,CAyErF;AASD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,CAQrF;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,eAAe,GAAG,IAAI,CAc7F"}
@@ -0,0 +1,197 @@
1
+ import { Scene } from './scene.js';
2
+ import { GameObject } from './game-object.js';
3
+ import { Transform } from './transform.js';
4
+ import { getComponentDef, getAllRegisteredComponents } from './component-registry.js';
5
+ function resolvePropertyPath(obj, path) {
6
+ const parts = path.split('.');
7
+ let current = obj;
8
+ for (const part of parts) {
9
+ if (current == null || typeof current !== 'object')
10
+ return undefined;
11
+ current = current[part];
12
+ }
13
+ return current;
14
+ }
15
+ function toSerializableValue(value) {
16
+ if (value instanceof Float32Array) {
17
+ return Array.from(value);
18
+ }
19
+ if (value instanceof GameObject) {
20
+ return value.id;
21
+ }
22
+ return value;
23
+ }
24
+ export function serializeScene(scene) {
25
+ const allComponents = getAllRegisteredComponents();
26
+ const ctorByName = new Map();
27
+ for (const [ctor, def] of allComponents) {
28
+ ctorByName.set(def.name, ctor);
29
+ }
30
+ const gameObjects = [];
31
+ for (const obj of scene.getAllObjects()) {
32
+ if (obj.transient)
33
+ continue;
34
+ const components = [];
35
+ // Serialize Transform (always present)
36
+ const transformDef = getComponentDef(Transform);
37
+ if (transformDef) {
38
+ const data = {};
39
+ for (const prop of transformDef.properties) {
40
+ data[prop.key] = toSerializableValue(resolvePropertyPath(obj.transform, prop.key));
41
+ }
42
+ components.push({ type: 'Transform', data });
43
+ }
44
+ // Serialize other components
45
+ for (const comp of obj.getComponents()) {
46
+ const def = getComponentDef(comp.constructor);
47
+ if (!def || def.name === 'Transform')
48
+ continue;
49
+ const data = {};
50
+ for (const prop of def.properties) {
51
+ data[prop.key] = toSerializableValue(resolvePropertyPath(comp, prop.key));
52
+ }
53
+ components.push({ type: def.name, data });
54
+ }
55
+ gameObjects.push({
56
+ name: obj.name,
57
+ id: obj.id,
58
+ parentId: obj.parent?.id ?? null,
59
+ components,
60
+ });
61
+ }
62
+ return { gameObjects };
63
+ }
64
+ function setPropertyPath(obj, path, value) {
65
+ const parts = path.split('.');
66
+ let current = obj;
67
+ for (let i = 0; i < parts.length - 1; i++) {
68
+ if (current == null || typeof current !== 'object')
69
+ return;
70
+ current = current[parts[i]];
71
+ }
72
+ if (current == null || typeof current !== 'object')
73
+ return;
74
+ const lastKey = parts[parts.length - 1];
75
+ const existing = current[lastKey];
76
+ if (existing instanceof Float32Array && Array.isArray(value)) {
77
+ for (let i = 0; i < value.length && i < existing.length; i++) {
78
+ existing[i] = value[i];
79
+ }
80
+ // Re-assign to trigger setter (e.g. HingeJoint.axis recreates joint)
81
+ current[lastKey] = existing;
82
+ }
83
+ else {
84
+ current[lastKey] = value;
85
+ }
86
+ }
87
+ export function applyComponentData(target, data) {
88
+ for (const [key, value] of Object.entries(data)) {
89
+ setPropertyPath(target, key, value);
90
+ }
91
+ }
92
+ export function deserializeScene(data, context) {
93
+ const scene = new Scene();
94
+ const objectsById = new Map();
95
+ const objectsByName = new Map();
96
+ // Build name→def lookup for resolving gameObjectRef properties
97
+ const defByName = new Map();
98
+ for (const [, def] of getAllRegisteredComponents()) {
99
+ defByName.set(def.name, def);
100
+ }
101
+ // Pass 1: create all game objects + apply transforms
102
+ for (const objData of data.gameObjects) {
103
+ const go = new GameObject(objData.name);
104
+ if (objData.id !== undefined)
105
+ objectsById.set(objData.id, go);
106
+ objectsByName.set(objData.name, go);
107
+ const transformData = objData.components.find((c) => c.type === 'Transform');
108
+ if (transformData) {
109
+ const td = transformData.data;
110
+ if (Array.isArray(td['position'])) {
111
+ const p = td['position'];
112
+ go.transform.setPosition(p[0], p[1], p[2]);
113
+ }
114
+ if (Array.isArray(td['rotation'])) {
115
+ const r = td['rotation'];
116
+ go.transform.setRotation(r[0], r[1], r[2], r[3]);
117
+ }
118
+ if (Array.isArray(td['scale'])) {
119
+ const s = td['scale'];
120
+ go.transform.setScale(s[0], s[1], s[2]);
121
+ }
122
+ }
123
+ }
124
+ // Pass 2: create components (all objects exist, so gameObjectRef ids can resolve)
125
+ for (const objData of data.gameObjects) {
126
+ const go = objData.id !== undefined ? objectsById.get(objData.id) : objectsByName.get(objData.name);
127
+ if (!go)
128
+ continue;
129
+ for (const compData of objData.components) {
130
+ if (compData.type === 'Transform')
131
+ continue;
132
+ // Resolve gameObjectRef ids → actual GameObjects
133
+ const def = defByName.get(compData.type);
134
+ if (def) {
135
+ for (const prop of def.properties) {
136
+ if (prop.type === 'gameObjectRef' && typeof compData.data[prop.key] === 'number') {
137
+ compData.data[prop.key] = objectsById.get(compData.data[prop.key]) ?? null;
138
+ }
139
+ }
140
+ }
141
+ context?.onComponent?.(go, compData.type, compData.data);
142
+ }
143
+ }
144
+ // Pass 3: set parent-child relationships (prefer id, fallback to name for old format)
145
+ for (const objData of data.gameObjects) {
146
+ const go = objData.id !== undefined ? objectsById.get(objData.id) : objectsByName.get(objData.name);
147
+ if (!go)
148
+ continue;
149
+ if (objData.parentId != null) {
150
+ const parent = objectsById.get(objData.parentId);
151
+ if (parent)
152
+ go.setParent(parent);
153
+ }
154
+ else if (objData.parentName) {
155
+ const parent = objectsByName.get(objData.parentName);
156
+ if (parent)
157
+ go.setParent(parent);
158
+ }
159
+ scene.add(go);
160
+ }
161
+ // NOTE: caller is responsible for awaiting context.onComplete() after this returns.
162
+ return scene;
163
+ }
164
+ const POST_PROCESS_KEYS = [
165
+ 'bloomIntensity', 'bloomThreshold', 'bloomRadius',
166
+ 'ssaoEnabled', 'ssaoRadius', 'ssaoBias', 'ssaoIntensity',
167
+ 'exposure', 'vignetteIntensity', 'vignetteRadius',
168
+ 'fogEnabled', 'fogMode', 'fogDensity', 'fogStart', 'fogEnd', 'fogColor',
169
+ ];
170
+ export function serializePostProcess(source) {
171
+ const result = {};
172
+ for (const key of POST_PROCESS_KEYS) {
173
+ const val = source[key];
174
+ if (val === undefined)
175
+ continue;
176
+ result[key] = toSerializableValue(val);
177
+ }
178
+ return result;
179
+ }
180
+ export function applyPostProcess(target, data) {
181
+ for (const key of POST_PROCESS_KEYS) {
182
+ const val = data[key];
183
+ if (val === undefined)
184
+ continue;
185
+ const existing = target[key];
186
+ if (existing instanceof Float32Array && Array.isArray(val)) {
187
+ for (let i = 0; i < val.length && i < existing.length; i++) {
188
+ existing[i] = val[i];
189
+ }
190
+ target[key] = existing;
191
+ }
192
+ else {
193
+ target[key] = val;
194
+ }
195
+ }
196
+ }
197
+ //# sourceMappingURL=scene-serializer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene-serializer.js","sourceRoot":"","sources":["../src/scene-serializer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { GameObject } from './game-object.js';
2
+ export type SceneLoader = (name: string) => void;
3
+ export declare class Scene {
4
+ /** The currently active scene, set automatically by Engine. */
5
+ static current: Scene | null;
6
+ private static _sceneLoader;
7
+ /** Register a callback that handles scene loading by name. */
8
+ static setSceneLoader(loader: SceneLoader | null): void;
9
+ /**
10
+ * Request loading a scene by name (e.g. 'level2').
11
+ * The registered loader will handle deserialization and scene swap.
12
+ */
13
+ static loadScene(name: string): void;
14
+ private readonly _roots;
15
+ private readonly _allObjects;
16
+ private _started;
17
+ get roots(): readonly GameObject[];
18
+ add(gameObject: GameObject): void;
19
+ remove(gameObject: GameObject): void;
20
+ /**
21
+ * Call onDestroy on components, then reset started flag so awakeAll/startAll fire again.
22
+ * Optional filter: only destroy components where filter returns true.
23
+ */
24
+ destroyAllComponents(filter?: (comp: import('./component.js').Component) => boolean): void;
25
+ awakeAll(): void;
26
+ startAll(): void;
27
+ updateAll(dt: number): void;
28
+ renderAll(): void;
29
+ /**
30
+ * Update root tracking for an object already in the scene.
31
+ * Does NOT destroy components — safe to call during reparenting.
32
+ */
33
+ updateRootStatus(gameObject: GameObject): void;
34
+ getAllObjects(): ReadonlySet<GameObject>;
35
+ /** Find all components of a given type across the entire scene. */
36
+ findAll<T extends import('./component.js').Component>(Ctor: new (...args: never[]) => T): T[];
37
+ }
38
+ //# sourceMappingURL=scene.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene.d.ts","sourceRoot":"","sources":["../src/scene.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAEjD,qBAAa,KAAK;IAChB,+DAA+D;IAC/D,MAAM,CAAC,OAAO,EAAE,KAAK,GAAG,IAAI,CAAQ;IAEpC,OAAO,CAAC,MAAM,CAAC,YAAY,CAA4B;IAEvD,8DAA8D;IAC9D,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI;IAIvD;;;OAGG;IACH,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA8B;IAC1D,OAAO,CAAC,QAAQ,CAAS;IAEzB,IAAI,KAAK,IAAI,SAAS,UAAU,EAAE,CAEjC;IAED,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAYjC,MAAM,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAgBpC;;;OAGG;IACH,oBAAoB,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,gBAAgB,EAAE,SAAS,KAAK,OAAO,GAAG,IAAI;IAS1F,QAAQ,IAAI,IAAI;IAQhB,QAAQ,IAAI,IAAI;IAUhB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAQ3B,SAAS,IAAI,IAAI;IAejB;;;OAGG;IACH,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IAU9C,aAAa,IAAI,WAAW,CAAC,UAAU,CAAC;IAIxC,mEAAmE;IACnE,OAAO,CAAC,CAAC,SAAS,OAAO,gBAAgB,EAAE,SAAS,EAClD,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,GAChC,CAAC,EAAE;CAQP"}
package/dist/scene.js ADDED
@@ -0,0 +1,142 @@
1
+ import { _setSceneClass } from './component.js';
2
+ export class Scene {
3
+ /** The currently active scene, set automatically by Engine. */
4
+ static current = null;
5
+ static _sceneLoader = null;
6
+ /** Register a callback that handles scene loading by name. */
7
+ static setSceneLoader(loader) {
8
+ Scene._sceneLoader = loader;
9
+ }
10
+ /**
11
+ * Request loading a scene by name (e.g. 'level2').
12
+ * The registered loader will handle deserialization and scene swap.
13
+ */
14
+ static loadScene(name) {
15
+ if (!Scene._sceneLoader) {
16
+ console.warn(`[Scene] No scene loader registered, cannot load "${name}"`);
17
+ return;
18
+ }
19
+ Scene._sceneLoader(name);
20
+ }
21
+ _roots = [];
22
+ _allObjects = new Set();
23
+ _started = false;
24
+ get roots() {
25
+ return this._roots;
26
+ }
27
+ add(gameObject) {
28
+ if (this._allObjects.has(gameObject))
29
+ return;
30
+ this._allObjects.add(gameObject);
31
+ if (!gameObject.parent) {
32
+ this._roots.push(gameObject);
33
+ }
34
+ // Recursively add all children
35
+ for (const child of gameObject.children) {
36
+ this.add(child);
37
+ }
38
+ }
39
+ remove(gameObject) {
40
+ if (!this._allObjects.has(gameObject))
41
+ return;
42
+ // Recursively remove all children first
43
+ for (const child of gameObject.children) {
44
+ this.remove(child);
45
+ }
46
+ this._allObjects.delete(gameObject);
47
+ const idx = this._roots.indexOf(gameObject);
48
+ if (idx !== -1)
49
+ this._roots.splice(idx, 1);
50
+ // Destroy components (always, regardless of enabled state — must free GPU/physics resources)
51
+ for (const comp of gameObject.getComponents()) {
52
+ if (comp.onDestroy)
53
+ comp.onDestroy();
54
+ }
55
+ }
56
+ /**
57
+ * Call onDestroy on components, then reset started flag so awakeAll/startAll fire again.
58
+ * Optional filter: only destroy components where filter returns true.
59
+ */
60
+ destroyAllComponents(filter) {
61
+ for (const obj of this._allObjects) {
62
+ for (const comp of obj.getComponents()) {
63
+ if (comp.onDestroy && (!filter || filter(comp)))
64
+ comp.onDestroy();
65
+ }
66
+ }
67
+ this._started = false;
68
+ }
69
+ awakeAll() {
70
+ for (const obj of this._allObjects) {
71
+ for (const comp of obj.getComponents()) {
72
+ if (comp.enabled && comp.onAwake)
73
+ comp.onAwake();
74
+ }
75
+ }
76
+ }
77
+ startAll() {
78
+ if (this._started)
79
+ return;
80
+ this._started = true;
81
+ for (const obj of this._allObjects) {
82
+ for (const comp of obj.getComponents()) {
83
+ if (comp.enabled && comp.onStart)
84
+ comp.onStart();
85
+ }
86
+ }
87
+ }
88
+ updateAll(dt) {
89
+ for (const obj of this._allObjects) {
90
+ for (const comp of obj.getComponents()) {
91
+ if (comp.enabled && comp.onUpdate)
92
+ comp.onUpdate(dt);
93
+ }
94
+ }
95
+ }
96
+ renderAll() {
97
+ // Update transforms top-down (skip clean hierarchies)
98
+ for (const root of this._roots) {
99
+ if (root.transform.isDirty) {
100
+ root.transform.updateWorldMatrix();
101
+ }
102
+ }
103
+ // Call onRender on all components
104
+ for (const obj of this._allObjects) {
105
+ for (const comp of obj.getComponents()) {
106
+ if (comp.enabled && comp.onRender)
107
+ comp.onRender();
108
+ }
109
+ }
110
+ }
111
+ /**
112
+ * Update root tracking for an object already in the scene.
113
+ * Does NOT destroy components — safe to call during reparenting.
114
+ */
115
+ updateRootStatus(gameObject) {
116
+ if (!this._allObjects.has(gameObject))
117
+ return;
118
+ const idx = this._roots.indexOf(gameObject);
119
+ if (!gameObject.parent && idx === -1) {
120
+ this._roots.push(gameObject);
121
+ }
122
+ else if (gameObject.parent && idx !== -1) {
123
+ this._roots.splice(idx, 1);
124
+ }
125
+ }
126
+ getAllObjects() {
127
+ return this._allObjects;
128
+ }
129
+ /** Find all components of a given type across the entire scene. */
130
+ findAll(Ctor) {
131
+ const results = [];
132
+ for (const obj of this._allObjects) {
133
+ const comp = obj.getComponent(Ctor);
134
+ if (comp)
135
+ results.push(comp);
136
+ }
137
+ return results;
138
+ }
139
+ }
140
+ // Break circular dependency: component.ts needs Scene.current but can't import Scene directly.
141
+ _setSceneClass(Scene);
142
+ //# sourceMappingURL=scene.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene.js","sourceRoot":"","sources":["../src/scene.ts"],"names":[],"mappings":"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"}
package/dist/time.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ export declare class Time {
2
+ deltaTime: number;
3
+ time: number;
4
+ frameCount: number;
5
+ private _lastTimestamp;
6
+ reset(): void;
7
+ update(timestamp: number): void;
8
+ }
9
+ //# sourceMappingURL=time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../src/time.ts"],"names":[],"mappings":"AAEA,qBAAa,IAAI;IACf,SAAS,SAAK;IACd,IAAI,SAAK;IACT,UAAU,SAAK;IAEf,OAAO,CAAC,cAAc,CAAK;IAE3B,KAAK,IAAI,IAAI;IAOb,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAUhC"}
package/dist/time.js ADDED
@@ -0,0 +1,24 @@
1
+ const MAX_DELTA = 1 / 10; // clamp to 100ms to avoid spiral of death
2
+ export class Time {
3
+ deltaTime = 0;
4
+ time = 0;
5
+ frameCount = 0;
6
+ _lastTimestamp = 0;
7
+ reset() {
8
+ this.deltaTime = 0;
9
+ this.time = 0;
10
+ this.frameCount = 0;
11
+ this._lastTimestamp = 0;
12
+ }
13
+ update(timestamp) {
14
+ if (this._lastTimestamp === 0) {
15
+ this._lastTimestamp = timestamp;
16
+ }
17
+ const rawDelta = (timestamp - this._lastTimestamp) / 1000;
18
+ this.deltaTime = Math.min(rawDelta, MAX_DELTA);
19
+ this.time += this.deltaTime;
20
+ this.frameCount++;
21
+ this._lastTimestamp = timestamp;
22
+ }
23
+ }
24
+ //# sourceMappingURL=time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.js","sourceRoot":"","sources":["../src/time.ts"],"names":[],"mappings":"AAAA,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,0CAA0C;AAEpE,MAAM,OAAO,IAAI;IACf,SAAS,GAAG,CAAC,CAAC;IACd,IAAI,GAAG,CAAC,CAAC;IACT,UAAU,GAAG,CAAC,CAAC;IAEP,cAAc,GAAG,CAAC,CAAC;IAE3B,KAAK;QACH,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,CAAC,SAAiB;QACtB,IAAI,IAAI,CAAC,cAAc,KAAK,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;QAClC,CAAC;QACD,MAAM,QAAQ,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC;QAC1D,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC/C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC;QAC5B,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;IAClC,CAAC;CACF"}