Skip to content

Canvas Engine Plugin and Marketplace Architecture

유용태 edited this page Jun 18, 2026 · 2 revisions

Canvas Engine Plugin and Marketplace Architecture

Date: 2026-06-18 Status: Working architecture record

Why This Exists

Canvas is not being built as one demo app and it is not only a Figma-like DOM editor. The target is a frontend canvas engine: a ProseMirror-like substrate that other FE products can embed, extend, and selectively assemble.

The key requirement is component-based composition. Reusable parts must be importable, visible, inspectable, and replaceable. When a component definition changes, all component instances must reflect that change through a stable document and component instance contract.

The second key requirement is installability. User-facing features should be packaged like plugins, extensions, marketplace add-ons, or feature packs. A host application must be able to install or uninstall a whole folder-level feature unit, enable or disable it at runtime when the feature supports it, and receive partial updates without rebuilding the whole canvas product.

Core alone does not have to be a product. Core should be stable and small. A starter pack, minimal pack, editor pack, inspector pack, or story canvas suite can turn the core into a usable product surface.

Executive Summary

Canvas should be separated into four decision levels:

Canvas Engine
|-- Immutable Foundations
|  |-- json-document
|  |-- nano-edit
|  `-- canvas-runtime-core
|-- Capability Protocols
|  |-- renderer contribution
|  |-- command contribution
|  |-- tool contribution
|  |-- item schema contribution
|  |-- inspector contribution
|  |-- importer/exporter contribution
|  |-- overlay contribution
|  `-- migration contribution
|-- Feature Packs
|  |-- install/uninstall unit
|  |-- enable/disable unit
|  |-- update/partial-update unit
|  `-- entitlement unit in a future marketplace
`-- Product Profiles
   |-- viewer
   |-- reviewer
   |-- inspector
   |-- editor
   |-- starter
   `-- custom host profiles

The core decision is:

Core = stable contracts and runtime lifecycle
Feature pack = user-visible capability with meaningful on/off semantics
Suite = cohesive group of packs installed together
Profile = default enabled combination for one product mode
Marketplace = distribution and entitlement layer over feature packs

Definitions

Immutable Foundation

An immutable foundation is code whose conceptual contract is expected to remain stable across products. It should not know a specific canvas product, whiteboard tool, editor UI, SaaS account model, or story viewer.

Current foundation candidates:

Immutable Foundations
|-- ../json-document
|  |-- JSON document model
|  |-- JSON Pointer / Patch boundary
|  |-- selection snapshot boundary
|  |-- history / patch planning substrate
|  `-- schema and migration substrate
|-- ../nano-edit
|  |-- contenteditable editing foundation
|  |-- text selection / IME boundary
|  |-- inline edit primitives
|  `-- browser text editing normalization
`-- canvas-runtime-core
   |-- feature lifecycle
   |-- extension registry
   |-- viewport model
   |-- selection model
   |-- coordinate system
   |-- command dispatch
   |-- renderer registry contract
   |-- hit-test registry contract
   `-- capability / affordance resolution

Important distinction:

  • json-document can be core because the document substrate is expected not to change per canvas feature.
  • nano-edit can be a text foundation, but text authoring is not automatically canvas core. Canvas should expose a text-pack that depends on nano-edit.
  • Shape authoring is not core. Shape item schema, creation, rendering, toolbar, and inspector belong in a basic-shapes-pack.
  • Story preview is not core. It belongs in a story canvas suite.
  • Shade, visual style, purple outlines, DOM edit affordances, and Story Canvas UI are not core. They are pack or suite behavior.

Capability Protocol

A capability protocol is an extension point that the core must keep stable. Feature packs contribute to these protocols.

Capability Protocols
|-- item schema
|  |-- kind
|  |-- version
|  |-- validator
|  |-- migration
|  `-- default factory
|-- renderer
|  |-- item renderer
|  |-- overlay renderer
|  |-- selection decoration
|  `-- portal / external surface renderer
|-- interaction
|  |-- tool
|  |-- gesture grammar
|  |-- hit-test contribution
|  `-- keyboard shortcut
|-- command
|  |-- command descriptor
|  |-- availability
|  |-- execution
|  `-- undo/redo patch plan
|-- inspector
|  |-- panel
|  |-- field contribution
|  `-- source navigation
|-- import/export
|  |-- story import
|  |-- image import
|  |-- text paste import
|  |-- board serialization
|  `-- external bridge import
`-- runtime
   |-- model hook
   |-- ephemeral state
   |-- persisted pack state
   |-- background task
   `-- telemetry hook

The core owns the protocol. Feature packs own contributions.

Feature Pack

A feature pack is the smallest unit that has meaningful user-facing cohesion and can be treated as an installable capability.

It may contain:

feature-pack/
|-- manifest
|-- commands
|-- tools
|-- renderers
|-- inspectors
|-- validators
|-- migrations
|-- runtime model
|-- view surfaces
|-- tests
`-- docs

