ST State Diagrammer
pre-launch v1.0.1
EN NL
Developer Log In
ST → Diagram

Turn Structured Text into clear diagrams

Paste or import your IEC 61131-3 ST code and instantly get a clean state or flow diagram, automatic validation, and export to 6 formats. Built for PLC engineers and system integrators.

Free to use · No registration · No code stored

The problem we solve

PLC state machines live as long CASE blocks — hard to review, harder to hand over.

Without ST State Diagrammer

  • State logic buried in hundreds of lines of CASE code.
  • Documentation drawn by hand in Visio — outdated the moment code changes.
  • Unreachable states, dead-ends and un-stopped timers slip through review.
  • Hard to onboard colleagues or hand machines over to a customer.

With ST State Diagrammer

  • Paste your ST and get a clean state & flow diagram in seconds.
  • Diagrams stay in sync with the code — re-generate any time.
  • Automatic validation flags unreachable states, dead-ends and timer issues.
  • Export to Word, PDF, SVG & more — review-ready documentation, instantly.

How it works

From source code to a shareable diagram in three steps.

1

Paste or import your ST code

Type or paste your Structured Text into the editor, or import a .txt file. Syntax highlighting helps you right away.

2

Pick state or flow diagram

The state variable is detected automatically. Choose the diagram type that best fits your machine.

3

Analyze, validate & export

Get a diagram, a validation score with checks, and an overview of every state and transition — ready to share.

See it in action

Pick an example and switch between state and flow — these are real diagrams generated by the tool, right here.

A compact four-state machine — the quickest way to read a diagram.

traffic_light.st
PROGRAM PRG_TrafficLight
VAR
    xEnable        : BOOL;        // Master enable for the intersection
    xPedestrian    : BOOL;        // Pedestrian request button
    iStep          : INT := 0;    // State machine step

    xRed           : BOOL;        // Red lamp output
    xYellow        : BOOL;        // Yellow lamp output
    xGreen         : BOOL;        // Green lamp output
    xWalk          : BOOL;        // Pedestrian "walk" lamp

    fbStepTimer    : TON;         // Phase timer
END_VAR

