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

@softwarity/geojson-editor

v1.0.29

Published

A feature-rich GeoJSON editor Web Component with syntax highlighting, collapsible nodes, and color picker

Readme

@softwarity/geojson-editor

A feature-rich, framework-agnostic Web Component for editing GeoJSON features with syntax highlighting, collapsible nodes, and integrated color picker.

🚀 Try the Live Demo | 📋 Release Notes

Why not Monaco, CodeMirror, or Prism?

| | @softwarity/geojson-editor | Monaco Editor | CodeMirror 6 | Prism.js | |---|:---:|:---:|:---:|:---:| | Size (gzip) | | ~2.5 MB* | ~150 KB* | ~20 KB* | | Editable | ✅ Full editor | ✅ Full editor | ✅ Full editor | ❌ Read-only | | GeoJSON validation | ✅ Built-in | ❌ Manual | ❌ Manual | ❌ None | | Type highlighting | ✅ Contextual | ⚠️ Generic JSON | ⚠️ Generic JSON | ⚠️ Generic JSON | | Invalid type detection | ✅ Visual feedback | ❌ | ❌ | ❌ | | Collapsible nodes | ✅ Native | ✅ | ✅ Plugin | ❌ | | Undo/Redo | ✅ With grouping | ✅ | ✅ | ❌ | | Color picker | ✅ Integrated | ❌ | ❌ | ❌ | | Boolean checkbox | ✅ Integrated | ❌ | ❌ | ❌ | | Feature visibility toggle | ✅ | ❌ | ❌ | ❌ | | Auto-collapse coordinates | ✅ | ❌ | ❌ | ❌ | | FeatureCollection output | ✅ Always | ❌ | ❌ | ❌ | | Clear button | ✅ | ❌ | ❌ | ❌ | | Save to file (Ctrl+S) | ✅ | ❌ | ❌ | ❌ | | Open from file (Ctrl+O) | ✅ | ❌ | ❌ | ❌ | | Error navigation | ✅ | ✅ | ✅ | ❌ | | Dark mode detection | ✅ Auto | ⚠️ Manual | ⚠️ Manual | ⚠️ Manual | | Dependencies | 0 | Many | Few | 0 | | Setup complexity | 1 line | Complex | Moderate | Simple |

* Estimated total size: Monaco includes web workers loaded dynamically; CodeMirror/Prism require plugins for equivalent functionality (line numbers, folding, language support).

TL;DR: If you're building a GeoJSON-focused application and need a lightweight, specialized editor with built-in validation and GeoJSON-aware features, this component does exactly that — without the overhead of a general-purpose code editor.

