Skip to content

Add a browser-based visual layout workbench - #7

Merged
LJAYi merged 3 commits into
mainfrom
agent/stage3-layout-workbench
Aug 4, 2026
Merged

LJAYi merged 3 commits into
mainfrom
agent/stage3-layout-workbench

Conversation

@LJAYi

@LJAYi LJAYi commented Jul 22, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • add a browser-based visual layout adjustment workspace
  • persist manual positions, routes, ports, labels, groups, and layers in a versioned sidecar
  • reconcile stable layout overrides when Mermaid source changes
  • keep all exports flowing through the shared forward-only Diagram IR

Scope

This PR keeps the visual layout workbench isolated from the export foundation delivered in PR #6. Reverse conversion remains deferred.

Testing

  • layout unit tests
  • visual workbench Playwright coverage
  • full repository CI

Summary by CodeRabbit

  • New Features
    • Added an interactive diagram layout editor with drag, resize, multi-select, alignment, distribution, layering, grouping, edge routing, label positioning, and keyboard nudging.
    • Added undo/redo, reset, import/export, and browser persistence for layout adjustments across source edits.
    • Updated exports to preserve customized layouts, routing, labels, groups, and arrowheads.
  • Bug Fixes
    • Improved layout reconciliation, collision handling, diagnostics, and fallback behavior when diagram semantics are unavailable.
  • Documentation
    • Expanded web app, layout workflow, architecture, and roadmap documentation.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@LJAYi, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c0e8930f-d0d7-446b-ba92-19115727bc72

📥 Commits

Reviewing files that changed from the base of the PR and between 71aa583 and 04aa02b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (12)
  • README.md
  • apps/web/package.json
  • apps/web/src/layout/editor.ts
  • apps/web/src/main.ts
  • apps/web/src/styles.css
  • apps/web/tests/e2e/workbench.spec.ts
  • docs/architecture.md
  • docs/roadmap.md
  • packages/core/src/exporters/svg.ts
  • packages/core/src/pptx.ts
  • packages/core/test/core.test.ts
  • packages/core/test/exporters/exporters.test.ts
📝 Walkthrough

Walkthrough

Changes

The PR adds a versioned layout sidecar model and core APIs for parsing, reconciliation, geometry application, routing, grouping, and z-order. The web app gains an interactive SVG layout editor with persistence, history, toolbar controls, and export integration. SVG and PPTX export behavior is also updated.

Layout sidecar and core processing

