create-photon-engine 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.
- package/dist/index.js +26 -0
- package/package.json +20 -0
- package/templates/browser/index.html +16 -0
- 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/package.json +17 -0
- package/templates/browser/src/main.ts +124 -0
- package/templates/browser/tsconfig.json +13 -0
- package/templates/browser/vite.config.ts +6 -0
- package/templates/electron/dist-renderer/assets/index-Dmalnvpw.js +32 -0
- package/templates/electron/dist-renderer/index.html +16 -0
- package/templates/electron/electron/main.cjs +21 -0
- package/templates/electron/index.html +16 -0
- package/templates/electron/node_modules/.vite/deps/_metadata.json +15 -0
- package/templates/electron/node_modules/.vite/deps/electron.js +56 -0
- package/templates/electron/node_modules/.vite/deps/electron.js.map +7 -0
- package/templates/electron/node_modules/.vite/deps/package.json +3 -0
- package/templates/electron/package.json +22 -0
- package/templates/electron/src/main.ts +124 -0
- package/templates/electron/tsconfig.json +13 -0
- package/templates/electron/vite.config.ts +8 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync, writeFileSync, mkdirSync, cpSync, existsSync } from "fs";
|
|
3
|
+
import { resolve, join } from "path";
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
const projectName = args[0] || "my-photon-game";
|
|
7
|
+
const template = args.includes("--electron") ? "electron" : "browser";
|
|
8
|
+
const cwd = resolve(projectName);
|
|
9
|
+
if (existsSync(cwd)) {
|
|
10
|
+
console.error(`Directory "${projectName}" already exists.`);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
console.log(`\n Creating Photon Engine project: ${projectName}`);
|
|
14
|
+
console.log(` Template: ${template}\n`);
|
|
15
|
+
mkdirSync(cwd, { recursive: true });
|
|
16
|
+
const templatesDir = resolve(import.meta.dirname || __dirname, "..", "templates", template);
|
|
17
|
+
cpSync(templatesDir, cwd, { recursive: true });
|
|
18
|
+
const pkgJson = JSON.parse(readFileSync(join(cwd, "package.json"), "utf-8"));
|
|
19
|
+
pkgJson.name = projectName;
|
|
20
|
+
delete pkgJson.private;
|
|
21
|
+
writeFileSync(join(cwd, "package.json"), JSON.stringify(pkgJson, null, 2));
|
|
22
|
+
console.log(" Installing dependencies...\n");
|
|
23
|
+
execSync(`npm install`, { cwd, stdio: "inherit" });
|
|
24
|
+
console.log(`\n Done! Run:\n`);
|
|
25
|
+
console.log(` cd ${projectName}`);
|
|
26
|
+
console.log(` npm run dev\n`);
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-photon-engine",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Scaffold a new Photon Engine project",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-photon-engine": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": ["dist", "templates"],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"typecheck": "tsc --noEmit",
|
|
13
|
+
"prepublishOnly": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"typescript": "^5.6.0",
|
|
17
|
+
"@types/node": "^20.0.0"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT"
|
|
20
|
+
}
|
|
@@ -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
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<canvas id="game-canvas"></canvas>
|
|
14
|
+
<script type="module" src="/src/main.ts"></script>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "photon-template-browser",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"photon-engine": "^0.1.1"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"vite": "^6.0.0",
|
|
15
|
+
"typescript": "^5.6.0"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Engine, Scene, Transform2D, Camera2D, Sprite, Component,
|
|
3
|
+
} from "photon-engine";
|
|
4
|
+
|
|
5
|
+
class OrbitalSpeed extends Component {
|
|
6
|
+
readonly type = "orbitalSpeed";
|
|
7
|
+
constructor(
|
|
8
|
+
public radius: number = 100,
|
|
9
|
+
public speed: number = 1,
|
|
10
|
+
public angleOffset: number = 0,
|
|
11
|
+
public orbitTilt: number = 0,
|
|
12
|
+
) { super(); }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class AtomScene extends Scene {
|
|
16
|
+
readonly name = "atom";
|
|
17
|
+
|
|
18
|
+
onEnter(): void {
|
|
19
|
+
const cam = this.world.createEntity();
|
|
20
|
+
this.world.addComponent(cam.id, new Transform2D());
|
|
21
|
+
const camComp = new Camera2D();
|
|
22
|
+
camComp.zoom = 1;
|
|
23
|
+
this.world.addComponent(cam.id, camComp);
|
|
24
|
+
|
|
25
|
+
const nucleus = this.world.createEntity().tag("nucleus");
|
|
26
|
+
const nPos = new Transform2D();
|
|
27
|
+
nPos.zIndex = 10;
|
|
28
|
+
this.world.addComponent(nucleus.id, nPos);
|
|
29
|
+
this.world.addComponent(nucleus.id, new Sprite(0.9, 0.6, 0.1, 1, 28, 28));
|
|
30
|
+
|
|
31
|
+
const glow = this.world.createEntity().tag("glow");
|
|
32
|
+
const gPos = new Transform2D();
|
|
33
|
+
gPos.zIndex = 9;
|
|
34
|
+
this.world.addComponent(glow.id, gPos);
|
|
35
|
+
this.world.addComponent(glow.id, new Sprite(0.9, 0.5, 0.1, 0.15, 60, 60));
|
|
36
|
+
|
|
37
|
+
const orbits = [
|
|
38
|
+
{ radius: 80, speed: 2.0, tilt: 0, color: [0.3, 0.7, 1.0], size: 8, offset: 0 },
|
|
39
|
+
{ radius: 130, speed: 1.3, tilt: Math.PI / 3, color: [0.4, 1.0, 0.6], size: 7, offset: Math.PI * 0.66 },
|
|
40
|
+
{ radius: 180, speed: 0.8, tilt: -Math.PI / 4, color: [1.0, 0.4, 0.8], size: 6, offset: Math.PI * 1.33 },
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
for (const orbit of orbits) {
|
|
44
|
+
const ringCount = 60;
|
|
45
|
+
for (let i = 0; i < ringCount; i++) {
|
|
46
|
+
const dot = this.world.createEntity().tag("ring");
|
|
47
|
+
const dPos = new Transform2D();
|
|
48
|
+
dPos.zIndex = 1;
|
|
49
|
+
this.world.addComponent(dot.id, dPos);
|
|
50
|
+
this.world.addComponent(dot.id, new OrbitalSpeed(
|
|
51
|
+
orbit.radius, 0, (i / ringCount) * Math.PI * 2, orbit.tilt
|
|
52
|
+
));
|
|
53
|
+
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
|
|
55
|
+
));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const electron = this.world.createEntity().tag("electron");
|
|
59
|
+
const ePos = new Transform2D();
|
|
60
|
+
ePos.zIndex = 5;
|
|
61
|
+
this.world.addComponent(electron.id, ePos);
|
|
62
|
+
this.world.addComponent(electron.id, new OrbitalSpeed(
|
|
63
|
+
orbit.radius, orbit.speed, orbit.offset, orbit.tilt
|
|
64
|
+
));
|
|
65
|
+
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
|
|
78
|
+
));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
onUpdate(): void {
|
|
83
|
+
const time = performance.now() * 0.001;
|
|
84
|
+
const entities = this.world.query("transform2d", "orbitalSpeed");
|
|
85
|
+
|
|
86
|
+
for (const arch of entities) {
|
|
87
|
+
const t = arch.get<Transform2D>("transform2d")!;
|
|
88
|
+
const o = arch.get<OrbitalSpeed>("orbitalSpeed")!;
|
|
89
|
+
|
|
90
|
+
const angle = o.angleOffset + time * o.speed;
|
|
91
|
+
const x = Math.cos(angle) * o.radius;
|
|
92
|
+
const y = Math.sin(angle) * o.radius * 0.4;
|
|
93
|
+
|
|
94
|
+
const cosT = Math.cos(o.orbitTilt);
|
|
95
|
+
const sinT = Math.sin(o.orbitTilt);
|
|
96
|
+
t.x = x * cosT - y * sinT;
|
|
97
|
+
t.y = x * sinT + y * cosT;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const nucleusArch = this.world.queryByTag("nucleus")[0];
|
|
101
|
+
if (nucleusArch) {
|
|
102
|
+
const nSprite = nucleusArch.get<Sprite>("sprite")!;
|
|
103
|
+
const pulse = 28 + Math.sin(time * 3) * 4;
|
|
104
|
+
nSprite.width = pulse;
|
|
105
|
+
nSprite.height = pulse;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const glowArch = this.world.queryByTag("glow")[0];
|
|
109
|
+
if (glowArch) {
|
|
110
|
+
const gSprite = glowArch.get<Sprite>("sprite")!;
|
|
111
|
+
const pulse = 60 + Math.sin(time * 2) * 10;
|
|
112
|
+
gSprite.width = pulse;
|
|
113
|
+
gSprite.height = pulse;
|
|
114
|
+
gSprite.colorA = 0.12 + Math.sin(time * 3) * 0.05;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
onExit(): void { this.world.clear(); }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const engine = new Engine({ canvasId: "game-canvas" });
|
|
122
|
+
engine.sceneManager.register(new AtomScene());
|
|
123
|
+
engine.sceneManager.switchTo("atom");
|
|
124
|
+
engine.start();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022", "DOM"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"noEmit": true
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*.ts"]
|
|
13
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
var L=Object.defineProperty;var D=(h,t,e)=>t in h?L(h,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):h[t]=e;var n=(h,t,e)=>D(h,typeof t!="symbol"?t+"":t,e);(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))s(r);new MutationObserver(r=>{for(const o of r)if(o.type==="childList")for(const i of o.addedNodes)i.tagName==="LINK"&&i.rel==="modulepreload"&&s(i)}).observe(document,{childList:!0,subtree:!0});function e(r){const o={};return r.integrity&&(o.integrity=r.integrity),r.referrerPolicy&&(o.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?o.credentials="include":r.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function s(r){if(r.ep)return;r.ep=!0;const o=e(r);fetch(r.href,o)}})();class T{constructor(){n(this,"listeners",new Map)}on(t,e){return this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e),()=>this.off(t,e)}once(t,e){const s=r=>{this.off(t,s),e(r)};return this.on(t,s)}off(t,e){var s;(s=this.listeners.get(t))==null||s.delete(e)}emit(t,e){const s=this.listeners.get(t);if(s)for(const r of s)try{r(e)}catch(o){console.error(`[EventBus] Error in "${t}":`,o)}}clear(t){t?this.listeners.delete(t):this.listeners.clear()}listenerCount(t){var e;return((e=this.listeners.get(t))==null?void 0:e.size)??0}}class U{constructor(t){n(this,"scenes",new Map);n(this,"current",null);n(this,"bus");this.bus=t??new T}register(t){this.scenes.set(t.name,t)}unregister(t){var e;((e=this.current)==null?void 0:e.name)===t&&(this.current.onExit(),this.current=null),this.scenes.delete(t)}switchTo(t){const e=this.scenes.get(t);return e?(this.current&&this.current.onExit(),this.current=e,this.current.onEnter(),this.bus.emit("scene:switched",t),!0):!1}get currentScene(){return this.current}get sceneNames(){return[...this.scenes.keys()]}get eventBus(){return this.bus}getScene(t){return this.scenes.get(t)}}class H{constructor(t,e,s){n(this,"gl");n(this,"program");this.gl=t;const r=this.compile(t.VERTEX_SHADER,e),o=this.compile(t.FRAGMENT_SHADER,s);if(this.program=t.createProgram(),t.attachShader(this.program,r),t.attachShader(this.program,o),t.linkProgram(this.program),!t.getProgramParameter(this.program,t.LINK_STATUS)){const i=t.getProgramInfoLog(this.program);throw t.deleteProgram(this.program),new Error(`Shader link error: ${i}`)}t.deleteShader(r),t.deleteShader(o)}compile(t,e){const s=this.gl.createShader(t);if(this.gl.shaderSource(s,e),this.gl.compileShader(s),!this.gl.getShaderParameter(s,this.gl.COMPILE_STATUS)){const r=this.gl.getShaderInfoLog(s);throw this.gl.deleteShader(s),new Error(`Shader compile error: ${r}`)}return s}use(){this.gl.useProgram(this.program)}getAttribLocation(t){return this.gl.getAttribLocation(this.program,t)}getUniformLocation(t){return this.gl.getUniformLocation(this.program,t)}setUniformMat3(t,e){const s=this.getUniformLocation(t);s&&this.gl.uniformMatrix3fv(s,!1,e)}setUniformVec4(t,e,s,r,o){const i=this.getUniformLocation(t);i&&this.gl.uniform4f(i,e,s,r,o)}setUniformVec2(t,e,s){const r=this.getUniformLocation(t);r&&this.gl.uniform2f(r,e,s)}setUniformFloat(t,e){const s=this.getUniformLocation(t);s&&this.gl.uniform1f(s,e)}setUniformInt(t,e){const s=this.getUniformLocation(t);s&&this.gl.uniform1i(s,e)}destroy(){this.gl.deleteProgram(this.program)}}const F=`#version 300 es
|
|
2
|
+
layout(location = 0) in vec2 aPosition;
|
|
3
|
+
layout(location = 1) in vec2 aTexCoord;
|
|
4
|
+
layout(location = 2) in vec4 aColor;
|
|
5
|
+
|
|
6
|
+
uniform mat3 uViewProj;
|
|
7
|
+
|
|
8
|
+
out vec2 vTexCoord;
|
|
9
|
+
out vec4 vColor;
|
|
10
|
+
|
|
11
|
+
void main() {
|
|
12
|
+
vec3 pos = uViewProj * vec3(aPosition, 1.0);
|
|
13
|
+
gl_Position = vec4(pos.xy, 0.0, 1.0);
|
|
14
|
+
vTexCoord = aTexCoord;
|
|
15
|
+
vColor = aColor;
|
|
16
|
+
}
|
|
17
|
+
`,z=`#version 300 es
|
|
18
|
+
precision mediump float;
|
|
19
|
+
|
|
20
|
+
in vec2 vTexCoord;
|
|
21
|
+
in vec4 vColor;
|
|
22
|
+
|
|
23
|
+
uniform sampler2D uTexture;
|
|
24
|
+
uniform float uUseTexture;
|
|
25
|
+
|
|
26
|
+
out vec4 fragColor;
|
|
27
|
+
|
|
28
|
+
void main() {
|
|
29
|
+
vec4 texColor = mix(vec4(1.0), texture(uTexture, vTexCoord), uUseTexture);
|
|
30
|
+
fragColor = vColor * texColor;
|
|
31
|
+
}
|
|
32
|
+
`,v=8,R=1e4;class I{constructor(t){n(this,"gl");n(this,"shader");n(this,"vao");n(this,"vbo");n(this,"vertices");n(this,"vertexCount",0);n(this,"currentTexture",null);const e=t.getContext("webgl2",{alpha:!1,antialias:!1,premultipliedAlpha:!1});if(!e)throw new Error("WebGL2 not supported");this.gl=e,this.shader=new H(e,F,z),this.vertices=new Float32Array(R*6*v),this.vao=e.createVertexArray(),this.vbo=e.createBuffer(),e.bindVertexArray(this.vao),e.bindBuffer(e.ARRAY_BUFFER,this.vbo),e.bufferData(e.ARRAY_BUFFER,this.vertices.byteLength,e.DYNAMIC_DRAW);const s=v*4;e.enableVertexAttribArray(0),e.vertexAttribPointer(0,2,e.FLOAT,!1,s,0),e.enableVertexAttribArray(1),e.vertexAttribPointer(1,2,e.FLOAT,!1,s,8),e.enableVertexAttribArray(2),e.vertexAttribPointer(2,4,e.FLOAT,!1,s,16),e.bindVertexArray(null),e.enable(e.BLEND),e.blendFunc(e.SRC_ALPHA,e.ONE_MINUS_SRC_ALPHA)}clear(t=0,e=0,s=0,r=1){this.gl.clearColor(t,e,s,r),this.gl.clear(this.gl.COLOR_BUFFER_BIT)}begin(t){this.shader.use(),this.shader.setUniformMat3("uViewProj",t.data),this.gl.bindVertexArray(this.vao)}drawSprite(t,e){const s=e.texture??null;(s!==this.currentTexture||this.vertexCount+6>R*6)&&(this.flush(),this.currentTexture=s),s?(this.gl.activeTexture(this.gl.TEXTURE0),this.gl.bindTexture(this.gl.TEXTURE_2D,s),this.shader.setUniformInt("uTexture",0),this.shader.setUniformFloat("uUseTexture",1)):this.shader.setUniformFloat("uUseTexture",0);const r=e.width*.5,o=e.height*.5,i=t.getLocalMatrix(),l=[{x:-r,y:-o,u:e.texCoordU,v:e.texCoordV},{x:r,y:-o,u:e.texCoordU+e.texCoordW,v:e.texCoordV},{x:r,y:o,u:e.texCoordU+e.texCoordW,v:e.texCoordV+e.texCoordH},{x:-r,y:o,u:e.texCoordU,v:e.texCoordV+e.texCoordH}].map(g=>{const f=i.transformPoint({x:g.x,y:g.y});return{x:f.x,y:f.y,u:g.u,v:g.v}}),a=this.vertices;let u=this.vertexCount*v;const m=g=>{const f=l[g];a[u++]=f.x,a[u++]=f.y,a[u++]=f.u,a[u++]=f.v,a[u++]=e.colorR,a[u++]=e.colorG,a[u++]=e.colorB,a[u++]=e.colorA};m(0),m(1),m(2),m(0),m(2),m(3),this.vertexCount+=6}flush(){this.vertexCount!==0&&(this.gl.bufferSubData(this.gl.ARRAY_BUFFER,0,this.vertices,0,this.vertexCount*v),this.gl.drawArrays(this.gl.TRIANGLES,0,this.vertexCount),this.vertexCount=0)}end(){this.flush(),this.gl.bindVertexArray(null),this.currentTexture=null}resize(t,e){this.gl.viewport(0,0,t,e)}get context(){return this.gl}destroy(){this.shader.destroy(),this.gl.deleteBuffer(this.vbo),this.gl.deleteVertexArray(this.vao)}}const d=class d{constructor(t=0,e=0){n(this,"x");n(this,"y");this.x=t,this.y=e}clone(){return new d(this.x,this.y)}set(t,e){return this.x=t,this.y=e,this}add(t){return new d(this.x+t.x,this.y+t.y)}sub(t){return new d(this.x-t.x,this.y-t.y)}mul(t){return new d(this.x*t,this.y*t)}div(t){return new d(this.x/t,this.y/t)}dot(t){return this.x*t.x+this.y*t.y}cross(t){return this.x*t.y-this.y*t.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 t=this.length();return t>0?this.div(t):d.ZERO.clone()}distance(t){return this.sub(t).length()}distanceSq(t){return this.sub(t).lengthSq()}angle(){return Math.atan2(this.y,this.x)}rotate(t){const e=Math.cos(t),s=Math.sin(t);return new d(this.x*e-this.y*s,this.x*s+this.y*e)}lerp(t,e){return new d(this.x+(t.x-this.x)*e,this.y+(t.y-this.y)*e)}equals(t,e=1e-6){return Math.abs(this.x-t.x)<e&&Math.abs(this.y-t.y)<e}static fromAngle(t,e=1){return new d(Math.cos(t)*e,Math.sin(t)*e)}static lerp(t,e,s){return t.lerp(e,s)}};n(d,"ZERO",new d(0,0)),n(d,"ONE",new d(1,1)),n(d,"UP",new d(0,-1)),n(d,"DOWN",new d(0,1)),n(d,"LEFT",new d(-1,0)),n(d,"RIGHT",new d(1,0));let w=d;class k{constructor(t){n(this,"canvas");n(this,"keysDown",new Set);n(this,"keysPressed",new Set);n(this,"keysReleased",new Set);n(this,"mouseButtonsDown",new Set);n(this,"mouseButtonsPressed",new Set);n(this,"mouseButtonsReleased",new Set);n(this,"mousePos",new w);n(this,"mouseDelta",new w);n(this,"scrollDelta",0);n(this,"bound",!1);n(this,"keyDownHandler");n(this,"keyUpHandler");n(this,"mouseMoveHandler");n(this,"mouseDownHandler");n(this,"mouseUpHandler");n(this,"wheelHandler");this.canvas=t,this.keyDownHandler=e=>{this.keysDown.has(e.code)||this.keysPressed.add(e.code),this.keysDown.add(e.code),e.preventDefault()},this.keyUpHandler=e=>{this.keysDown.delete(e.code),this.keysReleased.add(e.code)},this.mouseMoveHandler=e=>{const s=this.canvas.getBoundingClientRect(),r=e.clientX-s.left,o=e.clientY-s.top;this.mouseDelta=new w(r-this.mousePos.x,o-this.mousePos.y),this.mousePos=new w(r,o)},this.mouseDownHandler=e=>{this.mouseButtonsDown.has(e.button)||this.mouseButtonsPressed.add(e.button),this.mouseButtonsDown.add(e.button)},this.mouseUpHandler=e=>{this.mouseButtonsDown.delete(e.button),this.mouseButtonsReleased.add(e.button)},this.wheelHandler=e=>{this.scrollDelta=e.deltaY}}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))}endFrame(){this.keysPressed.clear(),this.keysReleased.clear(),this.mouseButtonsPressed.clear(),this.mouseButtonsReleased.clear(),this.mouseDelta=w.ZERO.clone(),this.scrollDelta=0}isKeyDown(t){return this.keysDown.has(t)}isKeyPressed(t){return this.keysPressed.has(t)}isKeyReleased(t){return this.keysReleased.has(t)}isMouseButtonDown(t=0){return this.mouseButtonsDown.has(t)}isMouseButtonPressed(t=0){return this.mouseButtonsPressed.has(t)}isMouseButtonReleased(t=0){return this.mouseButtonsReleased.has(t)}get mousePosition(){return this.mousePos.clone()}get mouseDeltaPosition(){return this.mouseDelta.clone()}get scrollY(){return this.scrollDelta}}class O{async collideAABB(t,e,s,r,o,i,c,l){return t<o+c&&t+s>o&&e<i+l&&e+r>i}async batchTransform(t,e){return t}async noise2D(t,e,s){const r=Math.sin(t*127.1+e*311.7)*43758.5453123;return r-Math.floor(r)}async pathfind(){return console.warn("[Ion] pathfind: no compute backend, returning null"),null}}class W{constructor(t){n(this,"fs");this.fs=t}async invoke(t,e){throw new Error(`[Ion] Native invoke "${t}" not available in browser mode`)}}class V{constructor(){n(this,"storage",new Map)}async readText(t){const e=this.storage.get(t);if(!e)throw new Error(`File not found: ${t}`);return new TextDecoder().decode(e)}async writeText(t,e){this.storage.set(t,new TextEncoder().encode(e)),this.persistToLocalStorage()}async readBinary(t){const e=this.storage.get(t);if(!e)throw new Error(`File not found: ${t}`);return e}async writeBinary(t,e){this.storage.set(t,e),this.persistToLocalStorage()}async exists(t){return this.storage.has(t)}async mkdir(t){}async remove(t){this.storage.delete(t),this.persistToLocalStorage()}async listDir(t){const e=t.endsWith("/")?t:t+"/",s=new Set;for(const r of this.storage.keys())if(r.startsWith(e)){const i=r.slice(e.length).split("/")[0];s.add(i)}return[...s]}async isFile(t){return this.storage.has(t)}async isDir(t){const e=t.endsWith("/")?t:t+"/";for(const s of this.storage.keys())if(s.startsWith(e))return!0;return!1}persistToLocalStorage(){try{const t={};for(const[e,s]of this.storage)t[e]=[...s];localStorage.setItem("ion:fs",JSON.stringify(t))}catch{}}loadFromLocalStorage(){try{const t=localStorage.getItem("ion:fs");if(!t)return;const e=JSON.parse(t);for(const[s,r]of Object.entries(e))this.storage.set(s,new Uint8Array(r))}catch{}}}class N{constructor(t={}){n(this,"sceneManager");n(this,"renderer");n(this,"input");n(this,"eventBus");n(this,"fs");n(this,"bridge");n(this,"compute");n(this,"running",!1);n(this,"lastTime",0);n(this,"rafId",0);n(this,"fixedAccumulator",0);n(this,"fixedStep",1e3/60);n(this,"canvas");n(this,"loop",t=>{if(!this.running)return;this.rafId=requestAnimationFrame(this.loop);const e=t-this.lastTime;this.lastTime=t;const s=Math.min(e,250);for(this.fixedAccumulator+=s;this.fixedAccumulator>=this.fixedStep;)this.fixedUpdate(this.fixedStep/1e3),this.fixedAccumulator-=this.fixedStep;this.update(s/1e3),this.render(),this.input.endFrame()});const e=t.canvasId??"ion-canvas",s=document.getElementById(e);if(!s)throw new Error(`Canvas "#${e}" not found`);if(s.width=t.width??window.innerWidth,s.height=t.height??window.innerHeight,this.canvas=s,this.eventBus=new T,this.renderer=new I(s),this.input=new k(s),this.sceneManager=new U(this.eventBus),t.fs)this.fs=t.fs;else{const r=new V;r.loadFromLocalStorage(),this.fs=r}this.bridge=t.nativeBridge??new W(this.fs),this.compute=new O,window.addEventListener("resize",()=>this.handleResize())}handleResize(){this.canvas.width=window.innerWidth,this.canvas.height=window.innerHeight,this.renderer.resize(this.canvas.width,this.canvas.height),this.eventBus.emit("engine:resize",{width:this.canvas.width,height:this.canvas.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(t){const e=this.sceneManager.currentScene;e&&(e.world.update(t),e.onUpdate(t))}update(t){}render(){const t=this.sceneManager.currentScene;if(!t){this.renderer.clear(.1,.1,.1);return}const e=t.world.query("camera2d","transform2d");if(e.length===0){this.renderer.clear(.1,.1,.1);return}const s=e[0],r=s.get("camera2d"),o=s.get("transform2d");r.x=o.x,r.y=o.y,r.rotation=o.rotation,r.viewportWidth=this.canvas.width,r.viewportHeight=this.canvas.height;const i=r.getViewProjectionMatrix();this.renderer.clear(.1,.1,.12),this.renderer.begin(i);const c=t.world.query("transform2d","sprite");c.sort((l,a)=>{const u=l.get("transform2d").zIndex,m=a.get("transform2d").zIndex;return u-m});for(const l of c){const a=l.get("transform2d"),u=l.get("sprite");this.renderer.drawSprite(a,u)}this.renderer.end()}destroy(){var t;this.stop(),this.renderer.destroy(),(t=this.sceneManager.currentScene)==null||t.world.clear(),this.eventBus.clear()}}class A{}let q=1;class Y{constructor(t){n(this,"id");n(this,"tags",new Set);n(this,"active",!0);this.id=t??q++}tag(...t){for(const e of t)this.tags.add(e);return this}untag(...t){for(const e of t)this.tags.delete(e);return this}hasTag(t){return this.tags.has(t)}equals(t){return this.id===t.id}}class j{constructor(t){n(this,"entity");n(this,"components",new Map);this.entity=t}add(t){return this.components.set(t.type,t),this}remove(t){const e=this.components.get(t);return this.components.delete(t),e}get(t){return this.components.get(t)}has(t){return this.components.has(t)}hasAll(t){for(const e of t)if(!this.components.has(e))return!1;return!0}getAll(){return new Map(this.components)}}class X{constructor(){n(this,"archetypes",new Map);n(this,"systems",[]);n(this,"entityRecycleBin",[]);n(this,"bus",new T)}createEntity(){const t=this.entityRecycleBin.length>0?this.entityRecycleBin.pop():void 0,e=new Y(t),s=new j(e);return this.archetypes.set(e.id,s),this.bus.emit("entity:created",e),e}destroyEntity(t){const e=this.archetypes.get(t);e&&(this.bus.emit("entity:destroyed",e.entity),this.archetypes.delete(t),this.entityRecycleBin.push(t))}getArchetype(t){return this.archetypes.get(t)}addComponent(t,e){const s=this.archetypes.get(t);s&&(s.add(e),this.bus.emit("component:added",{entityId:t,type:e.type}))}removeComponent(t,e){const s=this.archetypes.get(t);s&&(s.remove(e),this.bus.emit("component:removed",{entityId:t,type:e}))}getComponent(t,e){var s;return(s=this.archetypes.get(t))==null?void 0:s.get(e)}registerSystem(t){this.systems.push(t),this.systems.sort((e,s)=>e.priority-s.priority),t.onInit(this)}unregisterSystem(t){const e=this.systems.indexOf(t);e!==-1&&(t.onDestroy(this),this.systems.splice(e,1))}query(...t){const e=[];for(const[,s]of this.archetypes)s.entity.active&&s.hasAll(t)&&e.push(s);return e}queryByTag(t){const e=[];for(const[,s]of this.archetypes)s.entity.active&&s.entity.hasTag(t)&&e.push(s);return e}update(t){for(const e of this.systems){if(!e.active)continue;const s=this.query(...e.requiredComponents);e.onUpdate(this,s,t)}}get entityCount(){return this.archetypes.size}get eventBus(){return this.bus}clear(){for(const t of this.systems)t.onDestroy(this);this.systems=[],this.archetypes.clear(),this.entityRecycleBin=[],this.bus.clear()}}class G{constructor(){n(this,"world",new X)}moveEntityTo(t,e){const s=this.world.getArchetype(t);if(!s)return!1;const r=s.getAll(),o=s.entity;this.world.destroyEntity(t);const i=e.world.createEntity();i.tags=new Set(o.tags),i.active=o.active;const c=e.world.getArchetype(i.id);for(const[,l]of r)c.add(l);return!0}copyEntityTo(t,e){const s=this.world.getArchetype(t);if(!s)return null;const r=e.world.createEntity();r.tags=new Set(s.entity.tags);const o=e.world.getArchetype(r.id);for(const[,i]of s.getAll())o.add(i);return r}}class y{constructor(t=y.identity().data){n(this,"data");this.data=t}static identity(){return new y(new Float32Array([1,0,0,0,1,0,0,0,1]))}static translation(t,e){const s=y.identity();return s.data[6]=t,s.data[7]=e,s}static rotation(t){const e=Math.cos(t),s=Math.sin(t),r=y.identity();return r.data[0]=e,r.data[1]=s,r.data[3]=-s,r.data[4]=e,r}static scale(t,e){const s=y.identity();return s.data[0]=t,s.data[4]=e,s}static orthographic(t,e,s,r){const o=y.identity();return o.data[0]=2/(e-t),o.data[4]=2/(r-s),o.data[6]=-(e+t)/(e-t),o.data[7]=-(r+s)/(r-s),o}multiply(t){const e=this.data,s=t.data,r=new Float32Array(9);for(let o=0;o<3;o++)for(let i=0;i<3;i++)r[i*3+o]=e[o]*s[i*3]+e[3+o]*s[i*3+1]+e[6+o]*s[i*3+2];return new y(r)}transformPoint(t){const e=this.data;return new w(e[0]*t.x+e[3]*t.y+e[6],e[1]*t.x+e[4]*t.y+e[7])}clone(){return new y(new Float32Array(this.data))}invert(){const t=this.data,e=t[0]*(t[4]*t[8]-t[5]*t[7])-t[1]*(t[3]*t[8]-t[5]*t[6])+t[2]*(t[3]*t[7]-t[4]*t[6]);if(Math.abs(e)<1e-10)return y.identity();const s=1/e,r=new Float32Array(9);return r[0]=(t[4]*t[8]-t[5]*t[7])*s,r[1]=(t[2]*t[7]-t[1]*t[8])*s,r[2]=(t[1]*t[5]-t[2]*t[4])*s,r[3]=(t[5]*t[6]-t[3]*t[8])*s,r[4]=(t[0]*t[8]-t[2]*t[6])*s,r[5]=(t[2]*t[3]-t[0]*t[5])*s,r[6]=(t[3]*t[7]-t[4]*t[6])*s,r[7]=(t[1]*t[6]-t[0]*t[7])*s,r[8]=(t[0]*t[4]-t[1]*t[3])*s,new y(r)}}class C{constructor(t=0,e=0,s=0,r=0){n(this,"x");n(this,"y");n(this,"width");n(this,"height");this.x=t,this.y=e,this.width=s,this.height=r}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(t){return t.x>=this.left&&t.x<=this.right&&t.y>=this.top&&t.y<=this.bottom}intersects(t){return this.left<t.right&&this.right>t.left&&this.top<t.bottom&&this.bottom>t.top}clone(){return new C(this.x,this.y,this.width,this.height)}static fromPoints(t,e){const s=Math.min(t.x,e.x),r=Math.min(t.y,e.y);return new C(s,r,Math.max(t.x,e.x)-s,Math.max(t.y,e.y)-r)}}class p extends A{constructor(){super(...arguments);n(this,"type","transform2d");n(this,"x",0);n(this,"y",0);n(this,"rotation",0);n(this,"scaleX",1);n(this,"scaleY",1);n(this,"zIndex",0)}get position(){return new w(this.x,this.y)}set position(e){this.x=e.x,this.y=e.y}getLocalMatrix(){return y.translation(this.x,this.y).multiply(y.rotation(this.rotation)).multiply(y.scale(this.scaleX,this.scaleY))}}class $ extends A{constructor(){super(...arguments);n(this,"type","camera2d");n(this,"x",0);n(this,"y",0);n(this,"zoom",1);n(this,"rotation",0);n(this,"viewportWidth",1280);n(this,"viewportHeight",720)}get position(){return new w(this.x,this.y)}set position(e){this.x=e.x,this.y=e.y}getViewProjectionMatrix(){const e=this.viewportWidth*.5/this.zoom,s=this.viewportHeight*.5/this.zoom;return y.translation(-this.x,-this.y).multiply(y.rotation(-this.rotation)).multiply(y.orthographic(-e,e,-s,s))}screenToWorld(e,s){const r=e/this.viewportWidth*2-1,o=1-s/this.viewportHeight*2,i=this.viewportWidth*.5/this.zoom,c=this.viewportHeight*.5/this.zoom;return this.getViewProjectionMatrix().invert().transformPoint(new w(r*i,o*c))}getVisibleBounds(){const e=this.viewportWidth*.5/this.zoom,s=this.viewportHeight*.5/this.zoom;return new C(this.x-e,this.y-s,e*2,s*2)}}class x extends A{constructor(e=1,s=1,r=1,o=1,i=32,c=32,l,a=0,u=0,m=1,g=1){super();n(this,"colorR");n(this,"colorG");n(this,"colorB");n(this,"colorA");n(this,"width");n(this,"height");n(this,"texture");n(this,"texCoordU");n(this,"texCoordV");n(this,"texCoordW");n(this,"texCoordH");n(this,"type","sprite");this.colorR=e,this.colorG=s,this.colorB=r,this.colorA=o,this.width=i,this.height=c,this.texture=l,this.texCoordU=a,this.texCoordV=u,this.texCoordW=m,this.texCoordH=g}}class E extends A{constructor(e=100,s=1,r=0,o=0){super();n(this,"type","orbitalSpeed");this.radius=e,this.speed=s,this.angleOffset=r,this.orbitTilt=o}}class K extends G{constructor(){super(...arguments);n(this,"name","atom")}onEnter(){const e=this.world.createEntity();this.world.addComponent(e.id,new p);const s=new $;s.zoom=1,this.world.addComponent(e.id,s);const r=this.world.createEntity().tag("nucleus"),o=new p;o.zIndex=10,this.world.addComponent(r.id,o),this.world.addComponent(r.id,new x(.9,.6,.1,1,28,28));const i=this.world.createEntity().tag("glow"),c=new p;c.zIndex=9,this.world.addComponent(i.id,c),this.world.addComponent(i.id,new x(.9,.5,.1,.15,60,60));const l=[{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 a of l){for(let b=0;b<60;b++){const S=this.world.createEntity().tag("ring"),M=new p;M.zIndex=1,this.world.addComponent(S.id,M),this.world.addComponent(S.id,new E(a.radius,0,b/60*Math.PI*2,a.tilt)),this.world.addComponent(S.id,new x(a.color[0]*.3,a.color[1]*.3,a.color[2]*.3,.25,2,2))}const m=this.world.createEntity().tag("electron"),g=new p;g.zIndex=5,this.world.addComponent(m.id,g),this.world.addComponent(m.id,new E(a.radius,a.speed,a.offset,a.tilt)),this.world.addComponent(m.id,new x(a.color[0],a.color[1],a.color[2],1,a.size,a.size));const f=this.world.createEntity().tag("electron-glow"),B=new p;B.zIndex=4,this.world.addComponent(f.id,B),this.world.addComponent(f.id,new E(a.radius,a.speed,a.offset,a.tilt)),this.world.addComponent(f.id,new x(a.color[0],a.color[1],a.color[2],.2,a.size*4,a.size*4))}}onUpdate(){const e=performance.now()*.001,s=this.world.query("transform2d","orbitalSpeed");for(const i of s){const c=i.get("transform2d"),l=i.get("orbitalSpeed"),a=l.angleOffset+e*l.speed,u=Math.cos(a)*l.radius,m=Math.sin(a)*l.radius*.4,g=Math.cos(l.orbitTilt),f=Math.sin(l.orbitTilt);c.x=u*g-m*f,c.y=u*f+m*g}const r=this.world.queryByTag("nucleus")[0];if(r){const i=r.get("sprite"),c=28+Math.sin(e*3)*4;i.width=c,i.height=c}const o=this.world.queryByTag("glow")[0];if(o){const i=o.get("sprite"),c=60+Math.sin(e*2)*10;i.width=c,i.height=c,i.colorA=.12+Math.sin(e*3)*.05}}onExit(){this.world.clear()}}const P=new N({canvasId:"game-canvas"});P.sceneManager.register(new K);P.sceneManager.switchTo("atom");P.start();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<title>My Ion Game</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-Dmalnvpw.js"></script>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<canvas id="game-canvas"></canvas>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const { app, BrowserWindow } = require("electron");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
let win;
|
|
5
|
+
|
|
6
|
+
app.whenReady().then(() => {
|
|
7
|
+
win = new BrowserWindow({
|
|
8
|
+
width: 1280,
|
|
9
|
+
height: 720,
|
|
10
|
+
title: "Photon",
|
|
11
|
+
webPreferences: {
|
|
12
|
+
nodeIntegration: false,
|
|
13
|
+
contextIsolation: true,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
win.loadFile(path.join(__dirname, "..", "dist-renderer", "index.html"));
|
|
18
|
+
win.webContents.openDevTools();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
app.on("window-all-closed", () => app.quit());
|
|
@@ -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
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<canvas id="game-canvas"></canvas>
|
|
14
|
+
<script type="module" src="/src/main.ts"></script>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hash": "f73e02d2",
|
|
3
|
+
"configHash": "b8ee81f7",
|
|
4
|
+
"lockfileHash": "3b55699f",
|
|
5
|
+
"browserHash": "515ae1dd",
|
|
6
|
+
"optimized": {
|
|
7
|
+
"electron": {
|
|
8
|
+
"src": "../../../../../../../node_modules/electron/index.js",
|
|
9
|
+
"file": "electron.js",
|
|
10
|
+
"fileHash": "dd513bd8",
|
|
11
|
+
"needsInterop": true
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"chunks": {}
|
|
15
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
3
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
// browser-external:fs
|
|
7
|
+
var require_fs = __commonJS({
|
|
8
|
+
"browser-external:fs"(exports, module) {
|
|
9
|
+
module.exports = Object.create(new Proxy({}, {
|
|
10
|
+
get(_, key) {
|
|
11
|
+
if (key !== "__esModule" && key !== "__proto__" && key !== "constructor" && key !== "splice") {
|
|
12
|
+
console.warn(`Module "fs" has been externalized for browser compatibility. Cannot access "fs.${key}" in client code. See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// browser-external:path
|
|
20
|
+
var require_path = __commonJS({
|
|
21
|
+
"browser-external:path"(exports, module) {
|
|
22
|
+
module.exports = Object.create(new Proxy({}, {
|
|
23
|
+
get(_, key) {
|
|
24
|
+
if (key !== "__esModule" && key !== "__proto__" && key !== "constructor" && key !== "splice") {
|
|
25
|
+
console.warn(`Module "path" has been externalized for browser compatibility. Cannot access "path.${key}" in client code. See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// ../../../../node_modules/electron/index.js
|
|
33
|
+
var require_electron = __commonJS({
|
|
34
|
+
"../../../../node_modules/electron/index.js"(exports, module) {
|
|
35
|
+
var fs = require_fs();
|
|
36
|
+
var path = require_path();
|
|
37
|
+
var pathFile = path.join(__dirname, "path.txt");
|
|
38
|
+
function getElectronPath() {
|
|
39
|
+
let executablePath;
|
|
40
|
+
if (fs.existsSync(pathFile)) {
|
|
41
|
+
executablePath = fs.readFileSync(pathFile, "utf-8");
|
|
42
|
+
}
|
|
43
|
+
if (process.env.ELECTRON_OVERRIDE_DIST_PATH) {
|
|
44
|
+
return path.join(process.env.ELECTRON_OVERRIDE_DIST_PATH, executablePath || "electron");
|
|
45
|
+
}
|
|
46
|
+
if (executablePath) {
|
|
47
|
+
return path.join(__dirname, "dist", executablePath);
|
|
48
|
+
} else {
|
|
49
|
+
throw new Error("Electron failed to install correctly, please delete node_modules/electron and try installing again");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
module.exports = getElectronPath();
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
export default require_electron();
|
|
56
|
+
//# sourceMappingURL=electron.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["browser-external:fs", "browser-external:path", "../../../../../../../node_modules/electron/index.js"],
|
|
4
|
+
"sourcesContent": ["module.exports = Object.create(new Proxy({}, {\n get(_, key) {\n if (\n key !== '__esModule' &&\n key !== '__proto__' &&\n key !== 'constructor' &&\n key !== 'splice'\n ) {\n console.warn(`Module \"fs\" has been externalized for browser compatibility. Cannot access \"fs.${key}\" in client code. See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.`)\n }\n }\n}))", "module.exports = Object.create(new Proxy({}, {\n get(_, key) {\n if (\n key !== '__esModule' &&\n key !== '__proto__' &&\n key !== 'constructor' &&\n key !== 'splice'\n ) {\n console.warn(`Module \"path\" has been externalized for browser compatibility. Cannot access \"path.${key}\" in client code. See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.`)\n }\n }\n}))", "const fs = require('fs');\nconst path = require('path');\n\nconst pathFile = path.join(__dirname, 'path.txt');\n\nfunction getElectronPath () {\n let executablePath;\n if (fs.existsSync(pathFile)) {\n executablePath = fs.readFileSync(pathFile, 'utf-8');\n }\n if (process.env.ELECTRON_OVERRIDE_DIST_PATH) {\n return path.join(process.env.ELECTRON_OVERRIDE_DIST_PATH, executablePath || 'electron');\n }\n if (executablePath) {\n return path.join(__dirname, 'dist', executablePath);\n } else {\n throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again');\n }\n}\n\nmodule.exports = getElectronPath();\n"],
|
|
5
|
+
"mappings": ";;;;;;AAAA;AAAA;AAAA,WAAO,UAAU,OAAO,OAAO,IAAI,MAAM,CAAC,GAAG;AAAA,MAC3C,IAAI,GAAG,KAAK;AACV,YACE,QAAQ,gBACR,QAAQ,eACR,QAAQ,iBACR,QAAQ,UACR;AACA,kBAAQ,KAAK,kFAAkF,GAAG,mIAAmI;AAAA,QACvO;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAAA;AAAA;;;ACXF;AAAA;AAAA,WAAO,UAAU,OAAO,OAAO,IAAI,MAAM,CAAC,GAAG;AAAA,MAC3C,IAAI,GAAG,KAAK;AACV,YACE,QAAQ,gBACR,QAAQ,eACR,QAAQ,iBACR,QAAQ,UACR;AACA,kBAAQ,KAAK,sFAAsF,GAAG,mIAAmI;AAAA,QAC3O;AAAA,MACF;AAAA,IACF,CAAC,CAAC;AAAA;AAAA;;;ACXF;AAAA;AAAA,QAAM,KAAK;AACX,QAAM,OAAO;AAEb,QAAM,WAAW,KAAK,KAAK,WAAW,UAAU;AAEhD,aAAS,kBAAmB;AAC1B,UAAI;AACJ,UAAI,GAAG,WAAW,QAAQ,GAAG;AAC3B,yBAAiB,GAAG,aAAa,UAAU,OAAO;AAAA,MACpD;AACA,UAAI,QAAQ,IAAI,6BAA6B;AAC3C,eAAO,KAAK,KAAK,QAAQ,IAAI,6BAA6B,kBAAkB,UAAU;AAAA,MACxF;AACA,UAAI,gBAAgB;AAClB,eAAO,KAAK,KAAK,WAAW,QAAQ,cAAc;AAAA,MACpD,OAAO;AACL,cAAM,IAAI,MAAM,oGAAoG;AAAA,MACtH;AAAA,IACF;AAEA,WAAO,UAAU,gBAAgB;AAAA;AAAA;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "photon-template-electron",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"electron:dev": "electron .",
|
|
10
|
+
"electron:build": "vite build && electron-builder"
|
|
11
|
+
},
|
|
12
|
+
"main": "electron/main.cjs",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"photon-engine": "^0.1.1",
|
|
15
|
+
"photon-engine-electron": "^0.1.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"electron": "^28.0.0",
|
|
19
|
+
"vite": "^6.0.0",
|
|
20
|
+
"typescript": "^5.6.0"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Engine, Scene, Transform2D, Camera2D, Sprite, Component,
|
|
3
|
+
} from "photon-engine";
|
|
4
|
+
|
|
5
|
+
class OrbitalSpeed extends Component {
|
|
6
|
+
readonly type = "orbitalSpeed";
|
|
7
|
+
constructor(
|
|
8
|
+
public radius: number = 100,
|
|
9
|
+
public speed: number = 1,
|
|
10
|
+
public angleOffset: number = 0,
|
|
11
|
+
public orbitTilt: number = 0,
|
|
12
|
+
) { super(); }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class AtomScene extends Scene {
|
|
16
|
+
readonly name = "atom";
|
|
17
|
+
|
|
18
|
+
onEnter(): void {
|
|
19
|
+
const cam = this.world.createEntity();
|
|
20
|
+
this.world.addComponent(cam.id, new Transform2D());
|
|
21
|
+
const camComp = new Camera2D();
|
|
22
|
+
camComp.zoom = 1;
|
|
23
|
+
this.world.addComponent(cam.id, camComp);
|
|
24
|
+
|
|
25
|
+
const nucleus = this.world.createEntity().tag("nucleus");
|
|
26
|
+
const nPos = new Transform2D();
|
|
27
|
+
nPos.zIndex = 10;
|
|
28
|
+
this.world.addComponent(nucleus.id, nPos);
|
|
29
|
+
this.world.addComponent(nucleus.id, new Sprite(0.9, 0.6, 0.1, 1, 28, 28));
|
|
30
|
+
|
|
31
|
+
const glow = this.world.createEntity().tag("glow");
|
|
32
|
+
const gPos = new Transform2D();
|
|
33
|
+
gPos.zIndex = 9;
|
|
34
|
+
this.world.addComponent(glow.id, gPos);
|
|
35
|
+
this.world.addComponent(glow.id, new Sprite(0.9, 0.5, 0.1, 0.15, 60, 60));
|
|
36
|
+
|
|
37
|
+
const orbits = [
|
|
38
|
+
{ radius: 80, speed: 2.0, tilt: 0, color: [0.3, 0.7, 1.0], size: 8, offset: 0 },
|
|
39
|
+
{ radius: 130, speed: 1.3, tilt: Math.PI / 3, color: [0.4, 1.0, 0.6], size: 7, offset: Math.PI * 0.66 },
|
|
40
|
+
{ radius: 180, speed: 0.8, tilt: -Math.PI / 4, color: [1.0, 0.4, 0.8], size: 6, offset: Math.PI * 1.33 },
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
for (const orbit of orbits) {
|
|
44
|
+
const ringCount = 60;
|
|
45
|
+
for (let i = 0; i < ringCount; i++) {
|
|
46
|
+
const dot = this.world.createEntity().tag("ring");
|
|
47
|
+
const dPos = new Transform2D();
|
|
48
|
+
dPos.zIndex = 1;
|
|
49
|
+
this.world.addComponent(dot.id, dPos);
|
|
50
|
+
this.world.addComponent(dot.id, new OrbitalSpeed(
|
|
51
|
+
orbit.radius, 0, (i / ringCount) * Math.PI * 2, orbit.tilt
|
|
52
|
+
));
|
|
53
|
+
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
|
|
55
|
+
));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const electron = this.world.createEntity().tag("electron");
|
|
59
|
+
const ePos = new Transform2D();
|
|
60
|
+
ePos.zIndex = 5;
|
|
61
|
+
this.world.addComponent(electron.id, ePos);
|
|
62
|
+
this.world.addComponent(electron.id, new OrbitalSpeed(
|
|
63
|
+
orbit.radius, orbit.speed, orbit.offset, orbit.tilt
|
|
64
|
+
));
|
|
65
|
+
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
|
|
78
|
+
));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
onUpdate(): void {
|
|
83
|
+
const time = performance.now() * 0.001;
|
|
84
|
+
const entities = this.world.query("transform2d", "orbitalSpeed");
|
|
85
|
+
|
|
86
|
+
for (const arch of entities) {
|
|
87
|
+
const t = arch.get<Transform2D>("transform2d")!;
|
|
88
|
+
const o = arch.get<OrbitalSpeed>("orbitalSpeed")!;
|
|
89
|
+
|
|
90
|
+
const angle = o.angleOffset + time * o.speed;
|
|
91
|
+
const x = Math.cos(angle) * o.radius;
|
|
92
|
+
const y = Math.sin(angle) * o.radius * 0.4;
|
|
93
|
+
|
|
94
|
+
const cosT = Math.cos(o.orbitTilt);
|
|
95
|
+
const sinT = Math.sin(o.orbitTilt);
|
|
96
|
+
t.x = x * cosT - y * sinT;
|
|
97
|
+
t.y = x * sinT + y * cosT;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const nucleusArch = this.world.queryByTag("nucleus")[0];
|
|
101
|
+
if (nucleusArch) {
|
|
102
|
+
const nSprite = nucleusArch.get<Sprite>("sprite")!;
|
|
103
|
+
const pulse = 28 + Math.sin(time * 3) * 4;
|
|
104
|
+
nSprite.width = pulse;
|
|
105
|
+
nSprite.height = pulse;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const glowArch = this.world.queryByTag("glow")[0];
|
|
109
|
+
if (glowArch) {
|
|
110
|
+
const gSprite = glowArch.get<Sprite>("sprite")!;
|
|
111
|
+
const pulse = 60 + Math.sin(time * 2) * 10;
|
|
112
|
+
gSprite.width = pulse;
|
|
113
|
+
gSprite.height = pulse;
|
|
114
|
+
gSprite.colorA = 0.12 + Math.sin(time * 3) * 0.05;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
onExit(): void { this.world.clear(); }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const engine = new Engine({ canvasId: "game-canvas" });
|
|
122
|
+
engine.sceneManager.register(new AtomScene());
|
|
123
|
+
engine.sceneManager.switchTo("atom");
|
|
124
|
+
engine.start();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022", "DOM"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"noEmit": true
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*.ts"]
|
|
13
|
+
}
|