Repository navigation
Entity rotation #43
Copy link
Copy link
Open
Labels
enhancementNew feature or requestNew feature or request
Milestone
Description
Context
Entities are axis-aligned rectangles: Entity.bounds is { x, y, width, height }, with no rotation. Real floor plans need rotated items: desks at an angle, diagonal walls, a table turned 45°.
Rotation touches almost everything (types, hit testing, selection overlay, resize, snapping, the drag math), so this issue is design-first. Agree on the approach in the comments before writing code.
What changes (proposal)
Model. Add an optional rotation to the entity, in degrees, clockwise, around the center of bounds:
export interface Entity {
id: EntityId;
layer: LayerId;
bounds: Bounds; // unrotated box
rotation?: number; // degrees, default 0
data?: unknown;
selectable?: boolean;
}bounds keeps meaning the unrotated box. That keeps existing scenes valid and makes rotation: 0 behave exactly like today.
Core
hitTestPoint: transform the point into the entity's local space (inverse rotation around the center), then use the existing AABB test.sceneBounds/fitToScene: use the AABB of the rotated rectangle.- A helper such as
rotatedAABB(bounds, rotation): Boundsinutils.ts. applyResizeDelta: resize in local space so handles follow the rotated edges.
SVG and React
- Render each entity inside
<g transform="rotate(r cx cy)">, sodrawEntitykeeps drawing in unrotated coordinates. - Rotate the selection overlay and the resize handles with the entity.
- Optionally, a rotation handle above the
nhandle, with snapping to 15° steps while Shift is held.
Open questions
- Degrees or radians? Proposal: degrees (easier for app code and serialization).
- Should rotation be a separate milestone step: first model, rendering and hit testing; then a rotation handle; then resize of rotated entities?
- How does snap-to-grid apply to rotated entities: snap the center, or the AABB?
Affected files
| File | Change |
|---|---|
packages/core/src/types.ts |
rotation?: number on Entity |
packages/core/src/picking.ts |
Rotation-aware hit test |
packages/core/src/store.ts |
sceneBounds uses rotated AABBs |
packages/core/src/utils.ts |
Rotation helpers; applyResizeDelta in local space |
packages/svg/src/renderer.ts, selection-overlay.ts, resize-handles.ts, handlers.ts |
Rotated rendering and interaction |
packages/adapters/react/src/SpatialCanvas.tsx, internal/* |
Same for React |
Invariants to preserve
rotationundefined or0behaves exactly as today. All existing tests pass unchanged.drawEntitykeeps receiving unrotatedbounds; the renderer applies the transform.- No production dependencies.
Implementation checklist
- Agree on the design in this issue
- Model, helpers and hit testing in core, with tests (0°, 90°, 45°, points near the corners)
- Rotated rendering, overlay and handles in SVG and React
- Rotation handle (may be a follow-up issue)
- Docs, example and changeset
- Run
pnpm typecheck && pnpm test && pnpm lint
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request
Activity