A reference guide for working with bpmn-js modeler internals in web applications.

Install

mkdir -p .claude/skills/bpmn-js && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/9618" && unzip -o skill.zip -d .claude/skills/bpmn-js && rm skill.zip

Installs to .claude/skills/bpmn-js

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

bpmn-js modeler internals — EventBus, services, copy-paste architecture, clipboard polyfill, modeler lifecycle. Use when working on bpmn-webview, diagram interactions, copy-paste, clipboard, or element templates.
212 chars✓ has a “when” trigger
Advanced

Key capabilities

  • Manage bpmn-js modeler lifecycle
  • Handle diagram event bus
  • Implement clipboard polyfills
  • Configure Camunda engine variants

How it works

It wraps the bpmn-js modeler and manages lifecycle events, clipboard interception, and engine-specific module loading.

Inputs & outputs

You give it
BPMN XML
You get back
Rendered diagram interactions

When to use bpmn-js

  • Customizing bpmn-js element templates
  • Debugging modeler lifecycle events
  • Implementing custom copy-paste behavior
  • Configuring Camunda engine variants

About this skill

bpmn-js Modeler Internals

This skill covers how the BPMN webview (apps/bpmn-webview/) uses the bpmn-js library to render and edit BPMN diagrams, including the copy-paste architecture and clipboard polyfill.

Modeler Initialization

The modeler is encapsulated in apps/bpmn-webview/src/app/modeler.ts as a BpmnModeler class. It wraps the underlying camunda-bpmn-js modeler (which extends bpmn-js).

Engine Variants

The modeler supports two Camunda engine variants, selected at initialization:

  • Camunda 7 — imports BpmnModeler7 from camunda-bpmn-js/lib/camunda-platform/Modeler. Additional modules: CreateAppendElementTemplatesModule, TransactionBoundariesModule.
  • Camunda 8 — imports BpmnModeler8 from camunda-bpmn-js/lib/camunda-cloud/Modeler. No extra modules beyond the common set.

Both variants share TokenSimulationModule and ElementTemplateChooserModule as common modules.

Lifecycle

  1. window.onload in main.ts registers the message listener, installs the select-all handler, and initialises the theme
  2. main.ts sends GetBpmnFileCommand to the extension host and awaits the BpmnFileQuery response
  3. initializeModeler() calls BpmnModeler.create(engine) to mount the modeler
  4. BpmnModeler.loadDiagram(xml) imports the BPMN XML
  5. Viewport is restored from vscode.getState() if available
  6. Event listeners are installed for commandStack.changed and canvas.viewbox.changed
  7. The clipboard interceptor and contenteditable polyfill are installed (production only — see below)
  8. Element templates and modeler settings are requested from the extension host

Modeler Options

The modeler is created with these configuration options (see MODELER_OPTIONS constant):

  • container: "#js-canvas" — DOM element for the diagram canvas
  • propertiesPanel.parent: "#js-properties-panel" — DOM element for the properties panel sidebar
  • alignToOrigin: { alignOnSave: false, offset: 150, tolerance: 50 } — configures the auto-align plugin
  • additionalModules: Engine-specific modules (see Engine Variants above)

Core bpmn-js Services

Services are accessed via modeler.get('serviceName'). Key services used:

ServicePurpose
eventBusPub/sub event system — all modeler events flow through this
copyPasteHandles element copy/cut/paste operations on the diagram
moddleBPMN model factory — used by the paste reviver to reconstruct typed objects
canvasDiagram canvas — viewport management, zoom, scroll
elementTemplatesLoaderLoads element templates from JSON into the modeler
alignToOriginAuto-aligns diagram to canvas origin (configurable)
transactionBoundariesShows/hides transaction boundary overlays (C7 only)

EventBus Events

Events This Project Listens To