A feature pack can be:

  • installed
  • uninstalled
  • enabled
  • disabled
  • updated
  • partially updated
  • rolled back
  • sold or gated later by entitlement

The current repo already has a first version of this idea:

  • src/canvas/app/feature-packs/CanvasAppFeaturePacks.ts
  • src/canvas/app/feature-packs/CanvasAppFeaturePackManifests.ts
  • src/canvas/app/feature-packs/CanvasAppFeaturePackRuntimeModel.ts
  • src/canvas/app/feature-packs/story-preview/CanvasStoryPreviewItems.ts

The current model filters installed packs with disabledFeaturePackIds. The next architecture step is to separate:

Feature Pack Runtime State
|-- available
|-- installed
|-- enabled
|-- disabled
|-- updating
|-- partially-updated
|-- activation-failed
|-- rollback-available
`-- uninstalled

Suite

A suite is a cohesive group of feature packs that usually ships together but still contains internal pack boundaries. It is similar to an extension bundle or marketplace product bundle.

Example:

story-canvas-suite
|-- story-catalog-pack
|-- story-preview-pack
|-- source-layer-inspection-pack
|-- measurement-pack
|-- story-curation-pack
`-- css-token-inspection-pack

A suite is installable as a product unit. Its inner packs still need their own on/off semantics when the host wants a smaller profile.

Profile

A profile is a named default composition. It does not define new capability. It only says which packs are installed and which are enabled by default.

Profiles
|-- core-only
|  `-- no complete product guarantee
|-- minimal-viewer
|  |-- viewport
|  |-- selection
|  `-- readonly item rendering
|-- story-viewer
|  |-- story-catalog-pack
|  |-- story-preview-pack
|  `-- zoom/navigation
|-- inspector
|  |-- story-viewer
|  |-- source-layer-inspection-pack
|  |-- measurement-pack
|  `-- css-token-inspection-pack
|-- editor
|  |-- basic-shapes-pack
|  |-- text-pack
|  |-- component-authoring-pack
|  |-- toolbar-pack
|  `-- inspector-pack
`-- host-custom
   `-- app-owned pack selection

Core Boundary

Core must contain only things that are stable across feature packs and products.

canvas-runtime-core
|-- document adapter boundary
|-- item identity and reference boundary
|-- viewport and camera state
|-- coordinate transform
|-- selection state
|-- hit-test orchestration
|-- command dispatch contract
|-- undo/redo patch planning contract
|-- renderer contribution registry
|-- tool contribution registry
|-- inspector contribution registry
|-- feature lifecycle state machine
|-- extension registry validation
|-- compatibility negotiation
`-- host bridge contracts

Core should not include:

