Author: christianhohlfeld
A zero-dependency, single-file, browser-based finite-state-machine (FSM) prototype tool.
Build UI states by snapping the DOM, wire up transitions (events, property changes, or custom/async functions), share stateful context
data between states, and preview everything live—no bundler or build step required.
.
└── state.html # “MiniState” all-in-one demo + dev UI + runtime
Nothing else. Just open state.html
in your browser.
- Clone your repo
git clone https://github.com/christianhohlfeld/ministate.git cd ministate
- Open in browser
Double-clickstate.html
(oropen state.html
). - Enter Dev Mode
Click the red DEV MODE button at bottom-right. - Snapshot & Edit States
- Click + Snapshot Current to capture the DOM as a new state.
- ★ star any state to make it the initial state.
- Add Transitions
- Pick an element → “add rule: click()” / “prop change” / “custom fn”
- (Optionally) Attach a named async/sync JavaScript function as a condition or action.
- Map Context → DOM
- Define per-state JSON
context
- In “Edit State Entry Mappings,” map
context.*
paths to element IDs + properties.
- Define per-state JSON
- Single HTML file: zero install, zero build.
- DOM snapshots per state + live apply.
- Event, prop-change, or fn-call triggers.
- Async conditions & actions:
async (req, getState, ctx) => { … }
. - Shared
context
across states. - Data-mapping UI: map
context.foo
→#myEl.textContent
. - DaisyUI + Tailwind Dev UI.
- JSON import/export of your FSM spec.
- Clean logs via
console.log
, no alerts.
- Auto-track all
id
-ed elements’ key props (value, textContent, classList, disabled, …). - Snapshot saves “id.prop = value” pairs.
- Transitions:
- Event (
click
, etc.) - Property (
value
,checked
, etc.) - Function (custom code)
- Event (
- Conditions & actions can be async—MiniState shows a loading spinner and times out after 5 s.
- Context merge: if your condition/action mutates
context
, those values carry into the next state. - Entry hooks apply snapshot + data-mappings automatically.
Inside Dev UI → Custom Functions:
async (requestChange, getState, context) => {
// fetch some data
const res = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const data = await res.json();
context.last = data;
return true; // allow transition
}
Then in the next state’s “Edit State Entry Mappings”:
- Source:
context.last.title
→ Component:#dataTitle
→ Property:textContent
- Source:
context.last.completed ? '✓' : '✗'
→#dataDone.textContent
- Rename
MiniState
title or favicon as desired. - Drop in your own HTML/CSS structure ≤250 KB.
- All logic lives inside
<script>
—feel free to extend or embed into your app.
This project is MIT-licensed — see LICENSE for details.
Built by christianhohlfeld • Enjoy prototyping without the overhead!