Plugin support: Loader, Plugin-API v1 und Demo-Plugin #113

Closed
opened 2026-09-17 17:57:04 +02:00 by meleki · 1 comment
Owner

Der Editor soll sich per Plugin erweitern lassen. Ein Plugin ist eine einzelne .js-Datei; hochladen und aktivieren kommt später (eigene Issues, siehe unten). Dieses Issue legt die Architektur fest und liefert v1 nur mit dem, was das Demo-Plugin braucht.

Demo-Plugin (Ziel von v1):

  • ein eigener Tab
  • jedes Asset des Projekts als Node in einem Graph: leerer Node, Asset-Name als Titel. Kein Editing, keine Connections; Pan, Zoom und Fit gehen.
  • Asset anlegen, umbenennen oder löschen → der Tab zieht nach.

Entscheidungen (Planung 2026-09-17):

  1. Aktivierung: Alles, was in data/plugins/ liegt, ist aktiv. Aktiv/inaktiv unter Settings → #114.
  2. Serverweit, nicht pro Projekt.
  3. Quelle im Repo: plugins/demo-plugin.js. npm run build und tools/seed-e2e.mjs kopieren sie nach data/plugins/ (damit hat auch CI das Plugin). data/plugins/ kommt in .gitignore.
  4. Umfang: Architektur + API v1 nur für die Demo. Schreiben mit Undo, eigene Node-Typen im Behavior-Graph, eigene Asset-Typen, Inspector-Felder und Laufzeit-Hooks kommen als Folge-Issues, sobald es echte Nutzer dafür gibt – eine „vollständige“ API ohne Nutzer wird geraten.
  5. Nur im Editor, nicht im laufenden Spiel und nicht im Export.
  6. Sicherheit: Ein Plugin läuft mit allen Rechten des Editors. Für v1 hingenommen → #115.
  7. Keine Typen (.d.ts) für Plugin-Autoren vorerst.

