@certe/atmos-editor 0.5.0 → 0.7.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/bin/atmos-init.mjs +329 -1
- package/dist/project-seed.d.ts.map +1 -1
- package/dist/project-seed.js +4 -2
- package/dist/project-seed.js.map +1 -1
- package/package.json +6 -6
- package/vite-plugin.cjs +2 -0
- package/vite-plugin.mjs +2 -0
package/bin/atmos-init.mjs
CHANGED
|
@@ -78,8 +78,9 @@ if (!fs.existsSync(path.join(root, 'tsconfig.json'))) {
|
|
|
78
78
|
console.log('tsconfig.json already exists, skipping');
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
// 5. Install
|
|
81
|
+
// 5. Install dependencies
|
|
82
82
|
console.log('\nInstalling dependencies...');
|
|
83
|
+
execSync('npm install @certe/atmos-physics', { stdio: 'inherit', cwd: root });
|
|
83
84
|
execSync('npm install -D vite @vitejs/plugin-react typescript', { stdio: 'inherit', cwd: root });
|
|
84
85
|
|
|
85
86
|
// 6. Add scripts to package.json if missing
|
|
@@ -90,4 +91,331 @@ if (!updatedPkg.scripts.build) updatedPkg.scripts.build = 'vite build';
|
|
|
90
91
|
if (!updatedPkg.scripts.preview) updatedPkg.scripts.preview = 'vite preview';
|
|
91
92
|
fs.writeFileSync(pkgPath, JSON.stringify(updatedPkg, null, 2) + '\n');
|
|
92
93
|
|
|
94
|
+
// 7. Generate README.md with engine guide
|
|
95
|
+
const readme = `# Atmos Game Project
|
|
96
|
+
|
|
97
|
+
## Quick Start
|
|
98
|
+
|
|
99
|
+
\`\`\`bash
|
|
100
|
+
npm run dev # Start editor at localhost:5173
|
|
101
|
+
npm run build # Build standalone game (no editor)
|
|
102
|
+
npm run preview # Preview built game
|
|
103
|
+
\`\`\`
|
|
104
|
+
|
|
105
|
+
## Project Structure
|
|
106
|
+
|
|
107
|
+
\`\`\`
|
|
108
|
+
src/
|
|
109
|
+
main.ts # Editor bootstrap (DO NOT add game logic here)
|
|
110
|
+
scripts/ # Game scripts — all gameplay code goes here
|
|
111
|
+
MyScript.ts
|
|
112
|
+
scenes/
|
|
113
|
+
main.scene.json # Scene files (created/saved from editor)
|
|
114
|
+
materials/
|
|
115
|
+
default.mat.json # Material assets
|
|
116
|
+
textures/ # Image textures (.jpg, .png)
|
|
117
|
+
models/ # 3D models (.glb)
|
|
118
|
+
project-settings.json # Editor settings (default scene, physics)
|
|
119
|
+
vite.config.ts # Vite + Atmos plugin config
|
|
120
|
+
\`\`\`
|
|
121
|
+
|
|
122
|
+
## Imports — What Comes From Where
|
|
123
|
+
|
|
124
|
+
\`\`\`typescript
|
|
125
|
+
// Core — components, scene, engine, input
|
|
126
|
+
import { Component, GameObject, Scene, Transform, Input, Engine, Time } from '@certe/atmos-core';
|
|
127
|
+
import { serializeScene, deserializeScene } from '@certe/atmos-core';
|
|
128
|
+
|
|
129
|
+
// Math — vectors, quaternions, matrices, rays
|
|
130
|
+
import { Vec3, Quat, Mat4, Ray } from '@certe/atmos-math';
|
|
131
|
+
|
|
132
|
+
// Renderer — camera, lights, meshes, materials
|
|
133
|
+
import { Camera, MeshRenderer } from '@certe/atmos-renderer';
|
|
134
|
+
import { DirectionalLight, PointLight, SpotLight } from '@certe/atmos-renderer';
|
|
135
|
+
import { createMaterial, createMesh } from '@certe/atmos-renderer';
|
|
136
|
+
import { createCubeGeometry, createSphereGeometry, createPlaneGeometry, createCylinderGeometry } from '@certe/atmos-renderer';
|
|
137
|
+
|
|
138
|
+
// Physics — rigid bodies, colliders, joints, queries
|
|
139
|
+
import { RigidBody, Collider, Physics } from '@certe/atmos-physics';
|
|
140
|
+
import { HingeJoint, FixedJoint, SpringJoint } from '@certe/atmos-physics';
|
|
141
|
+
|
|
142
|
+
// Animation — skeletal animation
|
|
143
|
+
import { AnimationMixer } from '@certe/atmos-animation';
|
|
144
|
+
\`\`\`
|
|
145
|
+
|
|
146
|
+
## Writing Game Scripts
|
|
147
|
+
|
|
148
|
+
All game logic lives in \`src/scripts/\`. Each file exports Component subclasses
|
|
149
|
+
that are auto-discovered by the editor. **Never put game logic in main.ts.**
|
|
150
|
+
|
|
151
|
+
\`\`\`typescript
|
|
152
|
+
import { Component } from '@certe/atmos-core';
|
|
153
|
+
import { Vec3, Quat } from '@certe/atmos-math';
|
|
154
|
+
|
|
155
|
+
export class Rotator extends Component {
|
|
156
|
+
speed = 2;
|
|
157
|
+
|
|
158
|
+
// Expose properties to the editor inspector
|
|
159
|
+
static editorProperties = [
|
|
160
|
+
{ key: 'speed', type: 'number' as const, min: 0, max: 20, step: 0.1 },
|
|
161
|
+
];
|
|
162
|
+
|
|
163
|
+
onUpdate(dt: number) {
|
|
164
|
+
const q = this.transform.rotation;
|
|
165
|
+
const rot = Quat.create();
|
|
166
|
+
Quat.fromAxisAngle(rot, Vec3.fromValues(0, 1, 0), this.speed * dt);
|
|
167
|
+
Quat.multiply(q, rot, q);
|
|
168
|
+
this.transform.setRotationFrom(q);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
\`\`\`
|
|
172
|
+
|
|
173
|
+
### Component Lifecycle
|
|
174
|
+
|
|
175
|
+
\`\`\`
|
|
176
|
+
onAwake() — Called once when scene starts
|
|
177
|
+
onStart() — Called once after all awake calls
|
|
178
|
+
onUpdate(dt) — Called every frame (dt = seconds since last frame)
|
|
179
|
+
onRender() — Called after update, before GPU rendering
|
|
180
|
+
onDestroy() — Called when component or game object is removed
|
|
181
|
+
\`\`\`
|
|
182
|
+
|
|
183
|
+
### Accessing Other Components
|
|
184
|
+
|
|
185
|
+
\`\`\`typescript
|
|
186
|
+
// Get sibling component on same GameObject
|
|
187
|
+
const rb = this.getComponent(RigidBody);
|
|
188
|
+
|
|
189
|
+
// Search entire scene
|
|
190
|
+
const cameras = Component.findAll(Camera);
|
|
191
|
+
\`\`\`
|
|
192
|
+
|
|
193
|
+
### Input
|
|
194
|
+
|
|
195
|
+
\`\`\`typescript
|
|
196
|
+
import { Input } from '@certe/atmos-core';
|
|
197
|
+
|
|
198
|
+
onUpdate(dt: number) {
|
|
199
|
+
const input = Input.current!;
|
|
200
|
+
|
|
201
|
+
if (input.getKey('KeyW')) // Held down
|
|
202
|
+
if (input.getKeyDown('Space')) // Just pressed this frame
|
|
203
|
+
if (input.getKeyUp('KeyE')) // Just released this frame
|
|
204
|
+
|
|
205
|
+
if (input.getMouseButton(0)) // Left mouse held
|
|
206
|
+
const { x, y } = input.mouseDelta; // Mouse movement
|
|
207
|
+
}
|
|
208
|
+
\`\`\`
|
|
209
|
+
|
|
210
|
+
Key codes: \`KeyW\`, \`KeyA\`, \`KeyS\`, \`KeyD\`, \`Space\`, \`ShiftLeft\`, \`ArrowUp\`,
|
|
211
|
+
\`ArrowDown\`, \`ArrowLeft\`, \`ArrowRight\`, \`Digit1\`–\`Digit9\`, \`KeyE\`, \`KeyQ\`, etc.
|
|
212
|
+
|
|
213
|
+
## Math API
|
|
214
|
+
|
|
215
|
+
All math types are Float32Array. Functions use \`out\` as the first parameter
|
|
216
|
+
(output is written into \`out\` and returned). **No allocations in hot paths.**
|
|
217
|
+
|
|
218
|
+
\`\`\`typescript
|
|
219
|
+
import { Vec3, Quat, Mat4 } from '@certe/atmos-math';
|
|
220
|
+
|
|
221
|
+
// Vec3 — Float32Array[3]
|
|
222
|
+
const v = Vec3.fromValues(1, 2, 3);
|
|
223
|
+
const result = Vec3.create();
|
|
224
|
+
Vec3.add(result, a, b);
|
|
225
|
+
Vec3.sub(result, a, b);
|
|
226
|
+
Vec3.scale(result, v, 2.0);
|
|
227
|
+
Vec3.normalize(result, v);
|
|
228
|
+
Vec3.cross(result, a, b);
|
|
229
|
+
Vec3.lerp(result, a, b, 0.5);
|
|
230
|
+
Vec3.dot(a, b); // returns number
|
|
231
|
+
Vec3.length(v); // returns number
|
|
232
|
+
Vec3.distance(a, b); // returns number
|
|
233
|
+
|
|
234
|
+
// Quat — Float32Array[4] as [x, y, z, w]
|
|
235
|
+
const q = Quat.create(); // identity
|
|
236
|
+
Quat.fromAxisAngle(q, axis, radians);
|
|
237
|
+
Quat.fromEuler(q, xRad, yRad, zRad);
|
|
238
|
+
Quat.multiply(out, a, b);
|
|
239
|
+
Quat.slerp(out, a, b, t);
|
|
240
|
+
Vec3.transformQuat(out, vec, quat); // rotate vector by quaternion
|
|
241
|
+
|
|
242
|
+
// Mat4 — Float32Array[16], column-major
|
|
243
|
+
Mat4.perspective(out, fovY, aspect, near, far);
|
|
244
|
+
Mat4.lookAt(out, eye, center, up);
|
|
245
|
+
Mat4.multiply(out, a, b);
|
|
246
|
+
Mat4.invert(out, a);
|
|
247
|
+
\`\`\`
|
|
248
|
+
|
|
249
|
+
## Scene Files
|
|
250
|
+
|
|
251
|
+
Scenes are JSON. The editor saves/loads them automatically. You can also
|
|
252
|
+
create GameObjects programmatically in a script's \`onAwake\`, but prefer
|
|
253
|
+
building scenes in the editor and saving to \`scenes/*.scene.json\`.
|
|
254
|
+
|
|
255
|
+
### Scene JSON format
|
|
256
|
+
|
|
257
|
+
\`\`\`json
|
|
258
|
+
{
|
|
259
|
+
"gameObjects": [
|
|
260
|
+
{
|
|
261
|
+
"name": "Floor",
|
|
262
|
+
"id": 1,
|
|
263
|
+
"parentId": null,
|
|
264
|
+
"components": [
|
|
265
|
+
{
|
|
266
|
+
"type": "Transform",
|
|
267
|
+
"data": { "position": [0, 0, 0], "rotation": [0, 0, 0, 1], "scale": [10, 0.1, 10] }
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"type": "MeshRenderer",
|
|
271
|
+
"data": { "meshSource": "primitive:cube", "materialSource": "materials/default.mat.json" }
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"type": "RigidBody",
|
|
275
|
+
"data": { "bodyType": "fixed" }
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"type": "Collider",
|
|
279
|
+
"data": { "shape": { "type": "box", "halfExtents": { "x": 5, "y": 0.05, "z": 5 } } }
|
|
280
|
+
}
|
|
281
|
+
]
|
|
282
|
+
}
|
|
283
|
+
]
|
|
284
|
+
}
|
|
285
|
+
\`\`\`
|
|
286
|
+
|
|
287
|
+
### Mesh sources (meshSource)
|
|
288
|
+
|
|
289
|
+
- \`"primitive:cube"\` — Unit cube
|
|
290
|
+
- \`"primitive:sphere"\` — Sphere (radius 0.5)
|
|
291
|
+
- \`"primitive:plane"\` — Flat plane (1x1)
|
|
292
|
+
- \`"primitive:cylinder"\` — Cylinder (radius 0.5, height 1)
|
|
293
|
+
|
|
294
|
+
### Material files (.mat.json)
|
|
295
|
+
|
|
296
|
+
\`\`\`json
|
|
297
|
+
{
|
|
298
|
+
"name": "Metal",
|
|
299
|
+
"shader": "pbr",
|
|
300
|
+
"albedo": [0.8, 0.8, 0.8, 1.0],
|
|
301
|
+
"metallic": 0.9,
|
|
302
|
+
"roughness": 0.2,
|
|
303
|
+
"emissive": [0, 0, 0],
|
|
304
|
+
"emissiveIntensity": 0
|
|
305
|
+
}
|
|
306
|
+
\`\`\`
|
|
307
|
+
|
|
308
|
+
Set \`emissive\` + \`emissiveIntensity\` > 0 for glowing objects (works with bloom).
|
|
309
|
+
|
|
310
|
+
## Built-in Components
|
|
311
|
+
|
|
312
|
+
### Rendering
|
|
313
|
+
- **MeshRenderer** — meshSource, materialSource, castShadow, receiveSSAO
|
|
314
|
+
- **Camera** — fovY (radians), near, far, isMainCamera, clearColor
|
|
315
|
+
|
|
316
|
+
### Lights
|
|
317
|
+
- **DirectionalLight** — color, intensity, castShadows, shadowIntensity
|
|
318
|
+
- **PointLight** — color, intensity, range, castShadows
|
|
319
|
+
- **SpotLight** — color, intensity, range, innerAngle, outerAngle, castShadows
|
|
320
|
+
|
|
321
|
+
### Physics
|
|
322
|
+
- **RigidBody** — bodyType (dynamic/fixed/kinematic), linearDamping, angularDamping, gravityScale
|
|
323
|
+
- **Collider** — shape (box/sphere/capsule/cylinder), friction, restitution, density, isSensor
|
|
324
|
+
- **HingeJoint** — axis, connectedBody, limits, motor
|
|
325
|
+
|
|
326
|
+
### Animation
|
|
327
|
+
- **AnimationMixer** — initialClip, speed, loop, autoplay
|
|
328
|
+
|
|
329
|
+
## Physics
|
|
330
|
+
|
|
331
|
+
\`\`\`typescript
|
|
332
|
+
import { RigidBody, Collider, Physics } from '@certe/atmos-physics';
|
|
333
|
+
|
|
334
|
+
// Apply force
|
|
335
|
+
const rb = this.getComponent(RigidBody);
|
|
336
|
+
rb.body?.applyImpulse({ x: 0, y: 10, z: 0 }, true);
|
|
337
|
+
|
|
338
|
+
// Raycast
|
|
339
|
+
const hit = Physics.raycast(physicsWorld, origin, direction, 100);
|
|
340
|
+
if (hit) {
|
|
341
|
+
console.log(hit.gameObject.name, hit.point, hit.distance);
|
|
342
|
+
}
|
|
343
|
+
\`\`\`
|
|
344
|
+
|
|
345
|
+
## Editor Properties
|
|
346
|
+
|
|
347
|
+
Expose script fields to the inspector:
|
|
348
|
+
|
|
349
|
+
\`\`\`typescript
|
|
350
|
+
export class Enemy extends Component {
|
|
351
|
+
health = 100;
|
|
352
|
+
speed = 3;
|
|
353
|
+
color = new Float32Array([1, 0, 0]);
|
|
354
|
+
isFlying = false;
|
|
355
|
+
difficulty: string = 'normal';
|
|
356
|
+
target: GameObject | null = null;
|
|
357
|
+
|
|
358
|
+
static editorProperties = [
|
|
359
|
+
{ key: 'health', type: 'number' as const, min: 0, max: 1000, step: 10 },
|
|
360
|
+
{ key: 'speed', type: 'number' as const, min: 0, max: 20, step: 0.5 },
|
|
361
|
+
{ key: 'color', type: 'color' as const },
|
|
362
|
+
{ key: 'isFlying', type: 'boolean' as const },
|
|
363
|
+
{ key: 'difficulty', type: 'enum' as const, options: ['easy', 'normal', 'hard'] },
|
|
364
|
+
{ key: 'target', type: 'gameObjectRef' as const },
|
|
365
|
+
];
|
|
366
|
+
}
|
|
367
|
+
\`\`\`
|
|
368
|
+
|
|
369
|
+
Property types: \`number\`, \`string\`, \`boolean\`, \`vec3\`, \`quat\`, \`color\`,
|
|
370
|
+
\`enum\`, \`gameObjectRef\`, \`materialAsset\`
|
|
371
|
+
|
|
372
|
+
## AI Agent Instructions
|
|
373
|
+
|
|
374
|
+
> **WARNING — FILE PLACEMENT IS CRITICAL. Getting this wrong breaks the engine.**
|
|
375
|
+
> The ONLY directory inside \`src/\` is \`src/scripts/\`. Everything else is at the PROJECT ROOT.
|
|
376
|
+
> **NEVER create \`src/scenes/\`, \`src/materials/\`, \`src/textures/\`, or \`src/models/\`.**
|
|
377
|
+
|
|
378
|
+
### File placement rules
|
|
379
|
+
|
|
380
|
+
| What | Correct path | WRONG — never do this |
|
|
381
|
+
|---|---|---|
|
|
382
|
+
| Game scripts | \`src/scripts/MyScript.ts\` | \`src/MyScript.ts\`, \`main.ts\` |
|
|
383
|
+
| Scene files | \`scenes/main.scene.json\` | \`src/scenes/\`, \`src/main.scene.json\` |
|
|
384
|
+
| Material files | \`materials/metal.mat.json\` | \`src/materials/\`, \`src/metal.mat.json\` |
|
|
385
|
+
| Textures | \`textures/grass.png\` | \`src/textures/\` |
|
|
386
|
+
| Models | \`models/character.glb\` | \`src/models/\` |
|
|
387
|
+
|
|
388
|
+
### Rules
|
|
389
|
+
|
|
390
|
+
1. **All game logic goes in \`src/scripts/\`** as Component subclasses
|
|
391
|
+
2. **Scene files go in \`scenes/*.scene.json\`** at project root — the editor and build system read from this exact path
|
|
392
|
+
3. **Material files go in \`materials/*.mat.json\`** at project root — reference them in scene JSON and MeshRenderer.materialSource as \`"materials/metal.mat.json"\` (relative to project root)
|
|
393
|
+
4. **Textures go in \`textures/\`** at project root — reference in .mat.json as \`"textures/grass.png"\`
|
|
394
|
+
5. **Models go in \`models/\`** at project root
|
|
395
|
+
6. **main.ts is engine bootstrap only** — never modify it for game logic
|
|
396
|
+
7. **Use \`static editorProperties\`** so the editor can display and tweak values
|
|
397
|
+
8. **Math uses out-params** — always \`Vec3.add(out, a, b)\`, never \`a.add(b)\`
|
|
398
|
+
9. **Scripts are hot-reloaded** — the editor picks up new files in src/scripts/ automatically
|
|
399
|
+
10. **The default scene is \`scenes/main.scene.json\`** — the editor loads this on startup
|
|
400
|
+
|
|
401
|
+
### Creating materials
|
|
402
|
+
|
|
403
|
+
Create \`.mat.json\` files in \`materials/\` (project root):
|
|
404
|
+
|
|
405
|
+
materials/floor.mat.json <-- CORRECT
|
|
406
|
+
materials/metal.mat.json <-- CORRECT
|
|
407
|
+
src/materials/floor.mat.json <-- WRONG, engine will NOT find this
|
|
408
|
+
|
|
409
|
+
Then reference them in scene JSON by their project-root-relative path:
|
|
410
|
+
|
|
411
|
+
{ "type": "MeshRenderer", "data": { "materialSource": "materials/floor.mat.json" } }
|
|
412
|
+
`;
|
|
413
|
+
|
|
414
|
+
if (!fs.existsSync(path.join(root, 'README.md'))) {
|
|
415
|
+
fs.writeFileSync(path.join(root, 'README.md'), readme);
|
|
416
|
+
console.log('Created README.md');
|
|
417
|
+
} else {
|
|
418
|
+
console.log('README.md already exists, skipping');
|
|
419
|
+
}
|
|
420
|
+
|
|
93
421
|
console.log('\nDone! Run "npm run dev" to start the editor.');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-seed.d.ts","sourceRoot":"","sources":["../src/project-seed.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAczD,wBAAsB,WAAW,CAAC,SAAS,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"project-seed.d.ts","sourceRoot":"","sources":["../src/project-seed.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAczD,wBAAsB,WAAW,CAAC,SAAS,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B7E"}
|
package/dist/project-seed.js
CHANGED
|
@@ -24,8 +24,10 @@ export async function seedProject(projectFs) {
|
|
|
24
24
|
const json = serializeMaterialAsset(data);
|
|
25
25
|
writes.push(projectFs.writeFile(`materials/${key}.mat.json`, json));
|
|
26
26
|
}
|
|
27
|
-
// Empty scene
|
|
28
|
-
|
|
27
|
+
// Empty scene (only if none exists)
|
|
28
|
+
if (!(await projectFs.exists('scenes/main.scene.json'))) {
|
|
29
|
+
writes.push(projectFs.writeFile('scenes/main.scene.json', JSON.stringify({ gameObjects: [] }, null, 2)));
|
|
30
|
+
}
|
|
29
31
|
// Default project settings
|
|
30
32
|
if (!(await projectFs.exists('project-settings.json'))) {
|
|
31
33
|
writes.push(projectFs.writeFile('project-settings.json', JSON.stringify(DEFAULT_PROJECT_SETTINGS, null, 2)));
|
package/dist/project-seed.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-seed.js","sourceRoot":"","sources":["../src/project-seed.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,MAAM,cAAc,GAAoD;IACtE,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE;IACnF,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE;IAClF,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE;IACnF,MAAM,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE;IACrF,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE;IACnF,MAAM,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE;IACtF,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE;IACnF,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE;CACnF,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,SAA4B;IAC5D,4CAA4C;IAC5C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACnD,IAAI,MAAM;QAAE,OAAO;IAEnB,MAAM,SAAS,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACvC,MAAM,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAEpC,MAAM,MAAM,GAAoB,EAAE,CAAC;IAEnC,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACxD,MAAM,IAAI,GAAsB,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC;QACpD,MAAM,IAAI,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,aAAa,GAAG,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"project-seed.js","sourceRoot":"","sources":["../src/project-seed.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@certe/atmos-editor",
|
|
3
3
|
"description": "Browser-based Unity-style editor for the Atmos Engine — hierarchy, inspector, gizmos",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/certesolutions-cyber/atmos.git",
|
|
@@ -56,11 +56,11 @@
|
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@certe/atmos-animation": "^0.
|
|
60
|
-
"@certe/atmos-assets": "^0.
|
|
61
|
-
"@certe/atmos-core": "^0.
|
|
62
|
-
"@certe/atmos-math": "^0.
|
|
63
|
-
"@certe/atmos-renderer": "^0.
|
|
59
|
+
"@certe/atmos-animation": "^0.7.0",
|
|
60
|
+
"@certe/atmos-assets": "^0.7.0",
|
|
61
|
+
"@certe/atmos-core": "^0.7.0",
|
|
62
|
+
"@certe/atmos-math": "^0.7.0",
|
|
63
|
+
"@certe/atmos-renderer": "^0.7.0",
|
|
64
64
|
"react": "^19.0.0",
|
|
65
65
|
"react-dom": "^19.0.0"
|
|
66
66
|
},
|
package/vite-plugin.cjs
CHANGED
|
@@ -316,12 +316,14 @@ try {
|
|
|
316
316
|
async function handleFsAction(action, absPath, filePath, root, exclude, req, res, server) {
|
|
317
317
|
switch (action) {
|
|
318
318
|
case '/read': {
|
|
319
|
+
if (!fs.existsSync(absPath)) { res.statusCode = 404; res.end('Not found'); break; }
|
|
319
320
|
const data = fs.readFileSync(absPath);
|
|
320
321
|
res.setHeader('Content-Type', 'application/octet-stream');
|
|
321
322
|
res.end(data);
|
|
322
323
|
break;
|
|
323
324
|
}
|
|
324
325
|
case '/read-text': {
|
|
326
|
+
if (!fs.existsSync(absPath)) { res.statusCode = 404; res.end('Not found'); break; }
|
|
325
327
|
const text = fs.readFileSync(absPath, 'utf-8');
|
|
326
328
|
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
|
327
329
|
res.end(text);
|
package/vite-plugin.mjs
CHANGED
|
@@ -316,12 +316,14 @@ try {
|
|
|
316
316
|
async function handleFsAction(action, absPath, filePath, root, exclude, req, res, server) {
|
|
317
317
|
switch (action) {
|
|
318
318
|
case '/read': {
|
|
319
|
+
if (!fs.existsSync(absPath)) { res.statusCode = 404; res.end('Not found'); break; }
|
|
319
320
|
const data = fs.readFileSync(absPath);
|
|
320
321
|
res.setHeader('Content-Type', 'application/octet-stream');
|
|
321
322
|
res.end(data);
|
|
322
323
|
break;
|
|
323
324
|
}
|
|
324
325
|
case '/read-text': {
|
|
326
|
+
if (!fs.existsSync(absPath)) { res.statusCode = 404; res.end('Not found'); break; }
|
|
325
327
|
const text = fs.readFileSync(absPath, 'utf-8');
|
|
326
328
|
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
|
327
329
|
res.end(text);
|