Layer / File(s) Summary
Sidecar contracts and validation
packages/core/src/layout/*, packages/core/test/layout.test.ts, packages/core/src/index.ts
Defines typed sidecar entries, stable identities, validation, canonical serialization, reconciliation results, and public exports.
Layout reconciliation and application
packages/core/src/layout/apply.ts, packages/core/src/layout/reconcile.ts
Applies manual bounds, routes, labels, groups, and z-order to diagrams while reconciling changes across source updates.
Interactive SVG editing workflow
apps/web/src/layout/*, apps/web/src/main.ts, apps/web/src/styles.css, apps/web/src/svg-viewer.ts, apps/web/tests/*
Adds editing gestures, selection, arrangement, grouping, routing, undo/redo, persistence, sidecar import/export, toolbar controls, and browser coverage.
SVG and PPTX export adjustments
packages/core/src/exporters/svg.ts, packages/core/src/pptx*.ts, packages/core/src/stroke-style.ts, packages/core/test/*
Uses SVG markers for arrowheads, updates text/path rendering, removes node-text connector patching, and adjusts export summaries and tests.
Architecture and workflow documentation
README.md, docs/*, packages/core/README.md
Documents layout adjustment, sidecar persistence, reconciliation, optional overrides, and fallback behavior.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • LJAYi/mmd2pptx#5: Adds the preview pan/zoom behavior extended here for layout editing.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.13% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main addition: a browser-based visual layout workbench.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/stage3-layout-workbench

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@LJAYi LJAYi changed the title Add the Stage 3 visual layout workbench Add a browser-based visual layout workbench Jul 22, 2026
@LJAYi
LJAYi changed the base branch from agent/diagram-platform-foundation to main July 22, 2026 13:36
@LJAYi
LJAYi force-pushed the agent/stage3-layout-workbench branch from 268dbef to 71aa583 Compare July 22, 2026 13:38

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/pptx.ts (1)

482-501: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Exact-mode SVG embedding still leaves foreignObject labels untouched

svgStringToPptxBuffer(..., { mode: "exact" }) now sends the raw SVG into exactSvgToPptxBuffer, and sanitizeSvgForEmbedding() only strips active/external content — it does not normalize foreignObject labels. Mermaid node/edge labels can still disappear in PowerPoint/LibreOffice if the SVG importer drops foreignObject. Restore the normalization step or make the limitation explicit.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/pptx.ts` around lines 482 - 501, Update the exact-mode
branch of svgStringToPptxBuffer so the SVG passed to exactSvgToPptxBuffer is
normalized to replace or convert foreignObject labels into importer-compatible
content before embedding. Preserve parsed diagnostics and generated output
handling, and ensure exact mode no longer sends raw foreignObject labels that
PowerPoint or LibreOffice may drop.
🧹 Nitpick comments (2)
packages/core/src/exporters/svg.ts (1)

231-250: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

dominant-baseline:middle for multi-line labels is not reliably honored across tools, and the multi-line centering test was removed without replacement.

Adobe Illustrator does not respect dominant-baseline="middle" and instead renders it as the default baseline, producing misaligned text — confirmed by Adobe's own bug tracker: dominant-baseline="middle" is not respected, and is instead rendered as dominant-baseline="baseline", producing misaligned text, which is displayed aligned normally by Edge, Firefox, Chrome. This project already treats Illustrator SVG rendering fidelity as a real constraint (see the "Illustrator-invisible SVG" concern in stroke-consistency.test.ts), so relying on dominant-baseline:middle for label centering risks visibly broken multi-line label positioning when opened in Illustrator.

Separately, exporters.test.ts previously had a test validating vertical-centering baseline behavior for multi-line text; per the line-range change details it was removed and not replaced with an equivalent multi-line assertion (the remaining DIAGRAM fixture only has single-line labels). Consider adding a multi-line label test to lock in the new tspan/dy math, and re-evaluate whether an explicit y-per-tspan approach (as before) would be safer than dominant-baseline for cross-tool fidelity.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/exporters/svg.ts` around lines 231 - 250, Update textSvg to
avoid relying on dominant-baseline:middle for vertical centering, which is not
honored consistently by Illustrator. Emit explicit vertical positions for each
tspan using the existing centered startY and lineHeight calculations, and remove
the unsupported baseline dependency. Restore a multi-line assertion in the
exporter tests that verifies the generated positions and centering math.
apps/web/src/layout/editor.ts (1)

989-993: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Redundant collision computation on the drag hot path.

applyLayout() already computes collisions via updateCollisions() (Line 684), and notify() recomputes the same O(n²) collisionKeys over a freshly-built map. Both run on every pointermove while dragging. Store the count during updateCollisions and reuse it here.

♻️ Reuse the computed collision count
   private updateCollisions(
     entries: Map<string, { bounds: LayoutBounds; mode: string }>,
   ): void {
     const collisions = collisionKeys(entries);
+    this.collisionCount = collisions.size;
     for (const [key, handle] of this.nodeHandles) {
       handle.element.classList.toggle("layout-node-collision", collisions.has(key));
     }
   }

Then reference this.collisionCount in notify() instead of recomputing (default it to 0 and reset in clear()).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/layout/editor.ts` around lines 989 - 993, Eliminate the
duplicate collision computation in notify() by adding a collisionCount field
initialized to 0, assigning it from the collision result in updateCollisions(),
and using this.collisionCount for the emitted count. Reset collisionCount to 0
in clear() so stale values are not retained.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/core/src/pptx.ts`:
- Around line 482-501: Update the exact-mode branch of svgStringToPptxBuffer so
the SVG passed to exactSvgToPptxBuffer is normalized to replace or convert
foreignObject labels into importer-compatible content before embedding. Preserve
parsed diagnostics and generated output handling, and ensure exact mode no
longer sends raw foreignObject labels that PowerPoint or LibreOffice may drop.

---

Nitpick comments:
In `@apps/web/src/layout/editor.ts`:
- Around line 989-993: Eliminate the duplicate collision computation in notify()
by adding a collisionCount field initialized to 0, assigning it from the
collision result in updateCollisions(), and using this.collisionCount for the
emitted count. Reset collisionCount to 0 in clear() so stale values are not
retained.

In `@packages/core/src/exporters/svg.ts`:
- Around line 231-250: Update textSvg to avoid relying on
dominant-baseline:middle for vertical centering, which is not honored
consistently by Illustrator. Emit explicit vertical positions for each tspan
using the existing centered startY and lineHeight calculations, and remove the
unsupported baseline dependency. Restore a multi-line assertion in the exporter
tests that verifies the generated positions and centering math.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ada37fed-8ff3-4e89-ac05-66ff1565a91f

📥 Commits

Reviewing files that changed from the base of the PR and between d87d3f7 and 71aa583.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (34)
  • README.md
  • apps/web/package.json
  • apps/web/src/layout/arrange.ts
  • apps/web/src/layout/editor.ts
  • apps/web/src/layout/history.ts
  • apps/web/src/layout/index.ts
  • apps/web/src/main.ts
  • apps/web/src/styles.css
  • apps/web/src/svg-viewer.ts
  • apps/web/tests/e2e/layout-editor.spec.ts
  • apps/web/tests/e2e/workbench.spec.ts
  • apps/web/tests/layout/arrange.test.ts
  • apps/web/tests/layout/history.test.ts
  • docs/adr/0001-forward-only-unified-ir.md
  • docs/architecture.md
  • docs/roadmap.md
  • packages/core/README.md
  • packages/core/src/exporters/svg.ts
  • packages/core/src/index.ts
  • packages/core/src/layout/apply.ts
  • packages/core/src/layout/identity.ts
  • packages/core/src/layout/index.ts
  • packages/core/src/layout/reconcile.ts
  • packages/core/src/layout/sidecar.ts
  • packages/core/src/layout/types.ts
  • packages/core/src/pptx-connector-patch.ts
  • packages/core/src/pptx.ts
  • packages/core/src/stroke-style.ts
  • packages/core/test/core.test.ts
  • packages/core/test/exporters/exporters.test.ts
  • packages/core/test/exporters/stroke-consistency.test.ts
  • packages/core/test/layout.test.ts
  • packages/core/test/pptx-groups-z-order.test.ts
  • packages/core/test/public-api.test.ts

@LJAYi
LJAYi marked this pull request as ready for review August 4, 2026 14:50
@LJAYi
LJAYi merged commit a4712aa into main Aug 4, 2026
2 checks passed
@LJAYi
LJAYi deleted the agent/stage3-layout-workbench branch August 4, 2026 14:53
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