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 🙏

© 2026 – Pkg Stats / Ryan Hefner

velvet-canvas

v1.0.1

Published

A powerful, customizable whiteboard library built with Svelte 5, Konva.js, and RoughJS. Create interactive drawing applications with hand-drawn aesthetics, connectors, and full state management. Now enhanced for production use with real-time collaboration

Readme

Velvet Canvas - Production-Ready Whiteboard SaaS

A powerful, customizable whiteboard library built with Svelte 5, Konva.js, and RoughJS. Create interactive drawing applications with hand-drawn aesthetics, connectors, and full state management. Now enhanced for production use with real-time collaboration, robust error handling, and enterprise features.

🚀 Key Production Features

Real-Time Collaboration

  • Multi-user support with Yjs and WebSockets
  • Supabase integration for scalable real-time sync
  • Cursor presence showing other users' positions
  • Conflict resolution for simultaneous edits
  • Optimistic UI updates for better user experience

Robust Architecture

  • Enhanced error handling throughout the application
  • Memory leak prevention with proper cleanup
  • Performance optimizations for large canvases
  • Debounced operations to prevent excessive updates
  • Throttled cursor updates to reduce bandwidth usage

Enterprise Features

  • Undo/Redo history with configurable depth
  • Version control for whiteboard states
  • Auto-save functionality with local persistence
  • Export/Import capabilities (JSON, PNG, PDF)
  • Customizable permissions for team collaboration

🎨 Features

  • Rich Drawing Tools: Rectangle, circle, freehand lines, straight lines, arrows, and text
  • Advanced Text Editing: Full-featured rich text editor with formatting options
  • 🔗 Connectors: Link elements together with dynamic connectors and anchor points
  • ✏️ RoughJS Integration: Hand-drawn, artistic appearance with customizable roughness
  • 🎯 Selection & Transformation: Select, move, rotate, and scale elements
  • 💾 State Management: Save, load, export, and import whiteboard state as JSON
  • 🎛️ Context-Based API: Clean, reactive API using Svelte 5 contexts
  • 🖱️ Pan & Zoom: Navigate large canvases with pan tool
  • ⌨️ Keyboard Shortcuts: Quick tool switching with keyboard shortcuts
  • 🔄 Reactive: Built on Svelte 5 runes for optimal performance
  • 🌐 Responsive Design: Works on all device sizes and orientations

Installation

npm install velvet-canvas

Quick Start

1. Set Up the Canvas Context

Wrap your application with the CanvasContext component:

<script>
    import { CanvasContext } from 'velvet-canvas';
</script>

<CanvasContext>
    <!-- Your canvas content here -->
</CanvasContext>

2. Add the Canvas Board

Include the CanvasBoard component to render the drawing surface:

<script>
    import { CanvasContext, CanvasBoard } from 'velvet-canvas';
</script>

<CanvasContext>
    <CanvasBoard />
</CanvasContext>

3. Create a Toolbox (Optional)

Build your own toolbox using the context APIs:

<script>
    import { getToolContext, getElementsContext, getStorageContext } from 'velvet-canvas';

    const toolAPI = getToolContext();
    const elementsAPI = getElementsContext();
    const storageAPI = getStorageContext();
</script>

<div class="toolbar">
    <button onclick={() => toolAPI.setTool('rectangle')}>
        Rectangle
    </button>
    <button onclick={() => toolAPI.setTool('circle')}>
        Circle
    </button>
    <button onclick={() => toolAPI.setTool('text')}>
        Text
    </button>
    <button onclick={() => storageAPI.exportJSON()}>
        Export
    </button>
</div>

4. Enable Real-Time Collaboration

Add collaboration support with Yjs:

<script>
    import { CanvasContext } from 'velvet-canvas';
    import { YjsManager } from 'velvet-canvas/collaboration'; // Hypothetical import
    
    // Create a collaboration provider
    const collaborationProvider = new YjsManager(
        'my-whiteboard-room',
        'wss://my-websocket-server.com'
    );
</script>

<CanvasContext 
    collaborationProvider={collaborationProvider}
    userIdentity={{
        name: 'John Doe',
        color: '#FF5733'
    }}
>
    <CanvasBoard />
</CanvasContext>

API Reference

ToolContext

Manages the active drawing tool and drawing options.

<script>
    import { getToolContext } from 'velvet-canvas';

    const toolAPI = getToolContext();
</script>

Properties

  • activeTool: ToolType - Current active tool (read-only)
  • roughOptions: RoughOptions - Current RoughJS options (read-only)

