Econ Graph Studio

For AI agents & developers

Draw economics diagrams with an API

Send a small JSON spec, get back an SVG and a link that opens the graph in the editor. Free, no key, CORS enabled — built so Claude and other AI agents can make correct IB Economics diagrams for you.

llms.txt

The entry point agents look for. /llms-full.txt adds every template's parameters.

OpenAPI 3.1

Machine-readable description for tools, SDK generators and GPT-style actions.

Claude skill

Download the zip to add it in Claude, or install it in Claude Code with the command below.

Install the skill in Claude Code

mkdir -p ~/.claude/skills/ib-econ-graphs && curl -fsSL __ORIGIN__/skill/SKILL.md -o ~/.claude/skills/ib-econ-graphs/SKILL.md

On claude.ai, upload ib-econ-graphs.zip in your Skills settings. Or simply tell any agent: “Read __ORIGIN__/llms.txt and draw me a tariff diagram.”

Create IB Economics diagrams (SL and HL) from JSON. The API returns a crisp SVG plus an edit link that opens the exact same graph in the web editor, where a person can adjust it and export PNG, SVG or PDF.

Quick start

# 1. Find a template (or browse the index at the end of this guide)
curl -s "__ORIGIN__/api/v1/templates?q=tariff"

# 2. Read its schema: params (types, options, ranges, defaults) and label keys
curl -s "__ORIGIN__/api/v1/templates/tariff"

# 3. Render it
curl -s "__ORIGIN__/api/v1/render" \
  -H "content-type: application/json" \
  -d '{"template":"tariff","params":{"lettering":"letters"},"title":"Figure 1: Effect of a tariff on steel imports","labels":{"main.d":"D_{steel}"},"style":{"palette":"color","areaLabels":"inside"}}'

The render response is JSON:

{
  "template": { "id": "tariff", "name": "Tariff" },
  "svg": "<?xml …><svg …>…</svg>",
  "width": 590, "height": 520,
  "editUrl": "__ORIGIN__/graph/tariff/#g=…",
  "svgUrl": "__ORIGIN__/api/v1/render.svg?spec=…",
  "labels": [{ "key": "main.d", "text": "D_{steel}", "hint": "Curve", "panel": "main" }],
  "stats": null,
  "warnings": []
}

For the image only, ask for SVG directly: POST /api/v1/render?format=svg or POST /api/v1/render.svg.

One-line GET form

Every param can go in the query string, which makes embeddable image URLs easy:

__ORIGIN__/api/v1/render/market-equilibrium.svg?pointLabel=true&style.palette=mono&title=Figure%201
__ORIGIN__/api/v1/render/demand-shift.svg?dir=dec&shift=2.5&label.d1=D_1
__ORIGIN__/api/v1/render/tariff.json?lettering=letters

Reserved query keys: title, style.<option>, label.<key>, hide=<key>,<key>, fonts=embed. Everything else is a template param. For the full spec in a GET request, use /api/v1/render.svg?spec=<URL-encoded JSON>.

Recommended workflow for AI agents

  1. Choose a template from the index below (or GET /api/v1/templates?q=<words>). Prefer a specific template over blank-axes: templates compute intersections, welfare areas and cost curves correctly.
  2. Read the schema (GET /api/v1/templates/{id}) to learn its params and labels keys. Labels depend on params (toggles add elements), so the render response also lists the labels actually drawn.
  3. Render with POST /api/v1/render. Check warnings.
  4. Deliver: share editUrl with the person (best: they can fine-tune and export), and/or save the SVG.
  5. Need a PNG? The API returns SVG only. Convert locally (rsvg-convert -z 3 in.svg -o out.png, cairosvg, Inkscape, or a headless browser), or let the person open editUrl and use Export → PNG.

IB conventions worth following: label every curve (D, S, MSC, AD, SRAS…), label both axes, use subscripts for moved equilibria (P₁ → P₂), and give each figure a numbered title ("title": "Figure 1: …").

Endpoints

