create-photon-engine 0.1.2 → 0.2.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.
- package/package.json +1 -1
- package/templates/browser/node_modules/.vite/deps/_metadata.json +8 -0
- package/templates/browser/node_modules/.vite/deps/package.json +3 -0
- package/templates/browser/src/hud.pui +58 -0
- package/templates/browser/src/main.ts +45 -36
- package/templates/browser/src/vite-env.d.ts +1 -0
- package/templates/electron/dist-renderer/assets/__vite-browser-external-D7Ct-6yo.js +1 -0
- package/templates/electron/dist-renderer/assets/index-Cxo-KaTG.js +1 -0
- package/templates/electron/dist-renderer/assets/index-XXTau1xu.js +92 -0
- package/templates/electron/dist-renderer/index.html +16 -0
- package/templates/electron/src/hud.pui +58 -0
- package/templates/electron/src/main.ts +50 -37
- package/templates/electron/src/vite-env.d.ts +1 -0
package/package.json
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Photon Engine — HUD demo
|
|
2
|
+
panel "hud" {
|
|
3
|
+
x: 20; y: 20;
|
|
4
|
+
width: 300; height: 210;
|
|
5
|
+
color: [0.08, 0.08, 0.1, 0.85];
|
|
6
|
+
borderRadius: 8;
|
|
7
|
+
|
|
8
|
+
text "title" {
|
|
9
|
+
x: 0; y: 12;
|
|
10
|
+
width: 300; height: 28;
|
|
11
|
+
text: "Photon Engine UI Demo";
|
|
12
|
+
fontSize: 18;
|
|
13
|
+
color: [0.5, 0.7, 1, 1];
|
|
14
|
+
align: center;
|
|
15
|
+
bold: true;
|
|
16
|
+
zIndex: 1;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
text "score" {
|
|
20
|
+
x: 10; y: 52;
|
|
21
|
+
width: 280; height: 24;
|
|
22
|
+
text: "Clicks: 0";
|
|
23
|
+
fontSize: 15;
|
|
24
|
+
color: [1, 1, 1, 1];
|
|
25
|
+
fontFamily: monospace;
|
|
26
|
+
zIndex: 1;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
button "clickBtn" {
|
|
30
|
+
x: 70; y: 88;
|
|
31
|
+
width: 160; height: 38;
|
|
32
|
+
label: "Click Me!";
|
|
33
|
+
color: [0.16, 0.5, 1, 1];
|
|
34
|
+
hoverColor: [0.29, 0.62, 1, 1];
|
|
35
|
+
pressedColor: [0.1, 0.37, 0.8, 1];
|
|
36
|
+
borderRadius: 8;
|
|
37
|
+
fontSize: 15;
|
|
38
|
+
zIndex: 1;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
text "nameLabel" {
|
|
42
|
+
x: 10; y: 146;
|
|
43
|
+
width: 60; height: 22;
|
|
44
|
+
text: "Name:";
|
|
45
|
+
fontSize: 13;
|
|
46
|
+
color: [0.7, 0.7, 0.7, 1];
|
|
47
|
+
zIndex: 1;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
textInput "nameInput" {
|
|
51
|
+
x: 70; y: 143;
|
|
52
|
+
width: 220; height: 28;
|
|
53
|
+
placeholder: "Type here...";
|
|
54
|
+
maxLength: 64;
|
|
55
|
+
fontSize: 13;
|
|
56
|
+
zIndex: 1;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import puiSource from "./hud.pui?raw";
|
|
1
2
|
import {
|
|
2
3
|
Engine, Scene, Transform2D, Camera2D, Sprite, Component,
|
|
4
|
+
UIText, UIRenderSystem,
|
|
5
|
+
parsePui, loadPui,
|
|
3
6
|
} from "photon-engine";
|
|
4
7
|
|
|
5
8
|
class OrbitalSpeed extends Component {
|
|
@@ -12,15 +15,19 @@ class OrbitalSpeed extends Component {
|
|
|
12
15
|
) { super(); }
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
class
|
|
16
|
-
readonly name = "
|
|
18
|
+
class DemoScene extends Scene {
|
|
19
|
+
readonly name = "demo";
|
|
20
|
+
private uiSystem = new UIRenderSystem();
|
|
21
|
+
private clickCount = 0;
|
|
22
|
+
private scoreId = 0;
|
|
23
|
+
private btnId = 0;
|
|
17
24
|
|
|
18
25
|
onEnter(): void {
|
|
26
|
+
this.world.registerSystem(this.uiSystem);
|
|
27
|
+
|
|
19
28
|
const cam = this.world.createEntity();
|
|
20
29
|
this.world.addComponent(cam.id, new Transform2D());
|
|
21
|
-
|
|
22
|
-
camComp.zoom = 1;
|
|
23
|
-
this.world.addComponent(cam.id, camComp);
|
|
30
|
+
this.world.addComponent(cam.id, new Camera2D());
|
|
24
31
|
|
|
25
32
|
const nucleus = this.world.createEntity().tag("nucleus");
|
|
26
33
|
const nPos = new Transform2D();
|
|
@@ -35,9 +42,9 @@ class AtomScene extends Scene {
|
|
|
35
42
|
this.world.addComponent(glow.id, new Sprite(0.9, 0.5, 0.1, 0.15, 60, 60));
|
|
36
43
|
|
|
37
44
|
const orbits = [
|
|
38
|
-
{ radius: 80, speed: 2.0, tilt: 0,
|
|
39
|
-
{ radius: 130, speed: 1.3, tilt: Math.PI / 3,
|
|
40
|
-
{ radius: 180, speed: 0.8, tilt: -Math.PI / 4,
|
|
45
|
+
{ radius: 80, speed: 2.0, tilt: 0, color: [0.3, 0.7, 1.0], size: 8, offset: 0 },
|
|
46
|
+
{ radius: 130, speed: 1.3, tilt: Math.PI / 3, color: [0.4, 1.0, 0.6], size: 7, offset: Math.PI * 0.66 },
|
|
47
|
+
{ radius: 180, speed: 0.8, tilt: -Math.PI / 4, color: [1.0, 0.4, 0.8], size: 6, offset: Math.PI * 1.33 },
|
|
41
48
|
];
|
|
42
49
|
|
|
43
50
|
for (const orbit of orbits) {
|
|
@@ -48,10 +55,10 @@ class AtomScene extends Scene {
|
|
|
48
55
|
dPos.zIndex = 1;
|
|
49
56
|
this.world.addComponent(dot.id, dPos);
|
|
50
57
|
this.world.addComponent(dot.id, new OrbitalSpeed(
|
|
51
|
-
orbit.radius, 0, (i / ringCount) * Math.PI * 2, orbit.tilt
|
|
58
|
+
orbit.radius, 0, (i / ringCount) * Math.PI * 2, orbit.tilt,
|
|
52
59
|
));
|
|
53
60
|
this.world.addComponent(dot.id, new Sprite(
|
|
54
|
-
orbit.color[0] * 0.3, orbit.color[1] * 0.3, orbit.color[2] * 0.3, 0.25, 2, 2
|
|
61
|
+
orbit.color[0] * 0.3, orbit.color[1] * 0.3, orbit.color[2] * 0.3, 0.25, 2, 2,
|
|
55
62
|
));
|
|
56
63
|
}
|
|
57
64
|
|
|
@@ -60,37 +67,39 @@ class AtomScene extends Scene {
|
|
|
60
67
|
ePos.zIndex = 5;
|
|
61
68
|
this.world.addComponent(electron.id, ePos);
|
|
62
69
|
this.world.addComponent(electron.id, new OrbitalSpeed(
|
|
63
|
-
orbit.radius, orbit.speed, orbit.offset, orbit.tilt
|
|
70
|
+
orbit.radius, orbit.speed, orbit.offset, orbit.tilt,
|
|
64
71
|
));
|
|
65
72
|
this.world.addComponent(electron.id, new Sprite(
|
|
66
|
-
orbit.color[0], orbit.color[1], orbit.color[2], 1, orbit.size, orbit.size
|
|
67
|
-
));
|
|
68
|
-
|
|
69
|
-
const eGlow = this.world.createEntity().tag("electron-glow");
|
|
70
|
-
const egPos = new Transform2D();
|
|
71
|
-
egPos.zIndex = 4;
|
|
72
|
-
this.world.addComponent(eGlow.id, egPos);
|
|
73
|
-
this.world.addComponent(eGlow.id, new OrbitalSpeed(
|
|
74
|
-
orbit.radius, orbit.speed, orbit.offset, orbit.tilt
|
|
75
|
-
));
|
|
76
|
-
this.world.addComponent(eGlow.id, new Sprite(
|
|
77
|
-
orbit.color[0], orbit.color[1], orbit.color[2], 0.2, orbit.size * 4, orbit.size * 4
|
|
73
|
+
orbit.color[0], orbit.color[1], orbit.color[2], 1, orbit.size, orbit.size,
|
|
78
74
|
));
|
|
79
75
|
}
|
|
76
|
+
|
|
77
|
+
// Load UI from hud.pui
|
|
78
|
+
const ui = loadPui(this.world, parsePui(puiSource));
|
|
79
|
+
this.scoreId = ui.entities.get("score")!;
|
|
80
|
+
this.btnId = ui.entities.get("clickBtn")!;
|
|
81
|
+
|
|
82
|
+
this.world.eventBus.on<number>("ui:click", (entityId) => {
|
|
83
|
+
if (entityId === this.btnId) {
|
|
84
|
+
this.clickCount++;
|
|
85
|
+
const arch = this.world.getArchetype(this.scoreId);
|
|
86
|
+
if (arch) {
|
|
87
|
+
arch.get<UIText>("uiText")!.text = `Clicks: ${this.clickCount}`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
80
91
|
}
|
|
81
92
|
|
|
82
93
|
onUpdate(): void {
|
|
83
94
|
const time = performance.now() * 0.001;
|
|
84
|
-
const entities = this.world.query("transform2d", "orbitalSpeed");
|
|
85
95
|
|
|
86
|
-
for (const arch of
|
|
96
|
+
for (const arch of this.world.query("transform2d", "orbitalSpeed")) {
|
|
87
97
|
const t = arch.get<Transform2D>("transform2d")!;
|
|
88
98
|
const o = arch.get<OrbitalSpeed>("orbitalSpeed")!;
|
|
89
99
|
|
|
90
100
|
const angle = o.angleOffset + time * o.speed;
|
|
91
101
|
const x = Math.cos(angle) * o.radius;
|
|
92
102
|
const y = Math.sin(angle) * o.radius * 0.4;
|
|
93
|
-
|
|
94
103
|
const cosT = Math.cos(o.orbitTilt);
|
|
95
104
|
const sinT = Math.sin(o.orbitTilt);
|
|
96
105
|
t.x = x * cosT - y * sinT;
|
|
@@ -99,19 +108,19 @@ class AtomScene extends Scene {
|
|
|
99
108
|
|
|
100
109
|
const nucleusArch = this.world.queryByTag("nucleus")[0];
|
|
101
110
|
if (nucleusArch) {
|
|
102
|
-
const
|
|
111
|
+
const s = nucleusArch.get<Sprite>("sprite")!;
|
|
103
112
|
const pulse = 28 + Math.sin(time * 3) * 4;
|
|
104
|
-
|
|
105
|
-
|
|
113
|
+
s.width = pulse;
|
|
114
|
+
s.height = pulse;
|
|
106
115
|
}
|
|
107
116
|
|
|
108
117
|
const glowArch = this.world.queryByTag("glow")[0];
|
|
109
118
|
if (glowArch) {
|
|
110
|
-
const
|
|
119
|
+
const s = glowArch.get<Sprite>("sprite")!;
|
|
111
120
|
const pulse = 60 + Math.sin(time * 2) * 10;
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
121
|
+
s.width = pulse;
|
|
122
|
+
s.height = pulse;
|
|
123
|
+
s.colorA = 0.12 + Math.sin(time * 3) * 0.05;
|
|
115
124
|
}
|
|
116
125
|
}
|
|
117
126
|
|
|
@@ -119,6 +128,6 @@ class AtomScene extends Scene {
|
|
|
119
128
|
}
|
|
120
129
|
|
|
121
130
|
const engine = new Engine({ canvasId: "game-canvas" });
|
|
122
|
-
engine.sceneManager.register(new
|
|
123
|
-
engine.sceneManager.switchTo("
|
|
124
|
-
engine.start();
|
|
131
|
+
engine.sceneManager.register(new DemoScene());
|
|
132
|
+
engine.sceneManager.switchTo("demo");
|
|
133
|
+
engine.start();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e={},t=Object.freeze(Object.defineProperty({__proto__:null,default:e},Symbol.toStringTag,{value:"Module"}));export{t as _};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_ as u}from"./__vite-browser-external-D7Ct-6yo.js";function l(t,n){for(var r=0;r<n.length;r++){const e=n[r];if(typeof e!="string"&&!Array.isArray(e)){for(const o in e)if(o!=="default"&&!(o in t)){const i=Object.getOwnPropertyDescriptor(e,o);i&&Object.defineProperty(t,o,i.get?i:{enumerable:!0,get:()=>e[o]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}function f(t){if(Object.prototype.hasOwnProperty.call(t,"__esModule"))return t;var n=t.default;if(typeof n=="function"){var r=function e(){return this instanceof e?Reflect.construct(n,arguments,this.constructor):n.apply(this,arguments)};r.prototype=n.prototype}else r={};return Object.defineProperty(r,"__esModule",{value:!0}),Object.keys(t).forEach(function(e){var o=Object.getOwnPropertyDescriptor(t,e);Object.defineProperty(r,e,o.get?o:{enumerable:!0,get:function(){return t[e]}})}),r}const a=f(u);var c,s;function p(){if(s)return c;s=1;var t={};const n=a,r=a,e=r.join(__dirname,"path.txt");function o(){let i;if(n.existsSync(e)&&(i=n.readFileSync(e,"utf-8")),t.ELECTRON_OVERRIDE_DIST_PATH)return r.join(t.ELECTRON_OVERRIDE_DIST_PATH,i||"electron");if(i)return r.join(__dirname,"dist",i);throw new Error("Electron failed to install correctly, please delete node_modules/electron and try installing again")}return c=o(),c}var _=p();const y=l({__proto__:null},[_]);export{y as i};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./index-Cxo-KaTG.js","./__vite-browser-external-D7Ct-6yo.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
var N=Object.defineProperty;var V=(d,e,t)=>e in d?N(d,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):d[e]=t;var r=(d,e,t)=>V(d,typeof e!="symbol"?e+"":e,t);(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))i(s);new MutationObserver(s=>{for(const n of s)if(n.type==="childList")for(const o of n.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&i(o)}).observe(document,{childList:!0,subtree:!0});function t(s){const n={};return s.integrity&&(n.integrity=s.integrity),s.referrerPolicy&&(n.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?n.credentials="include":s.crossOrigin==="anonymous"?n.credentials="omit":n.credentials="same-origin",n}function i(s){if(s.ep)return;s.ep=!0;const n=t(s);fetch(s.href,n)}})();const X=`// Photon Engine — HUD demo
|
|
3
|
+
panel "hud" {
|
|
4
|
+
x: 20; y: 20;
|
|
5
|
+
width: 300; height: 210;
|
|
6
|
+
color: [0.08, 0.08, 0.1, 0.85];
|
|
7
|
+
borderRadius: 8;
|
|
8
|
+
|
|
9
|
+
text "title" {
|
|
10
|
+
x: 0; y: 12;
|
|
11
|
+
width: 300; height: 28;
|
|
12
|
+
text: "Photon Engine — Electron";
|
|
13
|
+
fontSize: 18;
|
|
14
|
+
color: [0.5, 0.7, 1, 1];
|
|
15
|
+
align: center;
|
|
16
|
+
bold: true;
|
|
17
|
+
zIndex: 1;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
text "score" {
|
|
21
|
+
x: 10; y: 52;
|
|
22
|
+
width: 280; height: 24;
|
|
23
|
+
text: "Clicks: 0";
|
|
24
|
+
fontSize: 15;
|
|
25
|
+
color: [1, 1, 1, 1];
|
|
26
|
+
fontFamily: monospace;
|
|
27
|
+
zIndex: 1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
button "clickBtn" {
|
|
31
|
+
x: 70; y: 88;
|
|
32
|
+
width: 160; height: 38;
|
|
33
|
+
label: "Click Me!";
|
|
34
|
+
color: [0.16, 0.5, 1, 1];
|
|
35
|
+
hoverColor: [0.29, 0.62, 1, 1];
|
|
36
|
+
pressedColor: [0.1, 0.37, 0.8, 1];
|
|
37
|
+
borderRadius: 8;
|
|
38
|
+
fontSize: 15;
|
|
39
|
+
zIndex: 1;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
text "nameLabel" {
|
|
43
|
+
x: 10; y: 146;
|
|
44
|
+
width: 60; height: 22;
|
|
45
|
+
text: "Name:";
|
|
46
|
+
fontSize: 13;
|
|
47
|
+
color: [0.7, 0.7, 0.7, 1];
|
|
48
|
+
zIndex: 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
textInput "nameInput" {
|
|
52
|
+
x: 70; y: 143;
|
|
53
|
+
width: 220; height: 28;
|
|
54
|
+
placeholder: "Type here...";
|
|
55
|
+
maxLength: 64;
|
|
56
|
+
fontSize: 13;
|
|
57
|
+
zIndex: 1;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
`;class W{constructor(){r(this,"listeners",new Map)}on(e,t){return this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t),()=>this.off(e,t)}once(e,t){const i=s=>{this.off(e,i),t(s)};return this.on(e,i)}off(e,t){var i;(i=this.listeners.get(e))==null||i.delete(t)}emit(e,t){const i=this.listeners.get(e);if(i)for(const s of i)try{s(t)}catch(n){console.error(`[EventBus] Error in "${e}":`,n)}}clear(e){e?this.listeners.delete(e):this.listeners.clear()}listenerCount(e){var t;return((t=this.listeners.get(e))==null?void 0:t.size)??0}}class j{constructor(e,t){r(this,"scenes",new Map);r(this,"current",null);r(this,"bus");r(this,"engine");this.bus=e??new W,this.engine=t}register(e){e.engine=this.engine,this.scenes.set(e.name,e)}unregister(e){var t;((t=this.current)==null?void 0:t.name)===e&&(this.current.onExit(),this.current=null),this.scenes.delete(e)}switchTo(e){const t=this.scenes.get(e);return t?(this.current&&this.current.onExit(),this.current=t,this.current.engine=this.engine,this.current.onEnter(),this.bus.emit("scene:switched",e),!0):!1}get currentScene(){return this.current}get sceneNames(){return[...this.scenes.keys()]}get eventBus(){return this.bus}getScene(e){return this.scenes.get(e)}}class K{constructor(e,t,i){r(this,"gl");r(this,"program");this.gl=e;const s=this.compile(e.VERTEX_SHADER,t),n=this.compile(e.FRAGMENT_SHADER,i);if(this.program=e.createProgram(),e.attachShader(this.program,s),e.attachShader(this.program,n),e.linkProgram(this.program),!e.getProgramParameter(this.program,e.LINK_STATUS)){const o=e.getProgramInfoLog(this.program);throw e.deleteProgram(this.program),new Error(`Shader link error: ${o}`)}e.deleteShader(s),e.deleteShader(n)}compile(e,t){const i=this.gl.createShader(e);if(this.gl.shaderSource(i,t),this.gl.compileShader(i),!this.gl.getShaderParameter(i,this.gl.COMPILE_STATUS)){const s=this.gl.getShaderInfoLog(i);throw this.gl.deleteShader(i),new Error(`Shader compile error: ${s}`)}return i}use(){this.gl.useProgram(this.program)}getAttribLocation(e){return this.gl.getAttribLocation(this.program,e)}getUniformLocation(e){return this.gl.getUniformLocation(this.program,e)}setUniformMat3(e,t){const i=this.getUniformLocation(e);i&&this.gl.uniformMatrix3fv(i,!1,t)}setUniformVec4(e,t,i,s,n){const o=this.getUniformLocation(e);o&&this.gl.uniform4f(o,t,i,s,n)}setUniformVec2(e,t,i){const s=this.getUniformLocation(e);s&&this.gl.uniform2f(s,t,i)}setUniformFloat(e,t){const i=this.getUniformLocation(e);i&&this.gl.uniform1f(i,t)}setUniformInt(e,t){const i=this.getUniformLocation(e);i&&this.gl.uniform1i(i,t)}destroy(){this.gl.deleteProgram(this.program)}}const Z=`#version 300 es
|
|
61
|
+
layout(location = 0) in vec2 aPosition;
|
|
62
|
+
layout(location = 1) in vec2 aTexCoord;
|
|
63
|
+
layout(location = 2) in vec4 aColor;
|
|
64
|
+
|
|
65
|
+
uniform mat3 uViewProj;
|
|
66
|
+
|
|
67
|
+
out vec2 vTexCoord;
|
|
68
|
+
out vec4 vColor;
|
|
69
|
+
|
|
70
|
+
void main() {
|
|
71
|
+
vec3 pos = uViewProj * vec3(aPosition, 1.0);
|
|
72
|
+
gl_Position = vec4(pos.xy, 0.0, 1.0);
|
|
73
|
+
vTexCoord = aTexCoord;
|
|
74
|
+
vColor = aColor;
|
|
75
|
+
}
|
|
76
|
+
`,J=`#version 300 es
|
|
77
|
+
precision mediump float;
|
|
78
|
+
|
|
79
|
+
in vec2 vTexCoord;
|
|
80
|
+
in vec4 vColor;
|
|
81
|
+
|
|
82
|
+
uniform sampler2D uTexture;
|
|
83
|
+
uniform float uUseTexture;
|
|
84
|
+
|
|
85
|
+
out vec4 fragColor;
|
|
86
|
+
|
|
87
|
+
void main() {
|
|
88
|
+
vec4 texColor = mix(vec4(1.0), texture(uTexture, vTexCoord), uUseTexture);
|
|
89
|
+
fragColor = vColor * texColor;
|
|
90
|
+
}
|
|
91
|
+
`,M=8,O=1e4;class Q{constructor(e){r(this,"gl");r(this,"shader");r(this,"vao");r(this,"vbo");r(this,"vertices");r(this,"vertexCount",0);r(this,"currentTexture",null);const t=e.getContext("webgl2",{alpha:!1,antialias:!1,premultipliedAlpha:!1});if(!t)throw new Error("WebGL2 not supported");this.gl=t,this.shader=new K(t,Z,J),this.vertices=new Float32Array(O*6*M),this.vao=t.createVertexArray(),this.vbo=t.createBuffer(),t.bindVertexArray(this.vao),t.bindBuffer(t.ARRAY_BUFFER,this.vbo),t.bufferData(t.ARRAY_BUFFER,this.vertices.byteLength,t.DYNAMIC_DRAW);const i=M*4;t.enableVertexAttribArray(0),t.vertexAttribPointer(0,2,t.FLOAT,!1,i,0),t.enableVertexAttribArray(1),t.vertexAttribPointer(1,2,t.FLOAT,!1,i,8),t.enableVertexAttribArray(2),t.vertexAttribPointer(2,4,t.FLOAT,!1,i,16),t.bindVertexArray(null),t.enable(t.BLEND),t.blendFunc(t.SRC_ALPHA,t.ONE_MINUS_SRC_ALPHA)}clear(e=0,t=0,i=0,s=1){this.gl.clearColor(e,t,i,s),this.gl.clear(this.gl.COLOR_BUFFER_BIT)}begin(e){this.shader.use(),this.shader.setUniformMat3("uViewProj",e.data),this.gl.bindVertexArray(this.vao)}drawSprite(e,t){const i=t.texture??null;(i!==this.currentTexture||this.vertexCount+6>O*6)&&(this.flush(),this.currentTexture=i),i?(this.gl.activeTexture(this.gl.TEXTURE0),this.gl.bindTexture(this.gl.TEXTURE_2D,i),this.shader.setUniformInt("uTexture",0),this.shader.setUniformFloat("uUseTexture",1)):this.shader.setUniformFloat("uUseTexture",0);const s=t.width*.5,n=t.height*.5,o=e.getLocalMatrix(),c=[{x:-s,y:-n,u:t.texCoordU,v:t.texCoordV},{x:s,y:-n,u:t.texCoordU+t.texCoordW,v:t.texCoordV},{x:s,y:n,u:t.texCoordU+t.texCoordW,v:t.texCoordV+t.texCoordH},{x:-s,y:n,u:t.texCoordU,v:t.texCoordV+t.texCoordH}].map(f=>{const g=o.transformPoint({x:f.x,y:f.y});return{x:g.x,y:g.y,u:f.u,v:f.v}}),h=this.vertices;let l=this.vertexCount*M;const u=f=>{const g=c[f];h[l++]=g.x,h[l++]=g.y,h[l++]=g.u,h[l++]=g.v,h[l++]=t.colorR,h[l++]=t.colorG,h[l++]=t.colorB,h[l++]=t.colorA};u(0),u(1),u(2),u(0),u(2),u(3),this.vertexCount+=6}flush(){this.vertexCount!==0&&(this.gl.bufferSubData(this.gl.ARRAY_BUFFER,0,this.vertices,0,this.vertexCount*M),this.gl.drawArrays(this.gl.TRIANGLES,0,this.vertexCount),this.vertexCount=0)}end(){this.flush(),this.gl.bindVertexArray(null),this.currentTexture=null}resize(e,t){this.gl.viewport(0,0,e,t)}get context(){return this.gl}destroy(){this.shader.destroy(),this.gl.deleteBuffer(this.vbo),this.gl.deleteVertexArray(this.vao)}}const p=class p{constructor(e=0,t=0){r(this,"x");r(this,"y");this.x=e,this.y=t}clone(){return new p(this.x,this.y)}set(e,t){return this.x=e,this.y=t,this}add(e){return new p(this.x+e.x,this.y+e.y)}sub(e){return new p(this.x-e.x,this.y-e.y)}mul(e){return new p(this.x*e,this.y*e)}div(e){return new p(this.x/e,this.y/e)}dot(e){return this.x*e.x+this.y*e.y}cross(e){return this.x*e.y-this.y*e.x}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}lengthSq(){return this.x*this.x+this.y*this.y}normalize(){const e=this.length();return e>0?this.div(e):p.ZERO.clone()}distance(e){return this.sub(e).length()}distanceSq(e){return this.sub(e).lengthSq()}angle(){return Math.atan2(this.y,this.x)}rotate(e){const t=Math.cos(e),i=Math.sin(e);return new p(this.x*t-this.y*i,this.x*i+this.y*t)}lerp(e,t){return new p(this.x+(e.x-this.x)*t,this.y+(e.y-this.y)*t)}equals(e,t=1e-6){return Math.abs(this.x-e.x)<t&&Math.abs(this.y-e.y)<t}static fromAngle(e,t=1){return new p(Math.cos(e)*t,Math.sin(e)*t)}static lerp(e,t,i){return e.lerp(t,i)}};r(p,"ZERO",new p(0,0)),r(p,"ONE",new p(1,1)),r(p,"UP",new p(0,-1)),r(p,"DOWN",new p(0,1)),r(p,"LEFT",new p(-1,0)),r(p,"RIGHT",new p(1,0));let T=p;var z;(function(d){d[d.Game=0]="Game",d[d.UI=100]="UI",d[d.Console=200]="Console",d[d.Modal=300]="Modal"})(z||(z={}));class tt{constructor(){r(this,"stack",[]);r(this,"counter",0)}request(e,t){const i=this.stack.findIndex(n=>n.holderId===e);i!==-1&&this.stack.splice(i,1);const s={holderId:e,priority:t,timestamp:this.counter++};return this.stack.push(s),this.stack.sort((n,o)=>n.priority!==o.priority?o.priority-n.priority:o.timestamp-n.timestamp),this.stack[0].holderId===e}release(e){const t=this.stack.findIndex(i=>i.holderId===e);t!==-1&&this.stack.splice(t,1)}isCaptured(){return this.stack.length>0}getCurrentHolder(){return this.stack.length>0?this.stack[0].holderId:null}hasOwnership(e){return this.stack.length>0&&this.stack[0].holderId===e}getStack(){return this.stack}clear(){this.stack=[],this.counter=0}}class et{constructor(e){r(this,"canvas");r(this,"keysDown",new Set);r(this,"keysPressed",new Set);r(this,"keysReleased",new Set);r(this,"mouseButtonsDown",new Set);r(this,"mouseButtonsPressed",new Set);r(this,"mouseButtonsReleased",new Set);r(this,"mousePos",new T);r(this,"mouseDelta",new T);r(this,"scrollDelta",0);r(this,"bound",!1);r(this,"captureStack",new tt);r(this,"keyDownHandler");r(this,"keyUpHandler");r(this,"mouseMoveHandler");r(this,"mouseDownHandler");r(this,"mouseUpHandler");r(this,"wheelHandler");this.canvas=e,this.keyDownHandler=t=>{this.captureStack.isCaptured()||(this.keysDown.has(t.code)||this.keysPressed.add(t.code),this.keysDown.add(t.code),t.preventDefault())},this.keyUpHandler=t=>{this.captureStack.isCaptured()||(this.keysDown.delete(t.code),this.keysReleased.add(t.code))},this.mouseMoveHandler=t=>{const i=this.canvas.getBoundingClientRect(),s=t.clientX-i.left,n=t.clientY-i.top;this.mouseDelta=new T(s-this.mousePos.x,n-this.mousePos.y),this.mousePos=new T(s,n)},this.mouseDownHandler=t=>{this.captureStack.isCaptured()||(this.mouseButtonsDown.has(t.button)||this.mouseButtonsPressed.add(t.button),this.mouseButtonsDown.add(t.button))},this.mouseUpHandler=t=>{this.captureStack.isCaptured()||(this.mouseButtonsDown.delete(t.button),this.mouseButtonsReleased.add(t.button))},this.wheelHandler=t=>{this.captureStack.isCaptured()||(this.scrollDelta=t.deltaY)}}capture(e,t=z.UI){return this.captureStack.request(e,t)}release(e){this.captureStack.release(e)}hasOwnership(e){return this.captureStack.hasOwnership(e)}isCaptured(){return this.captureStack.isCaptured()}getCurrentHolder(){return this.captureStack.getCurrentHolder()}init(){this.bound||(this.bound=!0,window.addEventListener("keydown",this.keyDownHandler),window.addEventListener("keyup",this.keyUpHandler),this.canvas.addEventListener("mousemove",this.mouseMoveHandler),this.canvas.addEventListener("mousedown",this.mouseDownHandler),this.canvas.addEventListener("mouseup",this.mouseUpHandler),this.canvas.addEventListener("wheel",this.wheelHandler))}destroy(){this.bound&&(this.bound=!1,window.removeEventListener("keydown",this.keyDownHandler),window.removeEventListener("keyup",this.keyUpHandler),this.canvas.removeEventListener("mousemove",this.mouseMoveHandler),this.canvas.removeEventListener("mousedown",this.mouseDownHandler),this.canvas.removeEventListener("mouseup",this.mouseUpHandler),this.canvas.removeEventListener("wheel",this.wheelHandler),this.captureStack.clear())}endFrame(){this.keysPressed.clear(),this.keysReleased.clear(),this.mouseButtonsPressed.clear(),this.mouseButtonsReleased.clear(),this.mouseDelta=T.ZERO.clone(),this.scrollDelta=0}isKeyDown(e){return this.captureStack.isCaptured()?!1:this.keysDown.has(e)}isKeyPressed(e){return this.captureStack.isCaptured()?!1:this.keysPressed.has(e)}isKeyReleased(e){return this.captureStack.isCaptured()?!1:this.keysReleased.has(e)}isMouseButtonDown(e=0){return this.captureStack.isCaptured()?!1:this.mouseButtonsDown.has(e)}isMouseButtonPressed(e=0){return this.captureStack.isCaptured()?!1:this.mouseButtonsPressed.has(e)}isMouseButtonReleased(e=0){return this.captureStack.isCaptured()?!1:this.mouseButtonsReleased.has(e)}get mousePosition(){return this.mousePos.clone()}get mouseDeltaPosition(){return this.mouseDelta.clone()}get scrollY(){return this.captureStack.isCaptured()?0:this.scrollDelta}}class st{async collideAABB(e,t,i,s,n,o,a,c){return e<n+a&&e+i>n&&t<o+c&&t+s>o}async batchTransform(e,t){return e}async noise2D(e,t,i){const s=Math.sin(e*127.1+t*311.7)*43758.5453123;return s-Math.floor(s)}async pathfind(){return console.warn("[Photon] pathfind: no compute backend, returning null"),null}}class it{constructor(e){r(this,"fs");this.fs=e}async invoke(e,t){throw new Error(`[Photon] Native invoke "${e}" not available in browser mode`)}}class rt{constructor(){r(this,"storage",new Map)}async readText(e){const t=this.storage.get(e);if(!t)throw new Error(`File not found: ${e}`);return new TextDecoder().decode(t)}async writeText(e,t){this.storage.set(e,new TextEncoder().encode(t)),this.persistToLocalStorage()}async readBinary(e){const t=this.storage.get(e);if(!t)throw new Error(`File not found: ${e}`);return t}async writeBinary(e,t){this.storage.set(e,t),this.persistToLocalStorage()}async exists(e){return this.storage.has(e)}async mkdir(e){}async remove(e){this.storage.delete(e),this.persistToLocalStorage()}async listDir(e){const t=e.endsWith("/")?e:e+"/",i=new Set;for(const s of this.storage.keys())if(s.startsWith(t)){const o=s.slice(t.length).split("/")[0];i.add(o)}return[...i]}async isFile(e){return this.storage.has(e)}async isDir(e){const t=e.endsWith("/")?e:e+"/";for(const i of this.storage.keys())if(i.startsWith(t))return!0;return!1}persistToLocalStorage(){try{const e={};for(const[t,i]of this.storage)e[t]=[...i];localStorage.setItem("photon:fs",JSON.stringify(e))}catch{}}loadFromLocalStorage(){try{const e=localStorage.getItem("photon:fs");if(!e)return;const t=JSON.parse(e);for(const[i,s]of Object.entries(t))this.storage.set(i,new Uint8Array(s))}catch{}}}class nt{constructor(e={}){r(this,"sceneManager");r(this,"renderer");r(this,"input");r(this,"eventBus");r(this,"fs");r(this,"bridge");r(this,"compute");r(this,"running",!1);r(this,"lastTime",0);r(this,"rafId",0);r(this,"fixedAccumulator",0);r(this,"fixedStep",1e3/60);r(this,"canvas");r(this,"dpr",1);r(this,"loop",e=>{if(!this.running)return;this.rafId=requestAnimationFrame(this.loop);const t=e-this.lastTime;this.lastTime=e;const i=Math.min(t,250);for(this.fixedAccumulator+=i;this.fixedAccumulator>=this.fixedStep;)this.fixedUpdate(this.fixedStep/1e3),this.fixedAccumulator-=this.fixedStep;this.update(i/1e3),this.render(),this.input.endFrame()});const t=e.canvasId??"photon-canvas",i=document.getElementById(t);if(!i)throw new Error(`Canvas "#${t}" not found`);this.dpr=window.devicePixelRatio||1;const s=e.width??window.innerWidth,n=e.height??window.innerHeight;if(i.style.width=s+"px",i.style.height=n+"px",i.width=Math.round(s*this.dpr),i.height=Math.round(n*this.dpr),this.canvas=i,this.eventBus=new W,this.renderer=new Q(i),this.input=new et(i),this.sceneManager=new j(this.eventBus,this),e.fs)this.fs=e.fs;else{const o=new rt;o.loadFromLocalStorage(),this.fs=o}this.bridge=e.nativeBridge??new it(this.fs),this.compute=new st,window.addEventListener("resize",()=>this.handleResize())}handleResize(){this.dpr=window.devicePixelRatio||1;const e=window.innerWidth,t=window.innerHeight;this.canvas.style.width=e+"px",this.canvas.style.height=t+"px",this.canvas.width=Math.round(e*this.dpr),this.canvas.height=Math.round(t*this.dpr),this.renderer.resize(this.canvas.width,this.canvas.height),this.eventBus.emit("engine:resize",{width:this.canvas.width,height:this.canvas.height})}get pixelRatio(){return this.dpr}get cssWidth(){return this.canvas.getBoundingClientRect().width}get cssHeight(){return this.canvas.getBoundingClientRect().height}start(){this.running||(this.running=!0,this.input.init(),this.lastTime=performance.now(),this.loop(this.lastTime),this.eventBus.emit("engine:start",null))}stop(){this.running=!1,this.input.destroy(),cancelAnimationFrame(this.rafId),this.eventBus.emit("engine:stop",null)}fixedUpdate(e){const t=this.sceneManager.currentScene;t&&(t.world.update(e),t.onUpdate(e))}update(e){}render(){const e=this.sceneManager.currentScene;if(!e){this.renderer.clear(.1,.1,.1);return}const t=e.world.query("camera2d","transform2d");if(t.length===0){this.renderer.clear(.1,.1,.1);return}const i=t[0],s=i.get("camera2d"),n=i.get("transform2d");s.x=n.x,s.y=n.y,s.rotation=n.rotation,s.viewportWidth=this.canvas.width,s.viewportHeight=this.canvas.height;const o=s.getViewProjectionMatrix();this.renderer.clear(.1,.1,.12),this.renderer.begin(o);const a=e.world.query("transform2d","sprite");a.sort((c,h)=>{const l=c.get("transform2d").zIndex,u=h.get("transform2d").zIndex;return l-u});for(const c of a){const h=c.get("transform2d"),l=c.get("sprite");this.renderer.drawSprite(h,l)}this.renderer.end()}resizeUIOverlay(){const e=document.getElementById("photon-ui-overlay");e&&(e.width=this.canvas.width,e.height=this.canvas.height)}destroy(){var e;this.stop(),this.renderer.destroy(),(e=this.sceneManager.currentScene)==null||e.world.clear(),this.eventBus.clear()}}class E{}let ot=1;class at{constructor(e){r(this,"id");r(this,"tags",new Set);r(this,"active",!0);this.id=e??ot++}tag(...e){for(const t of e)this.tags.add(t);return this}untag(...e){for(const t of e)this.tags.delete(t);return this}hasTag(e){return this.tags.has(e)}equals(e){return this.id===e.id}}class ht{constructor(e){r(this,"entity");r(this,"components",new Map);this.entity=e}add(e){return this.components.set(e.type,e),this}remove(e){const t=this.components.get(e);return this.components.delete(e),t}get(e){return this.components.get(e)}has(e){return this.components.has(e)}hasAll(e){for(const t of e)if(!this.components.has(t))return!1;return!0}getAll(){return new Map(this.components)}}class ct{constructor(){r(this,"priority",0);r(this,"active",!0)}}class dt{constructor(){r(this,"archetypes",new Map);r(this,"systems",[]);r(this,"entityRecycleBin",[]);r(this,"bus",new W);r(this,"scene")}createEntity(){const e=this.entityRecycleBin.length>0?this.entityRecycleBin.pop():void 0,t=new at(e),i=new ht(t);return this.archetypes.set(t.id,i),this.bus.emit("entity:created",t),t}destroyEntity(e){const t=this.archetypes.get(e);t&&(this.bus.emit("entity:destroyed",t.entity),this.archetypes.delete(e),this.entityRecycleBin.push(e))}getArchetype(e){return this.archetypes.get(e)}addComponent(e,t){const i=this.archetypes.get(e);i&&(i.add(t),this.bus.emit("component:added",{entityId:e,type:t.type}))}removeComponent(e,t){const i=this.archetypes.get(e);i&&(i.remove(t),this.bus.emit("component:removed",{entityId:e,type:t}))}getComponent(e,t){var i;return(i=this.archetypes.get(e))==null?void 0:i.get(t)}getEntity(e){var t;return(t=this.archetypes.get(e))==null?void 0:t.entity}hasEntity(e){return this.archetypes.has(e)}getAllEntities(){const e=[];for(const[,t]of this.archetypes)e.push(t.entity);return e}registerSystem(e){this.systems.push(e),this.systems.sort((t,i)=>t.priority-i.priority),e.onInit(this)}unregisterSystem(e){const t=this.systems.indexOf(e);t!==-1&&(e.onDestroy(this),this.systems.splice(t,1))}query(...e){const t=[];for(const[,i]of this.archetypes)i.entity.active&&i.hasAll(e)&&t.push(i);return t}queryByTag(e){const t=[];for(const[,i]of this.archetypes)i.entity.active&&i.entity.hasTag(e)&&t.push(i);return t}update(e){for(const t of this.systems){if(!t.active)continue;const i=this.query(...t.requiredComponents);t.onUpdate(this,i,e)}}get entityCount(){return this.archetypes.size}get eventBus(){return this.bus}clear(){for(const e of this.systems)e.onDestroy(this);this.systems=[],this.archetypes.clear(),this.entityRecycleBin=[],this.bus.clear()}}class lt{constructor(){r(this,"world");r(this,"engine");this.world=new dt,this.world.scene=this}moveEntityTo(e,t){const i=this.world.getArchetype(e);if(!i)return!1;const s=i.getAll(),n=i.entity;this.world.destroyEntity(e);const o=t.world.createEntity();o.tags=new Set(n.tags),o.active=n.active;const a=t.world.getArchetype(o.id);for(const[,c]of s)a.add(c);return!0}copyEntityTo(e,t){const i=this.world.getArchetype(e);if(!i)return null;const s=t.world.createEntity();s.tags=new Set(i.entity.tags);const n=t.world.getArchetype(s.id);for(const[,o]of i.getAll())n.add(o);return s}}class v{constructor(e=v.identity().data){r(this,"data");this.data=e}static identity(){return new v(new Float32Array([1,0,0,0,1,0,0,0,1]))}static translation(e,t){const i=v.identity();return i.data[6]=e,i.data[7]=t,i}static rotation(e){const t=Math.cos(e),i=Math.sin(e),s=v.identity();return s.data[0]=t,s.data[1]=i,s.data[3]=-i,s.data[4]=t,s}static scale(e,t){const i=v.identity();return i.data[0]=e,i.data[4]=t,i}static orthographic(e,t,i,s){const n=v.identity();return n.data[0]=2/(t-e),n.data[4]=2/(s-i),n.data[6]=-(t+e)/(t-e),n.data[7]=-(s+i)/(s-i),n}multiply(e){const t=this.data,i=e.data,s=new Float32Array(9);for(let n=0;n<3;n++)for(let o=0;o<3;o++)s[o*3+n]=t[n]*i[o*3]+t[3+n]*i[o*3+1]+t[6+n]*i[o*3+2];return new v(s)}transformPoint(e){const t=this.data;return new T(t[0]*e.x+t[3]*e.y+t[6],t[1]*e.x+t[4]*e.y+t[7])}clone(){return new v(new Float32Array(this.data))}invert(){const e=this.data,t=e[0]*(e[4]*e[8]-e[5]*e[7])-e[1]*(e[3]*e[8]-e[5]*e[6])+e[2]*(e[3]*e[7]-e[4]*e[6]);if(Math.abs(t)<1e-10)return v.identity();const i=1/t,s=new Float32Array(9);return s[0]=(e[4]*e[8]-e[5]*e[7])*i,s[1]=(e[2]*e[7]-e[1]*e[8])*i,s[2]=(e[1]*e[5]-e[2]*e[4])*i,s[3]=(e[5]*e[6]-e[3]*e[8])*i,s[4]=(e[0]*e[8]-e[2]*e[6])*i,s[5]=(e[2]*e[3]-e[0]*e[5])*i,s[6]=(e[3]*e[7]-e[4]*e[6])*i,s[7]=(e[1]*e[6]-e[0]*e[7])*i,s[8]=(e[0]*e[4]-e[1]*e[3])*i,new v(s)}}class D{constructor(e=0,t=0,i=0,s=0){r(this,"x");r(this,"y");r(this,"width");r(this,"height");this.x=e,this.y=t,this.width=i,this.height=s}get left(){return this.x}get right(){return this.x+this.width}get top(){return this.y}get bottom(){return this.y+this.height}get centerX(){return this.x+this.width*.5}get centerY(){return this.y+this.height*.5}contains(e){return e.x>=this.left&&e.x<=this.right&&e.y>=this.top&&e.y<=this.bottom}intersects(e){return this.left<e.right&&this.right>e.left&&this.top<e.bottom&&this.bottom>e.top}clone(){return new D(this.x,this.y,this.width,this.height)}static fromPoints(e,t){const i=Math.min(e.x,t.x),s=Math.min(e.y,t.y);return new D(i,s,Math.max(e.x,t.x)-i,Math.max(e.y,t.y)-s)}}class I extends E{constructor(){super(...arguments);r(this,"type","transform2d");r(this,"x",0);r(this,"y",0);r(this,"rotation",0);r(this,"scaleX",1);r(this,"scaleY",1);r(this,"zIndex",0)}get position(){return new T(this.x,this.y)}set position(t){this.x=t.x,this.y=t.y}getLocalMatrix(){return v.translation(this.x,this.y).multiply(v.rotation(this.rotation)).multiply(v.scale(this.scaleX,this.scaleY))}}class ut extends E{constructor(){super(...arguments);r(this,"type","camera2d");r(this,"x",0);r(this,"y",0);r(this,"zoom",1);r(this,"rotation",0);r(this,"viewportWidth",1280);r(this,"viewportHeight",720)}get position(){return new T(this.x,this.y)}set position(t){this.x=t.x,this.y=t.y}getViewProjectionMatrix(){const t=this.viewportWidth*.5/this.zoom,i=this.viewportHeight*.5/this.zoom;return v.translation(-this.x,-this.y).multiply(v.rotation(-this.rotation)).multiply(v.orthographic(-t,t,-i,i))}screenToWorld(t,i){const s=t/this.viewportWidth*2-1,n=1-i/this.viewportHeight*2,o=this.viewportWidth*.5/this.zoom,a=this.viewportHeight*.5/this.zoom;return this.getViewProjectionMatrix().invert().transformPoint(new T(s*o,n*a))}getVisibleBounds(){const t=this.viewportWidth*.5/this.zoom,i=this.viewportHeight*.5/this.zoom;return new D(this.x-t,this.y-i,t*2,i*2)}}class L extends E{constructor(t=1,i=1,s=1,n=1,o=32,a=32,c,h=0,l=0,u=1,f=1){super();r(this,"colorR");r(this,"colorG");r(this,"colorB");r(this,"colorA");r(this,"width");r(this,"height");r(this,"texture");r(this,"texCoordU");r(this,"texCoordV");r(this,"texCoordW");r(this,"texCoordH");r(this,"type","sprite");this.colorR=t,this.colorG=i,this.colorB=s,this.colorA=n,this.width=o,this.height=a,this.texture=c,this.texCoordU=h,this.texCoordV=l,this.texCoordW=u,this.texCoordH=f}}class ft extends E{constructor(t=0,i=0,s=100,n=100,o=0,a=0){super();r(this,"x");r(this,"y");r(this,"width");r(this,"height");r(this,"originX");r(this,"originY");r(this,"type","uiTransform");r(this,"zIndex",0);this.x=t,this.y=i,this.width=s,this.height=n,this.originX=o,this.originY=a}get drawX(){return this.x-this.width*this.originX}get drawY(){return this.y-this.height*this.originY}containsPoint(t,i){const s=this.drawX,n=this.drawY;return t>=s&&t<=s+this.width&&i>=n&&i<=n+this.height}}var B;(function(d){d.Left="left",d.Center="center",d.Right="right"})(B||(B={}));class $ extends E{constructor(t="",i="sans-serif",s=16,n=1,o=1,a=1,c=1,h=B.Left,l=!1,u=0,f=0,g=0,m=0,y=0,b=4){super();r(this,"text");r(this,"fontFamily");r(this,"fontSize");r(this,"colorR");r(this,"colorG");r(this,"colorB");r(this,"colorA");r(this,"align");r(this,"bold");r(this,"strokeR");r(this,"strokeG");r(this,"strokeB");r(this,"strokeA");r(this,"strokeWidth");r(this,"padding");r(this,"type","uiText");this.text=t,this.fontFamily=i,this.fontSize=s,this.colorR=n,this.colorG=o,this.colorB=a,this.colorA=c,this.align=h,this.bold=l,this.strokeR=u,this.strokeG=f,this.strokeB=g,this.strokeA=m,this.strokeWidth=y,this.padding=b}get fontString(){const t=[];return this.bold&&t.push("bold"),t.push(`${this.fontSize}px`),t.push(this.fontFamily),t.join(" ")}rgba(t,i,s,n){return`rgba(${t*255|0},${i*255|0},${s*255|0},${n})`}}class gt extends E{constructor(t=100,i=40,s="Button",n=.2,o=.5,a=1,c=1,h=.3,l=.6,u=1,f=1,g=.1,m=.4,y=.8,b=1,C=4,A=16,k=!0){super();r(this,"width");r(this,"height");r(this,"label");r(this,"r");r(this,"g");r(this,"b");r(this,"a");r(this,"hoverR");r(this,"hoverG");r(this,"hoverB");r(this,"hoverA");r(this,"pressedR");r(this,"pressedG");r(this,"pressedB");r(this,"pressedA");r(this,"borderRadius");r(this,"fontSize");r(this,"interactive");r(this,"type","uiButton");r(this,"hovered",!1);r(this,"pressed",!1);r(this,"focused",!1);this.width=t,this.height=i,this.label=s,this.r=n,this.g=o,this.b=a,this.a=c,this.hoverR=h,this.hoverG=l,this.hoverB=u,this.hoverA=f,this.pressedR=g,this.pressedG=m,this.pressedB=y,this.pressedA=b,this.borderRadius=C,this.fontSize=A,this.interactive=k}}class pt extends E{constructor(t=200,i=32,s="",n=256,o=.15,a=.15,c=.15,h=1,l=.4,u=.4,f=.4,g=1,m=.3,y=.6,b=1,C=1,A=14,k=3,P=!0){super();r(this,"width");r(this,"height");r(this,"placeholder");r(this,"maxLength");r(this,"bgColorR");r(this,"bgColorG");r(this,"bgColorB");r(this,"bgColorA");r(this,"borderColorR");r(this,"borderColorG");r(this,"borderColorB");r(this,"borderColorA");r(this,"focusBorderR");r(this,"focusBorderG");r(this,"focusBorderB");r(this,"focusBorderA");r(this,"fontSize");r(this,"borderRadius");r(this,"interactive");r(this,"type","uiTextInput");r(this,"focused",!1);r(this,"hovered",!1);r(this,"cursorBlink",0);r(this,"cursorVisible",!0);this.width=t,this.height=i,this.placeholder=s,this.maxLength=n,this.bgColorR=o,this.bgColorG=a,this.bgColorB=c,this.bgColorA=h,this.borderColorR=l,this.borderColorG=u,this.borderColorB=f,this.borderColorA=g,this.focusBorderR=m,this.focusBorderG=y,this.focusBorderB=b,this.focusBorderA=C,this.fontSize=A,this.borderRadius=k,this.interactive=P}}class mt extends E{constructor(t=200,i=200,s=.1,n=.1,o=.12,a=.9,c=6,h=.3,l=.3,u=.3,f=.5,g=1){super();r(this,"width");r(this,"height");r(this,"r");r(this,"g");r(this,"b");r(this,"a");r(this,"borderRadius");r(this,"borderR");r(this,"borderG");r(this,"borderB");r(this,"borderA");r(this,"borderWidth");r(this,"type","uiPanel");this.width=t,this.height=i,this.r=s,this.g=n,this.b=o,this.a=a,this.borderRadius=c,this.borderR=h,this.borderG=l,this.borderB=u,this.borderA=f,this.borderWidth=g}}function x(d,e,t,i){return`rgba(${d*255|0},${e*255|0},${t*255|0},${i})`}class yt extends ct{constructor(){super();r(this,"requiredComponents",["uiTransform"]);r(this,"overlay");r(this,"ctx");r(this,"engine");r(this,"bus");r(this,"focusedId",null);r(this,"hoveredId",null);r(this,"hiddenTextarea");r(this,"textareaEntityId",null);r(this,"_onMouseMove");r(this,"_onMouseDown");r(this,"_onMouseUp");r(this,"_onKeyDown");r(this,"_onResize");r(this,"_onInput");r(this,"_onBlur");r(this,"_onCompositionStart");r(this,"_onCompositionEnd");r(this,"logicalW",0);r(this,"logicalH",0);r(this,"isComposing",!1);r(this,"holderId");this.holderId=`ui-${Date.now()}-${Math.random().toString(36).slice(2)}`}onInit(t){var i;if(!((i=t.scene)!=null&&i.engine))throw new Error("UIRenderSystem requires scene registered via engine.sceneManager.register()");this.engine=t.scene.engine,this.bus=t.eventBus,this.setupOverlay(),this.setupHiddenTextarea(),this._onMouseMove=s=>{const n=this.engine.canvas.getBoundingClientRect();this.handleMouseMove(s.clientX-n.left,s.clientY-n.top)},this._onMouseDown=s=>{const n=this.engine.canvas.getBoundingClientRect();this.handleMouseDown(s.clientX-n.left,s.clientY-n.top,s.button),s.preventDefault()},this._onMouseUp=s=>{const n=this.engine.canvas.getBoundingClientRect();this.handleMouseUp(s.clientX-n.left,s.clientY-n.top,s.button)},this._onResize=()=>this.syncSize(),this._onKeyDown=s=>this.handleKeyDown(s),this.engine.canvas.addEventListener("mousemove",this._onMouseMove),this.engine.canvas.addEventListener("mousedown",this._onMouseDown),this.engine.canvas.addEventListener("mouseup",this._onMouseUp),window.addEventListener("resize",this._onResize),window.addEventListener("keydown",this._onKeyDown)}setupOverlay(){this.overlay=document.createElement("canvas"),this.overlay.style.cssText="position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:10;",this.engine.canvas.style.position="relative";const t=this.engine.canvas.parentElement;t&&(t.style.position="relative"),t==null||t.appendChild(this.overlay),this.ctx=this.overlay.getContext("2d"),this.syncSize()}syncSize(){const t=this.engine.pixelRatio,i=this.engine.canvas.getBoundingClientRect();this.logicalW=i.width,this.logicalH=i.height,this.overlay.width=Math.round(this.logicalW*t),this.overlay.height=Math.round(this.logicalH*t),this.overlay.style.width=this.logicalW+"px",this.overlay.style.height=this.logicalH+"px",this.ctx.setTransform(t,0,0,t,0,0)}setupHiddenTextarea(){this.hiddenTextarea=document.createElement("textarea"),this.hiddenTextarea.style.cssText="position:fixed;left:0;top:0;width:1px;height:1px;opacity:0.01;border:none;outline:none;padding:0;margin:0;",this.hiddenTextarea.setAttribute("autocomplete","off"),this.hiddenTextarea.setAttribute("autocorrect","off"),this.hiddenTextarea.setAttribute("autocapitalize","off"),this.hiddenTextarea.setAttribute("spellcheck","false"),this.hiddenTextarea.setAttribute("tabindex","-1"),document.body.appendChild(this.hiddenTextarea),this._onInput=()=>this.handleTextareaInput(),this._onBlur=()=>this.blurFocusedInput(),this._onCompositionStart=()=>{this.isComposing=!0},this._onCompositionEnd=t=>this.handleCompositionEnd(t),this.hiddenTextarea.addEventListener("input",this._onInput),this.hiddenTextarea.addEventListener("blur",this._onBlur),this.hiddenTextarea.addEventListener("compositionstart",this._onCompositionStart),this.hiddenTextarea.addEventListener("compositionend",this._onCompositionEnd)}focusInput(t){this.focusedId=t,this.textareaEntityId=t,this.isComposing=!1;const i=this.engine.sceneManager.currentScene;if(i){const s=i.world.getArchetype(t),n=s==null?void 0:s.get("uiText");this.hiddenTextarea.value=(n==null?void 0:n.text)??""}else this.hiddenTextarea.value="";this.engine.input.capture(this.holderId,z.UI),this.hiddenTextarea.focus(),this.bus.emit("ui:focus",t)}blurFocusedInput(){if(this.textareaEntityId!==null){const t=this.engine.sceneManager.currentScene;if(t){const i=t.world.getArchetype(this.textareaEntityId),s=i==null?void 0:i.get("uiTextInput");s&&(s.focused=!1)}this.bus.emit("ui:blur",this.textareaEntityId)}this.engine.input.release(this.holderId),this.textareaEntityId=null,this.focusedId=null,this.isComposing=!1,this.hiddenTextarea.blur()}handleTextareaInput(){if(this.textareaEntityId===null)return;const t=this.engine.sceneManager.currentScene;if(!t)return;const i=t.world.getArchetype(this.textareaEntityId);if(!i)return;const s=i.get("uiTextInput"),n=i.get("uiText");if(!s||!n)return;const o=n.text;n.text=this.hiddenTextarea.value.slice(0,s.maxLength),n.text!==o&&this.bus.emit("ui:change",{entityId:this.textareaEntityId,value:n.text})}handleCompositionEnd(t){this.isComposing=!1,this.handleTextareaInput()}handleMouseMove(t,i){const s=this.engine.sceneManager.currentScene;if(!s)return;let n=null;const o=s.world.query("uiTransform");for(let a=o.length-1;a>=0;a--){const c=o[a],h=c.get("uiTransform"),l=c.get("uiButton"),u=c.get("uiTextInput");if((((l==null?void 0:l.interactive)??!1)||((u==null?void 0:u.interactive)??!1))&&h!=null&&h.containsPoint(t,i)){n=c.entity.id;break}}if(this.hoveredId!==null&&this.hoveredId!==n){const a=s.world.getArchetype(this.hoveredId);if(a){const c=a.get("uiButton"),h=a.get("uiTextInput");c&&(c.hovered=!1),h&&(h.hovered=!1)}}if(n!==null){const a=s.world.getArchetype(n);if(a){const c=a.get("uiButton"),h=a.get("uiTextInput");c&&(c.hovered=!0),h&&(h.hovered=!0)}this.engine.canvas.style.cursor="pointer"}else this.engine.canvas.style.cursor="default";this.hoveredId=n}handleMouseDown(t,i,s){if(s!==0)return;const n=this.engine.sceneManager.currentScene;if(!n)return;const o=n.world.query("uiTransform");let a=!1;for(let c=o.length-1;c>=0;c--){const h=o[c],l=h.get("uiTransform");if(!(l!=null&&l.containsPoint(t,i)))continue;a=!0;const u=h.get("uiButton"),f=h.get("uiTextInput");u!=null&&u.interactive&&(u.pressed=!0,u.focused=!0),f!=null&&f.interactive?(this.focusInput(h.entity.id),f.focused=!0):this.textareaEntityId!==null&&this.blurFocusedInput(),this.focusedId=h.entity.id;break}!a&&this.textareaEntityId!==null&&this.blurFocusedInput()}handleMouseUp(t,i,s){if(s!==0)return;const n=this.engine.sceneManager.currentScene;if(!n)return;const o=n.world.query("uiTransform");for(const a of o){const c=a.get("uiButton"),h=a.get("uiTransform");!c||!h||(c.pressed&&h.containsPoint(t,i)&&this.bus.emit("ui:click",a.entity.id),c.pressed=!1)}}handleKeyDown(t){this.textareaEntityId!==null&&t.code==="Escape"&&(this.blurFocusedInput(),t.preventDefault())}onUpdate(t,i,s){const n=this.ctx;n.clearRect(0,0,this.logicalW,this.logicalH),i.sort((o,a)=>{var l,u;const c=((l=o.get("uiTransform"))==null?void 0:l.zIndex)??0,h=((u=a.get("uiTransform"))==null?void 0:u.zIndex)??0;return c-h});for(const o of i){const a=o.get("uiTransform");if(!a)continue;const c=o.get("uiPanel"),h=o.get("uiButton"),l=o.get("uiTextInput"),u=o.get("uiText");c&&this.drawPanel(n,a,c),h&&this.drawButton(n,a,h),l&&this.drawTextInput(n,a,l,u,s),u&&!h&&!l&&this.drawText(n,a,u,0,0,a.width,a.height)}}drawPanel(t,i,s){const n=i.drawX,o=i.drawY,a=s.width,c=s.height;t.fillStyle=x(s.r,s.g,s.b,s.a),t.beginPath(),this.roundRect(t,n,o,a,c,s.borderRadius),t.fill(),s.borderWidth>0&&(t.strokeStyle=x(s.borderR,s.borderG,s.borderB,s.borderA),t.lineWidth=s.borderWidth,t.stroke())}drawButton(t,i,s){const n=i.drawX,o=i.drawY;let a=s.r,c=s.g,h=s.b,l=s.a;s.pressed?(a=s.pressedR,c=s.pressedG,h=s.pressedB,l=s.pressedA):s.hovered&&(a=s.hoverR,c=s.hoverG,h=s.hoverB,l=s.hoverA),t.fillStyle=x(a,c,h,l),t.beginPath(),this.roundRect(t,n,o,s.width,s.height,s.borderRadius),t.fill(),t.save(),t.beginPath(),t.rect(n,o,s.width,s.height),t.clip(),t.font=`${s.fontSize}px sans-serif`,t.textAlign="center",t.textBaseline="middle",t.fillStyle=x(1,1,1,1),t.fillText(s.label,n+s.width/2,o+s.height/2),t.restore(),s.focused&&(t.strokeStyle=x(1,1,1,.6),t.lineWidth=2,t.beginPath(),this.roundRect(t,n,o,s.width,s.height,s.borderRadius),t.stroke())}drawTextInput(t,i,s,n,o){const a=i.drawX,c=i.drawY;t.fillStyle=x(s.bgColorR,s.bgColorG,s.bgColorB,s.bgColorA),t.beginPath(),this.roundRect(t,a,c,s.width,s.height,s.borderRadius),t.fill(),s.focused?t.strokeStyle=x(s.focusBorderR,s.focusBorderG,s.focusBorderB,s.focusBorderA):s.hovered?t.strokeStyle=x(.6,.6,.6,1):t.strokeStyle=x(s.borderColorR,s.borderColorG,s.borderColorB,s.borderColorA),t.lineWidth=1,t.stroke();const h=(n==null?void 0:n.text)??"",l=6;if(t.save(),t.beginPath(),t.rect(a,c,s.width,s.height),t.clip(),t.font=`${s.fontSize}px sans-serif`,t.textAlign="left",t.textBaseline="middle",h.length>0?(t.fillStyle=n?x(n.colorR,n.colorG,n.colorB,n.colorA):x(1,1,1,1),t.fillText(h,a+l,c+s.height/2)):s.placeholder.length>0&&(t.fillStyle=x(.5,.5,.5,1),t.fillText(s.placeholder,a+l,c+s.height/2)),s.focused&&(s.cursorBlink+=o,s.cursorBlink>1&&(s.cursorBlink-=1),s.cursorVisible=s.cursorBlink<.5,s.cursorVisible)){const u=t.measureText(h).width,f=a+l+u+1;t.fillStyle=x(1,1,1,1),t.fillRect(f,c+6,1,s.height-12)}t.restore()}drawText(t,i,s,n,o,a,c){t.save(),t.beginPath(),t.rect(i.drawX+n,i.drawY+o,a,c),t.clip(),t.font=s.fontString;let h="left",l=i.drawX+n+s.padding;s.align===B.Center?(h="center",l=i.drawX+n+a/2):s.align===B.Right&&(h="right",l=i.drawX+n+a-s.padding),t.textAlign=h,t.textBaseline="top";const u=i.drawY+o+s.padding;s.strokeWidth>0&&(t.strokeStyle=x(s.strokeR,s.strokeG,s.strokeB,s.strokeA),t.lineWidth=s.strokeWidth,t.strokeText(s.text,l,u)),t.fillStyle=x(s.colorR,s.colorG,s.colorB,s.colorA),t.fillText(s.text,l,u),t.restore()}roundRect(t,i,s,n,o,a){t.moveTo(i+a,s),t.lineTo(i+n-a,s),t.quadraticCurveTo(i+n,s,i+n,s+a),t.lineTo(i+n,s+o-a),t.quadraticCurveTo(i+n,s+o,i+n-a,s+o),t.lineTo(i+a,s+o),t.quadraticCurveTo(i,s+o,i,s+o-a),t.lineTo(i,s+a),t.quadraticCurveTo(i,s,i+a,s),t.closePath()}onDestroy(t){this.blurFocusedInput(),this.engine.input.release(this.holderId),this.engine.canvas.removeEventListener("mousemove",this._onMouseMove),this.engine.canvas.removeEventListener("mousedown",this._onMouseDown),this.engine.canvas.removeEventListener("mouseup",this._onMouseUp),window.removeEventListener("resize",this._onResize),this.hiddenTextarea.removeEventListener("input",this._onInput),this.hiddenTextarea.removeEventListener("blur",this._onBlur),this.hiddenTextarea.removeEventListener("compositionstart",this._onCompositionStart),this.hiddenTextarea.removeEventListener("compositionend",this._onCompositionEnd),window.removeEventListener("keydown",this._onKeyDown),this.hiddenTextarea.remove(),this.overlay.remove()}}const wt=new Set(["width","height","fontSize","borderRadius","padding","maxWidth","maxLength","strokeWidth","borderWidth","zIndex"]),vt=new Set(["x","y","originX","originY"]);function xt(d){return d.includes(":")&&!d.endsWith(":")}function bt(d){const e=d.match(/^(\s*)/);return e?e[1].length:0}function Ct(d){const e=d.split(`
|
|
92
|
+
`).map(n=>n.replace(/\s+$/,"")).filter(n=>n.length>0&&!n.startsWith("//"));let t=0;function i(n){const a=e[t].trim(),c=a.match(/^(\w+)\s+"([^"]*)"\s*\{$/)||a.match(/^(\w+)\s+'([^']*)'\s*\{$/)||a.match(/^(\w+)\s+(\S+)\s*\{$/)||a.match(/^(\w+)\s*\{$/);if(!c)throw new F(t+1,`Expected node declaration, got: ${a}`);const h=c[1],l=c[2]??"";t++;const u={},f=[];for(;t<e.length;){const g=e[t],m=bt(g),y=g.trim();if(m<n)break;if(y==="}"){t++;break}if(xt(y)){const b=y.split(";").map(C=>C.trim()).filter(C=>C.includes(":"));for(const C of b){const A=C.indexOf(":"),k=C.slice(0,A).trim(),P=C.slice(A+1).trim();k&&P&&(u[k]=St(k,P,t+1))}t++}else f.push(i(m))}return{type:h,name:l,props:u,children:f}}return{root:i(0)}}function St(d,e,t){if(e==="true")return!0;if(e==="false")return!1;if(e.startsWith("[")&&e.endsWith("]")){const i=e.slice(1,-1).split(",").map(s=>s.trim());if(i.length===4&&i.every(s=>!isNaN(Number(s))))return i.map(Number);throw new F(t,`Invalid color array for "${d}": ${e}`)}if(wt.has(d)||vt.has(d)){const i=Number(e);if(isNaN(i))throw new F(t,`Expected number for "${d}", got: ${e}`);return i}return e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}class F extends Error{constructor(t,i){super(`.pui syntax error (line ${t}): ${i}`);r(this,"line");this.line=t,this.name="PuiSyntaxError"}}function Tt(d,e){const t=new Map;return Y(d,e.root,t,0,0),{entities:t}}function w(d,e){return typeof d=="number"?d:e}function S(d,e,t,i,s){return Array.isArray(d)&&d.length===4?d:[e,t,i,s]}function R(d,e){return typeof d=="string"?d:e}function U(d,e){return typeof d=="boolean"?d:e}function Et(d){const e=R(d,"left");return e==="center"?B.Center:e==="right"?B.Right:B.Left}function Y(d,e,t,i,s){const n=d.createEntity();e.name&&t.set(e.name,n.id);const o=e.props,a=new ft(i+w(o.x,0),s+w(o.y,0),w(o.width,100),w(o.height,100),w(o.originX,0),w(o.originY,0));switch(a.zIndex=w(o.zIndex,0),d.addComponent(n.id,a),e.type){case"panel":{const c=S(o.color,.1,.1,.12,.9),h=S(o.borderColor,.3,.3,.3,.5);d.addComponent(n.id,new mt(a.width,a.height,c[0],c[1],c[2],c[3],w(o.borderRadius,6),h[0],h[1],h[2],h[3],w(o.borderWidth,1)));break}case"text":{const c=S(o.color,1,1,1,1),h=S(o.strokeColor,0,0,0,0);d.addComponent(n.id,new $(R(o.text,""),R(o.fontFamily,"sans-serif"),w(o.fontSize,16),c[0],c[1],c[2],c[3],Et(o.align),U(o.bold,!1),h[0],h[1],h[2],h[3],w(o.strokeWidth,0),w(o.padding,4)));break}case"button":{const c=S(o.color,.2,.5,1,1),h=S(o.hoverColor,.3,.6,1,1),l=S(o.pressedColor,.1,.4,.8,1);d.addComponent(n.id,new gt(a.width,a.height,R(o.label,"Button"),c[0],c[1],c[2],c[3],h[0],h[1],h[2],h[3],l[0],l[1],l[2],l[3],w(o.borderRadius,4),w(o.fontSize,16),U(o.interactive,!0)));break}case"textInput":{const c=S(o.bgColor,.15,.15,.15,1),h=S(o.borderColor,.4,.4,.4,1),l=S(o.focusBorderColor,.3,.6,1,1);d.addComponent(n.id,new pt(a.width,a.height,R(o.placeholder,""),w(o.maxLength,256),c[0],c[1],c[2],c[3],h[0],h[1],h[2],h[3],l[0],l[1],l[2],l[3],w(o.fontSize,14),w(o.borderRadius,3),U(o.interactive,!0)));const u=S(o.color,1,1,1,1);d.addComponent(n.id,new $(R(o.text,""),R(o.fontFamily,"sans-serif"),w(o.fontSize,14),u[0],u[1],u[2],u[3]));break}}for(const c of e.children)Y(d,c,t,a.drawX,a.drawY)}const Bt="modulepreload",kt=function(d,e){return new URL(d,e).href},G={},H=function(e,t,i){let s=Promise.resolve();if(t&&t.length>0){let o=function(l){return Promise.all(l.map(u=>Promise.resolve(u).then(f=>({status:"fulfilled",value:f}),f=>({status:"rejected",reason:f}))))};const a=document.getElementsByTagName("link"),c=document.querySelector("meta[property=csp-nonce]"),h=(c==null?void 0:c.nonce)||(c==null?void 0:c.getAttribute("nonce"));s=o(t.map(l=>{if(l=kt(l,i),l in G)return;G[l]=!0;const u=l.endsWith(".css"),f=u?'[rel="stylesheet"]':"";if(!!i)for(let y=a.length-1;y>=0;y--){const b=a[y];if(b.href===l&&(!u||b.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${l}"]${f}`))return;const m=document.createElement("link");if(m.rel=u?"stylesheet":Bt,u||(m.as="script"),m.crossOrigin="",m.href=l,h&&m.setAttribute("nonce",h),document.head.appendChild(m),u)return new Promise((y,b)=>{m.addEventListener("load",y),m.addEventListener("error",()=>b(new Error(`Unable to preload CSS for ${l}`)))})}))}function n(o){const a=new Event("vite:preloadError",{cancelable:!0});if(a.payload=o,window.dispatchEvent(a),!a.defaultPrevented)throw o}return s.then(o=>{for(const a of o||[])a.status==="rejected"&&n(a.reason);return e().catch(n)})};class Rt{constructor(){r(this,"nodeFs",null);r(this,"nodePath",null)}async getFs(){return this.nodeFs&&this.nodePath?{fs:this.nodeFs,path:this.nodePath}:(this.nodeFs=await H(()=>import("./__vite-browser-external-D7Ct-6yo.js").then(e=>e._),[],import.meta.url),this.nodePath=await H(()=>import("./__vite-browser-external-D7Ct-6yo.js").then(e=>e._),[],import.meta.url),{fs:this.nodeFs,path:this.nodePath})}async readText(e){const{fs:t}=await this.getFs();return t.promises.readFile(e,"utf-8")}async writeText(e,t){const{fs:i}=await this.getFs();await i.promises.writeFile(e,t,"utf-8")}async readBinary(e){const{fs:t}=await this.getFs(),i=await t.promises.readFile(e);return new Uint8Array(i.buffer,i.byteOffset,i.byteLength)}async writeBinary(e,t){const{fs:i}=await this.getFs();await i.promises.writeFile(e,t)}async exists(e){const{fs:t}=await this.getFs();try{return await t.promises.access(e),!0}catch{return!1}}async mkdir(e){const{fs:t}=await this.getFs();await t.promises.mkdir(e,{recursive:!0})}async remove(e){const{fs:t}=await this.getFs();await t.promises.rm(e,{recursive:!0,force:!0})}async listDir(e){const{fs:t}=await this.getFs();return(await t.promises.readdir(e,{withFileTypes:!0})).map(s=>s.name)}async isFile(e){const{fs:t}=await this.getFs();return(await t.promises.stat(e)).isFile()}async isDir(e){const{fs:t}=await this.getFs();return(await t.promises.stat(e)).isDirectory()}}class At{constructor(){r(this,"fs");this.fs=new Rt}async invoke(e,t){const{ipcRenderer:i}=await H(async()=>{const{ipcRenderer:s}=await import("./index-Cxo-KaTG.js").then(n=>n.i);return{ipcRenderer:s}},__vite__mapDeps([0,1]),import.meta.url);return i.invoke(e,t)}}class q extends E{constructor(t=100,i=1,s=0,n=0){super();r(this,"type","orbitalSpeed");this.radius=t,this.speed=i,this.angleOffset=s,this.orbitTilt=n}}class It extends lt{constructor(){super(...arguments);r(this,"name","demo");r(this,"uiSystem",new yt);r(this,"clickCount",0);r(this,"scoreId",0);r(this,"btnId",0)}onEnter(){this.world.registerSystem(this.uiSystem);const t=this.world.createEntity();this.world.addComponent(t.id,new I),this.world.addComponent(t.id,new ut);const i=this.world.createEntity().tag("nucleus"),s=new I;s.zIndex=10,this.world.addComponent(i.id,s),this.world.addComponent(i.id,new L(.9,.6,.1,1,28,28));const n=this.world.createEntity().tag("glow"),o=new I;o.zIndex=9,this.world.addComponent(n.id,o),this.world.addComponent(n.id,new L(.9,.5,.1,.15,60,60));const a=[{radius:80,speed:2,tilt:0,color:[.3,.7,1],size:8,offset:0},{radius:130,speed:1.3,tilt:Math.PI/3,color:[.4,1,.6],size:7,offset:Math.PI*.66},{radius:180,speed:.8,tilt:-Math.PI/4,color:[1,.4,.8],size:6,offset:Math.PI*1.33}];for(const h of a){for(let g=0;g<60;g++){const m=this.world.createEntity().tag("ring"),y=new I;y.zIndex=1,this.world.addComponent(m.id,y),this.world.addComponent(m.id,new q(h.radius,0,g/60*Math.PI*2,h.tilt)),this.world.addComponent(m.id,new L(h.color[0]*.3,h.color[1]*.3,h.color[2]*.3,.25,2,2))}const u=this.world.createEntity().tag("electron"),f=new I;f.zIndex=5,this.world.addComponent(u.id,f),this.world.addComponent(u.id,new q(h.radius,h.speed,h.offset,h.tilt)),this.world.addComponent(u.id,new L(h.color[0],h.color[1],h.color[2],1,h.size,h.size))}const c=Tt(this.world,Ct(X));this.scoreId=c.entities.get("score"),this.btnId=c.entities.get("clickBtn"),this.world.eventBus.on("ui:click",h=>{if(h===this.btnId){this.clickCount++;const l=this.world.getArchetype(this.scoreId);l&&(l.get("uiText").text=`Clicks: ${this.clickCount}`)}})}onUpdate(){const t=performance.now()*.001;for(const n of this.world.query("transform2d","orbitalSpeed")){const o=n.get("transform2d"),a=n.get("orbitalSpeed"),c=a.angleOffset+t*a.speed,h=Math.cos(c)*a.radius,l=Math.sin(c)*a.radius*.4,u=Math.cos(a.orbitTilt),f=Math.sin(a.orbitTilt);o.x=h*u-l*f,o.y=h*f+l*u}const i=this.world.queryByTag("nucleus")[0];if(i){const n=i.get("sprite"),o=28+Math.sin(t*3)*4;n.width=o,n.height=o}const s=this.world.queryByTag("glow")[0];if(s){const n=s.get("sprite"),o=60+Math.sin(t*2)*10;n.width=o,n.height=o,n.colorA=.12+Math.sin(t*3)*.05}}onExit(){this.world.clear()}}const _=new nt({canvasId:"game-canvas",nativeBridge:new At});_.sceneManager.register(new It);_.sceneManager.switchTo("demo");_.start();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<title>Photon</title>
|
|
6
|
+
<style>
|
|
7
|
+
* { margin: 0; padding: 0; }
|
|
8
|
+
html, body { width: 100%; height: 100%; overflow: hidden; background: #000; }
|
|
9
|
+
canvas { display: block; width: 100%; height: 100%; }
|
|
10
|
+
</style>
|
|
11
|
+
<script type="module" crossorigin src="./assets/index-XXTau1xu.js"></script>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<canvas id="game-canvas"></canvas>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Photon Engine — HUD demo
|
|
2
|
+
panel "hud" {
|
|
3
|
+
x: 20; y: 20;
|
|
4
|
+
width: 300; height: 210;
|
|
5
|
+
color: [0.08, 0.08, 0.1, 0.85];
|
|
6
|
+
borderRadius: 8;
|
|
7
|
+
|
|
8
|
+
text "title" {
|
|
9
|
+
x: 0; y: 12;
|
|
10
|
+
width: 300; height: 28;
|
|
11
|
+
text: "Photon Engine — Electron";
|
|
12
|
+
fontSize: 18;
|
|
13
|
+
color: [0.5, 0.7, 1, 1];
|
|
14
|
+
align: center;
|
|
15
|
+
bold: true;
|
|
16
|
+
zIndex: 1;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
text "score" {
|
|
20
|
+
x: 10; y: 52;
|
|
21
|
+
width: 280; height: 24;
|
|
22
|
+
text: "Clicks: 0";
|
|
23
|
+
fontSize: 15;
|
|
24
|
+
color: [1, 1, 1, 1];
|
|
25
|
+
fontFamily: monospace;
|
|
26
|
+
zIndex: 1;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
button "clickBtn" {
|
|
30
|
+
x: 70; y: 88;
|
|
31
|
+
width: 160; height: 38;
|
|
32
|
+
label: "Click Me!";
|
|
33
|
+
color: [0.16, 0.5, 1, 1];
|
|
34
|
+
hoverColor: [0.29, 0.62, 1, 1];
|
|
35
|
+
pressedColor: [0.1, 0.37, 0.8, 1];
|
|
36
|
+
borderRadius: 8;
|
|
37
|
+
fontSize: 15;
|
|
38
|
+
zIndex: 1;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
text "nameLabel" {
|
|
42
|
+
x: 10; y: 146;
|
|
43
|
+
width: 60; height: 22;
|
|
44
|
+
text: "Name:";
|
|
45
|
+
fontSize: 13;
|
|
46
|
+
color: [0.7, 0.7, 0.7, 1];
|
|
47
|
+
zIndex: 1;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
textInput "nameInput" {
|
|
51
|
+
x: 70; y: 143;
|
|
52
|
+
width: 220; height: 28;
|
|
53
|
+
placeholder: "Type here...";
|
|
54
|
+
maxLength: 64;
|
|
55
|
+
fontSize: 13;
|
|
56
|
+
zIndex: 1;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import puiSource from "./hud.pui?raw";
|
|
1
2
|
import {
|
|
2
3
|
Engine, Scene, Transform2D, Camera2D, Sprite, Component,
|
|
4
|
+
UIText, UIRenderSystem,
|
|
5
|
+
parsePui, loadPui,
|
|
3
6
|
} from "photon-engine";
|
|
7
|
+
import { ElectronNativeBridge } from "photon-engine-electron";
|
|
4
8
|
|
|
5
9
|
class OrbitalSpeed extends Component {
|
|
6
10
|
readonly type = "orbitalSpeed";
|
|
@@ -12,15 +16,19 @@ class OrbitalSpeed extends Component {
|
|
|
12
16
|
) { super(); }
|
|
13
17
|
}
|
|
14
18
|
|
|
15
|
-
class
|
|
16
|
-
readonly name = "
|
|
19
|
+
class DemoScene extends Scene {
|
|
20
|
+
readonly name = "demo";
|
|
21
|
+
private uiSystem = new UIRenderSystem();
|
|
22
|
+
private clickCount = 0;
|
|
23
|
+
private scoreId = 0;
|
|
24
|
+
private btnId = 0;
|
|
17
25
|
|
|
18
26
|
onEnter(): void {
|
|
27
|
+
this.world.registerSystem(this.uiSystem);
|
|
28
|
+
|
|
19
29
|
const cam = this.world.createEntity();
|
|
20
30
|
this.world.addComponent(cam.id, new Transform2D());
|
|
21
|
-
|
|
22
|
-
camComp.zoom = 1;
|
|
23
|
-
this.world.addComponent(cam.id, camComp);
|
|
31
|
+
this.world.addComponent(cam.id, new Camera2D());
|
|
24
32
|
|
|
25
33
|
const nucleus = this.world.createEntity().tag("nucleus");
|
|
26
34
|
const nPos = new Transform2D();
|
|
@@ -35,9 +43,9 @@ class AtomScene extends Scene {
|
|
|
35
43
|
this.world.addComponent(glow.id, new Sprite(0.9, 0.5, 0.1, 0.15, 60, 60));
|
|
36
44
|
|
|
37
45
|
const orbits = [
|
|
38
|
-
{ radius: 80, speed: 2.0, tilt: 0,
|
|
39
|
-
{ radius: 130, speed: 1.3, tilt: Math.PI / 3,
|
|
40
|
-
{ radius: 180, speed: 0.8, tilt: -Math.PI / 4,
|
|
46
|
+
{ radius: 80, speed: 2.0, tilt: 0, color: [0.3, 0.7, 1.0], size: 8, offset: 0 },
|
|
47
|
+
{ radius: 130, speed: 1.3, tilt: Math.PI / 3, color: [0.4, 1.0, 0.6], size: 7, offset: Math.PI * 0.66 },
|
|
48
|
+
{ radius: 180, speed: 0.8, tilt: -Math.PI / 4, color: [1.0, 0.4, 0.8], size: 6, offset: Math.PI * 1.33 },
|
|
41
49
|
];
|
|
42
50
|
|
|
43
51
|
for (const orbit of orbits) {
|
|
@@ -48,10 +56,10 @@ class AtomScene extends Scene {
|
|
|
48
56
|
dPos.zIndex = 1;
|
|
49
57
|
this.world.addComponent(dot.id, dPos);
|
|
50
58
|
this.world.addComponent(dot.id, new OrbitalSpeed(
|
|
51
|
-
orbit.radius, 0, (i / ringCount) * Math.PI * 2, orbit.tilt
|
|
59
|
+
orbit.radius, 0, (i / ringCount) * Math.PI * 2, orbit.tilt,
|
|
52
60
|
));
|
|
53
61
|
this.world.addComponent(dot.id, new Sprite(
|
|
54
|
-
orbit.color[0] * 0.3, orbit.color[1] * 0.3, orbit.color[2] * 0.3, 0.25, 2, 2
|
|
62
|
+
orbit.color[0] * 0.3, orbit.color[1] * 0.3, orbit.color[2] * 0.3, 0.25, 2, 2,
|
|
55
63
|
));
|
|
56
64
|
}
|
|
57
65
|
|
|
@@ -60,37 +68,39 @@ class AtomScene extends Scene {
|
|
|
60
68
|
ePos.zIndex = 5;
|
|
61
69
|
this.world.addComponent(electron.id, ePos);
|
|
62
70
|
this.world.addComponent(electron.id, new OrbitalSpeed(
|
|
63
|
-
orbit.radius, orbit.speed, orbit.offset, orbit.tilt
|
|
71
|
+
orbit.radius, orbit.speed, orbit.offset, orbit.tilt,
|
|
64
72
|
));
|
|
65
73
|
this.world.addComponent(electron.id, new Sprite(
|
|
66
|
-
orbit.color[0], orbit.color[1], orbit.color[2], 1, orbit.size, orbit.size
|
|
67
|
-
));
|
|
68
|
-
|
|
69
|
-
const eGlow = this.world.createEntity().tag("electron-glow");
|
|
70
|
-
const egPos = new Transform2D();
|
|
71
|
-
egPos.zIndex = 4;
|
|
72
|
-
this.world.addComponent(eGlow.id, egPos);
|
|
73
|
-
this.world.addComponent(eGlow.id, new OrbitalSpeed(
|
|
74
|
-
orbit.radius, orbit.speed, orbit.offset, orbit.tilt
|
|
75
|
-
));
|
|
76
|
-
this.world.addComponent(eGlow.id, new Sprite(
|
|
77
|
-
orbit.color[0], orbit.color[1], orbit.color[2], 0.2, orbit.size * 4, orbit.size * 4
|
|
74
|
+
orbit.color[0], orbit.color[1], orbit.color[2], 1, orbit.size, orbit.size,
|
|
78
75
|
));
|
|
79
76
|
}
|
|
77
|
+
|
|
78
|
+
// Load UI from hud.pui
|
|
79
|
+
const ui = loadPui(this.world, parsePui(puiSource));
|
|
80
|
+
this.scoreId = ui.entities.get("score")!;
|
|
81
|
+
this.btnId = ui.entities.get("clickBtn")!;
|
|
82
|
+
|
|
83
|
+
this.world.eventBus.on<number>("ui:click", (entityId) => {
|
|
84
|
+
if (entityId === this.btnId) {
|
|
85
|
+
this.clickCount++;
|
|
86
|
+
const arch = this.world.getArchetype(this.scoreId);
|
|
87
|
+
if (arch) {
|
|
88
|
+
arch.get<UIText>("uiText")!.text = `Clicks: ${this.clickCount}`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
});
|
|
80
92
|
}
|
|
81
93
|
|
|
82
94
|
onUpdate(): void {
|
|
83
95
|
const time = performance.now() * 0.001;
|
|
84
|
-
const entities = this.world.query("transform2d", "orbitalSpeed");
|
|
85
96
|
|
|
86
|
-
for (const arch of
|
|
97
|
+
for (const arch of this.world.query("transform2d", "orbitalSpeed")) {
|
|
87
98
|
const t = arch.get<Transform2D>("transform2d")!;
|
|
88
99
|
const o = arch.get<OrbitalSpeed>("orbitalSpeed")!;
|
|
89
100
|
|
|
90
101
|
const angle = o.angleOffset + time * o.speed;
|
|
91
102
|
const x = Math.cos(angle) * o.radius;
|
|
92
103
|
const y = Math.sin(angle) * o.radius * 0.4;
|
|
93
|
-
|
|
94
104
|
const cosT = Math.cos(o.orbitTilt);
|
|
95
105
|
const sinT = Math.sin(o.orbitTilt);
|
|
96
106
|
t.x = x * cosT - y * sinT;
|
|
@@ -99,26 +109,29 @@ class AtomScene extends Scene {
|
|
|
99
109
|
|
|
100
110
|
const nucleusArch = this.world.queryByTag("nucleus")[0];
|
|
101
111
|
if (nucleusArch) {
|
|
102
|
-
const
|
|
112
|
+
const s = nucleusArch.get<Sprite>("sprite")!;
|
|
103
113
|
const pulse = 28 + Math.sin(time * 3) * 4;
|
|
104
|
-
|
|
105
|
-
|
|
114
|
+
s.width = pulse;
|
|
115
|
+
s.height = pulse;
|
|
106
116
|
}
|
|
107
117
|
|
|
108
118
|
const glowArch = this.world.queryByTag("glow")[0];
|
|
109
119
|
if (glowArch) {
|
|
110
|
-
const
|
|
120
|
+
const s = glowArch.get<Sprite>("sprite")!;
|
|
111
121
|
const pulse = 60 + Math.sin(time * 2) * 10;
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
122
|
+
s.width = pulse;
|
|
123
|
+
s.height = pulse;
|
|
124
|
+
s.colorA = 0.12 + Math.sin(time * 3) * 0.05;
|
|
115
125
|
}
|
|
116
126
|
}
|
|
117
127
|
|
|
118
128
|
onExit(): void { this.world.clear(); }
|
|
119
129
|
}
|
|
120
130
|
|
|
121
|
-
const engine = new Engine({
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
const engine = new Engine({
|
|
132
|
+
canvasId: "game-canvas",
|
|
133
|
+
nativeBridge: new ElectronNativeBridge(),
|
|
134
|
+
});
|
|
135
|
+
engine.sceneManager.register(new DemoScene());
|
|
136
|
+
engine.sceneManager.switchTo("demo");
|
|
137
|
+
engine.start();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|