partforge 0.91.0 → 0.93.0
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/bin/cli.js +6 -3
- package/docs/AUTHORING-PARTS.md +184 -1
- package/docs/ERROR-PATTERNS.md +97 -0
- package/docs/KERNEL-CONTRACT.md +1 -0
- package/docs/VECTOR-FORMAT.md +737 -0
- package/package.json +9 -1
- package/src/app-emblem.js +15 -0
- package/src/emblem-worker.js +3 -0
- package/src/framework/asset-resolve.js +5 -4
- package/src/framework/geometry/arc-fit.js +146 -0
- package/src/framework/geometry/contour-offset.js +5 -0
- package/src/framework/geometry/curve-fill.js +57 -7
- package/src/framework/geometry/kernel-front.js +46 -0
- package/src/framework/geometry/kernel.js +1 -1
- package/src/framework/geometry/probe.js +1 -1
- package/src/framework/geometry/stroke-outline.js +119 -0
- package/src/framework/geometry/vector-format.js +334 -0
- package/src/framework/geometry/vector2d.js +96 -0
- package/src/framework/ingest/svg-ingest.js +212 -0
- package/src/framework/jobs.js +11 -0
- package/src/framework/lint/index.js +28 -3
- package/src/framework/lint/rules-vector.js +112 -0
- package/src/framework/mount.js +30 -2
- package/src/framework/pick-flash.js +31 -0
- package/src/framework/selection/pick.js +16 -1
- package/src/framework/vectors.js +170 -0
- package/src/framework/viewer.js +106 -7
- package/src/framework/worker.js +46 -1
- package/src/ingest.js +8 -0
- package/src/parts/assets/emblem.svg +10 -0
- package/src/parts/assets/emblem.vector.json +110 -0
- package/src/parts/assets/plate.vector.json +27 -0
- package/src/parts/emblem.js +102 -0
- package/src/testing/manifold.js +3 -1
- package/src/testing/occt.js +3 -1
- package/types/index.d.ts +22 -0
- package/types/ingest.d.ts +118 -0
- package/types/kernel.d.ts +28 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// partforge/ingest — SVG -> the partforge-vector JSON format (docs/VECTOR-FORMAT.md).
|
|
2
|
+
//
|
|
3
|
+
// DOM-dependent and main-thread-only: this entry is deliberately NOT reachable
|
|
4
|
+
// from the geometry worker, and is never re-exported from the main entry or
|
|
5
|
+
// from `partforge/geometry`. A host runs it once per artwork, in a browser,
|
|
6
|
+
// and stores the result — the same division of labour as `fontCatalog`.
|
|
7
|
+
// partforge does not write files.
|
|
8
|
+
//
|
|
9
|
+
// These declarations describe the FORMAT, not just what `ingestSvg` happens to
|
|
10
|
+
// emit — the same documents are hand-authored, so `bbox` and `source` are
|
|
11
|
+
// optional here even though ingest always writes both.
|
|
12
|
+
|
|
13
|
+
/** Coordinate meaning. `"mm"` places as authored; `"artwork"` requires a size at every call site. */
|
|
14
|
+
export type VectorUnits = "mm" | "artwork";
|
|
15
|
+
|
|
16
|
+
/** Whether a shape adds material to the composed result or is cut from it. `"add"` is the default. */
|
|
17
|
+
export type VectorRole = "add" | "subtract";
|
|
18
|
+
|
|
19
|
+
/** The document's tight bounding box. A cache, not an authority — placement recomputes it. */
|
|
20
|
+
export interface VectorBbox {
|
|
21
|
+
minX: number;
|
|
22
|
+
minY: number;
|
|
23
|
+
maxX: number;
|
|
24
|
+
maxY: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** A parsed `partforge-vector` JSON document — see docs/VECTOR-FORMAT.md. */
|
|
28
|
+
export interface VectorDocument {
|
|
29
|
+
format: "partforge-vector";
|
|
30
|
+
version: number;
|
|
31
|
+
units: VectorUnits;
|
|
32
|
+
/** Free text; ignored on load. Ingest writes the format's own one-paragraph summary. */
|
|
33
|
+
note?: string;
|
|
34
|
+
/** Provenance only — typically the original filename. Not validated or used at load/build time. */
|
|
35
|
+
source?: string | null;
|
|
36
|
+
/** Optional: an author need not compute analytic curve extrema, but a stale value is a named error. */
|
|
37
|
+
bbox?: VectorBbox;
|
|
38
|
+
/** Name -> shape. At least one shape, and at least one of them must have role `"add"`. */
|
|
39
|
+
shapes: Record<string, VectorShape>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A named shape: either a bare region list (role `"add"`) or `{ role, regions }`.
|
|
44
|
+
* Both forms exist because `"add"` is an honest default — a painted region adds
|
|
45
|
+
* material, which is what every file written before roles existed already meant.
|
|
46
|
+
*/
|
|
47
|
+
export type VectorShape = VectorRegion[] | { role?: VectorRole; regions: VectorRegion[] };
|
|
48
|
+
|
|
49
|
+
/** One filled region: an `outer` boundary with `holes` subtracted from it. */
|
|
50
|
+
export interface VectorRegion {
|
|
51
|
+
outer: VectorContour;
|
|
52
|
+
holes?: VectorContour[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** One closed contour: the explicit `"path"` form, or one of the three primitives. */
|
|
56
|
+
export type VectorContour = VectorPath | VectorCircle | VectorRect | VectorPolygon;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Segments run head-to-tail from `start`, and the contour closes IMPLICITLY from
|
|
60
|
+
* the last segment's `to` back to `start`. At least one segment, and at least two
|
|
61
|
+
* if they are all `"line"` — a single straight edge and its closure are the same
|
|
62
|
+
* line, so they bound nothing, while a single `"arc"` or `"cubic"` bounds area
|
|
63
|
+
* against the closing chord.
|
|
64
|
+
*/
|
|
65
|
+
export interface VectorPath {
|
|
66
|
+
kind: "path";
|
|
67
|
+
start: [number, number];
|
|
68
|
+
segments: VectorSegment[];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Expands to two 180-degree arcs, counter-clockwise. */
|
|
72
|
+
export interface VectorCircle {
|
|
73
|
+
kind: "circle";
|
|
74
|
+
center: [number, number];
|
|
75
|
+
r: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Axis-aligned, counter-clockwise. `radius` rounds all four corners; at most half the shorter side. */
|
|
79
|
+
export interface VectorRect {
|
|
80
|
+
kind: "rect";
|
|
81
|
+
center: [number, number];
|
|
82
|
+
width: number;
|
|
83
|
+
height: number;
|
|
84
|
+
radius?: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** At least 3 points, joined by straight edges in the author's own order. */
|
|
88
|
+
export interface VectorPolygon {
|
|
89
|
+
kind: "polygon";
|
|
90
|
+
points: Array<[number, number]>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export type VectorSegment =
|
|
94
|
+
| { kind: "line"; to: [number, number] }
|
|
95
|
+
| { kind: "arc"; to: [number, number]; through: [number, number] }
|
|
96
|
+
| { kind: "cubic"; to: [number, number]; c1: [number, number]; c2: [number, number] };
|
|
97
|
+
|
|
98
|
+
export interface IngestSvgOptions {
|
|
99
|
+
/**
|
|
100
|
+
* `"outline"` (default) turns strokes into filled geometry; `"ignore"` drops
|
|
101
|
+
* stroke geometry entirely and keeps only fills. There is no equivalent
|
|
102
|
+
* option on `k.vector2d` — once ingested, there is no stroke left to ignore.
|
|
103
|
+
*/
|
|
104
|
+
strokes?: "outline" | "ignore";
|
|
105
|
+
/** Provenance only — typically the original filename. Stored verbatim as `source`; not validated or used at load/build time. */
|
|
106
|
+
source?: string | null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Convert an SVG document (as text) into the `partforge-vector` JSON format a
|
|
111
|
+
* part's `k.vector2d()` calls can place. DOM-required — call this in a browser,
|
|
112
|
+
* store the returned document (e.g. as `<name>.vector.json` beside the part),
|
|
113
|
+
* and reference it from the part's `vectors` field. The result is always one
|
|
114
|
+
* shape named `"artwork"` in `"artwork"` units, with `bbox` and `source` written.
|
|
115
|
+
* Throws if the SVG can't be parsed, or if it contains no painted geometry (every
|
|
116
|
+
* element is `fill="none"` with no stroke, hidden, or empty).
|
|
117
|
+
*/
|
|
118
|
+
export function ingestSvg(svgText: string, opts?: IngestSvgOptions): VectorDocument;
|
package/types/kernel.d.ts
CHANGED
|
@@ -455,6 +455,29 @@ export interface Text2dOptions {
|
|
|
455
455
|
kerning?: boolean;
|
|
456
456
|
}
|
|
457
457
|
|
|
458
|
+
/** Horizontal alignment of a `vector2d` placement. */
|
|
459
|
+
export type Vector2dAlign = "center" | "left" | "right";
|
|
460
|
+
/** Vertical alignment of a `vector2d` placement. */
|
|
461
|
+
export type Vector2dValign = "middle" | "top" | "bottom";
|
|
462
|
+
|
|
463
|
+
export interface Vector2dOptions {
|
|
464
|
+
/**
|
|
465
|
+
* Name of one shape in the file, returned whatever its `role`. Omit for the
|
|
466
|
+
* composed result: every `"add"` shape unioned, minus every `"subtract"` one.
|
|
467
|
+
*/
|
|
468
|
+
shape?: string;
|
|
469
|
+
/** Target width in mm. At most one of `width`/`height`/`fit`; required for `units: "artwork"`. */
|
|
470
|
+
width?: number;
|
|
471
|
+
/** Target height in mm. At most one of `width`/`height`/`fit`; required for `units: "artwork"`. */
|
|
472
|
+
height?: number;
|
|
473
|
+
/** Target size in mm for the larger extent. At most one of `width`/`height`/`fit`; required for `units: "artwork"`. */
|
|
474
|
+
fit?: number;
|
|
475
|
+
/** Defaults to `"center"` for `units: "artwork"`, and to no horizontal translate for `units: "mm"`. */
|
|
476
|
+
align?: Vector2dAlign;
|
|
477
|
+
/** Defaults to `"middle"` for `units: "artwork"`, and to no vertical translate for `units: "mm"`. */
|
|
478
|
+
valign?: Vector2dValign;
|
|
479
|
+
}
|
|
480
|
+
|
|
458
481
|
/** Anything `k.hull`/`k.hullChain` accepts as one input. */
|
|
459
482
|
export type HullInput = Shape2D | Contour;
|
|
460
483
|
|
|
@@ -501,6 +524,11 @@ export interface GeometryKernel {
|
|
|
501
524
|
shape2d(profile: ProfileInput): Shape2D;
|
|
502
525
|
/** Render outline-font text as a `Shape2D`. */
|
|
503
526
|
text2d(string: string, opts?: Text2dOptions): Shape2D;
|
|
527
|
+
/**
|
|
528
|
+
* Place a declared vector file as a `Shape2D`. `name` is a key in the part's
|
|
529
|
+
* `vectors` field (`partforge-vector` JSON, not raw `.svg`).
|
|
530
|
+
*/
|
|
531
|
+
vector2d(name: string, opts?: Vector2dOptions): Shape2D;
|
|
504
532
|
/** Convex hull of all inputs → a convex (faceted) `Shape2D`. */
|
|
505
533
|
hull(inputs: HullInput[]): Shape2D;
|
|
506
534
|
/** Swept hull over an ordered sequence (>= 2 inputs). */
|