RSM: Road Sign Maker

RSM is a command-line application that creates high-quality vector graphics of road signs. It is currently in development and is not ready for release, but is stable enough to be used through a web interface.

This is only a temporary page, as I continue working to implement the rest of my website. Stay tuned for future changes to this page.

Check the source code of the last sign generated with RSM.

Documentation

You can customize the output of RSM by passing it some input flags. There are four flags:

Output format (-f)
The format to generate the image in. Possible values are svg and png (the default value is svg).
Scale (-s)
Size of the final image relative to the parameters given (which are in inches). The default scale is 1, i.e. 1 unit is equivalent to 1 pixel on the image.
Debug mode (-d)
If debug mode is enabled, the renderer will draw red boxes around the objects, corresponding to the bounding box and margin box of the objects. This is mostly for troubleshooting layout issues.
Verbose mode (-v)
If verbose mode is enabled, RSM will log the details of the rendering process. (On the web version, it will only log the input and output.)

Input Format

RSM takes input in a JSON format. The top-level object must be a stack, i.e. it must have a key called xstack, ystack, or zstack. The different types of elements can be identified by checking for their respective keys.

All dimensions should be provided in inches.

Stacks

A stack arranges a collection of elements along a certain axis. It can also represent a sign panel.

{
  "xstack": [       // xstack, ystack, zstack depending on orientation
    // child elements
  ],

  "backcolor": "green",   // background color
  "padding": [8,6,8,6],   // inside spacing on each side (left, top, right, bottom)

  "border": 2,            // border width
  "bordercolor": "white", // border color
  "bordergap": 1,         // space between border and edge of panel
  "borderon": [1,1,1,1],  // which edges have a border (left, top, right, bottom)

  "radius": [12,12,12,12],// corner radius (clockwise starting from top left)
  "rounding": [1,1,1,1],  // whether to round the corners of the panel, or just the border

  "margin": [8,6,8,6],    // margin on each side (left, top, right, bottom)
  "halign": "center",     // horizontal alignment (left, center, right, full)
  "valign": "middle"      // vertical alignment (top, middle, bottom, full)
}

Text

A text element represents one line of text. Multiple lines of text can be rendered by placing multiple text elements, each representing a line, in a ystack, and adding the appropriate spacing between them.

{
  "text": "Tampa",  // line of text to be displayed
  "size": 16,       // capital letter height
  "series": "EM",   // typeface series to use (B ... F, EM, 1B ... 6B, 1W ... 6W, 5WR)
  "color": "white", // color of text (can also specify hex code without #, e.g. "ffc0cb")

  "margin": [8,6,8,6], // same as above
  "halign": "center",
  "valign": "middle"
}

Arrows

{
  "arrow": "A16",   // type of arrow
  "color": "white", // color of arrow
  "angle": 30,      // angle of rotation, clockwise in degrees

  "margin": [8,6,8,6], // same as above
  "halign": "center",
  "valign": "middle"
}

Route Markers

{
  "route": 4,       // route number
  "marker": "2di",  // route marker

  "margin": [8,6,8,6], // same as above
  "halign": "center",
  "valign": "middle"
}

RSM includes a small number of arrows and route markers; you can see a list of them here: arrows, route markers.

Examples

All of these examples were created with scale 1 and exported to PNG format. Try using the debug mode input flag to see how they work.

