Road Sign MathGet the app

Feeds and data

Every sign on Road Sign Math is open to read. Follow new signs in a feed reader, or build something with them: a map, a quiz, a bot, a mashup. No key, no sign-up.

Feeds

The newest 50 signs, each with its photos, the math, who found it, when and where, and any other ways to make it true. Paste the address into any feed reader.

A sign’s item is dated when it was posted and updated when someone adds a way. Readers find the feeds on their own from any page here.

Every sign

https://roadsignmath.xyz/signs.json has every sign on the map, newest posted first, with everything its page shows. It opens from any web page: it is served with Access-Control-Allow-Origin: *.

const res = await fetch('https://roadsignmath.xyz/signs.json');
const { signs } = await res.json();
for (const sign of signs) {
  console.log(sign.title, sign.ways[0]?.text ?? 'not solved yet');
}

The file

Each of the three files starts with the same fields, then its list: signs, players or features.

FieldWhat it is
versionnumberThe file’s format, now 1. New fields can appear without it changing; it goes up if a field is renamed, removed or changes meaning.
titlestringThe file’s name.
descriptionstringWhat is in it.
home_page_urlstringThe site.
urlstringThe file itself.
docs_urlstringThis page.
license.namestringThe licence for everything in the file, photos too: CC BY 4.0.
license.urlstringThe licence’s text.
license.creditstringHow to give credit.
updatedstring or nullThe newest change to any sign: a post or a way, as a UTC time.
counts.signsnumberShown signs.
counts.playersnumberPlayers with a page: a name, and a sign or a badge on the map.
counts.statesnumberUS states with a sign.
counts.waysnumberWays to make the signs true, on all of them.

A sign

FieldWhat it is
idstringThe sign’s id. Never changes.
slugstringIts name in its address, /signs/<slug>. Never changes.
urlstringIts page.
titlestringIts title, as the poster wrote it.
captionstring or nullWhat the poster wrote about it.
found_onstringThe day it was found, YYYY-MM-DD, in the finder’s own time. A day, not a moment.
posted_atstringWhen it was posted, as a UTC time.
updated_atstringWhen it last changed: when it was posted, or its newest way.
posted_bystring or nullThe handle of the player who posted it.
place.labelstringWhere it was, in words: “I-35W northbound, Bloomington, Minnesota”.
place.statestring or nullThe two-letter US state, when known.
place.latnumber or nullLatitude. Null when nobody knows where it was.
place.lngnumber or nullLongitude. Null when nobody knows where it was.
place.approximatebooleanTrue when the point is only as good as a town or a state. Most are.
numbers[].valuestringA number on the sign as a plain decimal: “90”, “1.5”.
numbers[].textstring or nullWhat it was read from: “90th St”, “EXIT 7B”.
numbers[].whystring or nullWhy the value differs from the text: “Letters dropped”.
numbers[].boxarray or nullWhere it is on the first photo, [x, y, width, height] as fractions of the photo, from the top left.
finders[].namestringWho found it.
finders[].handlestring or nullTheir handle, when they play. Null for someone named who doesn’t.
finders[].urlstring or nullTheir page, when they have one.
finders[].rolestringfound, took_photo or spotted.
way_countnumberHow many ways there are.
ways[].textstringThe math as plain text, as the app’s checker writes it: “√(5 − 1) = 2”.
ways[].texstring or nullThe same math as LaTeX, as the site draws it (÷ is a stacked fraction).
ways[].valuestringWhat both sides come to.
ways[].numbersarray of stringsThe sign’s numbers the way used, in reading order.
ways[].byobject or nullWho found the way: handle, name and url (their page, or null).
ways[].created_atstringWhen it was added, as a UTC time. Ways are oldest first; the first is the one on the sign’s plate.
photos[].idstringThe photo’s id. Never changes.
photos[].widthnumberIts width in pixels, at the large size.
photos[].heightnumberIts height in pixels, at the large size.
photos[].altstringWhat the photo shows, in words.
photos[].urlstringThe photo, 1600 pixels on the long side, as a JPEG with no camera details or location.
photos[].thumb_urlstringThe same photo 480 pixels on the long side.

An example

The newest sign, cut to two of its numbers, its first way and one photo:

