User Guide

What is JSyntrax?

JSyntrax is a railroad diagram generator. It creates a visual illustration of the grammar used for programming languages. A specification file describes the syntax as a hierarchy of basic elements. This is processed into an image representing the same syntax with interconnected nodes.

The specification is a set of nested Groovy function calls:

  line(opt('-'), choice('0', line('1-9', loop(None, '0-9'))),
    opt('.', loop('0-9', None))),
  line(opt(choice('e', 'E'), choice(None, '+', '-'), loop('0-9', None)))

This is processed by JSyntrax to generate an SVG image:


JSyntrax can render to PNG bitmap images or SVG vector images. The SVG output can have hyperlinked text allowing users to quickly navigate to documentation of different syntax elements.

The original Syntrax was a heavily modified version of the railroad diagram generator used for the SQLite documentation implemented in Python. Then in JSyntrax it has been reimplemented in Java in order to simplify installation, get rid of required libraries and make it easily portable to any operating system.

JSyntrax vs. Syntrax

Why did you reimplement Syntrax in Java?

The problem with Syntrax is that it requires Pycairo and Pango which may be difficult to install, especially on Windows. JSyntrax requires only JDK 11, which is easily available for many platforms.

What output formats are supported?

JSyntrax produces SVG and PNG images. The original Syntrax can also produce PDF, PS, and EPS, these formats are not yet supported by JSyntrax.

Can I build my Syntrax specs with JSyntrax?

Yes, after only a couple of minor tweaks. If you use url maps, refer to Hyperlinked SVG section for Groovy-specific DSL which is a bit different from what was in original Syntrax (in short: you will have to replace {} with [] and add jsyntrax wrapper function). Also, text_mod attribute in Styling diagrams is not supported (the author of the original Syntrax warned about potential security issues with this attribute). Instead, if a style regexp pattern contains a capturing group, the node text will contain the contents of the first capturing group only.

Why your executable file is called syntrax, not jsyntrax?

This is made intentionally in order to use AsciiDoctor Diagram integration facility. JSyntrax executable has exactly the same command line arguments as Syntrax and can be used as a replacement for the original syntrax tool.


JSyntrax is licensed for free commercial and non-commercial use under the terms of the MIT license.

Requirements, download and installation

JSyntrax requires JDK 11+. No other software is required to run JSyntrax.

You can access the JSyntrax Git repository from Github, and download releases here.

Unzip file to any convenient folder. /bin directory will contain executable syntrax file.

Using JSyntrax

JSyntrax is a command line tool. You pass it an input specification file and it will generate a diagram in any of the supported output formats.

usage: syntrax [--get-style] [-h] [-i <arg>] [-o <arg>] [-s <arg>] [--scale
       <arg>] [-t] [--title <arg>] [-v]
Railroad diagram generator.
      --get-style        Create default style .ini
   -h,--help             Show this help message and exit
   -i,--input <arg>      Diagram spec file
   -o,--output <arg>     Output file
   -s,--style <arg>      Style config .ini file
      --scale <arg>      Scale image
   -t,--transparent      Transparent background
      --title <arg>      Diagram title
   -v,--version          JSyntrax version

Any argument not associated with a flag is assumed to be the input file name. The default output format is PNG.

> syntrax spec
Output file spec.png was created

You can specify the specific out file you want with the -o option. The extension determines the format. You can also pass just the extension to -o and Syntrax will use the input file base name for the output image:

>syntrax -i spec -o result.svg
Output file result.svg was created

>syntrax -i spec -o svg
Output file spec.svg was created


By default the images have a white background. If you want a transparent background pass the -t option.


You can control the scale of the resulting image with the --scale option. It takes a floating point scale factor. This is most useful for the PNG output to increase the resolution of the image or create thumbnails with less blurring than conventional bitmap resizing.

> syntrax -i scaling.spec -o small.svg --scale 0.5
> syntrax -i scaling.spec -o big.svg --scale 2.0


You can include a title in the generated diagram by passing a string to the --title option. The position of the title is controlled by the title_pos entry in the styling configuration. It defaults to the top left. The title_font entry is used to style the font.

> syntrax -i titling.spec -o svg --title="Diagram with title"

Specification language

