Repository navigation
Migrate the remaining 294 MUI X implementations to MUI X 9 in three chunks #12296
Description
Goal
Migrate the remaining 294 MUI X implementations of the catalogue from the MUI X 7 API to MUI X 9.16 (React 19, Material 9.5), restructure each to the adaptable-code convention, and hand them over so that the pipeline's Opus review finds no defect line, on a gemini/* branch in three chunks of 98 specs. After every hand-over Claude reviews the chunk and feeds it through the pipeline's adopt mode (render, Opus review, repair, merge) from the handed-over commit, while you continue with the next chunk. Nothing from this branch is merged directly.
Context
- The first batch of 20 files (Migrate 20 MUI X implementations to MUI X 9 and the adaptable-code convention #12267, draft feat(muix): migrate batch 1 (20 specs) to MUI X 9 and adaptable-code convention #12275, pipeline PRs feat(muix): implement alluvial-basic #12276–feat(muix): implement scatter-annotated #12295) measured the route: every file bundled and rendered, the Opus review scored them 77–89 at first sight, and 19 of 20 went through a repair round. What sent them to repair was not the design level: a review merges without repair when it scores 80 or more, names no defect line, and has every one of the 19 technical items (VQ, SC, DQ, CQ) at its maximum (
docs/workflows/overview.md, "Nothing to repair"). The first batch lost that on small things: text under 13 px inside marks, helper functions and components outside the default export, dead branches, abstract names such as "Model A", a truncated label, marks nudged off their coordinates, chrome drawn in a palette colour. The checklist under Constraints turns every one of those into a rule; it is the primary deliverable. The design and library levels (DE-01 to DE-03, LM-02) start at their defaults and are a bonus, see "Design level" under Constraints. - An independent review of the first batch also found 12 defects of the adaptable-code convention; they are in the checklist as well.
- The render stack moved to MUI X 9.16 in deps(js): bump MUI X Charts to 9.16 with React 19 and Material 9.5 #12243. Of the 323
muix.tsxfiles, 164 no longer bundle (the@mui/x-charts/ChartContainerpath is gone), 157 render differently (legendhiddenprop, v7 legend position and styling, v7 axis and font-size props, removed CSS classes; 67 with a blank axis). The per-spec measurement is in the first batch's issue (gh issue view 12267 --json title,body). - Worked examples of the target shape on
origin/mainaftergit fetch origin:plots/area-basic/implementations/javascript/muix.tsx,plots/alluvial-basic/…,plots/hexbin-basic/…,plots/recurrence-basic/…,plots/genome-track-multi/…,plots/calibration-beer-lambert/…. Do not copy the header ofgauge-basicorconfusion-matrixon main: both still carry a stale second header block below line 5, a pipeline defect that is being fixed separately. - The rules:
prompts/library/muix.md(section "MUI X v9 API — the pinned version" lists every API change; "The harness contract"; "Data block"; "When MUI X can't express the spec"; "Forbidden patterns"),prompts/adaptable-code.md(the JavaScript form: one record array as the data block, role constants, plot code that reads only the constants; the "Data shapes" section decides table, matrix, network or generated per spec),prompts/plot-generator.mdandprompts/default-style-guide.md(canvas, palette, imprint, sizing in CSS px, animation off, "Ordered Categories"), andprompts/quality-criteria.md(what the review scores; read VQ-01, VQ-07, SC-01 "Variant creep", SC-02, SC-03, DQ-02, CQ-01, CQ-04, DE-03, LM-02). - Each spec lives in
plots/<spec>/specification.md; its current implementation isplots/<spec>/implementations/javascript/muix.tsx. - The harness renders a file locally without credentials, from the repository root:
ANYPLOT_THEME=light node automation/js-render/render.mjs plots/<spec>/implementations/javascript/muix.tsxand the same withANYPLOT_THEME=dark. It writesplot-light.png/plot-light.html(ordark) into the current directory, not next to the file. Node 24 and the rootpackage.jsondependencies are needed (npm ciat the repository root,npx playwright install chromium); your clone has them from the first batch. - The canvas check:
PYTHON_DOTENV_DISABLED=1 uv run python -c "from core.canvas import check_png; print(check_png('plot-light.png', 'muix'))"must report the target size for both themes (3200×1800, or 2400×2400 for a square spec). - Claude never pushes to your branch during this task. Its fixes for a chunk go to a separate ref, and the pipeline takes each chunk from the commit SHA you name in the hand-over, so you keep committing while a chunk runs. At the start of a later session,
git statusandgit log origin/main..HEADtell you where you stopped; no pull, no merge, no rebase, even when GitHub marks the draft PR as conflicting (chunks that merged to main rewrite the headers, and that conflict is expected).
Steps
-
git fetch origin, render one already migrated file in both themes to confirm the local setup still works (for exampleplots/hexbin-basic/implementations/javascript/muix.tsx), thengit switch -c gemini/<this issue number>-muix-9-remaining origin/main. - Chunk 1, first ten specs: one commit per spec (
feat(muix): migrate <spec> to MUI X 9): read the specification and the current file, port the API to MUI X 9, restructure to the convention, apply the checklist, render both themes, run the canvas check, look at both PNGs (axes, ticks, legend, labels and imprint visible and inside the canvas, no blank axis, no cropped bottom, text readable at thumbnail size). After the tenth spec hand over: push, open the draft PR with the table for these ten and the hand-over commit SHA, and tell the owner "chunk 1a handed over at ". This early hand-over lets Claude catch a systematic misreading before 284 more files repeat it. Continue with the rest of chunk 1 right away. - Chunk 1, remaining 88 specs; hand over by pushing and updating the PR body (
gh api -X PATCH, see the hand-over format) with the table and the SHA; tell the owner "chunk 1 handed over at ". - Chunk 2, the same.
- Chunk 3, the same.
The chunks, in order:
Chunk 1 (98 specs): alluvial-opinion-flow, arc-basic, bar-3d-categorical, bar-error, bar-pareto, bar-permutation-importance, bifurcation-basic, biplot-pca, box-basic, box-grouped, box-horizontal, box-notched, boxen-basic, bubble-basic, bubble-packed, campbell-basic, candlestick-basic, candlestick-volume, cat-box-strip, chernoff-basic, chessboard-basic, chord-basic, circlepacking-basic, circos-basic, climograph-walter-lieth, coefficient-confidence, column-stratigraphic, contour-filled, contour-map-geographic, curve-dose-response, dendrogram-basic, dendrogram-radial, diagnostic-regression-panel, dot-matrix-proportional, dumbbell-basic, energy-level-atomic, errorbar-asymmetric, errorbar-basic, facet-grid, feynman-basic, flamegraph-basic, flowmap-origin-destination, forest-basic, frontier-efficient, funnel-basic, heatmap-annotated, heatmap-basic, heatmap-chromagram, heatmap-clustered, heatmap-cohort-retention, heatmap-loss-triangle, heatmap-mandelbrot, heatmap-polar, heatmap-risk-matrix, histogram-capability, histogram-density, histogram-epidemic, histogram-kde, histogram-returns-distribution, hive-basic, icicle-basic, indicator-ichimoku, indicator-macd, indicator-rsi, lightcurve-transit, line-3d-trajectory, line-growth-percentile, line-reaction-coordinate, line-tanabe-sugano, line-training-load-pmc, logistic-regression, lollipop-basic, lollipop-grouped, ma-differential-expression, map-connection-lines, map-projections, map-route-path, marimekko-basic, mohr-circle, network-basic, network-bipartite, network-directed, network-force-directed, network-hierarchical, network-transport-static, network-weighted, ohlc-bar, parallel-basic, parallel-categories-basic, parliament-basic, piano-roll-midi, point-and-figure-basic, point-basic, polar-bar, polar-basic, polar-line, polar-scatter, probability-weibull
Chunk 2 (98 specs): qq-basic, qrcode-basic, quiver-basic, radar-basic, radar-innovation-timeline, radar-multi, raincloud-basic, renko-basic, ridgeline-basic, rug-basic, sankey-basic, scatter-3d, scatter-ashby-material, scatter-basic, scatter-complex-plane, scatter-embedding, scatter-lag, scatter-pitch-events, scatter-regression-linear, scatter-regression-lowess, scatter-regression-polynomial, scatter-shot-chart, skewt-logp-atmospheric, smith-chart-basic, sn-curve-basic, spc-xbar-r, spectrogram-basic, spectrogram-mel, spiral-timeseries, star-chart-constellation, stem-basic, stereonet-equal-area, streamline-basic, strip-basic, surface-basic, swarm-basic, ternary-basic, tree-decision, tree-phylogenetic, treemap-basic, venn-basic, venn-labeled-items, violin-box, violin-grouped-swarm, violin-split, violin-swarm, voronoi-basic, waffle-basic, waterfall-basic, windbarb-basic, windrose-basic, wireframe-3d-basic, area-cumulative-flow, area-elevation-profile, audiogram-clinical, band-basic, bar-diverging, bar-diverging-likert, bar-feature-importance, barcode-ean13, bland-altman-basic, bubble-map-geographic, bump-basic, chessboard-pieces, contour-3d, contour-basic, contour-decision-boundary, contour-density, density-basic, density-rug, ecdf-basic, elbow-curve, funnel-meta-analysis, gain-curve, heatmap-geographic, heatmap-rainflow, histogram-2d, histogram-cumulative, histogram-stepwise, indicator-bollinger, indicator-ema, indicator-sma, line-annotated-events, line-arrhenius, line-basic, line-confidence, line-multi, line-pca-variance-cumulative, line-stock-comparison, line-stress-strain, line-timeseries-rolling, pdp-basic, phase-diagram-pt, psychrometric-basic, pyramid-basic, range-interval, residual-plot, roc-curve
Chunk 3 (98 specs): root-locus-basic, scatter-categorical, scatter-connected-temporal, scatter-constellation-diagram, scatter-hr-diagram, scatter-map-geographic, shap-summary, silhouette-basic, span-basic, spectrum-basic, spectrum-nmr, spirometry-flow-volume, step-basic, titration-curve, waveform-audio, andrews-curves, area-mountain-panorama, area-stacked-confidence, area-stacked-percent, bar-grouped, bar-heart-rate-zones, bar-horizontal, bar-spine, bar-stacked, bar-stacked-labeled, bar-stacked-percent, bar-tornado-sensitivity, barcode-code128, bode-basic, bullet-basic, burndown-sprint, cartogram-area-distortion, count-basic, crossword-basic, curve-bias-variance-tradeoff, curve-oc, curve-power-duration, dashboard-metrics-tiles, depth-order-book, donut-basic, donut-nested, drawdown-basic, ecg-twelve-lead, eye-diagram-basic, frequency-polygon-basic, gantt-basic, gantt-dependencies, heatmap-adjacency, heatmap-calendar, heatmap-correlation, heatmap-stripes-climate, hexbin-map-geographic, histogram-basic, histogram-overlapping, histogram-stacked, ice-basic, kagi-basic, ks-test-comparison, lift-curve, line-cycle-seasonal, line-filled, line-impurity-comparison, line-load-duration, line-markers, line-parametric, line-retention-cohort, line-timeseries, line-win-probability, line-yield-curve, manhattan-gwas, map-tilegrid, maze-circular, maze-printable, mosaic-categorical, nyquist-basic, pictogram-basic, pp-basic, precision-recall, rose-basic, scatter-marginal, scatter-matrix, scatter-text, shap-waterfall, slope-basic, sparkline-basic, stock-event-flags, streamgraph-basic, subplot-grid, subplot-mosaic, sudoku-basic, sunburst-basic, swimmer-clinical-timeline, timeline-basic, timeseries-decomposition, timeseries-forecast-uncertainty, upset-basic, volcano-basic, wordcloud-basic
Constraints
- Change only the 294 files
plots/<spec>/implementations/javascript/muix.tsxnamed above. No metadata files, no PNGs or HTML committed (rm -f plot-light.png plot-dark.png plot-light.html plot-dark.htmlin the repository root before each commit; stage only the one.tsxfile;git statusmust show nothing else), no other plots, no prompts, no workflows, no changelog fragment (catalogue-only changes are exempt). - Header. Exactly one header block of four
//lines at the top of the file (// anyplot.ai, the spec line, theLibrary:line, theQuality:line); keep itsQuality:andUpdated:/Created:values as they are, the pipeline rewrites them. For a square spec the directive//# anyplot-orientation: squaregoes on line 5, directly below the header, not on line 1: the pipeline's header writer replaces the leading//block and stops at a//#line, and a directive on line 1 makes it prepend a second header (the stale-header defect you see on 131 of these files). Remove every stale second header block. A landscape spec needs no directive. - Frozen after hand-over. Once a chunk is handed over, its files are frozen on your branch: the pipeline took them from that SHA. A later fix for one of them is a note in the next table, never a commit.
- Keep each file self-contained the way the harness contract requires: a default-exported React component, no manual mount, no network, no animation (
skipAnimationon every chart component and onChartsContainer), sizes fromwindow.ANYPLOT_SIZE, colours fromwindow.ANYPLOT_TOKENS(t.palette,t.ink,t.inkSoft,t.pageBg,t.elevatedBg,t.grid,t.amber,t.seq,t.div; there is not.muted). - The scenario and the chart type of the old file stay: same plot type, same story, same data unless it violates the convention, the spec, or the checklist. This is a migration plus a defect sweep, not a redesign.
- Data shape. The spec's
## Dataroles decide the shape per "Data shapes" inprompts/adaptable-code.md: table (the default), matrix, or generated. For a generated spec (boards, puzzles, encoded text, fractals, formula surfaces, diagrams such as Feynman or energy levels) the block holds named parameters, with no record array and no column constants, and checklist items 4, 5, 7, 9 and 10 do not apply. Geometry a chart needs beside its data (a coastline polygon, a board layout) is a named constant table in the Data block, not rows ofdata. Networks are not a MUI X shape (prompts/library/muix.md, "Forbidden patterns"). - Design level. DE-01 to DE-03 and LM-02 start at their defaults and the review raises them only for evidence beyond what the spec and the library prompt require. Within that: a subtitle or caption line that states a scenario or scale fact computed from the data (n, span, unit, a fit statistic), never an interpretation; quiet chrome (
t.grid,t.inkSoft) under clear data; realistic, specific names in the data. On a spec whose id ends in-basic: no focal element, no highlighted mark or band, no added reference line, fit, callout or annotation layer, no colour channel the spec does not offer (prompts/quality-criteria.md, SC-01 "Variant creep"; one such addition costs more than any DE credit it could earn). On every other spec: one focal element only where the Notes do not already prescribe a hierarchy, chosen by a rule over the data and applied through weight or contrast while the palette order stays canonical.ChartsLegendandChartsGridare the baseline, not mastery; LM credit comes only from a feature beyond the requirements (acolorMapon the axis that carries a quantity, hook-driven layers in data coordinates, a second y axis withposition: "right"). Never replace a working custom layer by a component that cannot draw the same thing. - Checklist. Every file you hand over satisfies all of these:
- Nothing spec-compliant from the old file is dropped: every reference line, annotation, identity line, curve type and multi-series legend entry that the spec requires or offers as optional is still there, or the table says why v9 cannot draw it. On a
-basicspec, drop the unrequested trend lines, mean lines, callouts and single-series legends the old file added, and note each removal in the table. - No axis limit, padding, bin size, radius or grid step is typed in data units below the Data block; they come from the data extent, through a unit-free share in
// Constantswhere padding or a bin count is needed. A threshold the plot type or the spec defines (RSI 30 and 70, a target the spec names) and a fixed mathematical domain (0–1, 0–100, 0–360) are typed constants in// Constants. - No column name, sample category, label text or unit string is typed in plot code (a callout says only what its rule guarantees; the unit comes from the column constant or the formatter). An encoding note that is true for any data stays.
- Every record cell is a scalar: no arrays or objects inside a record (two thresholds are two columns).
- No role column duplicates another; a class or category list is derived from every column that carries it (both label columns of a confusion matrix), in order of first appearance.
t.palette[i]by group position in order of first appearance, never% t.palette.length. Where a semantic map fixes a colour (loss red, a status), the remaining groups take the unused palette positions in order. Ordered categories (Likert, sentiment, risk levels) take a ramp (t.seq,t.div) per "Ordered Categories" in the style guide.- A series label comes from the rows that make up the series, not from the position of a value in a
Set. - A statistic's constant is looked up from the data's size, never fixed for the sample (a t quantile for df = n − 2 from a table, not 2.571).
- Every declared column constant is read by the plot code; a numeric or date x is sorted before lines are drawn, a categorical x keeps its order of appearance.
- Which renderer, panel or band a group gets is decided by a rule over its rows, not by its position in the data, and every renderer handles an empty group.
- Axis extents are padded so reference elements and outermost marks sit inside the drawing area.
- Marks sit at their exact data coordinates: no collision relaxation, force pass, jitter or nudge on plotted points (labels may move, marks never). On a geographic map, px per degree of latitude equals px per degree of longitude divided by cos(mean latitude); on a geometric plot (circles, complex plane, Smith chart, Voronoi) px per unit is equal on both axes.
- Every text element is 14 px or larger, in-mark labels, counts and reference labels included; axis and legend text 14–16 px, title about 22 px; no label is truncated in code (
slice), size the band instead. Text on a coloured mark uses a fixed ink chosen by the mark's luminance (#1A1A17or#FAF8F1), nevert.pageBgort.ink, which flip with the theme while data colours do not. - Non-data chrome (basemap, water, background bands, borders, separators) uses
t.inkSoft,t.gridort.elevatedBg, never at.paletteslot. - No helper function or component beyond the default export and the custom layers that need a hook (
useXScale,useYScale,useDrawingArea); statistics, binning and layout are flat module-level statements; axis styles set once in thexAxis/yAxisconfigs, not again on<ChartsXAxis />; no branch that cannot fire (a title-size branch for a fixed title). - None of the v7 names remains:
ChartContainer,ResponsiveChartContainer,DefaultChartsLegend,Unstable_,hidden: trueinsideslotProps.legend,labelStyle,padding,itemMarkWidth,itemMarkHeight,markGap,itemGapinsideslotProps.legend,labelFontSize,tickFontSize,topAxis/leftAxis/bottomAxis/rightAxis,.MuiAreaElement-root,.MuiLineElement-series-*,.MuiBarElement-root,.MuiMarkElement-root,.MuiScatterElement-root,.MuiPieArc-root,lineElementClasses,areaElementClasses,barElementClasses,markElementClasses,pieArcClasses,pieArcLabelClasses.
- Nothing spec-compliant from the old file is dropped: every reference line, annotation, identity line, curve type and multi-series legend entry that the spec requires or offers as optional is still there, or the table says why v9 cannot draw it. On a
- Branch
gemini/<this issue number>-muix-9-remainingfromorigin/main; a draft PR only. The draft is reviewed chunk by chunk and fed to the pipeline file by file; it is closed afterwards without a merge, so do not expect CI on it to be the acceptance.
Acceptance
For every one of the 294 files, from the repository root:
ANYPLOT_THEME=light node automation/js-render/render.mjs plots/<spec>/implementations/javascript/muix.tsx
ANYPLOT_THEME=dark node automation/js-render/render.mjs plots/<spec>/implementations/javascript/muix.tsx
PYTHON_DOTENV_DISABLED=1 uv run python -c "from core.canvas import check_png; print(check_png('plot-light.png', 'muix'), check_png('plot-dark.png', 'muix'))"
head -5 plots/<spec>/implementations/javascript/muix.tsx
grep -nE 'ResponsiveChartContainer|[^s]ChartContainer|DefaultChartsLegend|Unstable_|hidden: *true|labelFontSize|tickFontSize|\b(top|left|bottom|right)Axis\b|MuiAreaElement-root|MuiLineElement-series-|MuiBarElement-root|MuiMarkElement-root|MuiScatterElement-root|MuiPieArc-root|lineElementClasses|areaElementClasses|barElementClasses|markElementClasses|pieArcClasses|pieArcLabelClasses|itemMarkWidth|itemMarkHeight|markGap|itemGap|t\.muted' plots/<spec>/implementations/javascript/muix.tsx
Both renders exit 0 and both canvas checks report the target size; the first five lines are one header block and, for a square spec, the directive on line 5; the grep finds nothing; the PNGs show every axis, tick label, legend and the imprint; the checklist holds for every file. The existing rules still win where they conflict with a mechanical port or with the design level: the eight-hue palette order and "never recycle colours", the 3200×1800 canvas with sizes in CSS px, the imprint text, a legend outside the SVG that reserves its own height, the -basic variant rule above, and the data shape the spec's roles decide.
Hand-over format
The PR body carries one table per hand-over, appended each time, with the hand-over commit (git rev-parse HEAD) in its heading: spec, what changed (API, convention, checklist items that needed a change), render result, anything you could not solve or had to drop. Then the sections of the gemini-task hand-over format (Summary, Plan, Test plan, Decisions, Open steps and questions). Write the body into a temp file and apply it with gh api -X PATCH repos/{owner}/{repo}/pulls/<pr> -F body=@<file> (gh pr edit fails on this repository).
Decide yourself / report back
- Decide yourself: constant names, padding shares, how a lookup table is written, how a stale header is resolved, which v9 feature carries a custom layer, the subtitle fact per chart. Document the choices in the chunk's table.
- Report back in the table, do not guess: a spec whose old file draws something v9 cannot express (use the documented fallback from "When MUI X can't express the spec" in the library prompt and say so); a spec whose old file contradicts its specification; a file that does not render on 9 for a reason outside the file (harness, dependency); and any checklist item you could not satisfy.
Activity
[-]Migrate the remaining 294 MUI X implementations to MUI X 9 in six chunks[/-][+]Migrate the remaining 294 MUI X implementations to MUI X 9 in three chunks[/+]feat(muix): migrate box-horizontal to MUI X 9
feat(muix): migrate box-notched to MUI X 9
feat(muix): migrate boxen-basic to MUI X 9
feat(muix): migrate bubble-basic to MUI X 9
feat(muix): migrate bubble-packed to MUI X 9
feat(muix): migrate campbell-basic to MUI X 9
feat(muix): migrate candlestick-basic to MUI X 9
feat(muix): migrate candlestick-volume to MUI X 9
feat(muix): migrate cat-box-strip to MUI X 9
feat(muix): migrate chernoff-basic to MUI X 9
feat(muix): migrate chessboard-basic to MUI X 9
feat(muix): migrate chord-basic to MUI X 9
feat(muix): migrate circlepacking-basic to MUI X 9
176 remaining items
feat(muix): migrate sn-curve-basic to MUI X 9
feat(muix): migrate spc-xbar-r to MUI X 9
feat(muix): migrate spectrogram-basic to MUI X 9
feat(muix): migrate spectrogram-mel to MUI X 9
feat(muix): migrate spiral-timeseries to MUI X 9
feat(muix): migrate star-chart-constellation to MUI X 9
feat(muix): migrate stem-basic to MUI X 9
feat(muix): migrate stereonet-equal-area to MUI X 9
feat(muix): migrate streamline-basic to MUI X 9
feat(muix): migrate strip-basic to MUI X 9
feat(muix): migrate surface-basic to MUI X 9
feat(muix): migrate swarm-basic to MUI X 9
feat(muix): migrate ternary-basic to MUI X 9
feat(muix): migrate tree-decision to MUI X 9
feat(muix): migrate tree-phylogenetic to MUI X 9