Skip to content

BPC DSL — Language Specification

The Blueprint Chart format (.bpc) is a declarative text DSL for describing a chart and its scenes. It is parsed by a PEG grammar (Peggy) into an AST and converted at runtime into ChartData + ChartOptions.

The canonical grammar lives in packages/lib/src/dsl/grammar.peggy. This page is the human-readable specification.

Stability

The DSL is AST round-trip safe: parse(source)serialize(ast)parse(...) produces an equivalent AST. The round trip is over the AST, not the source text. Comments are parsed as whitespace and are not preserved through serialize, so a re-serialized document drops any // or /* */ comments the author wrote. Comment attachment is tracked on the roadmap.

A minimal example

bpc
chart line {
  title = "Bitcoin surged past $90,000 in 2024"
  description = "USD, year-end closing price"
  source = "CoinGecko"
  sourceUrl = "https://www.coingecko.com"
  colors = "#f7931a"
  lineSymbols = true
  lineSymbolShowOn = "all"
  lineSymbolShape = "diamond"
  verticalNumberFormat = ",.0f"
  tooltips = true

  annotation "2021" {
    text = "All-time high cycle"
    textOffsetY = -12
    showArrow = true
  }

  data {
    "2016" = 963
    "2017" = 13880
    "2018" = 3742
    "2019" = 7194
    "2020" = 28949
    "2021" = 46306
    "2022" = 16547
    "2023" = 42258
    "2024" = 93429
  }
}

From packages/lib/src/samples/bitcoin-price.bpc

A single-series line chart with a brand color, custom symbol shape, vertical-axis number format, and one point annotation — every feature appears in the same ~30-line block.

Top-level structure

A BPC document is exactly one chart block:

bpc
chart <chartType> {
  <properties>
  <data block>
  <series>
  <colorize / highlight / area-fill / annotation / range / note>
  <scenes>
  <transforms>
}

Where <chartType> is one of the registered chart-type identifiers (line, bar-vertical, bar-horizontal, bar-grouped, bar-stacked, bar-multi, bar-split, column-stacked, area, area-stacked, line-multi, pie, donut). The authoritative list is exported as ChartType from @blueprint-chart/lib.

Lexical grammar

Identifiers

Identifier ← [a-zA-Z_#] [a-zA-Z0-9_#-]*

Used for chart-type names, property keys, and transform names.

Strings

String ← '"' StringChar* '"'

Strings are double-quoted. Supported escapes: \\, \", \n, \t, \r, and \uXXXX (four hex digits, decoded to the matching code point). Any other escape sequence is a parse error.

Numbers

Number  ← '-'? ('.' Digit+ / Digit+ ('.' Digit*)?) ([eE] [+-]? Digit+)?
Percent ← Number '%'

Numbers accept an optional leading minus, a fractional part (including a leading-dot form such as .5), and an optional scientific-notation exponent (1e3, 2.5E-4). A trailing % marks the value as a percentage; the parser preserves isPercentage: true on the AST node so downstream code can distinguish 25 from 25%.

Comments

Two comment forms exist. Line comments start with // and run to end-of-line. Block comments are delimited by /* and */ and may span multiple lines. Both are treated as whitespace and carry no meaning in the AST.

Working with the AST

ts
import { parse, serialize, compactSerialize } from '@blueprint-chart/lib'

const ast = parse(source)        // BPC text → AST
const text = serialize(ast)      // AST → BPC text (pretty)
const tight = compactSerialize(ast) // AST → BPC text (compact)

For any value the grammar accepts, parse(serialize(parse(x))) is structurally equal to parse(x), and the test suite enforces it. The guarantee covers AST structure only: because comments are consumed as whitespace during parsing, serialize cannot reproduce them, so the emitted text will differ from a comment-bearing original.

Stability and versioning

  • parse errors throw SyntaxError with a 1-indexed location (line / column) for tooling.
  • Unknown property keys are preserved on the AST; renderers may ignore them.
  • Unknown top-level statements are a parse error — by design.
  • While Blueprint Chart is pre-1.0, the grammar may change in any release. Every DSL change is called out in the CHANGELOG under a dedicated DSL heading. From 1.0 onward, a breaking grammar change requires a major version bump.

See it in action

Every snippet across these DSL pages is taken verbatim from a runnable sample in packages/lib/src/samples/. The corresponding chart-type pages document the option surface and render live previews:

Feature shownSample fileChart-type page
Minimal example, point annotationbitcoin-price.bpcLine chart
Multi-series data, series meta-rowmedal-count.bpcBar multi
colorize single categoryletter-frequency.bpcBar vertical
Curved-leader annotationtemperature-anomaly.bpcLine chart
Scene-by-scene highlight tourco2-emissions-story.bpcBar horizontal
Scenes overriding chart typefarm-compass.bpcArea stacked
transform sortcoffee-production.bpcBar vertical

Next steps

The rest of the DSL specification is split across three chapter pages:

Released under the MIT License. Built static-first — your data never leaves the page.