min read

Announcing Lucy

Lucy is a new DSL (domain-specific language) for describing Finite State Machines and Statecharts. It compiles to JavaScript using XState.

A simple toggle machine looks like this:


state enabled {
toggle => disabled

initial state disabled {
toggle => enabled

Which compiles to this JavaScript:


import { Machine } from 'xstate';

export default Machine({
initial: 'disabled',
states: {
enabled: {
on: {
toggle: 'disabled'
disabled: {
on: {
toggle: 'enabled'

Lucy is alpha software. Do not use it if you expect it to always work or be well documented yet. It's not! But if you're adventurous and want to try out a way to more concisely describe state machines, or want to contribute, please give it a try.

The Lucy language guide contains more examples of what Lucy can do. It attempts to support most features of XState and comes pretty close. If there are missing features you'd like to see, please file an issue on GitHub.

Here's a more complex Lucy program that uses external JavaScript functions, multiple machines, and actors:

use './api' { deleteTodo }

machine todoItem {
state idle {
delete => deleting
state deleting {
invoke deleteTodo {
done => deleted
final state deleted {}

machine app {
state idle {
new => assign(todo, spawn(todoItem))
delete => send(todo, delete)


Lucy is based on Statecharts, the proven way to build user interface logic. It is written in C and compiled to native binaries (for the CLI compiler) and to Wasm, for use in JavaScript based build tools. Due to this, compiling Lucy code is extremely fast. Benchmarks are to come, but I feel confident that a project with dozens of Lucy files should feel near instant to compile.

Already Lucy supports Snowpack, Rollup, and Vite plugins with more tooling support to come. If you're interested in contributing a plugin for another build tool (they are very easy to write), please let me know.

See the install page for installing and using Lucy today.

The Name

Since I know people will ask... A few years ago I got tired of all of the npm package names being taken so I stopped trying to name my projects based on what they do. Instead I use a convention of naming (most of) my projects after classic gothic literature and cinema. Lucy is named after Lucy Westenra, an antogonist in the 1897 novel Dracula.

Why a DSL?

Finite State Machines and Statecharts are already used successfully in UI applications today. XState is the most robust way to build state logic on the web. I've used XState for many years, and am also the author of another FSM/Statechart library, Robot.

However I've always wanted a more concise way to describe state machines. Especially with XState it becomes a lot of options objects. DSLs are an underused way of making programming more declarative. If you've used CSS and enjoy it, you know the benefit of a DSL.

Futhermore, a static DSL opens up possibilities to improve both the developer and user experience of web applications. Svelte uses static templates to compile to a smaller and faster JavaScript output. Likewise, a DSL for runtime logic can potentially be used to reduce the size of client-side JavaScript even more. If you know what possible states exist for an application and you know what parts of a template are dynamic, you have everything you need to only compile to the minimum JavaScript that is absolutely necessary at runtime.

However these are ideas for the future. For now Lucy's aim is to improve the FSM (and XState in particular) developer experience. Please join me, download Lucy and kick the tires around.

You can ping me on Twitter and tell me what you think.