Method Path Returns
GET /api/v1 API index and links
GET /api/v1/templates All templates. Filters: ?q=words, `?unit=intro
GET /api/v1/templates/{id} One template's schema: params, defaults, panels, label keys, element keys, example
POST /api/v1/render Render a graph spec. ?format=json (default) or svg; also /render.svg, /render.json
GET /api/v1/render.svg?spec=… Render a spec passed in the URL (JSON, base64url JSON, or the value inside a returned svgUrl)
GET /api/v1/render/{id}.svg Render from query params (.json also works)
GET /openapi.json OpenAPI 3.1 description
GET /llms-full.txt This guide plus every template's full parameter reference
GET /skill/SKILL.md A Claude skill for this API (/skill/ib-econ-graphs.zip to upload)

Graph spec

{
  "template": "tariff",               // required — a template id
  "params": { "lettering": "letters" }, // template options; see the template's schema
  "title": "Figure 1: …",             // optional; shown above the graph when set
  "labels": { "main.d": "D_{steel}" }, // replace any label's text by key
  "hidden": ["main.q3:x"],            // hide elements or labels by key
  "colors": { "main.s": "#008300" },  // recolour curves, areas, arrows, points
  "dashed": { "main.s": true },       // dash a curve or arrow
  "offsets": { "main.d": [8, -6] },   // nudge a label by [dx, dy] pixels
  "annotations": [ … ],               // draw extra lines, points, shading, arrows, text
  "style": { "palette": "mono" },     // look and feel, see below
  "format": "json",                   // "json" (default) or "svg"
  "embedFonts": false                 // true = embed the web font in the SVG (bigger file)
}

Keys for labels, hidden, colors, dashed and offsets

Keys come from the template schema (labels[].key and elements[].key):

In single-panel diagrams the panel prefix is optional: "d1" means "main.d1". Multi-panel templates (e.g. perfect-competition-short-run has industry and firm) need the full key.

Label text

Plain text with a tiny markup: P_1 → P₁, P_{max} → P with subscript "max", x^2 → superscript, \n → new line. Example: "S_1 = MPC", "P_{w} + t".

Annotations (draw anything)

Coordinates are data coordinates of the panel: by default x and y both run 0–10 with the origin at the bottom-left (each panel's xRange/yRange is in the schema; Lorenz curves use 0–100).

kind fields
line / curve points: 2 points = straight line, 3+ = smooth curve through them; label; role (colour: demand, supply, social, mc, mr, atc, avc, afc, long-run, policy, world, neutral); dashed
point at; label; xLabel / yLabel draw dashed guides to the axes with those labels
area / shading points (polygon, 3+); role: cs, ps, dwl, gov, profit, loss, gain, cost, neutral; label
arrow from, to; label
text at, text

All kinds accept panel (default: the first panel) and color (#rrggbb). Up to 100 annotations.

Custom diagrams

For a diagram with no template, use blank-axes (params.axes: pq, macro, firm, labour, money, fx, phillips, ppc, time; params.numeric: true with xMax/yMax for a numbered scale) and draw it with annotations:

{
  "template": "blank-axes",
  "params": {
    "axes": "pq"
  },
  "title": "Figure 2: A subsidy on electric cars",
  "annotations": [
    {
      "kind": "line",
      "points": [
        [
          0,
          9
        ],
        [
          9,
          1.5
        ]
      ],
      "label": "D",
      "role": "demand"
    },
    {
      "kind": "line",
      "points": [
        [
          0,
          1.5
        ],
        [
          9,
          8.5
        ]
      ],
      "label": "S_1",
      "role": "supply"
    },
    {
      "kind": "line",
      "points": [
        [
          0,
          0.5
        ],
        [
          9,
          7.5
        ]
      ],
      "label": "S_2 = S_1 − subsidy",
      "role": "supply",
      "dashed": true
    },
    {
      "kind": "point",
      "at": [
        4.66,
        5.12
      ],
      "xLabel": "Q_1",
      "yLabel": "P_1"
    },
    {
      "kind": "point",
      "at": [
        5.28,
        4.6
      ],
      "xLabel": "Q_2",
      "yLabel": "P_2"
    },
    {
      "kind": "arrow",
      "from": [
        7.5,
        7.21
      ],
      "to": [
        7.5,
        6.45
      ],
      "label": "subsidy"
    },
    {
      "kind": "area",
      "points": [
        [
          0,
          9
        ],
        [
          0,
          5.12
        ],
        [
          4.66,
          5.12
        ]
      ],
      "role": "cs",
      "label": "CS"
    }
  ]
}

Compute intersection coordinates yourself so points and guides land exactly on the crossing.

Style

option values (default first)
palette color, classic (black curves, coloured shading), mono (black and white, hatched areas — for printing)
font sans, serif, hand
fontScale 1 (0.6–2)
strokeScale 1 (0.5–3)
areaLabels inside, legend, both, none
axisLabels end (textbook), center
areaOpacity 0.3 (0.05–1)
background white, transparent
showTitle false (true automatically when title is given)
axisArrows, showOrigin, dots false, true, true

Errors

Errors are JSON with an HTTP status: { "error": { "code": "unknown_template", "message": "No template \"tarrif\". Did you mean: tariff, …?", "suggestions": [ … ] } }. Invalid enum values list the allowed options. Problems that can be worked around (unknown params or keys, out-of-range numbers) are returned as warnings instead of errors.

Limits

Request bodies up to 100 KB, text fields up to 200 characters, 100 annotations. The service is free; please cache results and avoid bulk generation.

Template index

Unit 1 · Introduction to economics

Production possibilities

Unit 2 · Microeconomics

Demand & supply

Elasticity

Government intervention

Linear functions (HL)

Market failure

Costs & revenues (HL)

Perfect competition (HL)

Monopoly (HL)

Imperfect competition (HL)

Unit 3 · Macroeconomics

Economic activity

AD/AS model

Inflation & deflation

Unemployment

Phillips curve (HL)

Monetary & fiscal policy

Supply-side policies & growth

Inequality

Unit 4 · The global economy

International trade

Trade protection

Exchange rates

Balance of payments

Build your own

Build your own