Zu bauen:

  • Plugin-Format: ES-Modul mit export const meta = { id, name, version, api: 1 }, export function activate(api), optional export function deactivate(). Das Plugin importiert nichts – insbesondere kein eigenes Pixi (ein WebGL-Canvas, eine Pixi-Instanz); alles kommt über api.
  • Route plugins in api/index.php: listet data/plugins/*.js und liefert eine Datei mit Content-Type: text/javascript aus. Nur Dateinamen aus dem Ordner, kein Pfad (kein ..).
  • Loader im Editor: lädt beim Start alle Plugins per import() und ruft activate. Fehler beim Laden oder in activate → Console + Hinweis, der Editor läuft weiter. Ein Plugin mit unbekannter api-Version wird nicht aktiviert.
  • Plugin-API v1 (versioniert):
    • api.project – Assets lesen (id, name, type), Änderungen abonnieren (on('change', fn), liefert eine Abmelde-Funktion)
    • api.tabs.add({ id, label, create }) – dynamische Tabs zusätzlich zur festen CentreTab-Liste in src/editor/Editor.ts; deren Typsicherheit für die eingebauten Tabs bleibt.
    • api.ui.NodeBoard – reine Anzeige, setNodes([{ id, title, x, y }]), Pan/Zoom/Fit über FreeViewport, Look von NodeView. GraphCanvas wird dafür nicht wiederverwendet (hängt an EditorState und am Behavior-Graph).
  • Demo-Plugin plugins/demo-plugin.js: Tab „Assets“, ein Node je Asset, im Raster angeordnet.
  • Tests: Unit-Tests für Loader (defektes Plugin, falsche api-Version, Fehler in activate) und API; ein e2e-Modul öffnet den Tab und zählt die Nodes, auch nach Asset anlegen und löschen.
  • Wiki: neue Seite „Plugins“ (Format, API v1, Grenzen).

Offen:

  • Ladereihenfolge mehrerer Plugins. Vorschlag: nach Dateiname.
  • Zwei Plugins (oder ein Plugin und ein eingebauter Tab) mit derselben Tab-Id. Vorschlag: der zweite wird abgelehnt, Console-Warnung.

Folge-Issues: #114 Aktivieren unter Settings · #115 Sicherheit · #116 Upload

Der Editor soll sich per Plugin erweitern lassen. Ein Plugin ist eine einzelne `.js`-Datei; hochladen und aktivieren kommt später (eigene Issues, siehe unten). Dieses Issue legt die Architektur fest und liefert **v1 nur mit dem, was das Demo-Plugin braucht**. **Demo-Plugin (Ziel von v1):** - ein eigener Tab - jedes Asset des Projekts als Node in einem Graph: leerer Node, Asset-Name als Titel. Kein Editing, keine Connections; Pan, Zoom und Fit gehen. - Asset anlegen, umbenennen oder löschen → der Tab zieht nach. **Entscheidungen (Planung 2026-09-17):** 1. **Aktivierung:** Alles, was in `data/plugins/` liegt, ist aktiv. Aktiv/inaktiv unter Settings → #114. 2. **Serverweit**, nicht pro Projekt. 3. **Quelle im Repo:** `plugins/demo-plugin.js`. `npm run build` und `tools/seed-e2e.mjs` kopieren sie nach `data/plugins/` (damit hat auch CI das Plugin). `data/plugins/` kommt in `.gitignore`. 4. **Umfang:** Architektur + API v1 nur für die Demo. Schreiben mit Undo, eigene Node-Typen im Behavior-Graph, eigene Asset-Typen, Inspector-Felder und Laufzeit-Hooks kommen als Folge-Issues, sobald es echte Nutzer dafür gibt – eine „vollständige“ API ohne Nutzer wird geraten. 5. **Nur im Editor**, nicht im laufenden Spiel und nicht im Export. 6. **Sicherheit:** Ein Plugin läuft mit allen Rechten des Editors. Für v1 hingenommen → #115. 7. **Keine Typen** (`.d.ts`) für Plugin-Autoren vorerst. **Zu bauen:** - **Plugin-Format:** ES-Modul mit `export const meta = { id, name, version, api: 1 }`, `export function activate(api)`, optional `export function deactivate()`. Das Plugin importiert nichts – insbesondere kein eigenes Pixi (ein WebGL-Canvas, eine Pixi-Instanz); alles kommt über `api`. - **Route `plugins`** in `api/index.php`: listet `data/plugins/*.js` und liefert eine Datei mit `Content-Type: text/javascript` aus. Nur Dateinamen aus dem Ordner, kein Pfad (kein `..`). - **Loader im Editor:** lädt beim Start alle Plugins per `import()` und ruft `activate`. Fehler beim Laden oder in `activate` → Console + Hinweis, der Editor läuft weiter. Ein Plugin mit unbekannter `api`-Version wird nicht aktiviert. - **Plugin-API v1** (versioniert): - `api.project` – Assets lesen (`id`, `name`, `type`), Änderungen abonnieren (`on('change', fn)`, liefert eine Abmelde-Funktion) - `api.tabs.add({ id, label, create })` – dynamische Tabs zusätzlich zur festen `CentreTab`-Liste in `src/editor/Editor.ts`; deren Typsicherheit für die eingebauten Tabs bleibt. - `api.ui.NodeBoard` – reine Anzeige, `setNodes([{ id, title, x, y }])`, Pan/Zoom/Fit über `FreeViewport`, Look von `NodeView`. `GraphCanvas` wird dafür **nicht** wiederverwendet (hängt an `EditorState` und am Behavior-Graph). - **Demo-Plugin** `plugins/demo-plugin.js`: Tab „Assets“, ein Node je Asset, im Raster angeordnet. - **Tests:** Unit-Tests für Loader (defektes Plugin, falsche `api`-Version, Fehler in `activate`) und API; ein e2e-Modul öffnet den Tab und zählt die Nodes, auch nach Asset anlegen und löschen. - **Wiki:** neue Seite „Plugins“ (Format, API v1, Grenzen). **Offen:** - Ladereihenfolge mehrerer Plugins. Vorschlag: nach Dateiname. - Zwei Plugins (oder ein Plugin und ein eingebauter Tab) mit derselben Tab-Id. Vorschlag: der zweite wird abgelehnt, Console-Warnung. **Folge-Issues:** #114 Aktivieren unter Settings · #115 Sicherheit · #116 Upload
admin added this to the Development project 2026-09-17 18:32:35 +02:00
admin moved this to Next in Development on 2026-09-17 18:33:28 +02:00
Author
Owner

Umgesetzt in 57a97ba (Wiki 0576bba, neue Seite Plugins).

Was jetzt geht

  • Route plugins (api/index.php, api/lib/PluginStore.php): GET ?r=plugins listet die .js-Dateien in data/plugins/, sortiert nach Dateiname. GET ?r=plugins/{file} liefert eine Datei als text/javascript (nosniff, no-cache). Nur nackte Dateinamen: ../projects, x/../../api/index.php, .hidden.js, index.php → 404, POST → 405 (geprüft mit php -S im PHP-Container).
  • Loader (src/editor/plugins/): lädt nach dem Projekt, nacheinander in Dateinamen-Reihenfolge. Datei lädt nicht, meta/activate fehlt, falsche api-Version, doppelte meta.id, activate wirft → Plugin inaktiv, Zeile in der Console, Hinweis in der Toolbar; Editor und übrige Plugins laufen weiter.
  • API v1: api.project.assets() (Kopien), api.project.on('change', fn) (nur bei geänderter Asset-Liste: anlegen, umbenennen, löschen, Undo, Projektwechsel; liefert eine Abmelde-Funktion), api.tabs.add(…), api.ui.NodeBoard.
  • Offene Punkte entschieden wie vorgeschlagen: Reihenfolge nach Dateiname; belegte Tab-Id wird abgelehnt (false + Warnung, create wird nicht aufgerufen).
  • Demo-Plugin plugins/demo-plugin.js: Tab Assets, ein Node je Asset, vier pro Reihe. Build und seed-e2e kopieren nach data/plugins/ (gitignored).

Abweichungen

  • Nicht FreeViewport (der ist für Scene-Objekte): Grid, Zoom-Grenzen und Fit kommen aus dem Behavior-Graph und liegen jetzt gemeinsam in graph/graphView.ts.
  • Das Board bringt selbst einen Fit-Knopf und die Node-Zahl mit, weil ein Plugin in v1 keine Knöpfe bauen kann.
  • deactivate wird geprüft, aber noch nicht aufgerufen (kommt mit #114). Wirft activate nach tabs.add, bleibt der Tab stehen. Die Nodes zeigen den Einklapp-Pfeil aus NodeView.
  • ESLint prüft plugins/*.js und verbietet dort import.

Tests (lokal)

npm run check                                   → 93 Files, 1246 Tests (vorher 1228), CHECK EXIT 0
npm run build                                   → BUILD EXIT 0
GM_STEPS=38 (frisch geseedet)                   → ALL PASSED – 17 checks
GM_STEPS=1-16,19,23,26,36,38 (frisch geseedet)  → ALL PASSED – 600 checks
  • 18 neue Unit-Tests; Gegenprobe mit 4 absichtlich eingebauten Fehlern (Versionsprüfung, change-Filter, Tab-Id, doppelte Plugin-Id) → je genau ein Test rot, Originale zurück und per cmp geprüft.
  • Neues e2e-Modul 38 mit 15 Checks. Summe damit 963 (gerechnet, CI noch nicht gelesen).

Folgethemen: #114 (aktivieren/deaktivieren), #115 (Sicherheit), #116 (Upload).

Umgesetzt in `57a97ba` (Wiki `0576bba`, neue Seite **Plugins**). ## Was jetzt geht - **Route `plugins`** (`api/index.php`, `api/lib/PluginStore.php`): `GET ?r=plugins` listet die `.js`-Dateien in `data/plugins/`, sortiert nach Dateiname. `GET ?r=plugins/{file}` liefert eine Datei als `text/javascript` (`nosniff`, `no-cache`). Nur nackte Dateinamen: `../projects`, `x/../../api/index.php`, `.hidden.js`, `index.php` → 404, `POST` → 405 (geprüft mit `php -S` im PHP-Container). - **Loader** (`src/editor/plugins/`): lädt nach dem Projekt, nacheinander in Dateinamen-Reihenfolge. Datei lädt nicht, `meta`/`activate` fehlt, falsche `api`-Version, doppelte `meta.id`, `activate` wirft → Plugin inaktiv, Zeile in der Console, Hinweis in der Toolbar; Editor und übrige Plugins laufen weiter. - **API v1:** `api.project.assets()` (Kopien), `api.project.on('change', fn)` (nur bei geänderter Asset-Liste: anlegen, umbenennen, löschen, Undo, Projektwechsel; liefert eine Abmelde-Funktion), `api.tabs.add(…)`, `api.ui.NodeBoard`. - **Offene Punkte entschieden wie vorgeschlagen:** Reihenfolge nach Dateiname; belegte Tab-Id wird abgelehnt (`false` + Warnung, `create` wird nicht aufgerufen). - **Demo-Plugin** `plugins/demo-plugin.js`: Tab *Assets*, ein Node je Asset, vier pro Reihe. Build und `seed-e2e` kopieren nach `data/plugins/` (gitignored). ## Abweichungen - Nicht `FreeViewport` (der ist für Scene-Objekte): Grid, Zoom-Grenzen und Fit kommen aus dem Behavior-Graph und liegen jetzt gemeinsam in `graph/graphView.ts`. - Das Board bringt selbst einen Fit-Knopf und die Node-Zahl mit, weil ein Plugin in v1 keine Knöpfe bauen kann. - `deactivate` wird geprüft, aber noch nicht aufgerufen (kommt mit #114). Wirft `activate` nach `tabs.add`, bleibt der Tab stehen. Die Nodes zeigen den Einklapp-Pfeil aus `NodeView`. - ESLint prüft `plugins/*.js` und verbietet dort `import`. ## Tests (lokal) ``` npm run check → 93 Files, 1246 Tests (vorher 1228), CHECK EXIT 0 npm run build → BUILD EXIT 0 GM_STEPS=38 (frisch geseedet) → ALL PASSED – 17 checks GM_STEPS=1-16,19,23,26,36,38 (frisch geseedet) → ALL PASSED – 600 checks ``` - 18 neue Unit-Tests; Gegenprobe mit 4 absichtlich eingebauten Fehlern (Versionsprüfung, `change`-Filter, Tab-Id, doppelte Plugin-Id) → je genau ein Test rot, Originale zurück und per `cmp` geprüft. - Neues e2e-Modul 38 mit 15 Checks. Summe damit **963** (gerechnet, CI noch nicht gelesen). Folgethemen: #114 (aktivieren/deaktivieren), #115 (Sicherheit), #116 (Upload).
admin moved this to Done in Development on 2026-09-17 19:32:56 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#113