mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-22 18:22:19 +00:00
M15.1: web build (eframe wasm) + xtask web
- apps/effectcraft-web (L6): eframe web runner booting the shared EffectcraftApp with a browser session: in-memory file table, <input type=file> pickers and drag-and-drop for open/import, downloads for Save and Render Queue outputs (several files as one stored .zip), and the window.effectcraft promise API over the control channel. Demo project on start. - wasm32 runtime fixes: web-time for Instant/SystemTime (render, engine, export, ui-egui); Frames renders queued jobs on the UI thread (Frames::pump) instead of a thread pool; Render Queue runs inline; relative outputs resolve under / ; control PNGs inline. - effectcraft-export: per-job output Sink (files to memory instead of disk); host FileExporter carries it; test that sink exports touch no file. - xtask web [--dev] [--serve PORT] (wasm-bindgen 0.2.129, optional wasm-opt, COOP/COEP server); effectcraft-web in WEB_CRATES. docs/web.md, headless Chrome smoke test, favicon (+attribution). Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
c925ac8ae8
commit
31f192e2a9
30 files changed
+1361
-92
No files matched your search
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<!-- EffectCraft mark (original work): the header logo of crates/ui-egui/src/header.rs as SVG:
|
||||
a navy rounded square split blue/violet with a white keyframe diamond. -->
|
||||
<rect x="0" y="0" width="64" height="64" rx="12" fill="#1d2b5e"/>
|
||||
<path d="M14 4 H32 V60 H14 A10 10 0 0 1 4 50 V14 A10 10 0 0 1 14 4 Z" fill="#2d8ceb"/>
|
||||
<path d="M32 4 H50 A10 10 0 0 1 60 14 V50 A10 10 0 0 1 50 60 H32 Z" fill="#8e6bff"/>
|
||||
<path d="M32 15.4 L48.6 32 L32 48.6 L15.4 32 Z" fill="#ffffff"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 558 B |
@@ -0,0 +1,9 @@
|
||||
asset: favicon.svg
|
||||
title: EffectCraft web app icon (favicon)
|
||||
author: EffectCraft contributors
|
||||
source: original work
|
||||
license: MIT OR Apache-2.0
|
||||
added: 2026-10-01 by EffectCraft contributors (Claude agent, M15 web app)
|
||||
notes: Hand-written SVG of the code-drawn EffectCraft mark (`paint_logo` in
|
||||
crates/ui-egui/src/header.rs): a navy rounded square split into blue and violet halves
|
||||
with a white keyframe diamond, from basic shapes. Not derived from any other product's icon.
|
||||
@@ -0,0 +1,64 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="color-scheme" content="dark">
|
||||
<title>EffectCraft</title>
|
||||
<link rel="icon" href="favicon.svg" type="image/svg+xml">
|
||||
<style>
|
||||
html, body { margin: 0; height: 100%; overflow: hidden; background: #1b1c1f; }
|
||||
canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; outline: none; }
|
||||
#loading {
|
||||
position: absolute; inset: 0; display: flex; flex-direction: column; gap: 14px;
|
||||
align-items: center; justify-content: center; color: #c9c9cc;
|
||||
font: 14px/1.4 system-ui, sans-serif; pointer-events: none;
|
||||
}
|
||||
#loading img { width: 56px; height: 56px; }
|
||||
#loading .err { color: #ff8a7a; white-space: pre-wrap; max-width: 70ch; pointer-events: auto; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="effectcraft_canvas"></canvas>
|
||||
<div id="loading"><img src="favicon.svg" alt=""><div id="status">Loading EffectCraft…</div></div>
|
||||
<script type="module">
|
||||
import init, * as ec from "./effectcraft_web.js";
|
||||
const t0 = performance.now();
|
||||
window.effectcraftLoad = {};
|
||||
// The agent / test API: the desktop control channel as promises (docs/web.md).
|
||||
window.effectcraft = {
|
||||
request: (method, params) => ec.request(method, params ?? {}),
|
||||
execute: (command, params) => ec.request("engine.execute", { command, params: params ?? {} }),
|
||||
commands: () => ec.request("engine.commands", {}),
|
||||
inspect: () => ec.request("ui.inspect", {}),
|
||||
screenshot: (params) => ec.request("ui.screenshot", params ?? {}),
|
||||
renderFrame: (params) => ec.request("render.frame", { base64: true, ...(params ?? {}) }),
|
||||
files: () => ec.files(),
|
||||
readFile: (path) => ec.readFile(path),
|
||||
addFile: async (fileOrUrl, name) => {
|
||||
let bytes;
|
||||
if (typeof fileOrUrl === "string") {
|
||||
bytes = new Uint8Array(await (await fetch(fileOrUrl)).arrayBuffer());
|
||||
name = name ?? fileOrUrl.split("/").pop();
|
||||
} else {
|
||||
bytes = new Uint8Array(await fileOrUrl.arrayBuffer());
|
||||
name = name ?? fileOrUrl.name;
|
||||
}
|
||||
return ec.addFile(name, bytes);
|
||||
},
|
||||
info: () => ({ ...ec.info(), crossOriginIsolated: self.crossOriginIsolated, load: window.effectcraftLoad }),
|
||||
};
|
||||
try {
|
||||
await init();
|
||||
window.effectcraftLoad.wasmMs = performance.now() - t0;
|
||||
await ec.start("effectcraft_canvas");
|
||||
window.effectcraftLoad.readyMs = performance.now() - t0;
|
||||
} catch (e) {
|
||||
const s = document.getElementById("status");
|
||||
if (s) { s.className = "err"; s.textContent = "EffectCraft failed to start:\n" + (e && e.stack || e); }
|
||||
window.effectcraftLoad.error = String(e);
|
||||
throw e;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user