Add shared-scene 2D authoring, sprite animation and Rapier2D physics
CI / validate (push) Canceled after 0s

This commit is contained in:
emil28092005
2026-09-12 04:58:59 +03:00
parent 6f497d1977
commit 3afac743a4
32 changed files with 4999 additions and 270 deletions
+60 -5
View File
@@ -11,7 +11,13 @@ import { defaultProject } from "../engine/templates.ts";
import { entity, uid, validateProject } from "../engine/schema.ts";
import { projectArchive, gameArchive, decodeData } from "../engine/archive.ts";
import { createMcp, type EngineService } from "./mcp.ts";
import { portableModel, modelComponents, modelDataUri, modelProject } from "../engine/model-import.ts";
import {
portableModel,
modelComponents,
modelDataUri,
modelProject,
} from "../engine/model-import.ts";
import { imageAsset } from "../engine/image-import.ts";
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const mime: Record<string, string> = {
".html": "text/html; charset=utf-8",
@@ -23,6 +29,9 @@ const mime: Record<string, string> = {
".svg": "image/svg+xml",
".wasm": "application/wasm",
".png": "image/png",
".webp": "image/webp",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".zip": "application/zip",
};
export function inside(base: string, requested: string) {
@@ -201,6 +210,31 @@ export async function createService(
"Unzip and serve over HTTP. Entry index.html. No editor or MCP required.",
};
},
importImage: async (a: any) => {
if (Boolean(a.base64) === Boolean(a.path))
throw Error("Supply exactly one of base64 or path");
const bytes = a.base64
? Buffer.from(a.base64, "base64")
: await safeRead(projectDir, a.path);
const asset = imageAsset(bytes, a.name),
commands: any[] = [{ op: "asset.upsert", args: { asset } }];
if (a.instantiate)
commands.push({
op: "node.create",
args: {
entity: entity(asset.name, {
sprite: { assetId: asset.id, frame: 0 },
}),
},
});
return store.transaction({
commands,
expectedRevision: a.expectedRevision,
requestId: a.requestId,
label: "Импорт спрайта " + asset.name,
source: "mcp",
});
},
importModel: async (a: any) => {
if (Boolean(a.base64) === Boolean(a.path))
throw Error("Supply exactly one of base64 or path");
@@ -208,13 +242,34 @@ export async function createService(
? Buffer.from(a.base64, "base64")
: Buffer.from(await safeRead(projectDir, a.path));
const sourceName = a.path || a.name;
const model = await portableModel(bytes, sourceName, a.path ? file => safeRead(projectDir, file) : undefined);
const model = await portableModel(
bytes,
sourceName,
a.path ? (file) => safeRead(projectDir, file) : undefined,
);
const id = uid("asset");
const asset = { id, name: model.name, kind: "model", metadata: model.metadata, uri: modelDataUri(model) };
const asset = {
id,
name: model.name,
kind: "model",
metadata: model.metadata,
uri: modelDataUri(model),
};
const commands: any[] = [{ op: "asset.upsert", args: { asset } }];
if (a.instantiate) commands.push({ op: "node.create", args: { entity: entity(model.name.replace(/\.(glb|gltf)$/i, ""), modelComponents(id, model.metadata)) } });
if (a.instantiate)
commands.push({
op: "node.create",
args: {
entity: entity(
model.name.replace(/\.(glb|gltf)$/i, ""),
modelComponents(id, model.metadata),
),
},
});
return store.transaction({
commands: a.asScene ? [{ op: "project.replace", args: { project: modelProject(model) } }] : commands,
commands: a.asScene
? [{ op: "project.replace", args: { project: modelProject(model) } }]
: commands,
expectedRevision: a.expectedRevision,
requestId: a.requestId,
label: "Импорт " + a.name,