gerbers-renderer 0.1.2 โ†’ 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,178 +1,254 @@
1
1
  # gerbers-renderer
2
2
 
3
- Frontend-only Gerber viewer for the web.
4
- Render PCB Gerbers directly in the browser. No backend. No CAM tools. No DFM.
3
+ Pure frontend Gerber rendering for the web.
4
+ Render PCB Gerber bundles (`.zip`, `.rar`) directly in the browser with zero backend, zero native dependencies.
5
5
 
6
- ๐Ÿ‘‰ Upload a gerbers.zip
7
- ๐Ÿ‘‰ View Top / Bottom copper, mask, silkscreen, drills
8
- ๐Ÿ‘‰ Pan, zoom, fit, grid
9
- ๐Ÿ‘‰ Download the original Gerbers ZIP
6
+ Designed for:
10
7
 
11
- ## โœจ Features
8
+ - Web apps
9
+ - Browser extensions
10
+ - CI previews
11
+ - Manufacturing portals
12
+ - DFM tools
12
13
 
13
- - Fully client-side (runs in the browser)
14
- - Accepts standard gerbers.zip exports
15
- - Automatic layer classification
16
- - Correct board masking and clipping
17
- - Top / Bottom view toggle
18
- - Grid overlay (mm / inch)
19
- - Designed to embed into any website
20
- - No framework dependency (not React/Vue/etc.)
14
+ ## Features
21
15
 
22
- ## ๐Ÿš€ Installation
16
+ - ๐Ÿง  Gerber bundle detection (not just โ€œtry and failโ€)
17
+ - ๐Ÿ“ฆ Supports `.zip` and `.rar` archives (browser-side)
18
+ - ๐ŸŽจ 2D SVG-based board viewer
19
+ - ๐Ÿงฉ Drop-in viewer that mounts into any DOM node
20
+ - ๐Ÿงช Typed, deterministic render results
21
+ - ๐Ÿงผ No backend, no workers unless needed
22
+ - โšก Vite, React, vanilla JS friendly
23
+
24
+ ## Installation
23
25
 
24
- ### Install from npm (recommended)
25
26
  ```bash
26
27
  npm install gerbers-renderer
27
28
  ```
28
29
 
29
- ### ๐ŸŒ CDN Usage (No Build Tools)
30
- ```html
31
- <script src="https://unpkg.com/gerbers-renderer"></script>
32
- <script>
33
- const { createBoardViewer, renderGerbersZip } = window.GerbersRenderer;
34
- </script>
30
+ ## Quick start (minimal)
31
+
32
+ ```typescript
33
+ import { renderGerbers, createBoardViewer } from "gerbers-renderer";
34
+
35
+ const viewer = createBoardViewer(document.getElementById("pcb")!);
36
+
37
+ const file = input.files[0];
38
+ const buffer = await file.arrayBuffer();
39
+
40
+ const result = await renderGerbers(buffer, {
41
+ archiveWorkerUrl: "/libarchive-worker-bundle.js", // required for .rar
42
+ });
43
+
44
+ viewer.setData({
45
+ boardGeom: result.boardGeom,
46
+ layers: result.layers,
47
+ });
48
+ viewer.fit();
35
49
  ```
36
50
 
37
- Pin a version if needed:
51
+ Always call `result.revoke()` when replacing a render.
52
+
53
+ ## Live demo
38
54
 
39
- ```html
40
- <script src="https://unpkg.com/gerbers-renderer@0.1.0"></script>
55
+ ```bash
56
+ git clone https://github.com/asappcb/gerbers-renderer
57
+ npm install
58
+ npm run dev
41
59
  ```
42
60
 
43
- ## ๐Ÿงฉ Minimal Usage Example
61
+ Open:
62
+ ๐Ÿ‘‰ http://localhost:5173/demo/
63
+
64
+ ## Supported input formats
65
+
66
+ | Format | Supported | Notes |
67
+ |---|---:|---|
68
+ | `.zip` | โœ… | Native via JSZip |
69
+ | `.rar` | โœ… | Via libarchive.js (WASM) |
70
+ | `.7z` | โŒ (future) | Detection works |
71
+ | `.tar` | โŒ (future) | Detection works |
72
+ | Directory | โœ… | Use `renderGerbersFiles` |
73
+
74
+ ## Gerber bundle detection
75
+
76
+ Before rendering, you can detect whether an input is actually a Gerber bundle.
44
77
 
45
- **HTML**
46
- ```html
47
- <input type="file" id="file" accept=".zip" />
48
- <div id="viewer" style="width:100%; height:600px;"></div>
78
+ ```typescript
79
+ import { detectGerberBundle } from "gerbers-renderer";
80
+
81
+ const result = await detectGerberBundle(buffer);
82
+
83
+ if (!result.isGerber) {
84
+ console.log("Not a Gerber bundle:", result.reasons);
85
+ }
49
86
  ```
50
87
 
51
- **JavaScript / TypeScript**
52
88
  ```typescript
