Skip to content

Getting Started

Welcome to XMachines! This guide will help you understand what XMachines is and get you up and running with your first state machine.

What is XMachines?

XMachines is a TypeScript implementation of the Universal Player Architecture—a state machine library that strictly separates business logic from infrastructure. It enables logic-driven applications where state machines control routing, views, and navigation through standardized TC39 Signals.

At its core, XMachines is built on the actor model, following the principle that business logic must be the single source of truth for navigation, state, and UI structure. Infrastructure reflects actor state—it never decides.

Unlike traditional frameworks where your logic adapts to the framework, XMachines inverts this relationship. Your state machines own the application behavior, and the infrastructure (routers, view renderers, React components) passively observes and reflects the current state through signals. This results in complete runtime agnosticism—your logic has zero framework dependencies.

Why XMachines?

Type Safety with TypeScript

  • Full type inference from state machine catalog through to components
  • Catch navigation errors and state bugs at compile time
  • Zod validation for UI schemas and state structures

Predictable State Management

  • State machines make application behavior explicit and testable
  • Actor model ensures clear message passing patterns
  • Guard enforcement prevents invalid state transitions

Platform Flexibility

  • Runtime-agnostic core packages work in browser, Node, or Deno
  • Choose only the packages you need for your platform
  • Framework integrations (React, TanStack Router) are optional adapters

Modular Architecture

  • 8 focused packages that work together seamlessly
  • @xmachines/play foundation works with any infrastructure
  • Mix and match adapters based on your stack

Quick Start

Installation

First, install XMachines packages. See the complete Installation → guide for all package managers and environments.

Terminal window
npm install @xmachines/play @xmachines/play-xstate

Import and Create Your First Machine

import { createMachine } from "@xmachines/play-xstate";
// Define a simple traffic light machine
const trafficLightMachine = createMachine({
id: "trafficLight",
initial: "red",
states: {
red: {
on: { TIMER: "green" },
},
green: {
on: { TIMER: "yellow" },
},
yellow: {
on: { TIMER: "red" },
},
},
});

Create an Actor and Transition States

import { createActor } from "@xmachines/play-actor";
// Instantiate the machine as an actor
const actor = createActor(trafficLightMachine);
// Start the actor
actor.start();
// Check initial state
console.log(actor.getSnapshot().value); // "red"
// Send events to transition states
actor.send({ type: "TIMER" });
console.log(actor.getSnapshot().value); // "green"
actor.send({ type: "TIMER" });
console.log(actor.getSnapshot().value); // "yellow"

Observe State Changes with Signals

import { signal, computed } from "@xmachines/play-signals";
// Create a signal to track actor state
const currentState = signal(actor.getSnapshot().value);
// Subscribe to actor changes
actor.subscribe((snapshot) => {
currentState.value = snapshot.value;
});
// Create computed values
const canProceed = computed(() => currentState.value === "green");
console.log(canProceed.value); // true when light is green

Your First Machine: Toggle Example

Here’s a complete working example that demonstrates the core concepts:

import { createMachine } from "@xmachines/play-xstate";
import { createActor } from "@xmachines/play-actor";
import { signal } from "@xmachines/play-signals";
// Define the machine configuration
const toggleMachine = createMachine(
{
id: "toggle",
initial: "inactive",
context: {
count: 0,
},
states: {
inactive: {
on: {
TOGGLE: {
target: "active",
actions: "incrementCount",
},
},
},
active: {
on: {
TOGGLE: {
target: "inactive",
actions: "incrementCount",
},
},
},
},
},
{
actions: {
incrementCount: ({ context }) => ({
count: context.count + 1,
}),
},
},
);
// Create and start the actor
const toggleActor = createActor(toggleMachine);
toggleActor.start();
// Bind to a signal for reactive updates
const state = signal(toggleActor.getSnapshot());
toggleActor.subscribe((snapshot) => {
state.value = snapshot;
});
// Use the machine
toggleActor.send({ type: "TOGGLE" });
console.log(state.value.value); // "active"
console.log(state.value.context.count); // 1
toggleActor.send({ type: "TOGGLE" });
console.log(state.value.value); // "inactive"
console.log(state.value.context.count); // 2

Understanding the Parts

States: Discrete modes your application can be in (inactive, active)

Events: Messages that trigger transitions (TOGGLE)

Transitions: Rules that define which events move between which states (on: { TOGGLE: 'active' })

Context: Extended state data that persists across transitions (count: 0)

Actions: Side effects or context updates executed during transitions (incrementCount)

Actor: Runtime instance of a machine that processes events and emits state changes

Signals: Reactive primitives (TC39 Signals) that enable infrastructure to observe state changes without coupling

Next Steps

Now that you understand the basics, explore these resources:

Core Documentation

Platform Guides

Examples

  • Examples Directory - More code examples and usage patterns
  • Working dashboard demo (coming soon)

Ready to install?Installation Guide