npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@flowscape-ui/core-sdk

v1.0.3

Published

Framework-agnostic 2D canvas engine built on Konva

Readme

🎨 @flowscape-ui/core-sdk

Powerful 2D canvas engine built on Konva.js

npm version License: MIT Bundle Size

Documentation Interactive Demo Changelog


📖 Documentation

What's New in 1.0.3

  • History System — Full undo/redo support (Ctrl+Z / Ctrl+Shift+Z)
  • 📏 Alignment Guides — Smart guides appear during movement and resizing
  • ✏️ Inline Text Editing — Double-click text nodes to edit directly
  • 🔧 Addons API — Attach custom functionality to any component
  • 📐 Canvas Auto-Resize — Automatically adjusts to window size changes
  • Performance — Optimized to handle 1000+ nodes smoothly
  • 🎨 New Layer Shortcuts — Ctrl+Shift+[ / ] for send to back/bring to front
  • 📦 Full TypeScript — Complete type coverage across all components
  • 🎮 Storybook Demo — Interactive playground to test all features

✨ Features

  • 🎯 Framework-agnostic — works with React, Vue, Svelte, Angular or vanilla JS
  • 🧩 Plugin system — extensible architecture with ready-to-use plugins
  • 📐 Complete toolset — grid, rulers, guides, area selection, alignment guides
  • ⌨️ Hotkeys — Ctrl+C/V/X, Delete, Ctrl+G for grouping, Ctrl+Z/Shift+Z for undo/redo
  • 🎨 Rich shapes — rectangles, circles, text, images, arrows, stars
  • 🔄 Transformations — rotation, scaling, movement with aspect ratio lock
  • ✏️ Inline editing — double-click text nodes to edit directly on canvas
  • 🕐 History system — full undo/redo support with Ctrl+Z
  • 📦 TypeScript-first — full typing out of the box
  • 🚀 High performance — handles 1000+ nodes without FPS drops
  • 🎨 Addons API — extend any component with custom functionality

📦 Installation

npm install @flowscape-ui/core-sdk
# or
yarn add @flowscape-ui/core-sdk
# or
bun add @flowscape-ui/core-sdk

🚀 Quick Start

import { CoreEngine, GridPlugin, SelectionPlugin, NodeHotkeysPlugin } from '@flowscape-ui/core-sdk';

// Create engine with plugins
const engine = new CoreEngine({
  container: document.getElementById('canvas-container')!,
  width: 1200,
  height: 800,
  plugins: [
    new GridPlugin({ enabled: true }),
    new SelectionPlugin({ dragEnabled: true }),
    new NodeHotkeysPlugin(), // Ctrl+C/V/X, Delete
  ],
});

// Add shapes
const rect = engine.nodes.addShape({
  x: 100,
  y: 100,
  width: 200,
  height: 150,
  fill: '#3b82f6',
  cornerRadius: 8,
});

const text = engine.nodes.addText({
  x: 120,
  y: 140,
  text: 'Hello Flowscape!',
  fontSize: 24,
  fill: 'white',
});

// Grouping
const group = engine.nodes.addGroup({
  x: 400,
  y: 200,
});
rect.getNode().moveTo(group.getNode());
text.getNode().moveTo(group.getNode());

🔒 Public API Policy

  • All supported entities are exported only through the root package @flowscape-ui/core-sdk.
  • The src/public-api.ts file contains the complete list of stable exports; anything outside this file is considered internal API and may change without notice.
  • Do not import files directly via @flowscape-ui/core-sdk/src/... — such imports are not supported and may break during updates.

🏗️ Architecture

Core Components

┌─────────────────────────────────────┐
│         CoreEngine                  │
│  ┌──────────────────────────────┐   │
│  │     Plugin System            │   │
│  │  - GridPlugin                │   │
│  │  - SelectionPlugin           │   │
│  │  - RulerPlugin               │   │
│  │  - NodeHotkeysPlugin         │   │
│  └──────────────────────────────┘   │
│  ┌──────────────────────────────┐   │
│  │     Node Manager             │   │
│  │  - ShapeNode                 │   │
│  │  - TextNode                  │   │
│  │  - ImageNode                 │   │
│  │  - GroupNode                 │   │
│  └──────────────────────────────┘   │
│  ┌──────────────────────────────┐   │
│  │     Camera Manager           │   │
│  │  - Zoom (Ctrl+Wheel)         │   │
│  └──────────────────────────────┘   │
└─────────────────────────────────────┘

Plugin System

Plugins extend engine functionality without modifying the core:

import { Plugin, CoreEngine } from '@flowscape-ui/core-sdk';

class CustomPlugin extends Plugin {
  protected onAttach(core: CoreEngine): void {
    // Initialize on attach
    core.eventBus.on('node:created', (node) => {
      console.log('Node created:', node);
    });
  }

  protected onDetach(core: CoreEngine): void {
    // Cleanup on detach
    core.eventBus.off('node:created');
  }
}

// Usage
const engine = new CoreEngine({
  container: element,
  plugins: [new CustomPlugin()],
});

| Plugin | Description | | ---------------------- | ------------------------------------------------ | | GridPlugin | Adaptive grid with automatic scaling | | SelectionPlugin | Selection, transformation, drag & drop, grouping | | NodeHotkeysPlugin | Copy/paste/cut nodes, delete, z-index management | | CameraHotkeysPlugin | Zoom and pan controls with keyboard | | RulerPlugin | Rulers with measurement units | | RulerGuidesPlugin | Draggable guide lines from rulers | | RulerHighlightPlugin | Ruler highlighting on hover | | RulerManagerPlugin | Toggle rulers and manage guides | | AreaSelectionPlugin | Area selection with frame (Shift+Drag) | | VisualGuidesPlugin | Smart alignment guides during movement/resize | | HistoryPlugin | Undo/redo functionality with Ctrl+Z | | LogoPlugin | Watermark/logo on canvas |