53
- import { renderGerbersZip, createBoardViewer } from "gerbers-renderer";
89
+ type GerberDetectResult = {
90
+ isGerber: boolean;
91
+ archiveType: "zip" | "rar" | "7z" | "tar" | "directory" | "single-file" | "unknown";
92
+ confidence: number; // 0.0 โ€“ 1.0
93
+ reasons: string[];
94
+ files?: string[];
95
+ };
96
+ ```
54
97
 
55
- const input = document.getElementById("file") as HTMLInputElement;
56
- const host = document.getElementById("viewer")!;
98
+ ## Rendering APIs
57
99
 
58
- const viewer = createBoardViewer(host, {
59
- onDownload: () => {
60
- if (!lastZip) return;
61
- const a = document.createElement("a");
62
- const url = URL.createObjectURL(lastZip);
63
- a.href = url;
64
- a.download = lastZip.name;
65
- a.click();
66
- URL.revokeObjectURL(url);
100
+ ### `renderGerbers(...)` (recommended)
101
+
102
+ Single high-level entrypoint.
103
+
104
+ ```typescript
105
+ renderGerbers(
106
+ input: ArrayBuffer | Uint8Array,
107
+ options?: {
108
+ archiveWorkerUrl?: string; // required for rar
67
109
  }
68
- });
110
+ ): Promise<RenderResult>
111
+ ```
69
112
 
70
- let lastRender: any = null;
71
- let lastZip: File | null = null;
113
+ Handles:
72
114
 
73
- input.addEventListener("change", async () => {
74
- const file = input.files?.[0];
75
- if (!file) return;
115
+ - Archive detection
116
+ - Unpacking
117
+ - Validation
118
+ - Rendering
76
119
 
77
- lastZip = file;
78
- if (lastRender) lastRender.revoke();
120
+ ### `renderGerbersZip(...)`
79
121
 
80
- const out = await renderGerbersZip(file);
81
- lastRender = out;
122
+ Zip-only convenience wrapper.
82
123
 
83
- viewer.setData({
84
- boardGeom: out.boardGeom,
85
- layers: out.layers
86
- });
87
- });
124
+ ```typescript
125
+ renderGerbersZip(input: File | Blob | ArrayBuffer | Uint8Array)
88
126
  ```
89
127
 
90
- That's it. No server. No workers. No build assumptions.
128
+ ### `renderGerbersFiles(...)`
91
129
 
92
- ## ๐Ÿง  Core API
130
+ Lowest-level API if you already have files.
93
131
 
94
- ### `renderGerbersZip(file: File)`
132
+ ```typescript
133
+ renderGerbersFiles(
134
+ files: Record<string, Uint8Array>
135
+ )
136
+ ```
137
+
138
+ ## Viewer
95
139
 
96
- Parses and renders a Gerbers ZIP entirely in the browser.
140
+ Create a drop-in board viewer:
97
141
 
98
- **Returns:**
99
142
  ```typescript