Features

  • Full Editor - Complete editing capabilities with cursor navigation, selection, copy/paste, and keyboard shortcuts — unlike read-only syntax highlighters
  • GeoJSON-Aware Highlighting - Distinct colors for GeoJSON keywords (type, coordinates, geometry, etc.)
  • GeoJSON Type Validation - Valid types (Point, LineString, Polygon, etc.) highlighted distinctly; invalid types (LinearRing, unknown types) shown with error styling (colors configurable via theme)
  • Syntax Highlighting - JSON syntax highlighting with customizable color schemes
  • Collapsible Nodes - Collapse/expand JSON objects and arrays with visual indicators ({...} / [...]); use Enter to expand and Shift+Enter to collapse; coordinates auto-collapsed on load
  • Attribute Navigation - Tab/Shift+Tab to navigate between JSON attributes (keys and values) for quick editing
  • Virtualized Rendering - Monaco-like architecture: only visible lines are rendered to DOM for optimal performance with large GeoJSON files
  • Feature Visibility Toggle - Hide/show individual Features via eye icon in gutter; hidden features are grayed out and excluded from change events (useful for temporary filtering without deleting data)
  • Color Picker - Built-in color swatch for hex color properties (#rrggbb) displayed inline next to the value; click to open native color picker
  • Boolean Checkbox - Inline checkbox for boolean properties displayed next to the value; toggle to switch between true/false and emit changes (e.g., marker: true to show vertices)
  • Dark/Light Color Schemes - Automatic color scheme based on system preference via CSS light-dark() function
  • Auto-format - Automatic JSON formatting in real-time (always enabled)
  • Readonly Mode - Visual indicator with diagonal stripes when editing is disabled
  • Block Editing in Collapsed Areas - Prevents accidental edits in collapsed sections
  • Smart Copy/Paste - Copy includes expanded content even from collapsed nodes
  • FeatureCollection Output - Emits valid FeatureCollection with all edited features
  • Clear Button - Discreet ✕ button in suffix area to clear all editor content (hidden in readonly mode)
  • Undo/Redo - Full undo/redo support with Ctrl+Z / Ctrl+Y / Ctrl+Shift+Z; rapid keystrokes grouped as single undo step
  • Save to File - Ctrl+S to download GeoJSON as .geojson file; programmatic save(filename) method available
  • Open from File - Ctrl+O to open a .geojson or .json file from the client filesystem; programmatic open() method available
  • Error Navigation - Visual error indicators in gutter with navigation buttons (◀ ▶) to jump between errors; error count displayed in suffix area
  • Current Features Event - current-features event emitted as a FeatureCollection when cursor/selection changes; includes all features overlapping with selection; useful for synchronizing with maps

Installation

Option 1: CDN (No build step required)

Simply add a script tag to your HTML file:

<!-- Using unpkg -->
<script type="module" src="https://unpkg.com/@softwarity/geojson-editor"></script>

<!-- Or using jsDelivr -->
<script type="module" src="https://cdn.jsdelivr.net/npm/@softwarity/geojson-editor"></script>

You can also specify a version:

<!-- Specific version -->
<script type="module" src="https://unpkg.com/@softwarity/[email protected]"></script>

<!-- Latest minor/patch of v1 -->
<script type="module" src="https://unpkg.com/@softwarity/geojson-editor@1"></script>

Option 2: NPM (With bundler)

If you're using a bundler (Vite, Webpack, Rollup, etc.):

npm install @softwarity/geojson-editor

Then import in your JavaScript/TypeScript:

import '@softwarity/geojson-editor';

TypeScript Support

This package includes TypeScript type definitions out of the box. No additional @types/* package required.

import '@softwarity/geojson-editor';
import type { SetOptions, CursorPosition, GeometryType } from '@softwarity/geojson-editor';

// Type-safe editor access
const editor = document.querySelector('geojson-editor') as GeoJsonEditor;

// Full autocompletion and type checking
editor.set(features, { collapsed: ['coordinates'] });

Exported types:

  • GeoJsonEditor - The Web Component class
  • SetOptions - Options for set(), add(), insertAt(), open()
  • CursorPosition - Cursor position { line, column }
  • GeometryType - GeoJSON geometry types union

Usage

Basic Usage

<!DOCTYPE html>
<html lang="en">
<head>
  <script type="module" src="https://unpkg.com/@softwarity/geojson-editor"></script>
</head>
<body>
  <!-- User edits features, component wraps in FeatureCollection -->
  <geojson-editor placeholder="Enter GeoJSON features here..."></geojson-editor>
</body>
</html>

Users edit features directly (comma-separated), and the component automatically wraps them in a {"type": "FeatureCollection", "features": [...]} structure for validation and events.

With Theme Control

The component automatically adapts to system color scheme. Override with CSS:

<!-- Force dark mode -->
<geojson-editor style="color-scheme: dark;"></geojson-editor>

<!-- Force light mode -->
<geojson-editor style="color-scheme: light;"></geojson-editor>

Listen to Changes

const editor = document.querySelector('geojson-editor');

// Valid GeoJSON emits change event with parsed object directly
editor.addEventListener('change', (e) => {
  console.log('GeoJSON:', e.detail); // Parsed GeoJSON object
});

// Invalid JSON or GeoJSON validation error emits error event
editor.addEventListener('error', (e) => {
  console.error('Error:', e.detail.error);
  console.log('Errors:', e.detail.errors); // Array of validation errors (if GeoJSON validation)
});

Attributes

| Attribute | Type | Default | Description | |-----------|------|---------|-------------| | value | string | "" | Initial editor content (features array content) | | placeholder | string | "" | Placeholder text | | readonly | boolean | false | Make editor read-only |

Note: coordinates nodes are automatically collapsed when content is loaded to improve readability. Use Enter to expand and Shift+Enter to collapse nodes, or click the gutter toggle. Use Tab/Shift+Tab to navigate between attributes.

Themes

The component uses CSS light-dark() function for automatic dark/light mode switching based on the system's color-scheme preference.

Pre-built Themes

Ready-to-use theme CSS files are available:

| Theme | Description | CDN Link | |-------|-------------|----------| | Default (IntelliJ) | Built-in, no extra CSS needed | - | | VS Code | Visual Studio Code inspired colors | vscode.css | | GitHub | GitHub's code styling | github.css | | Monokai | Classic dark Monokai palette | monokai.css | | Solarized | Ethan Schoonover's precision colors | solarized.css |

Using via CDN:

<!-- Include theme CSS before the component -->
<link rel="stylesheet" href="https://unpkg.com/@softwarity/geojson-editor/themes/monokai.css">

<!-- Then use the component -->
<script type="module" src="https://unpkg.com/@softwarity/geojson-editor"></script>

Using via npm:

// Import theme CSS in your build
import '@softwarity/geojson-editor/themes/github.css';
import '@softwarity/geojson-editor';

Custom Themes

Create your own theme by overriding CSS custom properties on :root with the light-dark() function:

:root {
  /* Editor background and text */
  --geojson-editor-bg-color: light-dark(#ffffff, #1e1e1e);
  --geojson-editor-text-color: light-dark(#000000, #d4d4d4);
  --geojson-editor-caret-color: light-dark(#000000, #aeafad);

  /* Gutter (line numbers area) */
  --geojson-editor-gutter-bg: light-dark(#f3f3f3, #1e1e1e);
  --geojson-editor-gutter-border: light-dark(#e0e0e0, #333333);
  --geojson-editor-gutter-text: light-dark(#237893, #858585);

  /* JSON syntax highlighting */
  --geojson-editor-json-key: light-dark(#0451a5, #9cdcfe);
  --geojson-editor-json-string: light-dark(#a31515, #ce9178);
  --geojson-editor-json-number: light-dark(#098658, #b5cea8);
  --geojson-editor-json-boolean: light-dark(#0000ff, #569cd6);
  --geojson-editor-json-punct: light-dark(#000000, #d4d4d4);
  --geojson-editor-json-error: light-dark(#cd3131, #f44747);

  /* GeoJSON-specific */
  --geojson-editor-geojson-key: light-dark(#800000, #9cdcfe);
  --geojson-editor-geojson-type: light-dark(#008000, #4ec9b0);
  --geojson-editor-geojson-type-invalid: light-dark(#cd3131, #f44747);

  /* Controls (checkboxes, color swatches) */
  --geojson-editor-control-color: light-dark(#0000ff, #569cd6);
  --geojson-editor-control-bg: light-dark(#f3f3f3, #3c3c3c);
  --geojson-editor-control-border: light-dark(#c0c0c0, #6b6b6b);

  /* Selection and errors */
  --geojson-editor-selection-color: light-dark(rgba(173, 214, 255, 0.5), rgba(38, 79, 120, 0.5));
  --geojson-editor-error-color: light-dark(#cd3131, #f44747);
}

Forcing Light or Dark Mode

/* Force dark mode on specific editor */
geojson-editor.dark-editor {
  color-scheme: dark;
}

/* Force light mode */
geojson-editor.light-editor {
  color-scheme: light;
}

Integration with CSS Frameworks

The editor inherits color-scheme from parent elements. To integrate with frameworks that use class-based dark mode:

Tailwind CSS (uses html.dark):

html.dark { color-scheme: dark; }
html:not(.dark) { color-scheme: light; }

Bootstrap 5 (uses [data-bs-theme]):

[data-bs-theme="dark"] { color-scheme: dark; }
[data-bs-theme="light"] { color-scheme: light; }

DaisyUI / Other (any class-based theme):

.dark-theme { color-scheme: dark; }
.light-theme { color-scheme: light; }

CSS Custom Properties Reference

| Variable | Description | |----------|-------------| | --geojson-editor-bg-color | Editor background | | --geojson-editor-text-color | Default text color | | --geojson-editor-caret-color | Cursor color | | --geojson-editor-gutter-bg | Line numbers background | | --geojson-editor-gutter-border | Gutter border color | | --geojson-editor-gutter-text | Line numbers color | | --geojson-editor-json-key | JSON property keys | | --geojson-editor-json-string | String values | | --geojson-editor-json-number | Number values | | --geojson-editor-json-boolean | Boolean/null values | | --geojson-editor-json-punct | Punctuation (brackets, colons) | | --geojson-editor-json-error | Invalid JSON highlighting | | --geojson-editor-geojson-key | GeoJSON keywords (type, geometry, etc.) | | --geojson-editor-geojson-type | Valid geometry types (Point, Polygon, etc.) | | --geojson-editor-geojson-type-invalid | Invalid geometry types | | --geojson-editor-control-color | Inline controls accent color | | --geojson-editor-control-bg | Inline controls background | | --geojson-editor-control-border | Inline controls border | | --geojson-editor-selection-color | Text selection background | | --geojson-editor-error-color | Error indicators |

API Methods

const editor = document.querySelector('geojson-editor');

Features API

Programmatic manipulation of features:

| Method | Description | |--------|-------------| | set(input, options?) | Replace all features (throws if invalid) | | add(input, options?) | Add features at the end (throws if invalid) | | insertAt(input, index, options?) | Insert at index (negative = from end: -1 = before last) (throws if invalid) | | removeAt(index) | Remove feature at index (negative = from end), returns removed feature | | removeAll() | Remove all features, returns array of removed features | | get(index) | Get feature at index (negative = from end) | | getAll() | Get all features as an array | | emit() | Emit the current document on the change event |

Flexible Input: set(), add(), and insertAt() accept multiple input formats:

  • FeatureCollection → extracts the features array
  • Feature[] → uses the array directly
  • Feature → wraps in an array

Options Parameter: set(), add(), insertAt(), and open() accept an optional options object:

| Option | Type | Default | Description | |--------|------|---------|-------------| | collapsed | string[] | function | ['coordinates'] | Attributes to collapse after loading |

The collapsed option controls which JSON nodes are automatically collapsed:

  • string[]: Static list of attribute names to collapse (e.g., ['coordinates', 'properties'])
  • function(feature, index) => string[]: Dynamic function returning attributes per feature
  • '$root': Special keyword to collapse entire features
  • Empty array []: Disables auto-collapse (nothing collapsed)
// Default: only coordinates collapsed
editor.set(features);

// Collapse coordinates and properties
editor.set(features, { collapsed: ['coordinates', 'properties'] });

// Collapse entire features
editor.set(features, { collapsed: ['$root'] });

// No auto-collapse
editor.set(features, { collapsed: [] });

// Dynamic: collapse geometry only for Points
editor.set(features, {
  collapsed: (feature, index) => {
    if (feature.geometry?.type === 'Point') {
      return ['geometry'];
    }
    return ['coordinates'];
  }
});

Validation: All input features are validated before adding. Invalid features throw an Error with a descriptive message. A valid Feature must have:

  • type: "Feature"
  • geometry: object with valid type (Point, LineString, Polygon, etc.) and coordinates, or null
  • properties: object or null

Smart Paste: When pasting GeoJSON content (Ctrl+V), the editor automatically detects and normalizes the format (FeatureCollection, Feature[], or single Feature). Invalid GeoJSON falls back to raw text insertion.

// Set features from array
editor.set([
  { type: 'Feature', geometry: { type: 'Point', coordinates: [0, 0] }, properties: {} },
  { type: 'Feature', geometry: { type: 'Point', coordinates: [1, 1] }, properties: {} }
]);

// Set from FeatureCollection
editor.set({
  type: 'FeatureCollection',
  features: [{ type: 'Feature', geometry: { type: 'Point', coordinates: [0, 0] }, properties: {} }]
});

// Set a single feature
editor.set({ type: 'Feature', geometry: { type: 'Point', coordinates: [2, 2] }, properties: {} });

// Add multiple features at once
editor.add([feature1, feature2]);

// Insert FeatureCollection at position 1
editor.insertAt(featureCollection, 1);

// Remove last feature
const removed = editor.removeAt(-1);

// Get all features
const features = editor.getAll();

// Manually emit change event
editor.emit();

Undo/Redo API

Full undo/redo support with action grouping:

| Method | Description | |--------|-------------| | undo() | Undo last action, returns true if successful | | redo() | Redo previously undone action, returns true if successful | | canUndo() | Check if undo is available | | canRedo() | Check if redo is available | | clearHistory() | Clear undo/redo history |

Keyboard shortcuts:

  • Ctrl+Z / Cmd+Z - Undo
  • Ctrl+Y / Cmd+Y - Redo
  • Ctrl+Shift+Z / Cmd+Shift+Z - Redo (alternative)

Action grouping: Rapid keystrokes (< 500ms apart, same action type) are automatically grouped as a single undo step. This means typing "hello" quickly creates one undo entry, not five.

// Programmatic undo/redo
if (editor.canUndo()) {
  editor.undo();
}

// Clear history after saving
editor.clearHistory();

Save API

Save the current GeoJSON content to a file:

| Method | Description | |--------|-------------| | save(filename?) | Download GeoJSON as file, returns true if successful |

Keyboard shortcut:

  • Ctrl+S / Cmd+S - Save with default filename (features.geojson)
// Save with default filename
editor.save();  // Downloads "features.geojson"

// Save with custom filename
editor.save('my-map-data.geojson');

Open API

Open a GeoJSON file from the client filesystem:

| Method | Description | |--------|-------------| | open(options?) | Open file dialog, returns Promise<boolean> (true if loaded successfully) |

Keyboard shortcut:

  • Ctrl+O / Cmd+O - Open file dialog

Supported formats:

  • FeatureCollection (extracts features array)
  • Single Feature (wraps in array)
  • Array of Features

Note: The Ctrl+O shortcut is disabled in readonly mode, but open() remains available via API for programmatic loading.

// Open file dialog
const success = await editor.open();
if (success) {
  console.log('File loaded:', editor.getAll());
}

// Open with custom collapse options
const success = await editor.open({ collapsed: ['$root'] });

Error Navigation API

Navigate between syntax and structural errors:

| Method | Description | |--------|-------------| | goToNextError() | Navigate to next error, returns true if found | | goToPrevError() | Navigate to previous error, returns true if found |

Error lines are indicated with a red bar in the gutter. The error count is displayed in the suffix area between navigation buttons (◀ ▶).

// Navigate to errors programmatically
editor.goToNextError();
editor.goToPrevError();

Keyboard Shortcuts

| Shortcut | Action | |----------|--------| | Ctrl+S / Cmd+S | Save to file | | Ctrl+O / Cmd+O | Open file (disabled in readonly) | | Ctrl+Z / Cmd+Z | Undo | | Ctrl+Y / Cmd+Y | Redo | | Ctrl+Shift+Z / Cmd+Shift+Z | Redo (alternative) | | Ctrl+A / Cmd+A | Select all | | Ctrl+C / Cmd+C | Copy | | Ctrl+X / Cmd+X | Cut | | Ctrl+V / Cmd+V | Paste | | Ctrl+← / Cmd+← | Move cursor to previous word | | Ctrl+→ / Cmd+→ | Move cursor to next word | | Ctrl+Shift+← / Cmd+Shift+← | Select to previous word | | Ctrl+Shift+→ / Cmd+Shift+→ | Select to next word | | Enter | Expand collapsed node at cursor | | Shift+Enter | Collapse innermost node containing cursor | | Tab | Navigate to next attribute (key or value) | | Shift+Tab | Navigate to previous attribute | | Home | Go to start of line | | End | Go to end of line | | Ctrl+Home / Cmd+Home | Go to start of document | | Ctrl+End / Cmd+End | Go to end of document | | PageUp | Scroll up one page | | PageDown | Scroll down one page | | Shift+Home/End/PageUp/PageDown | Extend selection while navigating | | Ctrl+I / Cmd+I | Add feature via prompt (requires internal-add-shortcut attribute) |

Overriding Shortcuts

All keyboard shortcuts handled by the editor call stopPropagation() to prevent them from bubbling up. To override a default shortcut behavior, use a capture-phase event listener:

editor.addEventListener('keydown', async (e) => {
  // Override Ctrl+S to save to a remote server instead of downloading
  if (e.ctrlKey && e.key === 's') {
    e.preventDefault();
    e.stopPropagation();
    await saveToRemoteServer(editor.getAll());
  }
  // Override Ctrl+O to load from a remote API instead of local filesystem
  if (e.ctrlKey && e.key === 'o') {
    e.preventDefault();
    e.stopPropagation();
    const features = await openRemoteFeatureSelector();
    if (features) editor.set(features);
  }
}, { capture: true });  // capture: true is required to intercept before the editor

Events

change

Fired when content changes and GeoJSON is valid (debounced 150ms).

editor.addEventListener('change', (e) => {
  console.log(e.detail);  // Parsed GeoJSON object directly
});

Event detail: The parsed GeoJSON object (always a FeatureCollection).

Note: Hidden features (toggled via the eye icon) are automatically excluded from the emitted GeoJSON. This allows temporary filtering without modifying the actual JSON content.

Example:

// User edits features only, but change event includes the FeatureCollection wrapper
editor.addEventListener('change', (e) => {
  console.log(e.detail);
  // → { type: "FeatureCollection", features: [{ type: "Feature", ... }] }
});

error

Fired when content changes but JSON is invalid or GeoJSON validation fails (debounced 150ms).

editor.addEventListener('error', (e) => {
  console.error(e.detail.error);   // Error message
  console.log(e.detail.errors);    // Array of validation errors (GeoJSON validation only)
  console.log(e.detail.content);   // Raw content for debugging
});

Event detail properties:

| Property | Type | Description | |----------|------|-------------| | error | string | Error message (JSON parse error or GeoJSON validation summary) | | errors | string[] | Array of validation errors with paths (GeoJSON validation only) | | content | string | Raw editor content (for debugging) |

GeoJSON validation errors include:

  • Invalid types (e.g., "LinearRing")
  • Unknown types (any type value not in the GeoJSON specification)

current-features

Fired when the current feature(s) change. Useful for synchronizing the editor with a map display. Emits a FeatureCollection containing all features that overlap with the cursor position or selection.

Triggers:

  • Editor gains focus → emits FeatureCollection with feature at cursor
  • Cursor moves to a different feature → emits FeatureCollection with new feature(s)
  • Selection spans multiple features → emits FeatureCollection with all overlapping features
  • Cursor moves outside any feature → emits empty FeatureCollection
  • Editor loses focus → emits empty FeatureCollection
editor.addEventListener('current-features', (e) => {
  const featureCollection = e.detail;  // Always a FeatureCollection
  if (featureCollection.features.length > 0) {
    // Highlight these features on your map
    highlightLayer.setData(featureCollection);
  } else {
    // No current features
    highlightLayer.setData({ type: 'FeatureCollection', features: [] });
  }
});

Event detail: A FeatureCollection object containing:

  • All features overlapping with the current selection (if selection exists)
  • The single feature at cursor position (if no selection)
  • Empty features array if cursor is outside any feature or editor loses focus

Note: The event is only fired when the set of features changes, not on every cursor movement within the same feature. This prevents excessive event firing during normal editing.

Styling

The component uses Shadow DOM with CSS variables for theming. Customize colors via CSS custom properties (see Theme Control).

Browser Support

Works in all modern browsers supporting:

  • Web Components
  • Shadow DOM
  • ES6 Modules

Development

See DEVELOPMENT.md for detailed development guide.

# Install dependencies
npm install

# Start dev server with live demo
npm run dev

# Build for production
npm run build

License

MIT