{
  "id": "01K43VJQP8H8787XQXQDW47W0B",
  "slug": "i-35w-at-82nd-street",
  "url": "https://roadsignmath.xyz/signs/i-35w-at-82nd-street",
  "title": "I-35W at 82nd Street",
  "caption": "Tyler found this one driving up I-35W.",
  "found_on": "2025-09-01",
  "posted_at": "2025-09-02T00:00:13.000Z",
  "updated_at": "2025-09-02T00:00:13.000Z",
  "posted_by": "jamie",
  "place": {
    "label": "I-35W at 82nd Street, Bloomington, Minnesota",
    "state": "MN",
    "lat": 44.857,
    "lng": -93.29,
    "approximate": true
  },
  "numbers": [
    {
      "value": "2",
      "text": "HOV 2+",
      "why": "Read as 2",
      "box": null
    },
    {
      "value": "6",
      "text": "6AM-10AM",
      "why": "Times split in two",
      "box": null
    }
  ],
  "finders": [
    {
      "name": "Tyler",
      "handle": "tyler",
      "url": "https://roadsignmath.xyz/players/tyler",
      "role": "found"
    }
  ],
  "way_count": 1,
  "ways": [
    {
      "text": "(90 − 82) ÷ 8 × 1 × 2 = 6 ÷ (10 − 7)",
      "tex": "\\frac{90 - 82}{8} \\times 1 \\times 2 = \\frac{6}{10 - 7}",
      "value": "2",
      "numbers": [
        "90",
        "82",
        "8",
        "1",
        "2",
        "6",
        "10",
        "7"
      ],
      "by": {
        "handle": "tyler",
        "name": "Tyler",
        "url": "https://roadsignmath.xyz/players/tyler"
      },
      "created_at": "2025-09-02T00:00:13.000Z"
    }
  ],
  "photos": [
    {
      "id": "01k43vjqp8x8n82dwwwbbwgwhp",
      "width": 1600,
      "height": 1201,
      "alt": "Overhead signs on I-35W: Express Lane (E-ZPass or HOV 2+ only, 6AM-10AM Mon-Fri), Exit 8 82nd St 1 mile, and Exit 7B 90th St.",
      "url": "https://roadsignmath.xyz/p/01k43vjqp8x8n82dwwwbbwgwhp/large.jpg",
      "thumb_url": "https://roadsignmath.xyz/p/01k43vjqp8x8n82dwwwbbwgwhp/thumb.jpg"
    }
  ]
}

Players

https://roadsignmath.xyz/players.json has everyone with a sign or a badge on the map, most signs first: what their page shows, and never an email address.

FieldWhat it is
handlestringTheir handle. Never changes.
namestringTheir name.
urlstringTheir page.
feed_urlstringTheir JSON Feed; feed.xml beside it is Atom.
biostring or nullWhat they wrote about themselves.
avatar_colorstringThe colour behind their first letter when they have no photo.
avatar_urlstring or nullTheir profile photo, 512 pixels square.
avatar_thumb_urlstring or nullThe same, 160 pixels square.
sign_countnumberSigns they are a finder on.
way_countnumberWays they found, on anyone’s signs.
statesarray of stringsThe states of their signs, as two-letter codes.
first_yearnumber or nullThe year of their first sign.
signsarray of stringsThe slugs of their signs, newest first.
badges[].idstringA badge they earned. There are no points; badges are little road signs for what happened on the road.
badges[].shelfstringfirsts, places, math, seasons or secret.
badges[].namestringIts name.
badges[].howstringHow it is earned.
badges[].markstringWhat its little sign shows; for a stepped badge, the step reached.
badges[].earned_onstringThe day it was earned, YYYY-MM-DD.
badges[].signstringThe slug of the sign that earned it.

On a map

https://roadsignmath.xyz/signs.geojson is a GeoJSON FeatureCollection with a point for every sign that has a place, ready for Leaflet, MapLibre, QGIS or geojson.io. Most points are the town, not the exact spot. A sign nobody can place is left out; it is still in signs.json, with null coordinates.

FieldWhat it is
idstringThe sign’s id.
geometry.coordinatesarray[longitude, latitude], in that order, as GeoJSON has it.
properties.slugstringIts name in its address.
properties.titlestringIts title.
properties.urlstringIts page.
properties.found_onstringThe day it was found, YYYY-MM-DD.
properties.placestringWhere it was, in words.
properties.statestring or nullThe two-letter US state.
properties.approximatebooleanTrue when the point is the town, not the exact spot.
properties.mathstring or nullThe first way, as plain text. Null when nobody has solved it.
properties.way_countnumberHow many ways there are.
properties.findersstringWho found it, names separated by commas.
properties.photo_urlstring or nullThe first photo, large.
properties.thumb_urlstring or nullThe first photo, small.

The API

The iPhone app reads and posts through the API at https://roadsignmath.xyz/api/v1, version 1.7.0. These reads are public, JSON with snake_case keys. Its full description is OpenAPI 3.1 at /api/v1/openapi.json. Signing in and posting are for the app. The API is for apps and servers; from a web page, use the files above, which any site can fetch.

For agents

Using it