Not Core
|-- shape item kinds
|-- sticky note authoring
|-- text authoring UI
|-- arrow routing UI
|-- comments
|-- stamp authoring
|-- command palette
|-- toolbar
|-- minimap
|-- Story Canvas cards
|-- Story Canvas purple outlines
|-- DOM style editing
|-- CSS inspection UI
|-- image import/export UI
|-- board import/export products
|-- AI automation labs
|-- collaboration transport
|-- account / billing / entitlement
`-- SaaS workspace policy

The reason is not that these features are unimportant. They are exactly the product value. That is why they need to be installable, replaceable, and marketplace-shaped instead of frozen into core.

Cohesion Rules for Feature Packs

Use the following rules to decide whether code belongs in the same pack.

Same pack when:

  • It serves one user purpose.
  • It has the same reason to change.
  • It shares runtime state.
  • It shares persisted state or migration lifecycle.
  • It must be tested and released together.
  • It has a single natural install/uninstall story.
  • Turning off one half would make the other half meaningless.

Split into separate packs when:

  • A host app can reasonably use one without the other.
  • One feature can be sold, installed, updated, or rolled back independently.
  • One feature is read-only and the other is authoring.
  • One feature is runtime-only and the other changes document schema.
  • One feature is heavy or optional from a performance perspective.
  • One feature depends on browser IO or external service policy.
  • One feature should be allowed in a restricted viewer profile but the other should not.

Use suite when:

  • Packs are commonly installed together.
  • The user understands them as one product area.
  • Internal packs still have meaningful on/off or update boundaries.

Feature Lifecycle

Feature packs need a lifecycle that is stronger than a boolean config flag.

Feature Lifecycle
|-- discover
|  `-- registry knows the pack exists
|-- install
|  |-- dependencies resolved
|  |-- assets fetched
|  |-- migrations registered
|  `-- compatibility checked
|-- enable
|  |-- contributions activated
|  |-- commands registered
|  |-- tools visible if allowed
|  |-- renderers active
|  `-- runtime model started
|-- disable
|  |-- UI surfaces hidden
|  |-- shortcuts removed
|  |-- commands unavailable
|  `-- persisted document data remains readable
|-- update
|  |-- full pack update
|  |-- migration planning
|  `-- compatibility validation
|-- partial-update
|  |-- renderer only
|  |-- inspector only
|  |-- command only
|  |-- migration only
|  `-- asset only
|-- rollback
|  |-- previous version restored
|  `-- migrations must be reversible or guarded
`-- uninstall
   |-- pack state removed
   |-- commands/tools/renderers removed
   |-- orphaned document data policy applied
   `-- dependencies released if unused

Disabling is not the same as uninstalling:

  • Disable keeps the pack installed and document data readable.
  • Uninstall removes the pack from the host installation and must define what happens to existing document data.

Partial update is not the same as hot reload:

  • Hot reload is a development mechanism.
  • Partial update is a production capability where one contribution surface can be updated while compatibility remains valid.

Manifest Shape

The current manifest is intentionally small. It should evolve toward a full feature-pack descriptor.

type CanvasFeaturePackManifest = Readonly<{
  id: string
  version: string
  displayName: string
  category:
    | 'foundation'
    | 'authoring'
    | 'inspection'
    | 'review'
    | 'import-export'
    | 'collaboration'
    | 'automation'
    | 'view'
    | 'suite'
  lifecycle: {
    installable: boolean
    runtimeToggleable: boolean
    uninstallable: boolean
    partialUpdate: readonly CanvasContributionSurface[]
    hotReloadable: boolean
  }
  contributes: {
    commands?: readonly CanvasCommandContribution[]
    tools?: readonly CanvasToolContribution[]
    itemSchemas?: readonly CanvasItemSchemaContribution[]
    itemRenderers?: readonly CanvasItemRendererContribution[]
    viewRenderers?: readonly CanvasViewRendererContribution[]
    inspectors?: readonly CanvasInspectorContribution[]
    importers?: readonly CanvasImporterContribution[]
    exporters?: readonly CanvasExporterContribution[]
    overlays?: readonly CanvasOverlayContribution[]
    migrations?: readonly CanvasMigrationContribution[]
    runtimeModels?: readonly CanvasRuntimeModelContribution[]
  }
  requires?: readonly string[]
  optionalRequires?: readonly string[]
  conflicts?: readonly string[]
  provides?: readonly string[]
  compatibility: {
    engineVersion: string
    documentSchemaVersion?: string
    featureStateVersion?: string
  }
}>

