interface Point2D { x: number; y: number; } interface Point3D { x: number; y: number; z: number; } interface DxfDocument { header: DxfHeader; layers: Map; lineTypes: Map; styles: Map; blocks: Map; entities: DxfEntity[]; } interface DxfHeader { acadVersion: string; extMin?: Point3D; extMax?: Point3D; insUnits: number; measurement: number; ltScale: number; dwgCodePage?: string; handleSeed?: string; [key: string]: unknown; } interface DxfLayer { name: string; color: number; lineType: string; flags: number; lineWeight: number; trueColor?: number; isOff: boolean; isFrozen: boolean; isLocked: boolean; } interface DxfLineType { name: string; description: string; pattern: number[]; totalLength: number; } interface DxfStyle { name: string; fontName: string; bigFontName: string; height: number; widthFactor: number; obliqueAngle: number; } interface DxfBlock { name: string; basePoint: Point3D; entities: DxfEntity[]; flags: number; } interface DxfEntityBase { type: string; handle?: string; layer: string; color: number; trueColor?: number; lineType: string; lineTypeScale: number; lineWeight: number; visible: boolean; extrusion: Point3D; } interface DxfLineEntity extends DxfEntityBase { type: 'LINE'; start: Point3D; end: Point3D; } interface DxfCircleEntity extends DxfEntityBase { type: 'CIRCLE'; center: Point3D; radius: number; } interface DxfArcEntity extends DxfEntityBase { type: 'ARC'; center: Point3D; radius: number; startAngle: number; endAngle: number; } interface DxfLwPolylineVertex { x: number; y: number; bulge: number; startWidth: number; endWidth: number; } interface DxfLwPolylineEntity extends DxfEntityBase { type: 'LWPOLYLINE'; vertices: DxfLwPolylineVertex[]; closed: boolean; constantWidth: number; elevation: number; } interface DxfPolylineEntity extends DxfEntityBase { type: 'POLYLINE'; vertices: DxfLwPolylineVertex[]; closed: boolean; is3d: boolean; } interface DxfEllipseEntity extends DxfEntityBase { type: 'ELLIPSE'; center: Point3D; majorAxis: Point3D; minorRatio: number; startParam: number; endParam: number; } interface DxfSplineEntity extends DxfEntityBase { type: 'SPLINE'; degree: number; flags: number; knots: number[]; controlPoints: Point3D[]; fitPoints: Point3D[]; weights: number[]; startTangent?: Point3D; endTangent?: Point3D; } interface DxfTextEntity extends DxfEntityBase { type: 'TEXT'; text: string; insertionPoint: Point3D; alignmentPoint?: Point3D; height: number; rotation: number; widthFactor: number; obliqueAngle: number; style: string; hAlign: number; vAlign: number; generationFlags: number; } interface DxfMTextEntity extends DxfEntityBase { type: 'MTEXT'; text: string; insertionPoint: Point3D; height: number; width: number; attachmentPoint: number; drawingDirection: number; rotation: number; lineSpacingStyle: number; lineSpacingFactor: number; style: string; textDirection?: Point3D; bgFill: number; bgFillColor?: number; bgFillTrueColor?: number; bgFillScale: number; } interface DxfInsertEntity extends DxfEntityBase { type: 'INSERT'; blockName: string; insertionPoint: Point3D; scaleX: number; scaleY: number; scaleZ: number; rotation: number; columnCount: number; rowCount: number; columnSpacing: number; rowSpacing: number; attribs: DxfAttrib[]; } interface DxfAttrib { tag: string; text: string; insertionPoint: Point3D; height: number; rotation: number; style: string; layer: string; color: number; } interface DxfDimensionEntity extends DxfEntityBase { type: 'DIMENSION'; blockName: string; dimStyle: string; dimType: number; defPoint: Point3D; textMidpoint: Point3D; defPoint2?: Point3D; defPoint3?: Point3D; defPoint4?: Point3D; defPoint5?: Point3D; textOverride: string; rotation: number; textRotation: number; leaderLength: number; } interface DxfHatchBoundaryPath { type: 'polyline' | 'edges'; vertices?: Point2D[]; bulges?: number[]; isClosed?: boolean; edges?: DxfHatchEdge[]; flags: number; } type DxfHatchEdge = { type: 'line'; start: Point2D; end: Point2D; } | { type: 'arc'; center: Point2D; radius: number; startAngle: number; endAngle: number; ccw: boolean; } | { type: 'ellipse'; center: Point2D; majorAxis: Point2D; minorRatio: number; startAngle: number; endAngle: number; ccw: boolean; } | { type: 'spline'; degree: number; knots: number[]; controlPoints: Point2D[]; weights?: number[]; }; interface DxfHatchEntity extends DxfEntityBase { type: 'HATCH'; patternName: string; solidFill: boolean; associative: boolean; hatchStyle: number; patternType: number; patternAngle: number; patternScale: number; boundaryPaths: DxfHatchBoundaryPath[]; } interface DxfPointEntity extends DxfEntityBase { type: 'POINT'; position: Point3D; } type DxfEntity = DxfLineEntity | DxfCircleEntity | DxfArcEntity | DxfLwPolylineEntity | DxfPolylineEntity | DxfEllipseEntity | DxfSplineEntity | DxfTextEntity | DxfMTextEntity | DxfInsertEntity | DxfDimensionEntity | DxfHatchEntity | DxfPointEntity; /** * Error thrown when DXF parsing fails. */ declare class DxfParseError extends Error { readonly cause?: unknown | undefined; constructor(message: string, cause?: unknown | undefined); } /** * Parse a DXF file from string or ArrayBuffer. * * @throws {DxfParseError} If the input is empty, malformed, or cannot be parsed. */ declare function parseDxf(input: string | ArrayBuffer): DxfDocument; declare function aciToHex(aci: number): string | undefined; declare function aciToDisplayColor(aci: number, isDarkTheme: boolean): string; declare function trueColorToHex(trueColor: number): string; interface ViewTransform { scale: number; offsetX: number; offsetY: number; } declare function worldToScreen(vt: ViewTransform, wx: number, wy: number): [number, number]; declare function screenToWorld(vt: ViewTransform, sx: number, sy: number): [number, number]; declare function applyTransform(ctx: CanvasRenderingContext2D, vt: ViewTransform): void; declare function fitToView(canvasWidth: number, canvasHeight: number, minX: number, minY: number, maxX: number, maxY: number, padding?: number): ViewTransform; declare function zoomAtPoint(vt: ViewTransform, screenX: number, screenY: number, zoomFactor: number, minScale?: number, maxScale?: number): ViewTransform; declare class Camera { private transform; private minScale; private maxScale; constructor(options: { minZoom: number; maxZoom: number; }); getTransform(): ViewTransform; setTransform(vt: ViewTransform): void; pan(dx: number, dy: number): void; zoom(screenX: number, screenY: number, factor: number): void; } type Theme = 'dark' | 'light'; interface ThemeConfig { backgroundColor: string; defaultEntityColor: string; selectionColor: string; measureColor: string; gridColor: string; crosshairColor: string; } declare const THEMES: Record; interface RenderStats { entitiesDrawn: number; entitiesSkipped: number; drawCalls: number; byType: Record; } interface DebugOptions { showFps?: boolean; showRenderStats?: boolean; showDocumentInfo?: boolean; showTimings?: boolean; showCamera?: boolean; position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'; } interface DebugStats { fps: number; frameTime: number; renderStats: RenderStats; entityCount: number; layerCount: number; visibleLayerCount: number; blockCount: number; parseTime: number; spatialIndexBuildTime: number; totalLoadTime: number; zoom: number; pixelSize: number; viewportBounds: { minX: number; minY: number; maxX: number; maxY: number; }; fileName: string | null; fileSize: number; dxfVersion: string | null; } type ResolvedDebugOptions = Required; /** * Render a debug overlay panel on the canvas in screen space. * Follows the same pattern as renderMeasureOverlay — resets transform to screen space. */ declare function renderDebugOverlay(ctx: CanvasRenderingContext2D, stats: DebugStats, theme: Theme, options: ResolvedDebugOptions, canvasWidth: number, canvasHeight: number): void; interface BBox { minX: number; minY: number; maxX: number; maxY: number; } declare function computeEntitiesBounds(entities: DxfEntity[], doc?: DxfDocument): BBox | null; /** * Compute entity bbox without document context. * INSERT entities return a zero-size bbox at their insertion point. * For proper INSERT bounds, use computeEntityBBoxWithDoc() instead. */ declare function computeEntityBBox(entity: DxfEntity): BBox | null; /** * Resolve the display color for an entity. * * Resolution order: * 1. Entity true color (code 420) - highest priority * 2. Entity ACI color (code 62): * - 1-255: use ACI color table * - 0 (BYBLOCK): use parent INSERT color, or default if no parent * - 256 (BYLAYER): use layer color * 3. Layer color (from LAYER table) * 4. Default theme color (fallback) */ declare function resolveEntityColor(entity: DxfEntityBase, layers: Map, theme: Theme, parentColor?: string): string; declare class CanvasRenderer { private canvas; private ctx; private width; private height; constructor(canvas: HTMLCanvasElement); getContext(): CanvasRenderingContext2D; getWidth(): number; getHeight(): number; updateSize(): void; render(doc: DxfDocument, vt: ViewTransform, theme: Theme, visibleLayers: Set, selectedEntityIndex: number, visibleEntityIndices?: Set, entityBBoxes?: (BBox | null)[]): RenderStats; renderEmpty(theme: Theme): void; destroy(): void; } declare function drawEntity(ctx: CanvasRenderingContext2D, entity: DxfEntity, doc: DxfDocument, vt: ViewTransform, theme: Theme, pixelSize: number, stats?: RenderStats): void; interface SelectEvent { entity: DxfEntity; entityIndex: number; worldPoint: Point2D; screenPoint: Point2D; } interface MeasureEvent { distance: number; angle: number; deltaX: number; deltaY: number; points: [Point2D, Point2D]; } interface CadViewerEventMap { select: SelectEvent; measure: MeasureEvent; viewchange: ViewTransform; } declare class EventEmitter = Record> { private listeners; on(event: K, callback: (data: T[K]) => void): void; off(event: K, callback: (data: T[K]) => void): void; emit(event: K, data: T[K]): void; removeAllListeners(): void; } type Tool = 'pan' | 'select' | 'measure'; /** * Interface for registering custom file format converters. * Converters are checked in order during `loadFile()` and `loadBuffer()`. * The first converter whose `detect()` returns true will be used. */ interface FormatConverter { /** * Return true if the buffer is in this format. * Implementations should check magic bytes, not file extensions. * Must not throw — return false on any error. */ detect(buffer: ArrayBuffer): boolean; /** * Convert the buffer to a DXF string. * The returned string must be valid DXF parseable by `parseDxf()`. */ convert(buffer: ArrayBuffer): Promise; } interface CadViewerOptions { theme?: Theme; backgroundColor?: string; antialias?: boolean; minZoom?: number; maxZoom?: number; zoomSpeed?: number; initialTool?: Tool; /** Format converters for non-DXF file formats (e.g. DWG via @cadview/dwg). */ formatConverters?: FormatConverter[]; /** * Enable a debug overlay showing FPS, render stats, document info, timing, and camera data. * Pass `true` for defaults, or an object for granular control. */ debug?: boolean | DebugOptions; /** * Enable off-main-thread DXF parsing using a Web Worker. * When `true`, the async load methods (`loadFile()`, `loadBuffer()`) will * parse DXF content in a Web Worker to avoid blocking the UI thread. * Synchronous methods (`loadString()`, `loadArrayBuffer()`) are unaffected. * @default false */ worker?: boolean; } declare class CadViewer { private canvas; private renderer; private camera; private layerManager; private emitter; private spatialIndex; private measureTool; private doc; private options; private currentTool; private inputHandler; private resizeObserver; private formatConverters; private workerManager; private selectedEntityIndex; private renderPending; private destroyed; private loadGeneration; private mouseScreenX; private mouseScreenY; private debugEnabled; private debugOptions; private lastRenderStats; private lastDebugStats; private frameTimestamps; private lastDoRenderTime; private lastFrameTime; private parseTime; private spatialIndexBuildTime; private loadedFileName; private loadedFileSize; private debugRafId; constructor(canvas: HTMLCanvasElement, options?: CadViewerOptions); /** * Throws if the viewer has been destroyed. * Call at the start of any public method that mutates state. */ private guardDestroyed; /** * Run registered format converters on a buffer. * Returns the converted DXF string if a converter matched, or null otherwise. * Each converter's detect() is wrapped in try/catch — a throwing detect() is skipped. */ private runConverters; /** * Load a CAD file from a browser File object. * Automatically detects the format using registered converters (e.g. DWG). * Falls back to DXF parsing if no converter matches. */ loadFile(file: File): Promise; /** * Load a CAD file from an ArrayBuffer with format converter support. * Unlike `loadArrayBuffer()` (sync, DXF-only), this method is async and * checks registered FormatConverters for non-DXF formats. */ loadBuffer(buffer: ArrayBuffer): Promise; /** * Parse input using the Worker (if enabled) or the main-thread parser. * When the Worker is terminated (e.g. viewer destroyed) while a parse is * in flight, the rejection is swallowed if the load generation is stale. */ private parseWithOptionalWorker; /** * Load a pre-parsed DxfDocument directly, bypassing the parser. * Useful for custom parsers or pre-processed documents. */ loadDocument(doc: DxfDocument): void; /** * Load a DXF string directly (synchronous, no format conversion). */ loadString(dxf: string): void; /** * Load a DXF file from an ArrayBuffer (synchronous, no format conversion). * For format conversion support (e.g. DWG), use `loadFile()` or `loadBuffer()` instead. */ loadArrayBuffer(buffer: ArrayBuffer): void; /** * Clear the current document and reset all state without destroying the viewer. */ clearDocument(): void; private onDocumentLoaded; fitToView(): void; zoomTo(scale: number): void; panTo(worldX: number, worldY: number): void; getViewTransform(): ViewTransform; /** @internal */ getZoomSpeed(): number; getLayers(): DxfLayer[]; setLayerVisible(name: string, visible: boolean): void; setLayerColor(name: string, color: string): void; setTheme(theme: Theme): void; getTheme(): Theme; setBackgroundColor(color: string): void; setTool(tool: Tool): void; getTool(): Tool; private getCursorForTool; on(event: K, callback: (data: CadViewerEventMap[K]) => void): void; off(event: K, callback: (data: CadViewerEventMap[K]) => void): void; getDocument(): DxfDocument | null; getEntities(): DxfEntity[]; resize(): void; destroy(): void; /** @internal */ requestRender(): void; private doRender; /** * Enable or disable the debug overlay. * Pass `true` for defaults, `false` to disable, or an object for granular control. */ setDebug(debug: boolean | DebugOptions): void; private startDebugLoop; private stopDebugLoop; /** * Get the latest debug stats snapshot, or null if debug mode is off. */ getDebugStats(): DebugStats | null; private buildDebugStats; private computeViewportBounds; /** @internal */ handlePan(dx: number, dy: number): void; /** @internal */ handleZoom(screenX: number, screenY: number, factor: number): void; /** @internal */ handleClick(screenX: number, screenY: number): void; /** @internal — called by InputHandler for mouse move */ handleMouseMove(screenX: number, screenY: number): void; private handleSelect; private computeDocumentBounds; } declare class LayerManager { private layers; private visibility; private colorOverrides; private visibleCache; setLayers(layers: Map): void; getAllLayers(): DxfLayer[]; setVisible(name: string, visible: boolean): void; isVisible(name: string): boolean; setColorOverride(name: string, color: string): void; getColorOverride(name: string): string | undefined; getVisibleLayerNames(): Set; clear(): void; } interface SpatialItem { minX: number; minY: number; maxX: number; maxY: number; entityIndex: number; } declare class SpatialIndex { private tree; private items; /** Pre-computed bboxes parallel to the entity array (null if no bbox). */ private entityBBoxes; /** * Build the spatial index from entities. * When `doc` is provided, INSERT entities get proper transformed bounding boxes * (resolved from block contents) instead of degenerate zero-size points. */ build(entities: DxfEntity[], doc?: DxfDocument): void; search(minX: number, minY: number, maxX: number, maxY: number): SpatialItem[]; /** Get pre-computed bbox for an entity by index. */ getEntityBBox(index: number): BBox | null; /** Get the full pre-computed bbox array (parallel to entity array). */ getEntityBBoxes(): (BBox | null)[]; clear(): void; } /** * Find the nearest entity to a world point. * Returns entity index, or -1 if nothing is within tolerance. */ declare function hitTest(wx: number, wy: number, entities: DxfEntity[], spatialIndex: SpatialIndex, visibleLayers: Set, scale: number): number; type SnapType = 'endpoint' | 'midpoint' | 'center' | 'nearest'; interface SnapResult { point: Point2D; type: SnapType; entityIndex: number; } type MeasureState = { phase: 'idle'; } | { phase: 'first-point'; } | { phase: 'second-point'; firstPoint: Point2D; firstSnap?: SnapResult; } | { phase: 'done'; firstPoint: Point2D; secondPoint: Point2D; distance: number; angle: number; }; declare class MeasureTool { state: MeasureState; currentSnap: SnapResult | null; activate(): void; deactivate(): void; handleClick(wx: number, wy: number, snap: SnapResult | null): MeasureEvent | null; handleMove(snap: SnapResult | null): void; } declare function findSnaps(wx: number, wy: number, entities: DxfEntity[], spatialIndex: SpatialIndex, scale: number, snapTypes?: Set): SnapResult[]; declare function renderMeasureOverlay(ctx: CanvasRenderingContext2D, vt: ViewTransform, measureTool: MeasureTool, mouseScreenX: number, mouseScreenY: number, theme: Theme): void; export { type BBox, CadViewer, type CadViewerEventMap, type CadViewerOptions, Camera, CanvasRenderer, type DebugOptions, type DebugStats, type DxfArcEntity, type DxfAttrib, type DxfBlock, type DxfCircleEntity, type DxfDimensionEntity, type DxfDocument, type DxfEllipseEntity, type DxfEntity, type DxfEntityBase, type DxfHatchBoundaryPath, type DxfHatchEdge, type DxfHatchEntity, type DxfHeader, type DxfInsertEntity, type DxfLayer, type DxfLineEntity, type DxfLineType, type DxfLwPolylineEntity, type DxfLwPolylineVertex, type DxfMTextEntity, DxfParseError, type DxfPointEntity, type DxfPolylineEntity, type DxfSplineEntity, type DxfStyle, type DxfTextEntity, EventEmitter, type FormatConverter, LayerManager, type MeasureEvent, type MeasureState, MeasureTool, type Point2D, type Point3D, type RenderStats, type SelectEvent, type SnapResult, type SnapType, SpatialIndex, THEMES, type Theme, type ThemeConfig, type Tool, type ViewTransform, aciToDisplayColor, aciToHex, applyTransform, computeEntitiesBounds, computeEntityBBox, drawEntity, findSnaps, fitToView, hitTest, parseDxf, renderDebugOverlay, renderMeasureOverlay, resolveEntityColor, screenToWorld, trueColorToHex, worldToScreen, zoomAtPoint };