EventWherePurpose
commandStack.changedmodeler.tsTriggered after any modeler command. Exports XML and sends SyncDocumentCommand to host.
canvas.viewbox.changedmodeler.tsTriggered on scroll/zoom. Debounced (100ms), saves viewport to vscode.setState() for persistence.
copyPaste.elementsCopiedmodeler.tsTriggered when elements are copied. Intercepted to write descriptor JSON to system clipboard via extension host.
copyPaste.pasteElementsmodeler.tsTriggered when paste occurs. Intercepted to read descriptor JSON from system clipboard via extension host.
elementTemplates.errorsmodeler.tsTriggered when element template loading produces errors. Forwarded to a callback for error reporting.

Event Priority System

bpmn-js events use a priority system. Higher priority listeners fire first and can prevent lower-priority listeners from executing by returning false or calling event.stopPropagation().

  • Default priority: 1000
  • The element-clipboard interceptor in VsCodeClipboardModule uses priority 2051 — intentionally above bpmn-js's NativeCopyPaste (priority 2050) to intercept copyPaste.elementsCopied / copyPaste.pasteElements before the default handler runs

Copy-Paste Architecture (Three Layers)

Copy-paste in this project operates at three distinct layers. The first two are bpmn-js DI modules extracted into the shared libs/bpmn-clipboard package (@miragon/bpmn-modeler-clipboard) and installed as additionalModules in apps/bpmn-webview/src/main.ts; the third is a webview-local polyfill. The two DI modules receive their host bridges through didi value injection — elementClipboardBridge (element JSON) and textClipboardBridge (plain text), each a { requestClipboard, writeClipboard } pair wired in main.ts to the host clipboard commands. Because bpmn-js's own NativeCopyPaste still handles the canvas natively in a plain browser, the interception only matters inside the sandboxed VS Code / IntelliJ webview, where the iframe has no clipboard access.

Two separate host round-trips: element clipboard uses GetClipboardCommand / SetClipboardCommandClipboardQuery; text clipboard (labels, FEEL editor) uses GetTextClipboardCommand / SetTextClipboardCommandTextClipboardQuery.

Layer 1: Diagram Elements (VsCodeClipboardModule)

Handles copying/pasting of BPMN shapes and connections on the canvas.

Flow — Copy:

  1. User presses Cmd/Ctrl+C while diagram elements are selected
  2. bpmn-js CopyPaste module serializes selected elements into a descriptor tree (plain JS objects)
  3. copyPaste.elementsCopied event fires
  4. Our priority-2051 listener intercepts → prefixes the JSON with "bpmn-js-clip----" and sends it to the extension host via SetClipboardCommand
  5. Extension host writes to system clipboard via vscode.env.clipboard.writeText()

Flow — Paste:

  1. User presses Cmd/Ctrl+V while canvas is focused
  2. copyPaste.pasteElements event fires
  3. If context.tree already exists (same-editor paste), the interceptor does nothing — bpmn-js handles it internally
  4. Otherwise, the interceptor snapshots the current context, returns false to cancel the default paste, and sends GetClipboardCommand to the extension host
  5. Extension host reads system clipboard → responds with clipboard text via ClipboardQuery
  6. Listener checks for the "bpmn-js-clip----" prefix, strips it, and parses the JSON using createReviver(moddle) from bpmn-js-native-copy-paste — this reviver reconstructs typed BPMN model objects from plain JSON
  7. Calls copyPaste.paste() with the deserialized tree and the snapshotted context

Why snapshot the context? The return false in step 4 sets defaultPrevented: true on the event context object. Without snapshotting first, the async paste callback would inherit this flag, causing copyPaste.paste() to silently abort.

Why the interceptor? The webview runs in an iframe without clipboard API access. The extension host mediates clipboard access via vscode.env.clipboard.

Layer 2: Direct-Editing Label Overlays (LabelClipboardModule)

Handles copying/pasting text within contenteditable label overlays on the diagram canvas (e.g., when double-clicking a task to edit its name). This targets diagram-js's direct-editing overlays, not properties panel inputs — standard INPUT and TEXTAREA elements work natively in VS Code webviews.

