Files
web-cad/docs/PLUGIN_GUIDE.md
T

4.4 KiB
Raw Permalink Blame History

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)

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:

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)

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

// 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:

pluginRegistry.registerV2(stampPlugin);