Contribution surface candidates:

CanvasContributionSurface
|-- command
|-- tool
|-- item-schema
|-- item-renderer
|-- view-renderer
|-- inspector
|-- importer
|-- exporter
|-- overlay
|-- migration
|-- runtime-model
|-- asset
`-- documentation

Marketplace and Entitlement

The engine is not a SaaS product yet, but the architecture should not block a marketplace model.

Marketplace should be layered on top of feature packs:

Marketplace Layer
|-- catalog metadata
|-- license / entitlement
|-- price / plan
|-- install source
|-- version channel
|-- trust / verification
|-- update policy
`-- support policy

Feature Pack Layer
|-- manifest
|-- contributions
|-- lifecycle
|-- compatibility
`-- migrations

Core should not know billing. Core should only know whether a pack is available for installation and whether its contributions can be activated. Entitlement is a host or marketplace decision that filters availability.

This allows:

  • free core
  • free starter packs
  • paid add-ons
  • private internal add-ons
  • enterprise-only packs
  • app-specific packs
  • lab or experimental packs

Story Canvas Lessons

The Story Canvas from ../../NAVERCORP/cstar-ui-2 is important because it shows that a canvas can be valuable without editing.

Relevant source:

  • ../../NAVERCORP/cstar-ui-2/react/src/devtools/storyCanvas/StoryCanvasPage.tsx
  • ../../NAVERCORP/cstar-ui-2/react/src/devtools/storyCanvas/StoryCanvasCard.tsx
  • ../../NAVERCORP/cstar-ui-2/react/src/devtools/storyCanvas/StoryCanvasInspector.tsx
  • ../../NAVERCORP/cstar-ui-2/react/src/devtools/storyCanvas/StoryLayersPanel.tsx
  • ../../NAVERCORP/cstar-ui-2/react/src/devtools/storyCanvas/StoryElementPanel.tsx
  • ../../NAVERCORP/cstar-ui-2/react/src/devtools/storyCanvas/StoryCssPanel.tsx
  • ../../NAVERCORP/cstar-ui-2/react/src/devtools/storyCanvas/storyCanvasModules.tsx
  • ../../NAVERCORP/cstar-ui-2/react/src/devtools/storyCanvas/storyCanvasModel.ts

The copied local version currently lives under:

  • src/devtools/storyCanvas/StoryCanvasPage.tsx
  • src/devtools/storyCanvas/storyCanvasModules.tsx
  • src/devtools/storyCanvas/storyCanvasSeedStories.tsx
  • src/canvas/app/feature-packs/story-preview/CanvasStoryPreviewItems.ts

Story Canvas has these reusable feature ideas:

Story Canvas Capability Map
|-- story catalog
|  |-- route grouping
|  |-- foundation grouping
|  |-- entity grouping
|  |-- story metadata
|  `-- search/filter
|-- story preview
|  |-- preview cards
|  |-- responsive frames
|  |-- lazy mounted stories
|  |-- huggable content measurement
|  `-- viewport fit
|-- source layer inspection
|  |-- annotated DOM selection
|  |-- element layer tree
|  |-- source reference
|  |-- instance target
|  `-- source navigation
|-- measurement
|  |-- selected element bounds
|  |-- clip geometry
|  |-- element size
|  |-- edge distance
|  `-- Alt-hover distance reading
|-- review and curation
|  |-- favorites
|  |-- review notes
|  |-- bridge snapshots
|  `-- favorites-only filtering
|-- CSS and token inspection
|  |-- computed CSS
|  |-- matched rules
|  |-- token inspection
|  `-- optional style edit bridge
`-- readonly canvas host
   |-- pan
   |-- zoom
   |-- focus camera
   |-- select preview
   `-- select DOM element

This is not just an example page. It is evidence for a family of non-editing canvas features:

Non-Editing Canvas Modes
|-- viewer
|  |-- pan
|  |-- zoom
|  |-- select
|  `-- inspect
|-- reviewer
|  |-- viewer
|  |-- notes
|  |-- favorites
|  `-- copy context
|-- explorer
|  |-- viewer
|  |-- layer tree
|  |-- source navigation
|  `-- route/folder grouping
`-- inspector
   |-- explorer
   |-- measurement
   |-- CSS rules
   `-- token inspection

