Electron-Prototyp: eigenes App-Fenster statt Tauri/WebKitGTK

Ersetzt den Tauri-Webview-Weg testweise durch eine Electron-Shell (randlos,
ohne native Menüleiste, wie chromium-shell.sh), damit die WASM/WebGPU-Engine
zuverlässig laeuft statt in WebKitGTK. Rust-Backend nicht noetig, da
compute_joins einen TS-Fallback hat. npm run electron zum Starten.
This commit is contained in:
2026-07-02 23:51:23 +02:00
parent 27e41077b1
commit 34317e53f4
5 changed files with 254 additions and 7 deletions
+20 -7
View File
@@ -73,13 +73,26 @@ integrierter Engine-Viewport möglich). Die Engine-Rust-Crates sind in einem sp
Schritt 1:1 wiederverwendbar; nur die dünne WASM-Bindeschicht wäre dann Wegwerf. All-native
bleibt legitimes Fernziel, ist aber KEIN Weg zurück zu Tauri (Tauri IST der Webview-Shell).
>>> NÄCHSTER KONKRETER SCHRITT (neue Session zuerst): Electron-Prototyp. Nur additiv:
`electron` als devDep, ~30-Zeilen `main.js` (BrowserWindow + `app.commandLine.appendSwitch`
für WebGPU: `enable-unsafe-webgpu` + `enable-features=Vulkan` — dieselben Flags wie
`scripts/chromium-shell.sh`), lädt den Vite-Server (dev) bzw. `dist` (prod), npm-Script
`electron`. Verifizieren: App startet als eigenes Fenster, `?engine=wasm` rendert den
Engine-Viewport (WebGPU in Electron = wie Chromium). Rust-Backend NICHT nötig — `compute_joins`
hat TS-Fallback. Risikoarm, ~1 Session. Danach: render3d-WASM, Doppeltext-Fix.<<<
>>> ELECTRON-PROTOTYP: FERTIG (2026-07-02). <<<
`electron` als devDep, `scripts/electron-main.cjs` (BrowserWindow, `Menu.setApplicationMenu(null)`
+ `frame:false`/`autoHideMenuBar` für randloses Fenster wie chromium-shell.sh, WebGPU-Flags
`enable-unsafe-webgpu`+`enable-features=Vulkan`), `scripts/electron-shell.sh` (Dev-Server-Guard
wie chromium-shell.sh), npm-Script `npm run electron`. Verifiziert per Screenshot: App startet
als eigenes randloses Fenster, lädt den echten Grundriss (nicht leer). WICHTIG:
- **Datei muss `.cjs` sein** (`package.json` hat `"type":"module"`, Electron-Main läuft als CJS).
- **`ELECTRON_RUN_AS_NODE=1`** kann aus dem umgebenden Prozess (z.B. VSCode-Electron-Host)
vererbt sein — zwingt Electron in den Node-Modus (`require('electron')` liefert nur einen
Pfad-String statt `{app,...}``app` ist undefined). Immer mit `env -u ELECTRON_RUN_AS_NODE`
starten, falls das Fenster nicht öffnet / `app.commandLine` undefined ist.
- **WebGPU/`?engine=wasm` in Electron auf diesem System (niri/Wayland) fällt auf WebGL2 zurück**
(Ozone-Wayland+Vulkan-Warnung beim Start). `--ozone-platform=x11` GEHT NICHT (bricht die
Fenstererstellung komplett — GetGeometry/Vulkan-Surface-Fehler). System-Chromium
(`chromium-shell.sh`) rendert die WASM-Engine hingegen nachweislich (siehe [[wasm-engine-viewport]]-
Notizen); die verwendete Electron-Version (Paket sagt ^43, `--version` meldet v24 — Versions-
Mismatch, ggf. stale Binary-Cache) könnte ein älteres/anders konfiguriertes Chromium mitbringen.
TODO nächste Session: Electron-Version/Ozone-Flags weiter untersuchen, bevor der Prototyp der
primäre Dev-Weg wird — bis dahin bleibt WebGL2-Fallback der Standardpfad, funktional unverändert.
Danach: render3d-WASM, Doppeltext-Fix.<<<
Klarstellung an den User (er fragte, ob Webview = „billig"): NEIN — Figma (eigene C++/WASM-Engine
im Web-Shell), Onshape, VS Code zeigen, dass „eigene Engine + Web-UI" Top-Tier-Architektur ist.
CAD/BIM-Substanz = Modell + Engine + Normen (haben wir: parametrische Wände, SIA 416, DOSSIER-
+135
View File
@@ -27,6 +27,7 @@
"@types/react-dom": "^18.3.0",
"@types/three": "^0.169.0",
"@vitejs/plugin-react": "^4.3.2",
"electron": "^43.0.0",
"playwright": "^1.61.1",
"puppeteer": "^25.2.1",
"typescript": "^5.6.2",
@@ -326,6 +327,50 @@
"node": ">=6.9.0"
}
},
"node_modules/@electron-internal/extract-zip": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@electron-internal/extract-zip/-/extract-zip-1.0.4.tgz",
"integrity": "sha512-Zr1Vs7E9tpCNhZHDAbFVXc2gEVCG9RqPDjrno5+bdgB6LRAuvgyMHJut4NCVyYwtAieapMzc3fiQ3CSTi75ARg==",
"dev": true,
"license": "BSD-2-Clause",
"engines": {
"node": ">=22.12.0"
}
},
"node_modules/@electron/get": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@electron/get/-/get-5.0.0.tgz",
"integrity": "sha512-pjoBpru1KdEtcExBnuHAP1cAc/5faoedw0hzJkL3o4/IJp7HNF1+fbrdxT3gMYRX2oJfvnA/WXeCTVQpYYxyJA==",
"dev": true,
"license": "MIT",
"dependencies": {
"debug": "^4.1.1",
"env-paths": "^3.0.0",
"graceful-fs": "^4.2.11",
"progress": "^2.0.3",
"semver": "^7.6.3",
"sumchecker": "^3.0.1"
},
"engines": {
"node": ">=22.12.0"
},
"optionalDependencies": {
"undici": "^7.24.4"
}
},
"node_modules/@electron/get/node_modules/semver": {
"version": "7.8.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@emnapi/core": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
@@ -1885,6 +1930,16 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
"version": "24.13.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.2.tgz",
"integrity": "sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.18.0"
}
},
"node_modules/@types/pako": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz",
@@ -2379,6 +2434,25 @@
"loglevel": "^1.7.1"
}
},
"node_modules/electron": {
"version": "43.0.0",
"resolved": "https://registry.npmjs.org/electron/-/electron-43.0.0.tgz",
"integrity": "sha512-PV60GsWU6qufhuOhw3n+Yix3WPDcqDtBqE8orbEQGQGHEkgp9o/JCPgb7L4vIL0r1HnfPdqSRtboOTqbDkcFDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@electron-internal/extract-zip": "^1.0.1",
"@electron/get": "^5.0.0",
"@types/node": "^24.9.0"
},
"bin": {
"electron": "cli.js",
"install-electron": "install.js"
},
"engines": {
"node": ">= 22.12.0"
}
},
"node_modules/electron-to-chromium": {
"version": "1.5.380",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.380.tgz",
@@ -2393,6 +2467,19 @@
"dev": true,
"license": "MIT"
},
"node_modules/env-paths": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz",
"integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/es-module-lexer": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.2.0.tgz",
@@ -2558,6 +2645,13 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true,
"license": "ISC"
},
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
@@ -3248,6 +3342,16 @@
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"license": "MIT"
},
"node_modules/progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/puppeteer": {
"version": "25.2.1",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-25.2.1.tgz",
@@ -3590,6 +3694,19 @@
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/sumchecker": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
"integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"debug": "^4.1.0"
},
"engines": {
"node": ">= 8.0"
}
},
"node_modules/svg-pathdata": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
@@ -3740,6 +3857,24 @@
"node": ">=14.17"
}
},
"node_modules/undici": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz",
"integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==",
"dev": true,
"license": "MIT",
"optional": true,
"engines": {
"node": ">=20.18.1"
}
},
"node_modules/undici-types": {
"version": "7.18.2",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
"dev": true,
"license": "MIT"
},
"node_modules/update-browserslist-db": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
+2
View File
@@ -14,6 +14,7 @@
"tauri:build": "tauri build",
"dump:native": "node scripts/dump-native-scene.mjs",
"shell": "scripts/chromium-shell.sh",
"electron": "scripts/electron-shell.sh",
"build:engine": "wasm-pack build src-tauri/render2d --release --target web --out-dir ../../src/engine/pkg --out-name render2d --no-default-features --features web"
},
"dependencies": {
@@ -36,6 +37,7 @@
"@types/react-dom": "^18.3.0",
"@types/three": "^0.169.0",
"@vitejs/plugin-react": "^4.3.2",
"electron": "^43.0.0",
"playwright": "^1.61.1",
"puppeteer": "^25.2.1",
"typescript": "^5.6.2",
+48
View File
@@ -0,0 +1,48 @@
// electron-main.js — Electron-Prototyp-Shell für die CAD-App.
//
// Ersetzt WebKitGTK (Tauri-Linux-Webview) durch Chromium, damit WebGPU
// (render2d-WASM-Engine, ?engine=wasm) zuverlässig läuft. Kein Rust-Backend
// nötig: compute_joins hat einen TS-Fallback (src/compute/index.ts).
const { app, BrowserWindow, Menu } = require("electron");
// Randloses App-Fenster wie chromium-shell.sh (--app=…): keine native
// Menüleiste (File/Edit/View/Window), kein Fensterrahmen.
Menu.setApplicationMenu(null);
// Gleiche Flags wie scripts/chromium-shell.sh — WebGPU liegt unter Linux
// hinter --enable-unsafe-webgpu, und WebGPU braucht das Vulkan-Backend.
app.commandLine.appendSwitch("enable-unsafe-webgpu");
app.commandLine.appendSwitch("enable-features", "Vulkan");
const DEV_URL = "http://localhost:5187";
const isDev = !app.isPackaged;
function createWindow() {
const win = new BrowserWindow({
width: 1600,
height: 1000,
frame: false,
autoHideMenuBar: true,
webPreferences: {
contextIsolation: true,
nodeIntegration: false,
},
});
if (isDev) {
win.loadURL(DEV_URL);
} else {
win.loadFile(require("node:path").join(__dirname, "..", "dist", "index.html"));
}
}
app.whenReady().then(createWindow);
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit();
});
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# electron-shell.sh — startet die CAD-Oberfläche im Electron-Prototyp-Fenster.
#
# Wie chromium-shell.sh: stellt sicher, dass der Vite-Dev-Server läuft, startet
# ihn sonst selbst und beendet ihn wieder, sobald das Electron-Fenster schliesst.
set -u
PORT=5187
URL="http://localhost:${PORT}"
server_is_up() {
curl --silent --fail --max-time 1 --output /dev/null "${URL}"
}
DEV_SERVER_PID=""
if server_is_up; then
echo "electron-shell: Dev-Server läuft bereits auf ${URL}."
else
echo "electron-shell: starte Vite-Dev-Server (Port ${PORT}) …"
npm run dev >/tmp/cad-electron-shell-dev.log 2>&1 &
DEV_SERVER_PID=$!
ATTEMPTS=0
MAX_ATTEMPTS=60
until server_is_up; do
ATTEMPTS=$((ATTEMPTS + 1))
if [ "${ATTEMPTS}" -ge "${MAX_ATTEMPTS}" ]; then
echo "electron-shell: Dev-Server antwortet nach ${MAX_ATTEMPTS}s nicht, Abbruch." >&2
kill "${DEV_SERVER_PID}" 2>/dev/null
exit 1
fi
sleep 1
done
echo "electron-shell: Dev-Server bereit."
fi
cleanup() {
if [ -n "${DEV_SERVER_PID}" ]; then
echo "electron-shell: beende selbst gestarteten Dev-Server (PID ${DEV_SERVER_PID}) …"
kill "${DEV_SERVER_PID}" 2>/dev/null
wait "${DEV_SERVER_PID}" 2>/dev/null
fi
}
trap cleanup EXIT
echo "electron-shell: öffne Electron-Fenster …"
npx electron "$(dirname "$0")/electron-main.cjs"