@tscircuit/curvy-trace-solver 0.0.1 → 0.0.3

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.
@@ -0,0 +1,26 @@
1
+ # Created using @tscircuit/plop (npm install -g @tscircuit/plop)
2
+ name: Format Check
3
+
4
+ on:
5
+ push:
6
+ branches: [main]
7
+ pull_request:
8
+ branches: [main]
9
+
10
+ jobs:
11
+ format-check:
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Setup bun
18
+ uses: oven-sh/setup-bun@v2
19
+ with:
20
+ bun-version: latest
21
+
22
+ - name: Install dependencies
23
+ run: bun install
24
+
25
+ - name: Run format check
26
+ run: bun run format:check
@@ -0,0 +1,92 @@
1
+ # Created using @tscircuit/plop (npm install -g @tscircuit/plop)
2
+ name: Publish to npm
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ - '!version-bumps/**'
8
+ workflow_dispatch:
9
+
10
+ env:
11
+ UPSTREAM_REPOS: "" # comma-separated list, e.g. "eval,tscircuit,docs"
12
+ UPSTREAM_PACKAGES_TO_UPDATE: "" # comma-separated list, e.g. "@tscircuit/core,@tscircuit/protos"
13
+
14
+ jobs:
15
+ publish:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - name: Setup bun
20
+ uses: oven-sh/setup-bun@v2
21
+ with:
22
+ bun-version: latest
23
+ - uses: actions/setup-node@v4
24
+ with:
25
+ node-version: 20
26
+ registry-url: https://registry.npmjs.org/
27
+ - run: npm install -g pver
28
+ - run: bun install --frozen-lockfile
29
+ - run: bun run build
30
+ - run: pver release --no-push-main
31
+ env:
32
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
33
+ GITHUB_TOKEN: ${{ secrets.TSCIRCUIT_BOT_GITHUB_TOKEN }}
34
+
35
+ - name: Get package version
36
+ id: package-version
37
+ run: |
38
+ VERSION=$(node -p "require('./package.json').version")
39
+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
40
+
41
+
42
+ - name: Create Pull Request
43
+ id: create-pr
44
+ uses: peter-evans/create-pull-request@v6
45
+ with:
46
+ commit-message: "chore: bump version"
47
+ title: "chore: bump version to v${{ steps.package-version.outputs.version }}"
48
+ body: "Automated package update"
49
+ branch: version-bumps/v${{ steps.package-version.outputs.version }}
50
+ base: main
51
+ token: ${{ secrets.TSCIRCUIT_BOT_GITHUB_TOKEN }}
52
+ committer: tscircuitbot <githubbot@tscircuit.com>
53
+ author: tscircuitbot <githubbot@tscircuit.com>
54
+
55
+ - name: Enable auto-merge
56
+ if: steps.create-pr.outputs.pull-request-number != ''
57
+ run: |
58
+ gh pr merge ${{ steps.create-pr.outputs.pull-request-number }} --auto --squash --delete-branch
59
+ env:
60
+ GH_TOKEN: ${{ secrets.TSCIRCUIT_BOT_GITHUB_TOKEN }}
61
+
62
+ - name: Trigger upstream repo updates
63
+ if: env.UPSTREAM_REPOS && env.UPSTREAM_PACKAGES_TO_UPDATE
64
+ run: |
65
+ IFS=',' read -ra REPOS <<< "${{ env.UPSTREAM_REPOS }}"
66
+ for repo in "${REPOS[@]}"; do
67
+ if [[ -n "$repo" ]]; then
68
+ echo "Triggering update for repo: $repo"
69
+ curl -X POST \
70
+ -H "Accept: application/vnd.github.v3+json" \
71
+ -H "Authorization: token ${{ secrets.TSCIRCUIT_BOT_GITHUB_TOKEN }}" \
72
+ -H "Content-Type: application/json" \
73
+ "https://api.github.com/repos/tscircuit/$repo/actions/workflows/update-package.yml/dispatches" \
74
+ -d "{\"ref\":\"main\",\"inputs\":{\"package_names\":\"${{ env.UPSTREAM_PACKAGES_TO_UPDATE }}\"}}"
75
+ fi
76
+ done
77
+ - name: Notify release-tracker of version update
78
+ # Continue-on-error just in case the tracker is down
79
+ continue-on-error: true
80
+ run: |
81
+ VERSION=$(node -p "require('./package.json').version")
82
+ PACKAGE_JSON=$(cat package.json)
83
+ curl -X POST https://release-tracker.tscircuit.com/release_events/create \
84
+ -H "Content-Type: application/json" \
85
+ -d "{
86
+ \"event\": {
87
+ \"event_type\": \"versions_updated\",
88
+ \"repo\": \"tscircuit/circuit-json-to-kicad\",
89
+ \"version\": \"$VERSION\",
90
+ \"package_json\": $PACKAGE_JSON
91
+ }
92
+ }"
@@ -0,0 +1,40 @@
1
+ # Created using @tscircuit/plop (npm install -g @tscircuit/plop)
2
+ name: Bun Test
3
+
4
+ on:
5
+ pull_request:
6
+ push:
7
+ branches:
8
+ - main
9
+ - '!version-bumps/**'
10
+
11
+ jobs:
12
+ test:
13
+ runs-on: ubuntu-latest
14
+ timeout-minutes: 5
15
+
16
+ # Skip test for PRs that not chore: bump version
17
+ if: "${{ github.event_name != 'pull_request' || github.event.pull_request.title != 'chore: bump version' }}"
18
+
19
+ steps:
20
+ - name: Checkout code
21
+ uses: actions/checkout@v4
22
+
23
+ - name: Setup bun
24
+ uses: oven-sh/setup-bun@v2
25
+ with:
26
+ bun-version: latest
27
+
28
+ - name: Install dependencies
29
+ run: bun install
30
+
31
+ - name: Run tests
32
+ run: bun test
33
+
34
+ - name: Upload snapshot artifacts
35
+ if: always()
36
+ uses: actions/upload-artifact@v4
37
+ with:
38
+ name: test-snapshots
39
+ path: tests/**/__snapshots__/*.diff.png
40
+ if-no-files-found: ignore
@@ -0,0 +1,26 @@
1
+ # Created using @tscircuit/plop (npm install -g @tscircuit/plop)
2
+ name: Type Check
3
+
4
+ on:
5
+ push:
6
+ branches: [main]
7
+ pull_request:
8
+ branches: [main]
9
+
10
+ jobs:
11
+ type-check:
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Setup bun
18
+ uses: oven-sh/setup-bun@v2
19
+ with:
20
+ bun-version: latest
21
+
22
+ - name: Install dependencies
23
+ run: bun i
24
+
25
+ - name: Run type check
26
+ run: bunx tsc --noEmit
package/README.md CHANGED
@@ -1,3 +1,102 @@
1
1
  # @tscircuit/curvy-trace-solver
2
2
 
3
3
  Convert trace waypoints into curvy traces maximizing trace-to-trace and trace-to-obstacle distance
4
+
5
+ <img width="1352" height="1420" alt="image" src="https://github.com/user-attachments/assets/197d546a-6d2b-4bdc-8708-27a76430ff63" />
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ bun add @tscircuit/curvy-trace-solver
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### Basic Example
16
+
17
+ ```typescript
18
+ import { CurvyTraceSolver } from "@tscircuit/curvy-trace-solver"
19
+ import type { CurvyTraceProblem } from "@tscircuit/curvy-trace-solver"
20
+
21
+ const problem: CurvyTraceProblem = {
22
+ bounds: { minX: 0, minY: 0, maxX: 100, maxY: 100 },
23
+ waypointPairs: [
24
+ {
25
+ start: { x: 0, y: 10 },
26
+ end: { x: 100, y: 80 },
27
+ },
28
+ {
29
+ start: { x: 0, y: 20 },
30
+ end: { x: 100, y: 90 },
31
+ },
32
+ ],
33
+ obstacles: [],
34
+ preferredSpacing: 25,
35
+ }
36
+
37
+ const solver = new CurvyTraceSolver(problem)
38
+ solver.solve()
39
+
40
+ // Access the solved traces
41
+ console.log(solver.outputTraces)
42
+ // Each trace contains: { waypointPair, points: Point[], networkId? }
43
+ ```
44
+
45
+ ### Problem Definition
46
+
47
+ A `CurvyTraceProblem` consists of:
48
+
49
+ | Property | Type | Description |
50
+ | ------------------ | ---------------- | --------------------------------------------------------------------------- |
51
+ | `bounds` | `Bounds` | The rectangular area containing the traces (`minX`, `minY`, `maxX`, `maxY`) |
52
+ | `waypointPairs` | `WaypointPair[]` | Array of start/end point pairs to connect with traces |
53
+ | `obstacles` | `Obstacle[]` | Rectangular obstacles that traces should avoid |
54
+ | `preferredSpacing` | `number` | Minimum desired spacing between traces |
55
+
56
+ ### Waypoint Pairs
57
+
58
+ ```typescript
59
+ interface WaypointPair {
60
+ start: { x: number; y: number }
61
+ end: { x: number; y: number }
62
+ networkId?: string // Traces with the same networkId are allowed to intersect
63
+ }
64
+ ```
65
+
66
+ ### Obstacles
67
+
68
+ ```typescript
69
+ interface Obstacle {
70
+ minX: number
71
+ minY: number
72
+ maxX: number
73
+ maxY: number
74
+ center: { x: number; y: number }
75
+ networkId?: string // Traces with matching networkId can pass through this obstacle
76
+ }
77
+ ```
78
+
79
+ ### Output
80
+
81
+ After calling `solver.solve()`, access `solver.outputTraces` which contains:
82
+
83
+ ```typescript
84
+ interface OutputTrace {
85
+ waypointPair: WaypointPair
86
+ points: Point[] // Array of points forming the curved trace
87
+ networkId?: string
88
+ }
89
+ ```
90
+
91
+ ### Visualization
92
+
93
+ The solver provides a `visualize()` method that returns a `GraphicsObject` compatible with `graphics-debug`:
94
+
95
+ ```typescript
96
+ import { getSvgFromGraphicsObject } from "graphics-debug"
97
+
98
+ const solver = new CurvyTraceSolver(problem)
99
+ solver.solve()
100
+
101
+ const svg = getSvgFromGraphicsObject(solver.visualize())
102
+ ```
package/dist/index.js CHANGED
@@ -201,169 +201,9 @@ var require_deep_rename_keys = __commonJS({
201
201
  }
202
202
  });
203
203
 
204
- // node_modules/xml-reader/node_modules/eventemitter3/index.js
204
+ // node_modules/eventemitter3/index.js
205
205
  var require_eventemitter3 = __commonJS({
206
- "node_modules/xml-reader/node_modules/eventemitter3/index.js"(exports, module) {
207
- "use strict";
208
- var has = Object.prototype.hasOwnProperty;
209
- var prefix = "~";
210
- function Events() {
211
- }
212
- if (Object.create) {
213
- Events.prototype = /* @__PURE__ */ Object.create(null);
214
- if (!new Events().__proto__) prefix = false;
215
- }
216
- function EE(fn, context, once) {
217
- this.fn = fn;
218
- this.context = context;
219
- this.once = once || false;
220
- }
221
- function EventEmitter() {
222
- this._events = new Events();
223
- this._eventsCount = 0;
224
- }
225
- EventEmitter.prototype.eventNames = function eventNames() {
226
- var names = [], events, name;
227
- if (this._eventsCount === 0) return names;
228
- for (name in events = this._events) {
229
- if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
230
- }
231
- if (Object.getOwnPropertySymbols) {
232
- return names.concat(Object.getOwnPropertySymbols(events));
233
- }
234
- return names;
235
- };
236
- EventEmitter.prototype.listeners = function listeners(event, exists) {
237
- var evt = prefix ? prefix + event : event, available = this._events[evt];
238
- if (exists) return !!available;
239
- if (!available) return [];
240
- if (available.fn) return [available.fn];
241
- for (var i = 0, l = available.length, ee = new Array(l); i < l; i++) {
242
- ee[i] = available[i].fn;
243
- }
244
- return ee;
245
- };
246
- EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
247
- var evt = prefix ? prefix + event : event;
248
- if (!this._events[evt]) return false;
249
- var listeners = this._events[evt], len = arguments.length, args, i;
250
- if (listeners.fn) {
251
- if (listeners.once) this.removeListener(event, listeners.fn, void 0, true);
252
- switch (len) {
253
- case 1:
254
- return listeners.fn.call(listeners.context), true;
255
- case 2:
256
- return listeners.fn.call(listeners.context, a1), true;
257
- case 3:
258
- return listeners.fn.call(listeners.context, a1, a2), true;
259
- case 4:
260
- return listeners.fn.call(listeners.context, a1, a2, a3), true;
261
- case 5:
262
- return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
263
- case 6:
264
- return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
265
- }
266
- for (i = 1, args = new Array(len - 1); i < len; i++) {
267
- args[i - 1] = arguments[i];
268
- }
269
- listeners.fn.apply(listeners.context, args);
270
- } else {
271
- var length = listeners.length, j;
272
- for (i = 0; i < length; i++) {
273
- if (listeners[i].once) this.removeListener(event, listeners[i].fn, void 0, true);
274
- switch (len) {
275
- case 1:
276
- listeners[i].fn.call(listeners[i].context);
277
- break;
278
- case 2:
279
- listeners[i].fn.call(listeners[i].context, a1);
280
- break;
281
- case 3:
282
- listeners[i].fn.call(listeners[i].context, a1, a2);
283
- break;
284
- case 4:
285
- listeners[i].fn.call(listeners[i].context, a1, a2, a3);
286
- break;
287
- default:
288
- if (!args) for (j = 1, args = new Array(len - 1); j < len; j++) {
289
- args[j - 1] = arguments[j];
290
- }
291
- listeners[i].fn.apply(listeners[i].context, args);
292
- }
293
- }
294
- }
295
- return true;
296
- };
297
- EventEmitter.prototype.on = function on(event, fn, context) {
298
- var listener = new EE(fn, context || this), evt = prefix ? prefix + event : event;
299
- if (!this._events[evt]) this._events[evt] = listener, this._eventsCount++;
300
- else if (!this._events[evt].fn) this._events[evt].push(listener);
301
- else this._events[evt] = [this._events[evt], listener];
302
- return this;
303
- };
304
- EventEmitter.prototype.once = function once(event, fn, context) {
305
- var listener = new EE(fn, context || this, true), evt = prefix ? prefix + event : event;
306
- if (!this._events[evt]) this._events[evt] = listener, this._eventsCount++;
307
- else if (!this._events[evt].fn) this._events[evt].push(listener);
308
- else this._events[evt] = [this._events[evt], listener];
309
- return this;
310
- };
311
- EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
312
- var evt = prefix ? prefix + event : event;
313
- if (!this._events[evt]) return this;
314
- if (!fn) {
315
- if (--this._eventsCount === 0) this._events = new Events();
316
- else delete this._events[evt];
317
- return this;
318
- }
319
- var listeners = this._events[evt];
320
- if (listeners.fn) {
321
- if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) {
322
- if (--this._eventsCount === 0) this._events = new Events();
323
- else delete this._events[evt];
324
- }
325
- } else {
326
- for (var i = 0, events = [], length = listeners.length; i < length; i++) {
327
- if (listeners[i].fn !== fn || once && !listeners[i].once || context && listeners[i].context !== context) {
328
- events.push(listeners[i]);
329
- }
330
- }
331
- if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
332
- else if (--this._eventsCount === 0) this._events = new Events();
333
- else delete this._events[evt];
334
- }
335
- return this;
336
- };
337
- EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
338
- var evt;
339
- if (event) {
340
- evt = prefix ? prefix + event : event;
341
- if (this._events[evt]) {
342
- if (--this._eventsCount === 0) this._events = new Events();
343
- else delete this._events[evt];
344
- }
345
- } else {
346
- this._events = new Events();
347
- this._eventsCount = 0;
348
- }
349
- return this;
350
- };
351
- EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
352
- EventEmitter.prototype.addListener = EventEmitter.prototype.on;
353
- EventEmitter.prototype.setMaxListeners = function setMaxListeners() {
354
- return this;
355
- };
356
- EventEmitter.prefixed = prefix;
357
- EventEmitter.EventEmitter = EventEmitter;
358
- if ("undefined" !== typeof module) {
359
- module.exports = EventEmitter;
360
- }
361
- }
362
- });
363
-
364
- // node_modules/xml-lexer/node_modules/eventemitter3/index.js
365
- var require_eventemitter32 = __commonJS({
366
- "node_modules/xml-lexer/node_modules/eventemitter3/index.js"(exports, module) {
206
+ "node_modules/eventemitter3/index.js"(exports, module) {
367
207
  "use strict";
368
208
  var has = Object.prototype.hasOwnProperty;
369
209
  var prefix = "~";
@@ -533,7 +373,7 @@ var require_lexer = __commonJS({
533
373
  }
534
374
  return obj;
535
375
  }
536
- var EventEmitter = require_eventemitter32();
376
+ var EventEmitter = require_eventemitter3();
537
377
  var noop = function noop2() {
538
378
  };
539
379
  var State = {
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "@tscircuit/curvy-trace-solver",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.1",
4
+ "version": "0.0.3",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "cosmos",
8
+ "format": "biome format --write .",
9
+ "format:check": "biome format .",
8
10
  "build": "tsup ./lib/index.ts --format esm --dts",
9
11
  "build:site": "cosmos-export"
10
12
  },
@@ -1,16 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(npx tsc:*)",
5
- "mcp__ide__getDiagnostics",
6
- "Bash(xargs:*)",
7
- "Bash(npx tsx:*)",
8
- "Bash(npm run benchmark:*)",
9
- "Bash(for i in 1 2 3)",
10
- "Bash(do echo \"Run $i:\")",
11
- "Bash(done)",
12
- "Bash(UPDATE_SNAPSHOTS=1 bun test:*)",
13
- "Bash(BUN_UPDATE_SNAPSHOTS=true bun test:*)"
14
- ]
15
- }
16
- }