Story Canvas should become a suite, not one giant feature:

story-canvas-suite
|-- story-catalog-pack
|  |-- story import
|  |-- route/folder grouping
|  |-- foundation/entities views
|  `-- story metadata model
|-- story-preview-pack
|  |-- preview card
|  |-- preview group
|  |-- responsive frame
|  |-- lazy mount
|  `-- content hug measurement hook
|-- source-layer-inspection-pack
|  |-- annotated DOM layer selection
|  |-- Figma-like click grammar
|  |-- layer tree
|  |-- source reference
|  `-- instance source navigation
|-- measurement-pack
|  |-- selected bounds
|  |-- clip geometry
|  |-- Alt-hover element distance
|  `-- frame-to-frame distance
|-- story-curation-pack
|  |-- favorites
|  |-- favorites-only filter
|  |-- review notes
|  `-- bridge snapshot persistence
`-- css-token-inspection-pack
   |-- computed CSS
   |-- matched rules
   |-- token inspection
   `-- optional editable CSS bridge

The purple selection line from Story Canvas is not decoration. It is a reusable inspection affordance. It belongs in source-layer-inspection-pack or a shared selection-decoration contribution, not in canvas core.

Component-Based Engine Requirement

The engine must support component-based authoring and viewing.

Component Feature Area
|-- component library
|  |-- reusable components
|  |-- widgets
|  |-- features
|  |-- shared components
|  `-- host-provided components
|-- component instance
|  |-- instance id
|  |-- component reference
|  |-- props / overrides
|  |-- variant
|  `-- source metadata
|-- propagation
|  |-- definition change affects instances
|  |-- local overrides remain explicit
|  |-- missing component fallback
|  `-- migration of instance props
|-- authoring
|  |-- component palette
|  |-- insert component
|  |-- detach / relink
|  |-- variant selection
|  `-- component inspector
`-- viewing
   |-- component preview
   |-- source component navigation
   |-- parts tree
   `-- readonly instance inspection

This should not be treated as one screen-specific feature. It is a foundation for multiple packs:

component-system-suite
|-- component-registry-pack
|  |-- component definitions
|  |-- component resolver
|  `-- component version metadata
|-- component-instance-pack
|  |-- instance schema
|  |-- props / overrides
|  |-- propagation
|  `-- migration
|-- component-authoring-pack
|  |-- palette
|  |-- insert
|  |-- detach / relink
|  `-- inspector
|-- component-parts-inspection-pack
|  |-- parts tree
|  |-- source link
|  `-- purple source outline
`-- component-import-pack
   |-- Story Canvas story import
   |-- host widgets import
   |-- features import
   `-- shared components import

Question to preserve: component propagation requires stable identity, component reference semantics, and override semantics. Without those, feature packs can render component-like things but cannot become a real component engine.

User Feature Map

This is a user-facing, marketplace-shaped feature map. Each node should be able to become an installable pack, suite, or profile unless marked as core.

Canvas Engine User Feature Map
|-- Core Runtime [core, required]
|  |-- document adapter boundary
|  |-- viewport / camera
|  |-- coordinate transform
|  |-- selection model
|  |-- command dispatch
|  |-- renderer registry
|  |-- feature registry
|  |-- lifecycle state machine
|  `-- compatibility validation
|-- Component System [suite]
|  |-- component registry [pack]
|  |-- component instances [pack]
|  |-- component authoring [pack]
|  |-- component parts inspection [pack]
|  `-- component import [pack]
|-- Basic Authoring [suite]
|  |-- basic shapes [pack]
|  |-- text authoring [pack, depends on nano-edit]
|  |-- sticky notes [pack]
|  |-- drawing tools [pack]
|  |-- connectors / arrows [pack]
|  `-- object toolbar [pack]
|-- Story Canvas [suite]
|  |-- story catalog [pack]
|  |-- story preview [pack]
|  |-- source layer inspection [pack]
|  |-- measurement [pack]
|  |-- review / curation [pack]
|  `-- CSS/token inspection [pack]
|-- DOM Edit [suite]
|  |-- DOM selection [pack]
|  |-- DOM style editing [pack]
|  |-- DOM component mapping [pack]
|  |-- responsive preview [pack]
|  `-- source sync bridge [pack]
|-- Import / Export [suite]
|  |-- image import/export [pack]
|  |-- text paste import [pack]
|  |-- table import [pack]
|  |-- media link import [pack]
|  |-- board serialization [pack]
|  `-- story import [pack]
|-- Inspection [suite]
|  |-- layers panel [pack]
|  |-- object inspector [pack]
|  |-- measurement overlay [pack]
|  |-- CSS/token inspector [pack]
|  `-- source navigation [pack]
|-- Navigation [suite]
|  |-- zoom controls [pack]
|  |-- minimap [pack]
|  |-- focus camera [pack]
|  `-- search / find replace [pack]
|-- Facilitation [suite]
|  |-- timer [pack]
|  |-- voting [pack]
|  |-- spotlight [pack]
|  |-- emotes [pack]
|  `-- cursor chat [pack]
|-- Collaboration [suite, outside core]
|  |-- presence [pack]
|  |-- comments [pack]
|  |-- review workflow [pack]
|  |-- conflict / merge policy [pack]
|  `-- transport adapter [host-owned]
|-- Automation [suite]
|  |-- command palette [pack]
|  |-- AI labs [pack]
|  |-- macros [pack]
|  `-- scripted transforms [pack]
`-- Host Product Shell [host-owned]
   |-- routing
   |-- account / billing
   |-- workspace policy
   |-- persistence backend
   |-- entitlement filter
   `-- product navigation

