Skip to content

feat: charts and shape primitives + XML parser (full design, 5 phases)#11

Merged
RoboNET merged 119 commits into
mainfrom
feature/charts-and-shapes
Jun 14, 2026
Merged

feat: charts and shape primitives + XML parser (full design, 5 phases)#11
RoboNET merged 119 commits into
mainfrom
feature/charts-and-shapes

Conversation

@RoboNET

@RoboNET RoboNET commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Implements the complete charts-and-shapes design — all 5 phases — so LLM agents can generate polished graphics and charts from declarative templates without hand-written SVG.

Design spec: docs/superpowers/specs/2026-06-12-charts-and-shapes-design.md. Each phase has its own TDD plan under docs/superpowers/plans/.

Phase 1 — Shape primitives

  • Box shapes rect/circle/ellipse (fill/gradient/stroke/opacity, rect radius, circle size shorthand).
  • Gradient fill object ({gradient: linear|radial, colors, angle}) → reuses the existing CSS gradient renderer.
  • draw element — free-form absolute-coordinate shapes: line, polyline, rect, circle, path (M/L/Q/C/Z, hand-written AOT-safe tokenizer, no regex). ResourceLimits.MaxShapesPerDraw.

Phase 2 — Charts base

  • chart element: bar (vertical/horizontal/stacked), line/area (smooth curves, point markers), pie/donut (slice % / value labels).
  • Themes (light/dark/minimal) + palettes (ocean/sunset/forest/mono/vivid or explicit colors) — beautiful by default, zero styling decisions required.
  • Nice-tick axis math, grid, legend, title, "no data" placeholder. Series data binds from the data context like table rows (data: "{{ sales }}").

Phase 3 — Charts extension

  • scatter/bubble ([x,y] / [x,y,r] tuple data, X+Y axis scaling, radius-normalized bubbles), gauge (270° dial), progress (ring), sparkline (chrome-free inline line).

Phase 4 — Charts advanced

  • heatmap (2D grid, value→color scale, x/y labels, cell values), radar (category spokes, per-series filled polygons, concentric rings).

Phase 5 — FlexRender.Xml

  • New package: an alternative XML template syntax producing the same AST as YAML (LLMs emit XML attributes more reliably than YAML indentation). XmlTemplateParser translates XML → the shared ParseDocumentRoot, reusing all element/chart/shape parsing, KnownProperties validation + typo suggestions, and resource limits. RenderXml extension. Docs: docs/wiki/Xml-Syntax.md.

Quality

  • 3303 tests, 0 failures; build 0 errors. ~250 new tests + golden snapshots for every shape and chart type (visually verified).
  • AOT-safe throughout (no reflection/dynamic/runtime-regex; XDocument not XmlSerializer). Sealed classes, ArgumentNullException.ThrowIfNull, switch-based dispatch, XML docs on public API.
  • Hardened for untrusted LLM input: non-finite/non-numeric/over-limit data rejected on both inline and data-bound paths; tuple arity validated; degenerate geometry (empty series, single point, <3 radar categories, identical min/max) never crashes/NaNs/divides-by-zero; malformed XML and malformed <else-if> rejected with clear errors.
  • Resource limits added (MaxShapesPerDraw, MaxSeriesPerChart, MaxDataPointsPerSeries), never weakened.
  • A final holistic cross-cutting review gated merge on one real defect (data-bound series bypassing MaxDataPointsPerSeries), now fixed.

Docs

llms.txt, llms-full.txt, wiki Element-Reference/Visual-Reference/Xml-Syntax (with rendered examples under examples/visual-docs/), Playground JSON schema + autocomplete, AGENTS.md package structure.

Follow-ups (tracked in the phase plans)

  • Update flexrender/skills/template/SKILL.md in RoboNET/FlexRender-Marketplace.
  • Inner draw-shape & chart-series property typo validation; expression-bound scatter/bubble tuple data; MaxPathCommands as a configurable limit.

🤖 Generated with Claude Code

RoboNET added 30 commits June 12, 2026 13:48
@RoboNET RoboNET changed the title feat: shape primitives (rect, circle, ellipse, draw) — Phase 1 feat: charts and shape primitives + XML parser (full design, 5 phases) Jun 13, 2026
RoboNET added 9 commits June 14, 2026 06:55
…pped

ComputePlotArea now accepts a topGutter parameter reserved at the top of
the plot regardless of whether a title is present. The topmost y-axis tick
label is drawn centered at plot.Top, so with no top headroom its upper half
was clipped against the chart box top edge; the tallest bar/line point hit
the same edge. Axis-based renderers (bars, line/area, scatter/bubble) now
pass topGutter = theme.LabelSize * 0.6f to clear half the top tick label.

Regenerated affected chart goldens and their visual-docs mirror copies.
@RoboNET

RoboNET commented Jun 14, 2026

Copy link
Copy Markdown
Owner Author

Follow-up refactor: decouple FlexRender.Xml from FlexRender.Yaml

Per review feedback ("why does the XML parser depend on YAML? they should be independent"), FlexRender.Xml now depends only on FlexRender.Core — no FlexRender.Yaml, no YamlDotNet.

What changed (6 commits, 58cc825..202244e):

  • New format-neutral node model in Core: TemplateMapping / TemplateSequence / TemplateScalar (FlexRender.Parsing.Nodes, zero external deps).
  • The shared parsing engine moved into Core (Parsing/Engine/): TemplateEngine.ParseDocumentRoot(TemplateMapping) + ElementParsers, ChartParsers, ShapeParsers, KnownProperties, NodePropertyHelpers — retyped from the YamlDotNet DOM onto the neutral model.
  • FlexRender.Yaml is now a thin facade: YamlDotNet → YamlNodeConverter → Core engine. Public API (TemplateParser) unchanged.
  • FlexRender.Xml converts XDocumentXmlNodeConverter → the same Core engine. Dropped the FlexRender.Yaml project reference and the old XmlToYamlNodeConverter.
  • Dropped the now-unneeded InternalsVisibleTo("FlexRender.Xml") from Yaml; updated AGENTS.md + llms.txt.

Result: both format packages share one engine in Core and neither depends on the other. YamlDotNet stays confined to FlexRender.Yaml.

Verification: full suite green on net10.0 — 3311 passed, 0 failed (3060 main + 164 ImageSharp + 87 CLI). Build clean (0 errors). XML produces the identical Template AST as before (XmlYamlEquivalence tests pass).

@RoboNET RoboNET merged commit f9d8c81 into main Jun 14, 2026
4 checks passed
@RoboNET RoboNET deleted the feature/charts-and-shapes branch June 14, 2026 05:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant