A visual, interactive toolkit for building and simulating Finite State Machines.
Design, connect, and explore DFAs, NFAs, and free-form state machines — all from your browser.
FSM Engine is an open-source, web-based tool for creating, editing, and visualizing Finite State Machines. It pairs a powerful, framework-agnostic TypeScript engine (@fsm/engine) with a rich, canvas-driven Svelte 5 frontend — giving you both a programmatic API and a visual editor in a single monorepo.
Whether you're a student learning automata theory, an educator preparing a lecture, or an engineer prototyping state-driven logic, FSM Engine gets you from concept to diagram in seconds.
| Mode | Description |
|---|---|
| Add | Click the canvas to place a new state |
| Connect | Click two states to draw a directed transition (self-loops supported) |
| Remove | Single-click to delete any state or transition |
| Zoom | Zoom in / out with buttons or scroll wheel |
.fsm (JSON) format@fsm/engine)FSM Engine is structured as a Bun workspace monorepo with a clear separation between the computational core and the visual layer:
┌─────────────────────────────────────────────────────────┐
│ Monorepo Root │
│ (bun workspaces) │
├──────────────┬──────────────────────┬───────────────────┤
│ │ │ │
│ packages/ │ apps/web │ apps/docs │
│ engine │ (Svelte 5 + Konva) │ (Astro Starlight)│
│ │ │ │
│ ┌─────────┐ │ ┌────────────────┐ │ ┌─────────────┐ │
│ │FSMEngine│◄┼──│ store.svelte │ │ │ Starlight │ │
│ │ DFA │ │ │ (Project) │ │ │ Docs Site │ │
│ │ types │ │ │ │ │ │ │ │
│ └─────────┘ │ └───────┬────────┘ │ └─────────────┘ │
│ │ │ │ │
│ │ ┌─────▼─────┐ │ │
│ │ │ Editor │ │ │
│ │ │ Canvas │ │ │
│ │ │ (Konva) │ │ │
│ │ └───────────┘ │ │
└──────────────┴──────────────────────┴───────────────────┘
Key design decisions:
$state, $effect, $derived) with SvelteMap for fine-grained reactive state management.svelte-konva, giving hardware-accelerated 2D drawing.Map<number, State> store is shared by reference with the Svelte frontend's reactive SvelteMap, keeping both layers synchronized with minimal overhead.| Layer | Technology |
|---|---|
| Runtime | Bun |
| Language | TypeScript 5 (strict mode) |
| Frontend Framework | Svelte 5 (Runes mode) |
| Canvas | Konva + svelte-konva |
| Styling | Tailwind CSS 4 + shadcn-svelte |
| Graph Layout | @dagrejs/dagre |
| Icons | @lucide/svelte |
| Bundler | Rolldown Vite |
| Documentation | Astro + Starlight |
| Linting | ESLint 9 + Prettier |
| Git Hooks | Husky + lint-staged |
# Clone the repository
git clone https://github.com/karthik-saiharsh/fsm-engine.git
cd fsm-engine
# Install all workspace dependencies
bun install
# Start the web editor (apps/web)
cd apps/web
bun run dev
# Start the documentation site (apps/docs)
cd apps/docs
bun run dev
cd apps/web
bun run build
bun run preview # Preview the production build locally
fsm-engine/
├── packages/
│ └── engine/ # @fsm/engine — headless FSM library
│ ├── FSMEngine.ts # Base engine: states, transitions, save/load
│ ├── DFA.ts # DFA subclass: alphabet enforcement, string validation
│ ├── index.ts # Public API barrel export
│ └── utils/
│ └── types.ts # Shared types: State, Transition, EngineTypes
│
├── apps/
│ ├── web/ # Svelte 5 visual editor
│ │ ├── src/
│ │ │ ├── App.svelte # Root component: Launch screen ↔ Editor
│ │ │ ├── app.css # Design tokens (oklch), Geist font, Tailwind
│ │ │ └── lib/
│ │ │ ├── brain/ # State management layer
│ │ │ │ ├── store.svelte.ts # Project singleton (engine + UI state)
│ │ │ │ ├── extras.svelte.ts # Secondary reactive stores
│ │ │ │ └── types.ts # Frontend-specific types
│ │ │ └── components/ # UI components
│ │ │ ├── Editor.svelte # Konva canvas + rendering loop
│ │ │ ├── Dock.svelte # Bottom toolbar (Add/Remove/Connect/Zoom)
│ │ │ ├── Launch.svelte # Welcome / project picker screen
│ │ │ ├── Alert.svelte # Notification overlay
│ │ │ ├── editor/ # TopBar, MachinePicker
│ │ │ ├── popus/ # NodeCustomizer, TransitionCustomizer, etc.
│ │ │ ├── generic/ # Window, ScreenSizeFallback
│ │ │ └── ui/ # shadcn-svelte primitives
│ │ ├── index.html
│ │ ├── vite.config.ts
│ │ └── svelte.config.js
│ │
│ └── docs/ # Astro Starlight documentation site
│ ├── astro.config.mjs
│ └── src/content/docs/
│
├── package.json # Workspace root (bun workspaces)
├── tsconfig.json # Shared TypeScript config
├── eslint.config.mts # ESLint flat config
├── .prettierrc # Prettier formatting rules
└── .husky/pre-commit # Pre-commit lint hook
The @fsm/engine package exposes two main classes that can be used independently of the UI:
FSMEngine (Free-form)import { FSMEngine } from "@fsm/engine";
const fsm = new FSMEngine("MyStateMachine");
// Add states (returns a numeric reference ID)
const s0 = fsm.addState("q0");
const s1 = fsm.addState("q1");
const s2 = fsm.addState("q2");
// Mark state types
fsm.setStart(s0);
fsm.setEnd(s2);
// Add transitions
fsm.addTransition(s0, s1, "a");
fsm.addTransition(s1, s2, "b");
fsm.addTransition(s1, s1, "a"); // self-loop
// Query the machine
fsm.searchStates("q1"); // → [1]
fsm.searchTransition(s0, s1); // → [0]
fsm.getTransitionsOn("a"); // → [0, 2]
// Serialize / Deserialize
const snapshot = fsm.saveProject();
fsm.loadProject(snapshot);
DFA (Deterministic Finite Automaton)import { DFA } from "@fsm/engine";
const dfa = new DFA("BinaryStrings");
// Define language alphabet
dfa.addAlphabets("0", "1");
// Build states
const q0 = dfa.addState("q0");
const q1 = dfa.addState("q1");
dfa.setStartState(q0);
dfa.endState.add(q1);
// Add deterministic transitions
dfa.addTransition(q0, q1, "1");
dfa.addTransition(q0, q0, "0");
dfa.addTransition(q1, q1, "0");
dfa.addTransition(q1, q0, "1");
// Validate strings
dfa.validateString("1010");
// → { path: [0, 1, 1, 0], accepted: true }
DFA enforcement: Adding a duplicate transition on the same alphabet from the same state will throw an error, guaranteeing determinism at the API level.
Contributions are welcome and greatly appreciated! Here's how to get involved:
git checkout -b feat/amazing-feature)git commit -m 'feat: add amazing feature')git push origin feat/amazing-feature)bun run lint before submitting to ensure code quality.fsm JSON format)This project is licensed under the GNU General Public License v3.0.
Copyright (C) 2026 Illindala Karthik Saiharsh
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Built with ♥ by Karthik Saiharsh and contributors
Report Bug · Request Feature or Ask/Share Something · Live Demo