CASE iStep OF

    0: // RED
        xRed    := TRUE;
        xYellow := FALSE;
        xGreen  := FALSE;
        xWalk   := FALSE;
        fbStepTimer(IN := TRUE, PT := T#5s);
        IF xEnable AND fbStepTimer.Q THEN
            fbStepTimer(IN := FALSE);
            iStep := 10; // Go to green
        END_IF;

    10: // GREEN
        xRed    := FALSE;
        xGreen  := TRUE;
        fbStepTimer(IN := TRUE, PT := T#8s);
        IF fbStepTimer.Q THEN
            fbStepTimer(IN := FALSE);
            iStep := 20; // Time to clear the intersection
        END_IF;

    20: // YELLOW
        xGreen  := FALSE;
        xYellow := TRUE;
        fbStepTimer(IN := TRUE, PT := T#3s);
        IF fbStepTimer.Q THEN
            fbStepTimer(IN := FALSE);
            IF xPedestrian THEN
                iStep := 30; // Serve waiting pedestrians
            ELSE
                iStep := 0;  // Back to red
            END_IF;
        END_IF;

    30: // WALK
        xRed    := TRUE;
        xYellow := FALSE;
        xWalk   := TRUE;
        fbStepTimer(IN := TRUE, PT := T#6s);
        IF fbStepTimer.Q THEN
            fbStepTimer(IN := FALSE);
            xWalk := FALSE;
            iStep := 0; // Back to red
        END_IF;

END_CASE;
PROGRAM PLC_PRG
VAR
    // System Control Inputs
    xStartKnop          : BOOL;    // Starts the batch process
    xStopKnop           : BOOL;    // Pauses the process safely
    xNoodstop           : BOOL;    // Emergency Stop (Active LOW)
    xResetKnop          : BOOL;    // Resets faults

    // Process Feedback Sensors
    rActueelGewicht     : REAL;    // Current tank weight from load cells [kg]
    rDoelGewicht        : REAL := 500.0; // Target weight for raw material [kg]
    xNiveauHoog         : BOOL;    // High level switch sensor (safety backup)
    xNiveauLaag         : BOOL;    // Low level switch sensor (tank empty indicator)

    // Actuator Outputs
    xVulVentiel         : BOOL;    // Control valve for filling raw material
    xMengMotor          : BOOL;    // Motor control for the tank mixer
    xAfvoerVentiel      : BOOL;    // Control valve for discharging final product

    // Internal State Machine Variables
    diStap              : DINT := 0;  // Current step indicator for state machine
    diVorigeStap        : DINT := -1; // Tracking for ENTRY logic execution
    xFoutActief         : BOOL;    // System fault flag
    sStatusMelding      : STRING;  // Human-readable status message

    // Process Timers
    fbMengTimer         : TON;     // Timer for the mixing duration
    fbVulTimeout        : TON;     // Safety timeout if filling takes too long
END_VAR

// =============================================================================
// GLOBAL SAFETY INTERLOCKS (Executed every cycle)
// =============================================================================
IF NOT xNoodstop THEN
    diStap := 100; // Immediate jump to Emergency Stop State
END_IF;

// =============================================================================
// MAIN STATE MACHINE
// =============================================================================
CASE diStap OF

    0: // IDLE STATE 
        sStatusMelding := "0 - System Idle. Awaiting Start.";
        xVulVentiel    := FALSE;
        xMengMotor     := FALSE;
        xAfvoerVentiel := FALSE;

        // Transition Condition
        IF xStartKnop AND NOT xStopKnop AND NOT xFoutActief THEN
            diStap := 10; // Proceed to Initialization
        END_IF;


    10: //  INITIALIZATION 
        sStatusMelding := "10 - Initializing Process and Verifying Sensors.";
        
        // Reset process timers
        fbMengTimer(IN := FALSE);
        fbVulTimeout(IN := FALSE);

        // Transition Condition (Verify tank is ready and empty)
        IF NOT xNiveauHoog THEN
            diStap := 20; // Proceed to Filling
        ELSE
            xFoutActief := TRUE;
            diStap := 90; // High level fault on startup
        END_IF;


    20: //  FILLING RAW MATERIAL 
        sStatusMelding := "20 - Filling Valve Open. Dosing Material.";
        xVulVentiel    := TRUE;

        // Run safety filling timeout
        fbVulTimeout(IN := TRUE, PT := T#45s);

        // Transition Conditions
        IF rActueelGewicht >= rDoelGewicht THEN
            xVulVentiel := FALSE;
            diStap      := 30; // Weight reached, go to Mixing
        ELSIF fbVulTimeout.Q OR xNiveauHoog THEN
            xVulVentiel := FALSE;
            xFoutActief := TRUE;
            diStap      := 91; // Timeout or Overflow Fault
        ELSIF xStopKnop THEN
            xVulVentiel := FALSE;
            diStap      := 50; // Pause requested
        END_IF;


    30: // MIXING PROCESS 
        sStatusMelding := "30 - Mixing Agitator Running.";
        xMengMotor     := TRUE;

        // Run mixing timer (e.g., 15 seconds)
        fbMengTimer(IN := TRUE, PT := T#15s);

        // Transition Conditions
        IF fbMengTimer.Q THEN
            xMengMotor := FALSE;
            diStap     := 40; // Mixing done, go to Discharge
        ELSIF xStopKnop THEN
            xMengMotor := FALSE;
            diStap     := 50; // Pause requested
        END_IF;


    40: //  DISCHARGING TANK 
        sStatusMelding := "40 - Discharge Valve Open. Emptying Tank.";
        xAfvoerVentiel := TRUE;

        // Transition Conditions
        IF NOT xNiveauLaag AND rActueelGewicht <= 5.0 THEN
            xAfvoerVentiel := FALSE;
            diStap         := 0; // Tank is empty, return to Idle
        ELSIF xStopKnop THEN
            xAfvoerVentiel := FALSE;
            diStap         := 50; // Pause requested
        END_IF;


    50: // PAUSE STATE 
        sStatusMelding := "50 - Process Paused by Operator.";
        // Keep all actuators safely off during pause
        xVulVentiel    := FALSE;
        xMengMotor     := FALSE;
        xAfvoerVentiel := FALSE;

        // Transition Condition (Resume or Abort)
        IF xStartKnop AND NOT xStopKnop THEN
            // Retain timers and jump back to previous execution state
            IF rActueelGewicht < rDoelGewicht THEN
                diStap := 20; // Resume Filling
            ELSE
                diStap := 30; // Resume Mixing
            END_IF;
        END_IF;


    90: // FAULT: STARTUP HIGH LEVEL OVERFLOW 
        sStatusMelding := "90 - CRITICAL FAULT: Tank high level on startup.";
        IF xResetKnop THEN
            xFoutActief := FALSE;
            diStap      := 0;
        END_IF;


    91: // FAULT: FILLING TIMEOUT / OVERFLOW 
        sStatusMelding := "91 - CRITICAL FAULT: Filling timeout or sensor high active.";
        IF xResetKnop AND NOT xNiveauHoog THEN
            xFoutActief := FALSE;
            diStap      := 10; // Re-initialize
        END_IF;


    100: //  EMERGENCY STOP ACTIVE 
        sStatusMelding := "100 - EMERGENCY STOP ACTIVE. Hard shutdown.";
        xVulVentiel    := FALSE;
        xMengMotor     := FALSE;
        xAfvoerVentiel := FALSE;

        // Transition Condition (Only allow escape if hardware E-stop is physically cleared)
        IF xNoodstop AND xResetKnop THEN
            diStap := 0; // Return to Idle safely
        END_IF;

ELSE
    // Catch-all safety for undefined states
    diStap := 100;
END_CASE;

// =============================================================================
// TIMER FUNCTION BLOCK CALLS (Executed every cycle)
// =============================================================================
fbMengTimer();
fbVulTimeout();
PROGRAM PRG_ConveyorSorter
VAR
    xStart         : BOOL;        // Start / run request
    xPartPresent   : BOOL;        // Photo-eye: part on the belt
    xScanDone      : BOOL;        // Vision scan finished
    xIsReject      : BOOL;        // Scan result: bad part
    xDiverted      : BOOL;        // Pusher reached end position
    xFault         : BOOL;        // Any drive / sensor fault
    xReset         : BOOL;        // Operator reset

    xBelt          : BOOL;        // Belt motor output
    xPusher        : BOOL;        // Divert pusher output
    iStep          : INT := 0;    // State machine step

    fbScan         : TON;         // Vision scan dwell timer
END_VAR

IF xFault THEN
    iStep := 90; // Jump to fault from any state
END_IF;

CASE iStep OF

    0: // IDLE
        xBelt   := FALSE;
        xPusher := FALSE;
        IF xStart AND xPartPresent THEN
            iStep := 10; // Part detected, start transporting
        END_IF;

    10: // TRANSPORT
        xBelt := TRUE;
        fbScan(IN := TRUE, PT := T#1s);
        IF fbScan.Q THEN
            fbScan(IN := FALSE);
            iStep := 20; // Hold under the scanner
        END_IF;

    20: // SCAN
        xBelt := FALSE;
        IF xScanDone THEN
            IF xIsReject THEN
                iStep := 40; // Bad part, push to reject lane
            ELSE
                iStep := 30; // Good part, pass through
            END_IF;
        END_IF;

    30: // ACCEPT
        xBelt := TRUE;
        IF NOT xPartPresent THEN
            iStep := 0; // Part has left the belt
        END_IF;

    40: // DIVERT
        xBelt   := FALSE;
        xPusher := TRUE;
        IF xDiverted THEN
            xPusher := FALSE;
            iStep := 0; // Reject pushed off, back to idle
        END_IF;

    90: // FAULT
        xBelt   := FALSE;
        xPusher := FALSE;
        IF xReset THEN
            iStep := 0; // Cleared, back to idle
        END_IF;

END_CASE;
Click a block Generated live
Traffic light – State Diagram LEGENDA Hoofdstroom Timeout-toestand Fouttoestand → Hoofd ⤳ Timeout (gestreept) → Fout / ELSE ⤸ Reset (rechterkanaal) ⇠ Terug (links) [fbStepTimer.Q AND NOT xPedestrian] [fbStepTimer.Q AND xPedestrian] [xEnable AND fbStepTimer.Q] [fbStepTimer.Q] [fbStepTimer.Q] 0 RED ENTRY: fbStepTimer.PT := T#5s TIMERS: fbStepTimer (TON, T#5s) OUT: xRed := TRUE xYellow := FALSE xGreen := FALSE xWalk := FALSE 10 GREEN ENTRY: fbStepTimer.PT := T#8s TIMERS: fbStepTimer (TON, T#8s) OUT: xRed := FALSE xGreen := TRUE fbStepTimer(IN:=TRUE, PT:=T#8s… 20 YELLOW ENTRY: fbStepTimer.PT := T#3s TIMERS: fbStepTimer (TON, T#3s) OUT: xGreen := FALSE xYellow := TRUE fbStepTimer(IN:=TRUE, PT:=T#3s… 30 WALK ENTRY: fbStepTimer.PT := T#6s TIMERS: fbStepTimer (TON, T#6s) OUT: xRed := TRUE xYellow := FALSE xWalk := TRUE fbStepTimer(IN:=TRUE, PT:=T#6s… OUTPUTS PER STAP 0 xRed := TRUE; xYellow := FALSE; xGreen := FALSE 10 xRed := FALSE; xGreen := TRUE; fbStepTimer(IN:=TRUE, PT… 20 xGreen := FALSE; xYellow := TRUE; fbStepTimer(IN:=TRUE,… 30 xRed := TRUE; xYellow := FALSE; xWalk := TRUE
These are live SVGs straight from the renderer — export-ready to DOCX, PDF, SVG, PNG & JSON. Open the tool to run your own code.

Design state machines visually

No code yet? Build the machine on a canvas and let the Designer write clean IEC 61131-3 Structured Text for you.

Designer & Digital Twin — account + paid plan
The visual Designer canvas with state blocks and generated Structured Text The visual Designer canvas with state blocks and generated Structured Text
  • Drag & connect Drop Step, Transition, Action and Fault/Error blocks onto the canvas and wire them together.
  • Inline conditions & actions Type transition guards and step actions with variable autocomplete — unknown names can be created on the fly.
  • Variable manager & I/O Manage BOOLs, analog I/O (raw→engineering scaling) and TON software timers in one place.
  • Built-in safety Emergency state 99, manual overrides, interlocks and a global E-Stop gate baked into the generated code.
  • Generate & export ST One click turns your design into review-ready Structured Text you can export as a .st file.

Bring the black box to life with the Digital Twin

Split the Designer canvas and watch your machine's I/O on a live 3D or 2D twin — then run the sequence to test its behaviour.

Designer & Digital Twin — account + paid plan
Designer split view with the state machine on the left and the Digital Twin panel on the right Designer split view with the state machine on the left and the Digital Twin panel on the right
Split view: Designer canvas on the left, live twin on the right
Digital Twin 3D I/O cube showing outputs, inputs and analog tiles Digital Twin 3D I/O cube showing outputs, inputs and analog tiles
3D I/O cube
Digital Twin 2D flat board split into outputs, inputs, analog and timers Digital Twin 2D flat board split into outputs, inputs, analog and timers
2D flat board

What you can do

Everything you need to document and review PLC logic.

State diagram

States as nodes, transitions as arrows — one-to-one with your PLC logic.

Flow diagram

Flowchart with decision diamonds and global overrides, conforming to IEC 61131-3.

Validation & checks

Automatic score with checks for unreachable states, dead-ends and un-stopped timers.

6 export formats

Word, PDF, SVG, PNG, JSON and a full report.

Zoom & lock

Zoom, pan and fit the diagram, with a lock against accidental scrolling.

Dark mode & NL/EN

Full light/dark mode and switch between English and Dutch.

Export to 6 formats

Share your diagram however your team works.

DOCXPDFSVGPNGJSONFULL REPORT

Zero-storage policy (GDPR compliant)

We do not use a database for your code. All uploaded Structured Text is processed entirely in the server's volatile memory (RAM) solely for the analysis and diagram rendering. Your industrial code is immediately and permanently destroyed the moment your session ends. Your intellectual property remains 100% yours.

Frequently asked questions

What teams ask before they try it.

Which Structured Text dialects does it support?
ST State Diagrammer reads standard IEC 61131-3 Structured Text — the CASE-based state machines used in environments such as CODESYS, TwinCAT and Siemens. Paste the relevant PROGRAM / CASE block or import a .txt file and the state variable is detected automatically.
Is my PLC code stored anywhere?
No. We do not use a database for your code. Your Structured Text is processed entirely in the server's volatile memory (RAM) solely to run the analysis and render the diagram, and it is destroyed the moment your session ends. Your intellectual property stays 100% yours.
Does it handle multiple or parallel state machines?
Yes. A program with several CASE blocks (for example a main, a safety and a communication machine) is detected automatically and each machine is laid out in its own lane, with every transition routed around the blocks so no line ever runs through a state.
What can I export to?
Every diagram can be exported to Word (DOCX), PDF, SVG, PNG and JSON, plus a full report combining the diagram, validation and an overview of all states and transitions.
What does the automatic validation check?
It produces a validation score with checks for unreachable states, dead-ends, states without a way back, and timers that are started but never stopped — the kind of issues that slip through a manual review.
Do I need to install anything?
No. ST State Diagrammer runs entirely in your browser — there is nothing to install and nothing to configure. It works in light and dark mode and in both English and Dutch.
Do I need an account, and is it free?
The analysis workspace — parsing your ST into state and flow diagrams, the validation, the live simulator and every export — is free and needs no account. Just open the tool from the homepage and paste or upload your code. The visual Designer (building machines on a canvas, the Digital Twin and ST generation) is a separate, account-based product on a paid plan.
What is the Designer and how do I get access?
The Designer is our visual state-machine builder: drag Step, Transition, Action and Fault blocks onto a canvas, manage variables and I/O, watch the machine on a live Digital Twin and generate IEC 61131-3 Structured Text. It requires an account and a paid plan — sign in once your access is set up. Get in touch if you'd like to try it.
Launching soon

Be the first to know when we launch

Leave your e-mail and we'll let you know the moment ST State Diagrammer goes public — plus the big milestones. No spam, unsubscribe anytime.

We only store your e-mail for the launch list — never your code.