Postmortem: The Shape Classifier Broke Every Time We Added a New Domain
TLDR
Our original shape classifier relied on hardcoded CSS class names (.wire, .junction, .component). As we expanded from electrical schematics to construction floorplans and software architecture diagrams, the classifier accumulated over 120 lines of domain-specific branching logic (if (domain === 'construction') ...). SVG imports continuously broke because imported files lacked class tags. Replacing class conditionals with a 4-phase geometric pipeline eliminated all domain branches.
| System Aspect | Legacy Class Classifier | Refactored Geometric Pipeline |
|---|---|---|
| Domain Scaling | Required new if/else per domain | Zero domain-specific code |
| SVG Import Compatibility | Fails on unclassed SVGs | 100% Compatible across all domains |
| Codebase Complexity | ~120 lines of nested branching | Single unified math pipeline |
Problem statement: the branching explosion across multi-domain support
Initially, our editor targeted electrical schematics: wires were .wire and junction dots were .junction.
When we added support for construction diagrams, walls (.wall) needed to behave like wires in connectivity analysis. When we added software architecture diagrams, dependency arrows (.dep-arrow) needed wire behavior while module containers (.module-box) needed component behavior.
The shape classifier evolved into a messy nested conditional:
// DEPRECATED: Domain-specific class branching (~120 lines deleted) if (domainMode === 'electrical') { if (cls.includes('wire')) return 'wire'; } else if (domainMode === 'construction') { if (cls.includes('wall')) return 'wire'; } else if (domainMode === 'software') { if (cls.includes('dep-arrow')) return 'wire'; }
Every new domain required adding new class lists, and SVG imports from external tools failed completely.
Technical failure mode: the import desync incident
When a user imported an architectural floorplan SVG from Inkscape, the walls were exported as unclassed <path> elements.
Because cls.includes('wall') evaluated to false, the classifier categorized all wall paths as generic component nodes. Spatial wall-junction calculations failed silently, generating broken structural reports.
The fix & architecture: the 4-phase geometric pipeline
We deleted 120 lines of domain conditional logic and replaced them with a 4-phase geometric pipeline:
- Path Extraction & Parsing: Parse path
dattributes into point arrays. - Coordinate Canonicalization: Apply matrix transforms (
DOMMatrix) to convert points to global world space. - Metric Calculation: Compute Linearity Ratio ($L$) and Isoperimetric Quotient ($Q$).
- Classification Pass: Evaluate universal thresholds ($L > 0.85 \rightarrow \text{wire}$; $Q > 0.65 \rightarrow \text{connector}$).
// REFACTORED: Unified 4-phase geometry classifier
function classifyElement(el) {
// Respect explicit metadata override if present
const meta = el.getAttribute('data-geo-class');
if (meta) return meta;
// Universal geometric fallback const points = extractGlobalWorldPoints(el); const isClosed = isPathClosed(el); return classifyByGeometry(points, isClosed); }
A wall in a construction diagram and a wire in an electrical schematic both exhibit high linearity ($L > 0.85$). The geometric classifier identifies both correctly without knowing or caring which domain is active.
Rule of thumb: Eliminate domain-specific class branching by deriving classifications from intrinsic spatial properties rather than author-assigned metadata.