Last updated: 2026-05-14 (Phase 9 styling features)
npm run dev
Then open http://localhost:5173 in your browser.
Phases follow the order agreed at session start. A phase ends when each of its acceptance points is verifiable in the running app.
- done
- [~] in progress
- not started
Goal: App boots to an empty shell that looks like the eventual editor.
- Vite + React 18 + JS-only setup
- Tailwind + shadcn CSS variables
- Project directory structure (per spec §3)
- Three-pane layout (TopBar / DataManager / Canvas / ControlPanel)
- Zustand store with 5 slices (canvas, layout, plots, data, ui) + meta/theme/labeling
- ULID-style id generator
- Schema constants + structural validator
- Built-in themes (3) and palettes (4) data tables
- shadcn
Buttonprimitive (JS port) -
npm installsucceeds andnpm run buildproduces a working bundle (184 kB JS gz 59 kB) - Empty shell renders with "New session" button (dialog itself lands in Phase 2)
Goal: User can create a session, see the grid, merge cells, resize tracks.
-
NewSessionDialog— canvas preset + rows/cols + live preview - Canvas surface renders at real proportions with drop shadow + neutral bg
- N×M panel grid render (
Panel,EmptyPanel) - Panel selection (2px accent outline, hairline on hover)
- Cell-merge mode toolbar + click-two-cells flow + rectangle validation
-
GridDividertrack resizer (drag, snap, min size) - Auto-labeling:
PanelLabelin reading order (A/B/C…) - Per-panel label override (
label.auto = false) via Inspector when a panel is selected - Canvas zoom-to-fit button (
FitinCanvasToolbar, also auto-fits on resize)
Goal: User can upload data and drag it onto a panel.
-
DataManageradd-dataset flow via PapaParse (CSV) and JSON parser -
DatasetCardshows column count, row count, type chips -
ColumnPickerreusable component - dnd-kit: dataset → panel
- Image panel path (SVG/PNG via file picker,
object-fit: contain) - Image controls: alt text, background, border
- Toy example datasets in
public/examples/+ "Load examples" button (Phase 9 item delivered early)
Goal: Five chart types render with the full styling control panel.
-
PlotEngineinterface + Plotly mounting - Chart renderers: bar, histogram, pie, heatmap, scatter
- Per-chart parameter schemas
- Control panel renders schemas dynamically (slider, color, font, select…)
- Apply / Reset draft model
- Overflow rules (
engine/overflow.js) - Shared X / Shared Y linking within row/column
-
stackedBarrenderer (grouped + normalized variants) - Theme switcher applies defaults to new plots
- Custom palette swatch row
- Font dropdown wired to bundled fonts (still loaded via Google Fonts at this stage)
-
exportSession.jswrites.figaro.jsonmatching schema -
importSession.jsparses + validates -
LocateFilesDialogwalks datasets/imageRefs and rebinds files - Round-trip test (save → reopen → relocate → identical render)
Order: SVG → PNG → HTML → PDF.
- SVG export (composed master SVG with auto-labels as
<text>) - PNG export (offscreen canvas at 2× DPI)
- HTML export (self-contained with Plotly inline)
- PDF export — jsPDF + svg2pdf.js +
<foreignObject>fallback note in dialog - Export dialog with format tabs + PNG resolution selector
- Edges dataset picker in control panel
- d3-force layout (force-directed + circular fallback)
- Plotly traces: nodes (scatter) + edges (lines)
- Re-layout button + cached positions
- Node label toggle, sizing, edge opacity
-
public/examples/with 3 example CSVs + "Load example" button (delivered in Phase 3) - Per-element font size sliders — title, axis labels, tick labels, legend each have an independent size slider; null = auto (scales from base font size)
- Title position slider — horizontal drag-to-position slider (0 = left, 1 = right); also saved automatically when Plotly fires a relayout event
- Legend drag & save — drag the legend anywhere on the chart; position is persisted in the plot style and restored on re-render
- Click-to-highlight — clicking a plot element (title, axis label, ticks, legend) highlights the relevant Inspector controls with a ring and scrolls to them
- 4-style visual font picker — 2×2 button grid showing "Aa" in Inter (Sans), Merriweather (Serif), IBM Plex Mono (Mono), Lato (Round)
- Inner plot border toggle — "Plot border" checkbox draws a box frame around the plot area via Plotly
mirroraxes - Logo updated — replaced figaro_logo.svg with figaro_logo2.png at 60 px height in a 72 px top bar
- Walk through every acceptance criterion in spec §14
- Performance pass on 10k-row dataset
- Sweep code for
TODO(v2)markers on out-of-scope items
- Add
VITE_BASE_PATHenv var tovite.config.js(relative base for R server) - Install
cross-envdev dependency (works on Mac/Linux/Windows) - Add
build:rnpm script → outputs todist-r/withbase: './'
- Add
window.__FIGARO_INITIAL_SESSION__hook tosrc/App.jsx -
window.__FIGARO_R_SERVER__injected by R server for/restyleendpoint -
RPlotStyleInspectorwired intoControlPanelfor image panels withrPlot: true -
npm run build:r→dist-r/copied tofigaro-r/inst/www/
-
figaro-r/package scaffold:DESCRIPTION,NAMESPACE,R/,inst/www/,tests/ -
R/utils.R:new_id(),iso_now(),infer_col_type(),classify_input(),file_to_data_url()(PNG/JPEG/WebP/PDF),plot_to_data_url()(ggplot2 + base R),df_to_rows() -
R/session.R:build_session()— data frames, ggplot2 (native extraction with image fallback), recordedPlot, file paths;ggplot_to_figaro()extractor;figaro_save();build_loaded() -
R/server.R:start_server(), MIME helper,/restylePOST endpoint,r_plotsin-memory store -
R/figaro.R:figaro(),figaro_stop(),.figaro_env -
src/components/controls/RPlotStyleInspector.jsx: title, axis labels, font size, legend position, width/height sliders; calls/restyleand updates panel image in-place
- Unit tests: session schema, column types, round-trip JSON
- Unit tests: simple ggplot2 → native plot extraction (xCol/yCol/title/fontSize)
- Unit tests: complex multi-layer ggplot → image fallback
- Unit tests: mixed data frame + ggplot → empty + plot panels
- Integration test: server starts, index.html contains injection
- Manual tests (see plan for full checklist)
- R CMD check passes (0 errors, 0 warnings)
Undo/redo, keyboard shortcuts, live preview, data transforms, free-form label positioning, decorative overlay layer, custom font upload, JSON power-editor, mobile/tablet, RTL/i18n, CMYK PDF, LaTeX in labels, embedded data in session, schema migrations, JSON compression, multi-page figures.