# Plugin Guide – WebCAD Plugin API v2 WebCAD Plugin API v2 erlaubt die Erweiterung des CAD um Werkzeuge, Panels und Block-Bibliotheken – ohne Kerncode anzufassen. ## Plugin-Typ (PluginV2) ```ts import type { PluginV2, ToolExtensionV2 } from './plugins'; export const myPlugin: PluginV2 = { manifest: { id: 'my-tools', name: 'Meine Werkzeuge', version: '1.0.0', author: 'Du', description: 'Beschreibung', category: 'tools', // tools|elements|library|import-export|theme|other enabledByDefault: true, }, tools: [/* ToolExtensionV2[] */], panels: [/* PanelExtension[] (optional) */], libraryProviders: [/* LibraryProviderExtension[] (optional) */], onInit?() {}, onActivate?() {}, onDeactivate?() {}, onDestroy?() {}, }; ``` ## Werkzeug (ToolExtensionV2) Ein Werkzeug besteht aus Manifest, Options-Schema und Handlern: ```ts export const myTool: ToolExtensionV2 = { manifest: { id: 'my-tool', label: 'Mein Werkzeug', icon: 'M', ribbonTab: 'canvas', // canvas|insert|format tags: ['basic'], // basic = sichtbar im simple-Mode, ['pro'] nur pro-Mode description: 'Was es tut', }, optionsSchema: [ { key: 'width', label: 'Breite', type: 'number', min: 1, max: 500 }, { key: 'color', label: 'Farbe', type: 'color' }, { key: 'style', label: 'Stil', type: 'select', options: [{ value: 'a', label: 'A' }, { value: 'b', label: 'B' }] }, { key: 'frame', label: 'Rahmen', type: 'checkbox' }, ], handlers: { down(e, ctx) { // e.world = Weltkoordinaten, e.shift, e.ctrl // ctx.doc = CADDocument (CRUD + transact + undo) // ctx.setStatus('...'), ctx.setPreview?.(element) const c = ctx as FullToolContext; if (!c.doc) return; c.doc.transact(() => c.doc!.addElement({ /* CADElement */ })); }, move(e, ctx) { /* Live-Preview */ }, up(e, ctx) { /* Commit */ }, key(k, ctx) { /* return true = konsumiert (z. B. Enter) */ }, cancel(ctx) { /* ESC/Rechtsklick: Session-State zurücksetzen */ }, }, }; ``` ### Kernregeln 1. **Eine Aktion = eine `doc.transact(() => ...)`** = genau ein Undo-Schritt. 2. **Session-State als Modul-Member** (nicht in `options` – diese sind geteilter UI-State). 3. **`cancel` setzt den Session-State immer zurück.** 4. **Koordinaten-Konventionen:** rect `x/y` = Zentrum der BBox; circle/arc `el.x/el.y` = Zentrum; Winkel in Grad (0° = 3 Uhr, CCW). 5. **Undo-fähig schreiben** nur über `doc.addElement/updateElement/deleteElements`. ## Bibliotheks-Provider (LibraryProviderExtension) ```ts const myProvider: LibraryProviderExtension = { id: 'my-catalog', label: 'Mein Katalog', async listFolders() { return [{ id: 'f1', label: 'Ordner', parentId: null }]; }, async listBlocks(folderId) { return [/* LibBlock[] */]; }, async getBlock(id) { return /* LibBlock */; }, }; ``` `LibBlock.payload` = JSON-String eines CADElement-Arrays → Drag&Drop in die Zeichenfläche funktioniert automatisch über den bestehenden Drop-Kanal. Thumbnail = eigenständiges SVG. ## Registrierung Built-in-Plugins werden in `src/plugins/index.ts` per `pluginRegistry.registerV2(plugin)` registriert; `enabledByDefault` macht sie aktiv (alternativ per `pluginRegistry.enableV2(id)`). ## Beispiel: Minimal-Plugin ```ts // plugins/builtin/stamp/index.ts import type { PluginV2, ToolExtensionV2 } from '../../types'; const stampTool: ToolExtensionV2 = { manifest: { id: 'stamp', label: 'Stempel', icon: '\u25c6', ribbonTab: 'insert', tags: ['basic'], description: 'Platziert ein Quadrat', }, optionsSchema: [{ key: 'size', label: 'Größe', type: 'number', min: 10, max: 200 }], handlers: { down(e, ctx) { const c = ctx as any; if (!c.doc) return; const size = (ctx.options.size as number | undefined) ?? 50; c.doc.transact(() => c.doc.addElement({ id: `stamp_${Date.now()}`, type: 'rect', layerId: 'layer-0', x: e.world.x, y: e.world.y, width: size, height: size, properties: {}, })); ctx.setStatus('Stempel platziert'); }, }, }; export const stampPlugin: PluginV2 = { manifest: { id: 'stamp', name: 'Stempel', version: '1.0.0', author: 'WebCAD', description: 'Beispielplugin', category: 'elements', enabledByDefault: true, }, tools: [stampTool], }; ``` Registrieren in `src/plugins/index.ts`: ```ts pluginRegistry.registerV2(stampPlugin); ```