JSyntrax diagrams are created using a Groovy-based specification language. A series of nestable function calls generate specific diagram elements. Nodes in the diagram are represented by quoted strings. Nodes default to rounded bubbles but will change to a box when prefixed with "/". Note that this is the reverse of how the original SQLite generator works. The rounded bubbles are typically used for literal tokens. Boxes are typically place holders for syntactic elements too complex to include in the current diagram. Nodes starting with a non-alphanumeric character are rendered with their own font style so that punctuation tokens can be made more distinct.

The following functions are available for creating diagrams:











A line() creates a series of nodes arranged horizontally from left to right.

line('[', 'foo', ',', '/bar', ']')


A loop() represents a repeatable section of the syntax diagram. It takes two arguments. The first is the line of nodes for the forward path and the second is the nodes for the backward path. The backward path is rendered with nodes ordered from right to left.

loop(line('/forward', 'path'), line('backward', 'path'))

Either the forward or backward path can be None to represent no nodes on that portion of the loop.

loop('forward', None)


A toploop() is a variant of loop() that places the backward path above the forward path.

toploop(line('(', 'forward', ')'), line('(', 'backward', ')'))


The choice() element represents a branch between multiple syntax options.

choice('A', 'B', 'C')


An opt() element specifies an optional portion of the syntax. The main path bypasses the optional portion positioned below.

opt('A', 'B', 'C')

opt() is a special case of the choice() function where the first choice is None and the remaining nodes are put into a single line for the second choice. The example above is equivalent the following:

choice(None, line('A', 'B', 'C'))


The optx() element is a variant of opt() with the main path passing through the nodes.

optx('A', 'B', 'C')


The elements described above will concatenate indefinitely from left to right. To break up long sections of a diagram you use the stack() element. Each of its arguments forms a separate line that is stacked from top to bottom.

  line('top', 'line'),
  line('bottom', 'line')

When an inner element of a stack argument list is an opt() or an optx() it will be rendered with a special vertical bypass.

  line('A', 'B'),


For more control of the stacking you can use the indentstack() element. It shifts lower lines to the right relative to the top line of the stack. Its first argument is an integer specifing the amount of indentation.

  line('top', 'line'),
  line('bottom', 'line')


The rightstack() element will right align successive lines without needing to determine the indentation.

  line('top', 'line', 'with', 'more', 'code'),
  line('bottom', 'line')

Styling diagrams

You can control the styling of the generated diagrams by passing in a style INI file with the -s option.

You can use the --get-style option to generate a copy of the default styles in the current directory so you can quickly make modifications.

Here is the default styling:

line_width = 2
outline_width = 2
padding = 5
line_color = (0, 0, 0)
max_radius = 9
h_sep = 17
v_sep = 9
arrows = True
title_pos = 'tl'
bullet_fill = (255, 255, 255)
text_color = (0, 0, 0)
shadow = True
shadow_fill = (0, 0, 0, 127)
title_font = ('Sans', 22, 'bold')

pattern = '(^\w+)'
shape = 'bubble'
font = ('Sans', 14, 'bold')
text_color = (0, 0, 0)
fill = (179, 229, 252)

pattern = '^/(.+)'
shape = 'box'
font = ('Times', 14, 'italic')
text_color = (0, 0, 0)
fill = (144, 164, 174)

pattern = '(.*)'
shape = 'bubble'
font = ('Sans', 16, 'bold')
text_color = (0, 0, 0)
fill = (179, 229, 252)
vhdl attribute spec

Here is the same diagram with modified styling:

; Thicker lines
line_width = 3
outline_width = 3
padding = 5
line_color = (0, 0, 0)
; Larger radii
max_radius = 29
h_sep = 17
v_sep = 9
; Remove arrows
arrows = False
title_pos = 'tl'
; yellow
bullet_fill = (255,255,0)
text_color = (0, 0, 0)
shadow = True
shadow_fill = (0, 0, 0, 127)
title_font = ('Sans', 22, 'bold')

; User-defined style name
pattern = '(^\w+)'
; Hexagon shape for node
shape = 'hex'
font = ('Sans', 14, 'bold')
; Alpha component for transparent fills
fill = (255,0,0,127)

pattern = '^/(.*)'
shape = 'box'
font = ('Sans', 14, 'bold')
text_color = (100, 100, 100)
fill = (144, 164, 174)