100
- {
101
- boardGeom: {
102
- widthMm: number;
103
- heightMm: number;
104
- },
105
- layers: {
106
- top_copper?: string;
107
- bottom_copper?: string;
108
- top_silk?: string;
109
- bottom_silk?: string;
110
- top_mask?: string;
111
- bottom_mask?: string;
112
- drills?: string;
113
- top_board_mask?: string;
114
- bottom_board_mask?: string;
143
+ const viewer = createBoardViewer(container, {
144
+ onDownload: () => {
145
+ /* optional */
115
146
  },
116
- revoke: () => void
117
- }
147
+ });
148
+
149
+ viewer.setData({
150
+ boardGeom,
151
+ layers,
152
+ });
153
+
154
+ viewer.setSideMode("top"); // "top" | "bottom"
155
+ viewer.fit();
118
156
  ```
119
157
 
120
- Layer values are blob URLs containing SVGs.
158
+ The viewer supports:
121
159
 
122
- Call `revoke()` when replacing or discarding a render.
160
+ - Pan / zoom
161
+ - Layer toggling
162
+ - Top / bottom switching
163
+ - Download hook (original Gerbers)
123
164
 
124
- ### `createBoardViewer(host, options?)`
165
+ ## Return value
125
166
 
126
- Mounts an interactive PCB viewer into a DOM element.
167
+ All render functions return a deterministic object:
127
168
 
128
169
  ```typescript
129
- createBoardViewer(host, {
130
- onDownload?: () => void
131
- });
170
+ type RenderResult = {
171
+ boardGeom: BoardGeom;
172
+ layers: ViewerLayers;
173
+ revoke: () => void; // revoke blob URLs
174
+ };
175
+ ```
176
+
177
+ Always call `revoke()` when replacing a render.
178
+
179
+ ## `.rar` support (important)
180
+
181
+ To support `.rar` archives, you must host the libarchive worker bundle.
182
+
183
+ Setup
184
+
185
+ Copy:
186
+
187
+ ```text
188
+ node_modules/libarchive.js/dist/worker-bundle.js
132
189
  ```
133
190
 
134
- The viewer handles:
135
- - pan / zoom / fit
136
- - Top / Bottom switching
137
- - layer visibility
138
- - board clipping mask
191
+ To:
139
192
 
140
- The viewer is intentionally stateless with respect to parsing.
193
+ ```text
194
+ public/libarchive-worker-bundle.js
195
+ ```
141
196
 
142
- ## ๐Ÿ“ฆ Download Behavior
197
+ Then pass:
198
+
199
+ ```typescript
200
+ renderGerbers(buffer, {
201
+ archiveWorkerUrl: "/libarchive-worker-bundle.js",
202
+ });
203
+ ```
143
204
 
144
- The viewer does not decide what "Download" means.
205
+ ZIP users do not pay this cost.
145
206
 
146
- Instead, you supply a handler via `onDownload`.
207
+ ## Error handling
147
208
 
148
- Typical use:
149
- - download the original gerbers.zip
150
- - export SVG layers
151
- - export screenshots
152
- - pipe into manufacturing workflows
209
+ Errors are typed and structured.
153
210
 
154
- This keeps the viewer reusable across products.
211
+ ```typescript
212
+ class GerberError extends Error {
213
+ code:
214
+ | "NOT_AN_ARCHIVE"
215
+ | "UNSUPPORTED_ARCHIVE"
216
+ | "NOT_GERBER"
217
+ | "MISSING_LAYERS"
218
+ | "PARSE_ERROR";
219
+ details?: any;
220
+ }
221
+ ```
155
222
 
156
- ## ๐Ÿงญ Design Philosophy
223
+ Always catch and inspect `error.code` in UI or CI.
157
224
 
158
- - Viewer โ‰  parser โ‰  renderer
159
- - Frontend-only by design
160
- - No assumptions about backend or manufacturing
161
- - Safe to embed anywhere
162
- - Easy to extend
225
+ ## What this is not
163
226
 
164
- This project is intentionally not a CAM tool or DFM checker.
227
+ - โŒ Not a CAM tool
228
+ - โŒ Not a DRC / DFM engine
229
+ - โŒ Not a backend renderer
165
230
 
166
- ## โŒ What This Is Not
231
+ This library is intentionally focused on fast, accurate visualization.
167
232
 
168
- - Not a DFM rules engine
169
- - Not a fabrication quote system
170
- - Not a replacement for CAM software
233
+ ## Roadmap
171
234
 
172
- It's a fast, embeddable Gerber viewer.
235
+ - 7z / tar unpacking
236
+ - Inner-layer rendering
237
+ - Canvas renderer
238
+ - WASM-only core split
239
+ - Headless CI validation mode
173
240
 
174
- ## ๐Ÿ“„ License
241
+ ## License
175
242
 
176
243
  MIT
177
244
 
178
- Use it freely in commercial or open-source projects.
245
+ ## Why this exists
246
+
247
+ Most Gerber viewers:
248
+
249
+ - require servers
250
+ - are untyped
251
+ - break in browsers
252
+ - silently mis-detect archives
253
+
254
+ gerbers-renderer is designed from first principles for modern web tooling.
@@ -0,0 +1,2 @@
1
+ import { GerberDetectResult } from './types';
2
+ export declare function detectGerberBundle(input: ArrayBuffer | Uint8Array | Record<string, Uint8Array>): Promise<GerberDetectResult>;
@@ -0,0 +1,5 @@
1
+ export declare class GerberError extends Error {
2
+ code: "NOT_AN_ARCHIVE" | "UNSUPPORTED_ARCHIVE" | "NOT_GERBER" | "MISSING_LAYERS" | "PARSE_ERROR";
3
+ details?: unknown;
4
+ constructor(code: GerberError["code"], message: string, details?: unknown);
5
+ }
@@ -0,0 +1,2 @@
1
+ import { GerberFileListResult } from './types';
2
+ export declare function listGerberFiles(input: ArrayBuffer | Uint8Array | Record<string, Uint8Array>): Promise<GerberFileListResult>;
@@ -0,0 +1,18 @@
1
+ export type GerberBundleType = "zip" | "rar" | "7z" | "tar" | "directory" | "single-file" | "unknown";
2
+ export type GerberDetectResult = {
3
+ isGerber: boolean;
4
+ archiveType: GerberBundleType;
5
+ confidence: number;
6
+ reasons: string[];
7
+ files?: string[];
8
+ };
9
+ export type ListedLayer = {
10
+ filename: string;
11
+ type: "copper" | "mask" | "silk" | "drill" | "outline" | "unknown";
12
+ side?: "top" | "bottom" | "inner";
13
+ };
14
+ export type GerberFileListResult = {
15
+ layers: ListedLayer[];
16
+ boardOutlinePresent: boolean;
17
+ drillPresent: boolean;
18
+ };