Let users change a placed component's silhouette - #24
Open
augustomesquita wants to merge 2 commits into
Open
Conversation
Whether a shape stands on a disc or a slab was decided by repeating `kind === "circle" || kind === "icon"` at six independent call sites: edge anchoring, viewport culling, the selection outline, click targeting, and both the per-view and batched render paths. pointInShape held a seventh copy that had already drifted, testing only "circle". Introduce isRoundFootprint as the single definition and route every site through it. The predicate reads an optional silhouette override and otherwise falls back to the previous kind test, so behaviour is unchanged until something writes that field. pedestalBatch is the site that matters most here: it dispatched on kind directly, so any future disagreement between kind and footprint would have drawn a slab in the batched path and a disc in the per-view one.
The footprint of a component was fixed at creation: an icon dropped from the palette was always round, and the only way to get a square one was to delete it and rebuild it as a rectangle, losing the artwork, label, floor and every connected edge. Add an optional silhouette override on Shape, written by a new setShapesSilhouette action, and surface it as a Shape control in the style panel and two entries in the right-click menu. It applies to every kind that raises a pedestal — icon, circle, rect and image — and skips text and code, which have no footprint to swap. Dimensions are deliberately untouched, so a non-square box turned round draws a disc across its shorter side and still restores exactly when switched back. Undo, autosave, clipboard and share links need no work: the action bumps the revision the history and autosave already watch, and the field rides along in the shapes the clipboard and encoder copy wholesale. Boards and share links predating the field carry no override and fall back to the kind default, so they render exactly as before.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
The pedestal a component stands on is decided when it's created and can never be changed. An icon dropped from the palette is round forever. The only way to get a square one is to delete it and rebuild the node as a rectangle, losing the artwork, the label, the floor assignment and every edge already connected to it.
Every other property of a placed component (fill, label, text size, floor, z-order) can be edited after the fact. The footprint was the one that couldn't.
The proposal
Shapegains an optionalsilhouetteoverride. When it's absent the footprint is derived from the kind exactly as today, so existing boards and share links are unaffected and there's no migration.Users reach it from a Shape field in the style panel and two entries in the right-click menu. It covers every kind that raises a pedestal (icon, circle, rect, image) and skips text and code.
For review
The footprint rule was duplicated across six call sites: edge anchoring, culling, selection outline, click targeting, and both render paths. A single
isRoundFootprintpredicate now backs all of them, which is why the diff touches more files than the feature might suggest.I split it into two commits so the refactor can be judged on its own. The first is behaviour-preserving, the second is the feature.
A few decisions worth knowing before reading the diff:
kind, becauseimagehas no round counterpart and an icon flipped torectwould lose its artwork on a?g=round trip.GeneratedGraphand the OpenAI schema are deliberately untouched. That schema isstrictwith every property required, so adding a field would change generation behaviour. Happy to follow up if you want it exposed.Testing
New suite in
test/silhouette.test.ts.npm testpasses 40 tests across 9 files andnpm run buildis clean.Two assertions in
test/renderPerf.test.tsfail on my machine, but they fail identically on an unmodifiedmain, so they look environment-bound rather than caused by this change.Also verified in the browser: inserting an icon, switching it to square, and confirming the pedestal renders as a slab, the outline becomes a box, both edges re-anchor, and the change survives autosave.