35 Commits

Author SHA1 Message Date
39290bc153 Add xlsx as explicit dependency (was missing from package.json)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 17:24:35 +04:00
f8a26b4dd3 Fix all TypeScript errors: readonly cast, pdfjs types, vite config types
- Cast EPC defaultWaypoints readonly tuple to EpcWaypoint[] in collision.ts
- Fix pdfjs render() call with canvas property
- Remove unused @ts-expect-error directive
- Add @types/node and type annotations for vite.config.ts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 17:23:51 +04:00
c01173aa7b Draw conveyors/chutes/tippers/extendos programmatically for consistent stroke
SVG-based rendering caused non-uniform stroke scaling when symbols were
stretched. Now conveyor, chute, tipper are drawn as canvas rects, and
extendo is drawn as a canvas path with fixed left bracket proportions.
All use consistent 0.5px stroke regardless of size.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 17:22:14 +04:00
775c6e2e99 Make conveyors/chutes/inductions/extendos/spurs white; fix PE stroke and size
- Change all conveyance SVGs from black fill to white fill with black stroke
- Update programmatic rendering (curves, induction, spur) to white fill
- Replace PE 3-slice rendering with programmatic canvas paths for
  consistent stroke width at any size
- Reduce PE default size from 56x20 to 30x14 to fit around conveyor devices
- Update SVG export to match new white fills

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 17:17:09 +04:00
20b9547578 Fix EPC export: match end box position and stroke width to canvas renderer
- Right box x offset: 0 → -rb.w (extend backward, matching canvas)
- Stroke width: hardcoded 0.3 → EPC_CONFIG.lineWidth (1.5, matching line)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:50:53 +04:00
595c47fbf8 Rotate EPC end box 90°: swap dimensions to match start icon orientation
End box was 10×20 (tall/narrow perpendicular to line), now 20×10
(wide/squat along line), matching the start icon's landscape proportions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:48:26 +04:00
e4c67b165b Fix EPC end box collision and bounds to match 90° rotation
Rotate the direction vector -90° for the right box in collision
detection and bounds calculation to match the perpendicular
rendering orientation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:38:37 +04:00
a4884b4e9b Fix EPC SVG export: match stroke width and right box position; rotate end 90°
- Right box stroke now uses EPC_CONFIG.lineWidth (1.5) instead of 0.3
- Right box positioned at -rb.w (backward) matching canvas renderer
- End box rotated 90° (perpendicular to line) in canvas, export, and hit-testing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:38:07 +04:00
d721f47757 Improve EPC clickability: shape-accurate hit testing with generous margin
Replace bounding-box hit test with proper shape-aware check that tests
proximity to line segments and oriented end boxes with 8px hit margin,
making the thin EPC much easier to select and drag.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:27:30 +04:00
82bb1b46c8 Make EPC start/end outline thickness match the connecting line (1.5px)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:26:09 +04:00
db12a30701 Fix EPC jump on mouseup: stop shifting origin in recalcEpcBounds
Just expand w/h to cover the full waypoint extent without moving
sym.x/y. The origin-shifting math was causing the symbol to jump
in the direction of waypoint movement on mouse release.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:20:33 +04:00
c3da2da20d Fix EPC symbol jump on mouseup: preserve rotation center when updating bounds
recalcEpcBounds now properly normalizes the bounding box to start at
(0,0) in local space, adjusting sym.x/y to compensate so the world
position and rotation center stay constant. Handles rotated symbols
by rotating the center offset into world space.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:18:54 +04:00
eb4a570a70 Fix EPC waypoint jumping: defer bounds recalc to mouseup
Updating sym.w/h mid-drag shifted the rotation center used by
toSymbolLocal, causing waypoints to jump. Now recalcEpcBounds
only runs on mouseup, keeping the coordinate transform stable.
Also removed the endpoint slide constraint that was causing
instability due to using the moving position as direction source.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:17:18 +04:00
81e0bd0f3d Stabilize EPC waypoint dragging: constrain endpoints to slide along segment
- First/last waypoints now only extend/shorten along their segment direction,
  preventing unwanted rotation of the end boxes