{
  "backcolor": "blue",
  "padding": [18,3,18,3],
  "xstack": [
    {
      "text": "Eastern",
      "series": "3W",
      "color": "white",
      "size": 16
    },
    {
      "text": "Ave",
      "series": "3W",
      "color": "white",
      "size": 8,
      "valign": "top",
      "margin": [8,0,0,0]
    }
  ]
}
{
  "border": 0.75,
  "bordergap": 0.25,
  "bordercolor": "white",
  "backcolor": "black",
  "radius": [3,3,3,3],
  "ystack": [
    {
      "backcolor": "white",
      "radius": [1,1,1,1],
      "margin": [1,1,1,0],
      "ystack": [
        {
          "text": "MAXIMUM",
          "series": "C",
          "size": 10,
          "color": "black",
          "margin": [3.375,8,3.375,13]
        },
        {
          "text": "80",
          "series": "D",
          "size": 30,
          "color": "black",
          "margin": [0,0,0,10]
        }
      ]
    },
    {
      "text": "km/h",
      "size": 12.5,
      "series": "EM",
      "color": "white",
      "margin": [0,2.75,0,2.75]
    }
  ]
}
{
  "backcolor": "green",
  "border": 2,
  "bordercolor": "white",
  "radius": [12,12,12,12],
  "rounding": [0,0,0,0],
  "padding": [8,6,8,6],
  "ystack": [
    {
      "xstack": [
        {
          "route": 5,
          "marker": "2di",
          "margin": [8,6,8,6]
        },
        {
          "text": "NORTH",
          "size": 12,
          "color": "white",
          "series": "E",
          "valign": "top",
          "margin": [8,6,8,6]
        }
      ]
    },
    {
      "text": "San Jose",
      "size": 16,
      "color": "white",
      "series": "EM",
      "margin": [8,6,8,6]
    }
  ]
}
{
  "ystack": [
    {
      "backcolor": "green",
      "border": 2,
      "bordercolor": "white",
      "borderon": [1,1,1,0],
      "radius": [12,12,0,0],
      "rounding": [0,0,0,0],
      "padding": [6,2,6,2],
      "halign": "right",
      "xstack": [
        {
          "text": "EXIT",
          "size": 12,
          "color": "white",
          "series": "5W",
          "margin": [8,6,8,6]
        },
        {
          "text": "162",
          "size": 16,
          "color": "white",
          "series": "5W",
          "margin": [8,6,8,6]
        }
      ]
    },
    {
      "backcolor": "green",
      "border": 2,
      "bordercolor": "white",
      "radius": [12,0,12,12],
      "rounding": [0,0,0,0],
      "padding": [8,6,8,6],
      "xstack": [
        {
          "ystack": [
            {
              "text": "Jackson Rd",
              "size": 16,
              "color": "white",
              "series": "5W",
              "valign": "top",
              "margin": [8,6,8,6]
            },
            {
              "text": "Old US-12",
              "size": 16,
              "color": "white",
              "series": "5W",
              "valign": "top",
              "margin": [8,6,8,6]
            }
          ]
        },
        {
          "arrow": "A16",
          "color": "white",
          "angle": 30,
          "margin": [8,6,8,6]
        }
      ]
    }
  ]
}
{
  "ystack": [
    {
      "backcolor": "green",
      "padding": [8,6,8,6],
      "border": 2,
      "bordercolor": "white",
      "borderon": [1,1,1,0],
      "radius": [12,12,0,0],
      "rounding": [0,0,0,0],
      "ystack": [
        {
          "xstack": [
            {
              "route": 509,
              "marker": "3dsr",
              "margin": [8,6,8,6]
            },
            {
              "valign": "top",
              "margin": [8,6,8,6],
              "xstack": [
                {
                  "text": "N",
                  "color": "white",
                  "series": "E",
                  "size": 15
                },
                {
                  "text": "ORTH",
                  "color": "white",
                  "series": "E",
                  "size": 12,
                  "valign": "bottom",
                  "margin": [2,0,0,0]
                }
              ]
            }
          ]
        },
        {
          "text": "S 21st Street",
          "color": "white",
          "series": "EM",
          "size": 16,
          "margin": [8,6,8,6]
        },
        {
          "text": "Port of Tacoma",
          "color": "white",
          "series": "EM",
          "size": 16,
          "margin": [8,6,8,6]
        }
      ]
    },
    {
      "backcolor": "yellow",
      "padding": [8,6,8,6],
      "border": 2,
      "bordercolor": "black",
      "borderon": [1,0,1,1],
      "radius": [0,0,12,12],
      "rounding": [0,0,0,0],
      "halign": "full",
      "xstack": [
        {
          "text": "EXIT",
          "size": 12,
          "color": "black",
          "series": "E"
        },
        {
          "arrow": "A16",
          "color": "black",
          "angle": 45,
          "margin": [15,0,12,0]
        },
        {
          "text": "ONLY",
          "size": 12,
          "color": "black",
          "series": "E"
        }
      ]
    }
  ]
}