Required vs Optional

Required Core
|-- document boundary
|-- item identity boundary
|-- viewport / coordinate transform
|-- selection model
|-- command dispatch
|-- renderer registry
|-- feature registry
|-- lifecycle state machine
`-- compatibility checks

Optional Packs
|-- basic shapes
|-- text authoring
|-- sticky notes
|-- arrows
|-- drawing
|-- component authoring
|-- story preview
|-- DOM edit
|-- measurement
|-- CSS inspection
|-- minimap
|-- toolbar
|-- command palette
|-- facilitation
|-- collaboration
`-- AI labs

Some optional packs are required by a profile:

Profile Required Packs
|-- story-viewer-profile
|  |-- story-catalog-pack
|  `-- story-preview-pack
|-- story-inspector-profile
|  |-- story-viewer-profile
|  |-- source-layer-inspection-pack
|  `-- measurement-pack
|-- editor-profile
|  |-- basic-shapes-pack
|  |-- text-pack
|  |-- toolbar-pack
|  `-- object-inspector-pack
`-- component-editor-profile
   |-- editor-profile
   |-- component-registry-pack
   |-- component-instance-pack
   `-- component-authoring-pack

Refactoring Direction

The current repo should evolve in tracer bullets rather than a single broad move.

Refactoring Roadmap
|-- 1. Manifest Strengthening
|  |-- add category
|  |-- add requires / optionalRequires / conflicts / provides
|  |-- add lifecycle flags
|  |-- add contribution surface list
|  `-- add compatibility metadata
|-- 2. Runtime State Split
|  |-- available packs
|  |-- installed packs
|  |-- enabled packs
|  |-- disabled packs
|  |-- failed activation
|  `-- pending updates
|-- 3. Profile Assembly
|  |-- core-only
|  |-- minimal-viewer
|  |-- story-viewer
|  |-- inspector
|  |-- editor
|  `-- component-editor
|-- 4. Story Canvas Suite
|  |-- story-catalog-pack
|  |-- story-preview-pack
|  |-- source-layer-inspection-pack
|  |-- measurement-pack
|  |-- story-curation-pack
|  `-- css-token-inspection-pack
|-- 5. Component System Suite
|  |-- component-registry-pack
|  |-- component-instance-pack
|  |-- component-authoring-pack
|  |-- component-parts-inspection-pack
|  `-- component-import-pack
|-- 6. Core Guardrails
|  |-- no shape/text/story imports in core
|  |-- no host product policy in core
|  |-- no billing or entitlement in core
|  `-- no browser IO in core
`-- 7. Marketplace Readiness
   |-- signed pack metadata later
   |-- entitlement filter later
   |-- version channel later
   `-- partial update policy later

Implementation Acceptance Criteria

A feature is correctly modeled as a feature pack when:

  • It has a manifest with stable id and version.
  • It declares required and optional dependencies.
  • It declares contribution surfaces.
  • It can be excluded from a profile without type holes.
  • It can be disabled without corrupting existing document data.
  • Its persisted data has a readable fallback when the pack is disabled.
  • Its renderer, commands, tools, inspectors, and migrations register through explicit contribution points.
  • Tests cover enabled and disabled states.
  • Tests cover duplicate ids and missing dependency failures.
  • The host can assemble a profile without importing internal implementation subpaths.

A feature should be moved out of core when:

  • It has a visible user workflow.
  • It can be priced, shipped, or updated independently.
  • It has a concrete UI surface.
  • It owns a specific item kind.
  • It depends on browser IO or external service policy.
  • It is useful in some profiles but not others.

A feature may remain core only when:

  • Every canvas product needs it.
  • It is a protocol rather than a product capability.
  • It has no meaningful runtime off state.
  • It has no product-specific UI.
  • Its contract is expected to be stable across packs.

Open Questions

  • What is the exact component instance override model?
  • Which part of component propagation belongs in json-document and which part belongs in a component feature pack?
  • Should Story Canvas import stories from route modules, file manifests, or a host-provided story registry protocol?
  • Which packs must be safe to disable at runtime without remounting the canvas?
  • Which packs can support production partial update?
  • Should marketplace pack loading be local-only first, then remote later?
  • How should orphaned document data be shown when a required renderer pack is disabled or uninstalled?
  • Which extension APIs must be stable before third-party pack authors can use them?

Immediate Next Issues

Issue Candidates
|-- Define full CanvasFeaturePackManifest contract
|-- Split installed/enabled/available feature pack runtime state
|-- Add profile assembly for core-only, viewer, inspector, editor
|-- Promote Story Canvas into story-canvas-suite packs
|-- Extract source-layer-inspection-pack from Story Canvas
|-- Extract measurement-pack from Story Canvas
|-- Define component registry and component instance contracts
|-- Add component propagation tests
|-- Add core guardrail tests that prevent feature imports into core
`-- Document marketplace entitlement as host layer, not core layer

Current Local Anchors

Use these files as anchors when implementing:

  • docs/adr/0001-canvas-reusable-module-seams.md
  • docs/adr/0003-canvas-foundation-extension-architecture.md
  • src/canvas/app/feature-packs/CanvasAppFeaturePacks.ts
  • src/canvas/app/feature-packs/CanvasAppFeaturePackManifests.ts
  • src/canvas/app/feature-packs/CanvasAppFeaturePackRuntimeModel.ts
  • src/canvas/app/feature-packs/story-preview/CanvasStoryPreviewItems.ts
  • src/devtools/storyCanvas/StoryCanvasPage.tsx
  • src/devtools/storyCanvas/storyCanvasModules.tsx

Decision Summary

Canvas should be built as an installable feature-pack engine. Core should be stable and small. Story Canvas proves that readonly canvas products are valid, so editing must be optional. Component-based behavior, especially shared component definitions propagating to instances, is a first-class engine goal. Marketplace, paid add-ons, and entitlement should be possible later because the feature-pack lifecycle is explicit now, but billing must not leak into core.

Clone this wiki locally