Problem: diagram-js's DirectEditing._handleKey calls stopPropagation() on every keydown from the contenteditable overlay. This prevents native clipboard handling from reaching the element. Additionally, VS Code webview iframes lack clipboard-read/clipboard-write permissions.

Solution: LabelClipboardModule is a bpmn-js DI module that attaches a capture-phase keydown listener on the label element, only while direct editing is active (scoped tighter than the old document-wide listener). Capture phase fires before bubble phase, so it runs before diagram-js can stop propagation.

Capture phase (our listener) → Target → Bubble phase (diagram-js listener)

For Cmd/Ctrl+C it reads window.getSelection() and writes via the injected textClipboardBridge.writeClipboard; for Cmd/Ctrl+V it prevents default, reads via textClipboardBridge.requestClipboard, then dispatches a synthetic ClipboardEvent("paste"), falling back to document.execCommand('insertText') if no handler consumes it.

Layer 3: FEEL Editor Polyfill + Select-All Guard (propertiesPanelClipboard.ts)

The C8 properties panel's FEEL expression editor is CodeMirror 6, which lives outside the bpmn-js DI context — so the two DI modules above can't reach it. installContentEditableClipboardPolyfill(requestTextClipboard, writeTextClipboard) (still webview-local in apps/bpmn-webview/src/app/propertiesPanelClipboard.ts, installed from main.ts) fills that gap: a capture-phase keydown listener that bridges Cmd/Ctrl+C/V on any contenteditable/text-editing surface through the host text clipboard.

It also guards Cmd/Ctrl+A: without it, bpmn-js's Keyboard service steals Ctrl+A in a text field and selects all diagram shapes. The polyfill lets Ctrl+A select text within the focused editable element (canvas Ctrl+A stays owned by bpmn-js's SelectionKeyBindings).

Element Templates

Element templates are JSON files that define custom property configurations for BPMN elements. They are loaded by:

  1. Extens

Content truncated.

When not to use it

  • When working outside of bpmn-webview
  • When not using bpmn-js library

Prerequisites

bpmn-jsCamunda engine

Limitations

  • Clipboard interception is production-only

How it compares

It provides deep internal access to modeler services and event bus priorities rather than just basic rendering.

Compared to similar skills

bpmn-js side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
bpmn-js (this skill)03moReviewAdvanced
add-announcement17moReviewBeginner
scroll-experience1016moNo flagsIntermediate
anthropic-frontend-design126moNo flagsIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

add-announcement

Agenta-AI

Helps add announcement cards to the sidebar banner system. Use when adding changelog entries, feature announcements, updates, or promotional banners to the Agenta sidebar. Handles both simple changelog entries and complex custom banners.

11

scroll-experience

davila7

Expert in building immersive scroll-driven experiences - parallax storytelling, scroll animations, interactive narratives, and cinematic web experiences. Like NY Times interactives, Apple product pages, and award-winning web experiences. Makes websites feel like experiences, not just pages. Use when: scroll animation, parallax, scroll storytelling, interactive story, cinematic website.

101142

anthropic-frontend-design

chaibuilder

Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.

1237

threejs-postprocessing

CloudAI-X

Three.js post-processing - EffectComposer, bloom, DOF, screen effects. Use when adding visual effects, color grading, blur, glow, or creating custom screen-space shaders.

17

snapdom

2025Emma

snapDOM is a fast, accurate DOM-to-image capture tool that converts HTML elements into scalable SVG images. Use for capturing HTML elements, converting DOM to images (SVG, PNG, JPG, WebP), preserving styles, fonts, and pseudo-elements.

14

keyboard-shortcuts

mae616

UIキーボードショートカットを「公式基準(W3C APG / WCAG)+プラットフォーム規約(Apple HIG / Fluent UI)+デファクトスタンダード(GitHub・Gmail・Slack等)」に沿って設計し、衝突なく・発見しやすく・無効化可能な形で実装するための判断軸。

00

Search skills

Search the agent skills registry