pattern = '(.*)'
shape = 'bubble'
font = ('Times', 16, 'italic')
fill = (0,255,0,127)
vhdl attribute spec styled

The style configuration file has a main section named "[style]" followed by user-defined sections for various node types. The node style is chosen based on a regex pattern applied to the text. The first matched pattern sets the style for a node. Patterns are tested in the same order they appear in the configuration file. The first node style is used by default if no pattern matched the text. If the pattern contains a capturing group, then the resulting text in the node will be equal to the contents of this group (otherwise, the full text will be used).

The [style] section contains the following keys:


Connecting line width in pixels. Default is 2.


Node outline width in pixels. Default is 2.


Additional padding around each edge of the image in pixels. Default is5.


Color of the connecting lines and node outlines. Default is (0,0,0) Black.


Maximum radius for turnbacks on loops and stacked connections.


Horizontal separation between nodes.


Vertical separation between line elements.


Boolean used to control rendering of line arrows. Default is True.


Position of the title text. String containing one of 'left', 'center', or 'right' for horizontal position and 'top' or 'bottom' for vertical. These can be abbreviated as 'l', 'c', 'r', 't', and 'b'. Other characters are ignored. Examples are 'top-left', 'bottom center', 'cr', and 'rt'.


Fill color for small bullets at start and end of the diagram.


Default color of all text. Can be overridden with text_color in a node style section


Boolean controlling the rendering of node shadows. Default is True.


Fill color for shadows.


Font for image title.

Node styles

Nodes are styled with a user-defined section name. The built-in sections are [bubble] for tokens that start with an alphanumeric character, [box] for symbols drawn with a boxed outline, and [token] for tokens that consist of a single punctuation character. You are not limited to these three node styles. Any number of node types can be defined provided they have distinct patterns to match against the node text in your specification file.

The node sections contain the following keys:


A regex pattern to match the node text to a style. Notes about pattern format:

  • Must satisfy regex java semantics

  • Matches the whole input sequence exclusively (input "</>Hello" corresponds to this: "</>.*", not this: "</>")

  • You may not want to see control characters of your regex in diagram output. To omit them, use capture groups to wrap the content you want to display. Examples:

    • <b>(.*)</b> - matches <b>my_text</b> and will display my_text

    • ^/(.+) -→ /my_text -→ my_text

    • "^</(.*)>" -→ "</my_text>" -→ "my_text"

  • If given input sequence does not match specified expression, default style will be used.


Node outline shape. Must be "bubble", "box", or "hex".


Font style for the node.


Optional font color for the node. If omitted, the text_color from the [style] section is used.


Shape fill color for the node.


The various keys controlling coloration can use a variety of color formats. The primary color representation is a 3 or 4-tuple representing RGB or RGBA channels. All channels are an integer ranging from 0 to 255.

; Supported color formats:

(255,100,0)     ; RGB
(255,100,0,100) ; RGBA


Fonts are specified as a tuple of three items in the following order:

  • Font family (Helvetica, Times, Courier, etc.)

  • Point size (12, 14, 16, etc.)

  • Style ('normal', 'bold', 'italic')

title_font = ('Helvetica', 14, 'bold')

Hyperlinked SVG

SVG images can have hyperlinked node text. This is implemented by adding a url_map parameter to jsyntrax wrapper function. The keys of the dictionary are the text identifying the node and their values are the URL for the link. The text key should not include any leading "/" character for the box nodes.

 line('attribute', '/(attribute) identifier', 'of'),
 line(choice(toploop('/entity_designator', ','), 'others', 'all'), ':'),
 line('/entity_class', 'is', '/expression', ';')
  'entity_class': '',
  '(attribute) identifier': ''
Note for Syntrax (Python) users

Note that in Groovy, unlike Python, maps are enclosed in brackets [], not braces {}.


Current browser policies lump SVG hyperlinks together with embedded Javascript. Because of this they do not support hyperlinks when an SVG is referenced through an HTML <img> tag. To get functional links on a web page you must use an <object> tag instead:

<object type="image/svg+xml" data="path/to/your.svg"></object>

In Asciidoctor diagrams, we should put set opts=interactive or opts=inline on the diagram block:

jsyntrax( ... ,