| Plugin | Description | | ------------------------ | ----------------------------------------------------- | | GridPlugin | Adaptive grid with automatic scaling and snap-to-grid | | SelectionPlugin | Selection, transformation, drag & drop, grouping | | AreaSelectionPlugin | Area selection with frame (Shift+Drag) | | NodeHotkeysPlugin | Copy/paste/cut nodes, delete, z-index management | | CameraHotkeysPlugin | Zoom and pan controls with keyboard | | RulerPlugin | Rulers with measurement units | | RulerGuidesPlugin | Draggable guide lines from rulers | | RulerHighlightPlugin | Ruler highlighting on hover | | RulerManagerPlugin | Toggle rulers and manage guides | | LogoPlugin | Watermark/logo on canvas |


⌨️ Keyboard Shortcuts

Node Operations (NodeHotkeysPlugin)

| Shortcut | Action | | ---------------------- | ---------------------------- | | Ctrl+C | Copy selected nodes | | Ctrl+X | Cut selected nodes | | Ctrl+V | Paste nodes | | Delete / Backspace | Delete selected nodes | | Ctrl+] | Move node forward (z-index) | | Ctrl+[ | Move node backward (z-index) | | Ctrl+Shift+] | Bring to front | | Ctrl+Shift+[ | Send to back |

Grouping (SelectionPlugin)

| Shortcut | Action | | ----------------------- | --------------------------------- | | Ctrl+G | Group selected nodes | | Ctrl+Shift+G | Ungroup selected group | | Shift+Click | Add/remove node to/from selection | | Shift (during resize) | Lock aspect ratio |

History (HistoryPlugin)

| Shortcut | Action | | -------------- | ------ | | Ctrl+Z | Undo | | Ctrl+Shift+Z | Redo |

Camera Controls (CameraHotkeysPlugin)

| Shortcut | Action | | ------------------- | ----------- | | Ctrl+Wheel | Zoom in/out | | + / = | Zoom in | | - | Zoom out | | Arrow Keys | Pan camera | | Middle Mouse+Drag | Pan camera | | Right Mouse+Drag | Pan camera |

Ruler Controls (RulerManagerPlugin)

| Shortcut | Action | | ---------------------- | ------------------------ | | Shift+R | Toggle rulers visibility | | Delete / Backspace | Delete active guide | | Drag from ruler | Create guide line |


📚 Usage Examples

Creating Shapes

// Rectangle with rounded corners
const rect = engine.nodes.addShape({
  x: 50,
  y: 50,
  width: 200,
  height: 100,
  fill: '#10b981',
  cornerRadius: 12,
});

// Circle
const circle = engine.nodes.addCircle({
  x: 300,
  y: 100,
  radius: 50,
  fill: '#f59e0b',
  stroke: '#d97706',
  strokeWidth: 3,
});

// Text
const text = engine.nodes.addText({
  x: 400,
  y: 50,
  text: 'Flowscape UI',
  fontSize: 32,
  fontFamily: 'Inter',
  fill: '#1f2937',
});

// Image
const image = engine.nodes.addImage({
  x: 100,
  y: 200,
  width: 200,
  height: 150,
  src: '/path/to/image.jpg',
});

Working with Events

// Subscribe to events
engine.eventBus.on('node:created', (node) => {
  console.log('Node created:', node);
});

engine.eventBus.on('node:selected', (node) => {
  console.log('Node selected:', node);
});

engine.eventBus.on('camera:zoom', ({ scale }) => {
  console.log('Zoom changed:', scale);
});

// Unsubscribe
const handler = (node) => console.log(node);
engine.eventBus.on('node:created', handler);
engine.eventBus.off('node:created', handler);

Grouping and Management

// Create group
const group = engine.nodes.addGroup({ x: 0, y: 0 });

// Add nodes to group
const rect1 = engine.nodes.addShape({ x: 10, y: 10, width: 50, height: 50 });
const rect2 = engine.nodes.addShape({ x: 70, y: 10, width: 50, height: 50 });

rect1.getNode().moveTo(group.getNode());
rect2.getNode().moveTo(group.getNode());

// Manage z-index
rect1.getNode().moveUp(); // Move up one level
rect2.getNode().moveDown(); // Move down one level
rect1.getNode().moveToTop(); // Move to top

Camera and Navigation

// Programmatic zoom
engine.camera.zoomIn(); // Zoom in
engine.camera.zoomOut(); // Zoom out
engine.camera.setZoom(1.5); // Set specific scale

// Panning
engine.camera.pan(100, 50); // Pan by dx, dy

// Center on node
const node = engine.nodes.addShape({ x: 500, y: 500, width: 100, height: 100 });
engine.camera.centerOn(node);

// Reset camera
engine.camera.reset();

🔧 Development

# Install dependencies
bun install

# Run playground
bun run dev

# Build library
bun run build

# Tests
bun run test          # Watch mode
bun run test:run      # Single run
bun run test:coverage # With coverage

# Linting
bun run lint          # ESLint
bun run lint:ts       # TypeScript check
bun run lint:fix      # Auto-fix

📄 License

MIT © Flowscape UI Team


Star on GitHub • 🐛 Report Bug • 💡 Request Feature