Methods

  • setTool(tool: ToolType): Switch to a different tool
  • setRoughOptions(options: RoughOptions): Update drawing style options

Available Tools

  • 'select' - Select and transform elements
  • 'connect' - Connect elements with lines
  • 'rectangle' - Draw rectangles
  • 'circle' - Draw circles
  • 'line' - Freehand drawing
  • 'straightLine' - Draw straight lines
  • 'arrow' - Draw arrows
  • 'text' - Add text elements
  • 'pan' - Pan around the canvas

Example

<script>
    import { getToolContext } from 'velvet-canvas';

    const toolAPI = getToolContext();

    // Switch tools
    toolAPI.setTool('rectangle');
    toolAPI.setTool('circle');

    // Update colors
    toolAPI.setRoughOptions({
        stroke: '#ff0000',
        fill: 'rgba(255, 0, 0, 0.1)'
    });
</script>

ElementsContext

Access and manage canvas elements.

<script>
    import { getElementsContext } from 'velvet-canvas';

    const elementsAPI = getElementsContext();
</script>

Properties

  • elements: SvelteMap<number, WhiteboardElement> - All elements on the canvas (read-only)
  • selectedIds: SvelteSet<number> - IDs of currently selected elements (read-only)

Methods

  • clearAll(): Remove all elements and connectors, reset counters
  • deleteSelected(): Delete all currently selected elements
  • updateSelectedColors(options: RoughOptions): Update colors of selected elements
  • onElementAdded(callback: (element: WhiteboardElement) => void): Subscribe to element additions
  • onElementsRemoved(callback: (removedIds: Set<number>) => void): Subscribe to element removals

Example

<script>
    import { getElementsContext } from 'velvet-canvas';

    const elementsAPI = getElementsContext();

    // Listen for element additions
    elementsAPI.onElementAdded((element) => {
        console.log('Element added:', element.id, element.type);
    });

    // Update selected elements
    elementsAPI.updateSelectedColors({
        stroke: 'blue',
        fill: 'lightblue'
    });

    // Delete selected
    elementsAPI.deleteSelected();
</script>

<!-- Display element count -->
<p>Elements on canvas: {elementsAPI.elements.size}</p>
<p>Selected: {elementsAPI.selectedIds.size}</p>

StorageContext

Manage save, load, export, and import operations.

<script>
    import { getStorageContext } from 'velvet-canvas';

    const storageAPI = getStorageContext();
</script>

Methods

  • save(): WhiteboardData - Get current whiteboard state as data object
  • load(data: WhiteboardData): boolean - Load whiteboard state from data object
  • clear() - Clear all elements (with confirmation)
  • exportJSON() - Download current state as JSON file
  • importJSON() - Prompt user to import JSON file

Example

<script>
    import { getStorageContext } from 'velvet-canvas';

    const storageAPI = getStorageContext();

    function handleSave() {
        const data = storageAPI.save();
        // Do something with the data (e.g., send to server)
        console.log('Saved:', data);
    }

    function handleExport() {
        storageAPI.exportJSON();
    }

    function handleImport() {
        storageAPI.importJSON();
    }
</script>

<button onclick={handleSave}>Save</button>
<button onclick={handleExport}>Export JSON</button>
<button onclick={handleImport}>Import JSON</button>

UndoRedoContext

Handle undo/redo operations.

<script>
    import { getUndoRedoContext } from 'velvet-canvas';

    const undoRedoAPI = getUndoRedoContext();
</script>

Properties

  • canUndo: boolean - Whether undo is possible
  • canRedo: boolean - Whether redo is possible

Methods

  • undo() - Undo the last action
  • redo() - Redo the last undone action

Types

ToolType

type ToolType =
    | "select"
    | "connect"
    | "rectangle"
    | "circle"
    | "line"
    | "straightLine"
    | "arrow"
    | "text"
    | "pan";

WhiteboardElement

interface WhiteboardElement {
    id: number;
    type: string;
    konvaNode: any; // Konva node instance
}

WhiteboardData

interface WhiteboardData {
    elements: ElementData[];
    connectors: ConnectorData[];
    elementIdCounter: number;
    connectorIdCounter: number;
    timestamp: number;
}

RoughOptions

interface RoughOptions {
    stroke?: string;
    fill?: string;
    strokeWidth?: number;
    roughness?: number;
    // ... other RoughJS options
}

Architecture