- Middle waypoints remain freely draggable for direction changes
- Add default middle waypoint so new EPCs have 3 control points

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:14:25 +04:00
c9a8dd8f5b Fix EPC rendering: thicker line, consistent strokes, correct end rotation
- Increase EPC line width from 0.4 to 1.5 for visibility
- Increase right box stroke from 0.3 to 1.0 to match left icon stroke
- Fix right box to extend behind last waypoint (like left icon), not forward

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:11:09 +04:00
db19535f39 Make BCN, SOL, PDP symbols consistent: same viewBox, font, and size
All three now use identical 20x20 viewBox, 19x19 rect, font-size 8,
centered text with dominant-baseline="central". Updated symbol defs
to match the new 20x20 dimensions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:20:49 +04:00
34ec2a8450 Fix BCN, SOL, PDP symbol text: center properly and fit inside box
Reduced font sizes and used dominant-baseline="central" with y at
the vertical center so text is centered both horizontally and
vertically inside the box without overlapping the border.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:19:12 +04:00
84bd2f2978 Add default MCM symbol to every MCM's device list
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:18:10 +04:00
224aad4408 Fix reversed resize direction on mirrored symbols
When a symbol is mirrored, negate the horizontal drag delta and swap
the left/right handle identity so resizing matches the visual direction.
Also fixes spur handle resize with mirrored spurs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:12:33 +04:00
4f1d680406 Merge device dock into single smart list: drop to place or assign ID
- Remove tabs, single unified device list grouped by type
- Drop on empty space → places new symbol with device ID
- Drop on existing symbol → assigns the device ID as label
- Drop-target highlight shown when hovering over existing symbols
- Always sorted ascending by device type

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:07:42 +04:00
d09ffd4a22 Fix spur/induction collision polygons to account for mirrored state
Collision detection now mirrors spur trapezoid and induction arrow
vertices when the symbol is mirrored, matching the visual appearance.
Previously the collision polygon stayed unmirrored causing false
positives/misaligned collision zones.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 19:05:53 +04:00
31ea4c0908 Add shift+drag to constrain movement to horizontal or vertical axis
Holding Shift while dragging locks movement to the dominant axis
(whichever has the larger delta from drag start). Works for both
single and multi-selection moves.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 18:59:51 +04:00
b4e3a7d6ff Always sort IDs tab ascending by device type, not just when searching
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 18:46:10 +04:00
da17f95a33 Add symbol icons to IDs tab and sort search results by device type
- Each ID entry now shows a small SVG icon of its symbol type
- Device type name shown as subtle suffix
- Search results sorted ascending by device type, then by ID
- Search also matches device type name

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 18:45:19 +04:00
18c0e03287 Add marquee selection: click and drag on empty space to select multiple symbols
- Blue dashed rectangle drawn while dragging
- Selects all visible symbols whose bounding box intersects the marquee
- Respects hidden symbols and hidden groups

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 18:42:21 +04:00
3c532b8cfe Reduce label font size from 10px to 3px
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 18:41:18 +04:00
51794cb9ae Add device visibility controls: right-click hide and top bar type toggles
- Right-click context menu: "Hide" option to hide individual symbols
- "Show All Hidden" appears in context menu when anything is hidden
- Top visibility bar with toggle chips for each device group
- Hidden symbols are excluded from rendering, hit testing, and SVG export

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 18:36:01 +04:00
cc91481c98 Change beacon SVG label from B to BCN
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 18:34:00 +04:00
8336018042 Fix SVG export: preserve original structure, no stray elements
- Single-element SVGs: id/label/transform directly on the element (no <g>)
- SVGs with <g> group (dpm, diverter): keep the group, put id/label on it
- Multi-child SVGs without group (beacon): wrap in <g> with id/label
- Programmatic shapes (induction, curved, spur): single <path> with id

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 18:29:17 +04:00
8c29d9266c Shape-based collision, hit-testing, and export for all symbol types
- Add induction collision vertices (arrow+strip polygon instead of full OBB)
- Add getShapeVertices() dispatcher for unified shape-based collision
- Shape-following hit tests: curved (arc band), induction (arrow+strip), spur (trapezoid)
- Curved SVG export uses programmatic arc path matching renderer
- EPC: right-click adds waypoint, free polyline (no angle snap)
- Thinner selection/collision outlines, smaller resize handles with larger hit area

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 18:16:15 +04:00
93afd0a554 Add device dock search, IDs drag-to-assign tab, and label drop-target highlight
- Add search filter to Devices tab in right dock
- Add IDs tab: flat list of unassigned device IDs, drag onto placed symbol to assign label
- Highlight drop target symbol with cyan glow during label drag
- Add labelDropTarget state and dropTarget theme entry

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 17:40:08 +04:00
6f0ac836fb Refactor collision/distance modules, fix curved geometry, add mirror support
- Split collision.ts (707→549): extract distance.ts (pure math) and grid-snap.ts
- Fix curved conveyor/chute outline to match SVG viewBox geometry
- Draw curves programmatically with fixed 30px band width (no SVG stretching)
- Single resize handle for curves (was 2)
- Add .gitattributes for consistent line endings
- Make Vec2 type module-private
- Add mirror transform support in renderer

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 17:21:04 +04:00
c5bb986a82 Refactor: extract render theme, hit-testing module, clean up legacy exports
- Extract 25+ hardcoded colors/sizes to render-theme.ts
- Extract pure hit-testing functions to hit-testing.ts (-104 lines from interactions.ts)
- Remove 11 legacy re-exports from symbols.ts, use config objects directly
- Fix preloadSymbolImages async/await anti-pattern
- Extract ensureEpcWaypoints() helper (3x dedup)
- Fix PDF not clearing on MCM switch
- Fix MCM persistence on reload
- Change defaults: grid off, grid size 2, min spacing 2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 19:03:38 +04:00
20e9c60afa Update README with full project docs, setup, and device classification
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 17:50:09 +04:00
eda97fc5bc real commit 2026-03-20 17:46:47 +04:00