The library is built on a modular architecture:

  • CanvasManager: Manages Konva stage and layers
  • ShapeManager: Factory for creating different shape types
  • InteractionHandler: Handles mouse/touch interactions
  • ConnectorManager: Manages connections between elements
  • AnchorManager: Displays and manages connection anchors
  • StorageManager: Handles save/load operations with enhanced error handling
  • TextManager: Manages text editing with rich text support
  • WhiteboardStore: Central reactive store using Svelte 5 runes
  • CursorManager: Handles user cursor presence in collaborative mode

Customization

Styling the Canvas

You can customize the canvas container styles:

<CanvasContext canvasStyles={{ background: '#f0f0f0' }}>
    <CanvasBoard />
</CanvasContext>

Custom Shapes

The library uses RoughJS for hand-drawn aesthetics. You can customize the appearance via setRoughOptions:

toolAPI.setRoughOptions({
    stroke: '#333',
    strokeWidth: 2,
    fill: 'rgba(0,0,0,0.1)',
    roughness: 1.5,
    bowing: 0.5
});

Production Deployment

Environment Configuration

Set up your environment variables for production:

VITE_SUPABASE_URL=your_supabase_url
VITE_SUPABASE_ANON_KEY=your_supabase_anon_key

Server-Side Rendering

Velvet Canvas is compatible with SSR. Make sure to handle browser-specific APIs appropriately:

<script>
    import { onMount } from 'svelte';
    
    let isBrowser = false;
    
    onMount(() => {
        isBrowser = true;
        // Initialize canvas only in browser
    });
</script>

{#if isBrowser}
    <CanvasContext>
        <CanvasBoard />
    </CanvasContext>
{/if}

Performance Tips

  • Use debounced operations for frequent updates
  • Implement virtual scrolling for large canvases
  • Optimize image handling with lazy loading
  • Use proper cleanup to prevent memory leaks

Examples

Complete Example

<script>
    import {
        CanvasContext,
        CanvasBoard,
        getToolContext,
        getElementsContext,
        getStorageContext,
        getUndoRedoContext
    } from 'velvet-canvas';

    const toolAPI = getToolContext();
    const elementsAPI = getElementsContext();
    const storageAPI = getStorageContext();
    const undoRedoAPI = getUndoRedoContext();

    function handleColorChange(event) {
        toolAPI.setRoughOptions({ stroke: event.target.value });
    }
</script>

<CanvasContext>
    <div class="toolbar">
        <button onclick={() => toolAPI.setTool('select')}>Select</button>
        <button onclick={() => toolAPI.setTool('rectangle')}>Rectangle</button>
        <button onclick={() => toolAPI.setTool('circle')}>Circle</button>
        <button onclick={() => toolAPI.setTool('text')}>Text</button>

        <input
            type="color"
            onchange={handleColorChange}
            value={toolAPI.roughOptions.stroke || '#000000'}
        />

        <button onclick={() => storageAPI.exportJSON()}>Export</button>
        <button disabled={!undoRedoAPI.canUndo} onclick={() => undoRedoAPI.undo()}>Undo</button>
        <button disabled={!undoRedoAPI.canRedo} onclick={() => undoRedoAPI.redo()}>Redo</button>
    </div>

    <CanvasBoard />
</CanvasContext>

<style>
    .toolbar {
        position: absolute;
        top: 10px;
        left: 10px;
        z-index: 100;
        display: flex;
        gap: 8px;
        padding: 8px;
        background: white;
        border-radius: 8px;
        box-shadow: 0 2px 8px rgba(0,0,0,0.1);
        border: 1px solid #e5e7eb;
    }
</style>

🚀 Coming Soon

We're continually working to enhance Velvet Canvas. Here's a peek at what's next on our roadmap:

  • ✍️ Advanced Font and Text Styling APIs:
    • Dedicated APIs within ToolContext to easily manage text color, font family, font size, and styling options like bold and italic.
  • 🖼️ Image and Media Support:
    • The ability to easily import, place, and transform images on the canvas.
  • 📊 Chart and Diagram Components:
    • Pre-built components for common diagrams like flowcharts, mind maps, and UML diagrams.
  • 📱 Mobile Optimization:
    • Enhanced touch gesture support and mobile-first UI components.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

Development Setup

  1. Fork and clone the repository
  2. Install dependencies: npm install
  3. Start the development server: npm run dev
  4. Make your changes
  5. Run tests: npm run test
  6. Submit a pull request

Testing

Run the test suite:

npm run test

Run end-to-end tests:

npm run test:e2e

License

MIT

Support

Need help? Open an issue in our GitHub repository or join our community Discord.


Made with ❤️ for the whiteboard community