partforge 0.96.0 → 0.98.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 +128 -9
- package/docs/AUTHORING-PARTS.md +371 -5
- package/docs/ERROR-PATTERNS.md +25 -1
- package/docs/KERNEL-CONTRACT.md +1 -0
- package/docs/VECTOR-FORMAT.md +23 -17
- package/package.json +9 -1
- package/src/app-relief.js +16 -0
- package/src/framework/app.css +30 -0
- package/src/framework/backend-select.js +7 -2
- package/src/framework/font-source.js +18 -1
- package/src/framework/geometry/heightfield.js +129 -0
- package/src/framework/geometry/kernel.js +3 -0
- package/src/framework/geometry/manifold-backend.js +61 -0
- package/src/framework/geometry/occt-backend.js +148 -1
- package/src/framework/geometry/op-options.js +10 -0
- package/src/framework/geometry/png-decode.js +107 -0
- package/src/framework/geometry/solid-hash.js +96 -0
- package/src/framework/image-source.js +76 -0
- package/src/framework/images.js +66 -0
- package/src/framework/ingest/image-ingest.js +41 -0
- package/src/framework/ingest/node-dom.js +69 -0
- package/src/framework/ingest/registry.js +57 -0
- package/src/framework/ingest/sniff.js +96 -0
- package/src/framework/jobs.js +107 -6
- package/src/framework/lint/index.js +2 -1
- package/src/framework/lint/rules-images.js +109 -0
- package/src/framework/lint/rules-vector.js +68 -3
- package/src/framework/measure/measure-mode.js +2 -1
- package/src/framework/mount.js +14 -1
- package/src/framework/oracle/verify.js +6 -1
- package/src/framework/panel/image-picker.js +152 -0
- package/src/framework/panel/render.js +2 -0
- package/src/framework/panel/widget-specs.js +4 -0
- package/src/framework/panel/widgets/file-drop.js +321 -0
- package/src/framework/panel/widgets/font.js +51 -12
- package/src/framework/panel/widgets/image.js +178 -0
- package/src/framework/panel/widgets/index.js +11 -5
- package/src/framework/panel/widgets/vector.js +77 -0
- package/src/framework/param-deps.js +7 -2
- package/src/framework/vector-source.js +127 -0
- package/src/framework/vectors.js +9 -0
- package/src/ingest.js +1 -0
- package/src/parts/assets/relief-demo.png +0 -0
- package/src/parts/emblem.js +2 -1
- package/src/parts/relief.js +84 -0
- package/src/relief-worker.js +3 -0
- package/src/testing/manifold.js +7 -1
- package/src/testing/occt.js +4 -1
- package/types/index.d.ts +67 -0
- package/types/ingest.d.ts +13 -0
- package/types/kernel.d.ts +32 -0
- package/types/part.d.ts +21 -0
package/types/index.d.ts
CHANGED
|
@@ -101,6 +101,50 @@ export interface MountElements {
|
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
/** Which control family a dropped file belongs to. */
|
|
105
|
+
export type AssetKind = "image" | "vector" | "font";
|
|
106
|
+
|
|
107
|
+
/** One selectable face in a `FontCatalog` family. */
|
|
108
|
+
export interface FontVariant {
|
|
109
|
+
variant: string;
|
|
110
|
+
label: string;
|
|
111
|
+
/** What the picker writes into `params`. */
|
|
112
|
+
url: string;
|
|
113
|
+
bytes?: number;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface FontFamily {
|
|
117
|
+
id: string;
|
|
118
|
+
family: string;
|
|
119
|
+
category?: string;
|
|
120
|
+
variants: FontVariant[];
|
|
121
|
+
/** A name-only subset used to draw the list row. */
|
|
122
|
+
menuUrl?: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Backs `type: "font"` controls. Supplied by the host; partforge ships none. */
|
|
126
|
+
export interface FontCatalog {
|
|
127
|
+
search: (query: string, opts: { limit?: number }) => Promise<FontFamily[]>;
|
|
128
|
+
/** Reverse lookup, so a hashed-filename URL can still be named in the UI. */
|
|
129
|
+
describe?: (source: string) => { family: string; variant: string } | null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface ImageAsset {
|
|
133
|
+
id: string;
|
|
134
|
+
label: string;
|
|
135
|
+
/** What the picker writes into `params`. */
|
|
136
|
+
url: string;
|
|
137
|
+
width?: number;
|
|
138
|
+
height?: number;
|
|
139
|
+
thumbUrl?: string;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Backs `type: "image"` controls. Supplied by the host; partforge ships none. */
|
|
143
|
+
export interface ImageCatalog {
|
|
144
|
+
search: (query: string, opts: { limit?: number }) => Promise<ImageAsset[]>;
|
|
145
|
+
describe?: (source: string) => { label: string; width: number; height: number } | null;
|
|
146
|
+
}
|
|
147
|
+
|
|
104
148
|
export interface MountOptions {
|
|
105
149
|
/**
|
|
106
150
|
* Spawns a geometry worker. Called once per backend with `name` as the
|
|
@@ -143,6 +187,28 @@ export interface MountOptions {
|
|
|
143
187
|
* part cannot support is dropped, never fatal.
|
|
144
188
|
*/
|
|
145
189
|
viewerState?: ViewerState | null;
|
|
190
|
+
/**
|
|
191
|
+
* A provider backing every `type: "font"` control in the part. partforge
|
|
192
|
+
* ships none — without one, a font control renders as a plain URL field.
|
|
193
|
+
*/
|
|
194
|
+
fontCatalog?: FontCatalog;
|
|
195
|
+
/**
|
|
196
|
+
* A provider backing every `type: "image"` control in the part. Without one,
|
|
197
|
+
* an image control degrades to a plain URL field.
|
|
198
|
+
*/
|
|
199
|
+
imageCatalog?: ImageCatalog;
|
|
200
|
+
/**
|
|
201
|
+
* The upload hook for the drop target shared by the `"image"`, `"vector"`
|
|
202
|
+
* and `"font"` controls. Called with the CONVERTED artifact — a PNG, a
|
|
203
|
+
* partforge-vector document serialized as JSON, or the original file for a
|
|
204
|
+
* font — never the user's raw drop, and must resolve to a non-empty source
|
|
205
|
+
* string (an `https:` URL, or a host-defined `pfc-asset:` token) which is
|
|
206
|
+
* written into the param. Anything else, or a rejection, is reported through
|
|
207
|
+
* the control's own error line and never written. Omit it and the converted
|
|
208
|
+
* artifact lands in the param directly — the path a host that cannot fetch
|
|
209
|
+
* URLs needs, not a degraded fallback.
|
|
210
|
+
*/
|
|
211
|
+
onAssetUpload?: (blob: Blob, info: { kind: AssetKind; filename: string }) => Promise<string>;
|
|
146
212
|
/** @deprecated alias for `elements.viewer`. */
|
|
147
213
|
container?: HTMLElement | null;
|
|
148
214
|
/** @deprecated alias for `elements.controls`. */
|
|
@@ -454,3 +520,4 @@ export function viewSubParts(
|
|
|
454
520
|
view: string,
|
|
455
521
|
params: Record<string, ParamValue>,
|
|
456
522
|
): string[];
|
|
523
|
+
|
package/types/ingest.d.ts
CHANGED
|
@@ -116,3 +116,16 @@ export interface IngestSvgOptions {
|
|
|
116
116
|
* element is `fill="none"` with no stroke, hidden, or empty).
|
|
117
117
|
*/
|
|
118
118
|
export function ingestSvg(svgText: string, opts?: IngestSvgOptions): VectorDocument;
|
|
119
|
+
|
|
120
|
+
export interface ImageToPngOptions {
|
|
121
|
+
/** Long-edge cap in px; an image already under this is not upscaled. Default 1024. */
|
|
122
|
+
maxSize?: number;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Convert any image the browser can decode into a PNG `Blob`, downsampling the
|
|
127
|
+
* long edge to `maxSize` on the way. Main-thread only (uses `createImageBitmap`
|
|
128
|
+
* and a canvas) — for a host normalising uploads before storing them, since a
|
|
129
|
+
* part's `images` field decodes PNG only. Never call from a part's `build`.
|
|
130
|
+
*/
|
|
131
|
+
export function imageToPng(fileOrBlob: Blob | File, options?: ImageToPngOptions): Promise<Blob>;
|
package/types/kernel.d.ts
CHANGED
|
@@ -481,6 +481,31 @@ export interface Vector2dOptions {
|
|
|
481
481
|
/** Anything `k.hull`/`k.hullChain` accepts as one input. */
|
|
482
482
|
export type HullInput = Shape2D | Contour;
|
|
483
483
|
|
|
484
|
+
/** An inline depth-map grid, row-major, 0..65535 per sample. */
|
|
485
|
+
export interface HeightfieldGrid {
|
|
486
|
+
width: number;
|
|
487
|
+
height: number;
|
|
488
|
+
data: Uint16Array;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/** k.heightfield — a depth map as a relief solid. */
|
|
492
|
+
export interface HeightfieldOptions {
|
|
493
|
+
w: number;
|
|
494
|
+
d: number;
|
|
495
|
+
/** Slab thickness under the relief (mm, > 0). Default 1. */
|
|
496
|
+
base?: number;
|
|
497
|
+
/** Relief height above `base` at a full-scale (1.0) sample. Default 1. */
|
|
498
|
+
maxZ?: number;
|
|
499
|
+
/** Sample spacing (mm, > 0); clamped to a vertex budget with a build warning. Default 0.5. */
|
|
500
|
+
pitch?: number;
|
|
501
|
+
/** Flip sampled value as `1 - v`, applied after `range`. */
|
|
502
|
+
invert?: boolean;
|
|
503
|
+
/** Remap with clamped ends: `range[0]` -> 0, `range[1]` -> 1. Default [0, 1]. */
|
|
504
|
+
range?: [number, number];
|
|
505
|
+
/** Footprint placement in XY only — the base always sits at z = 0. Default "center". */
|
|
506
|
+
origin?: "center" | "corner";
|
|
507
|
+
}
|
|
508
|
+
|
|
484
509
|
// --- the kernel -------------------------------------------------------------
|
|
485
510
|
|
|
486
511
|
/**
|
|
@@ -541,6 +566,13 @@ export interface GeometryKernel {
|
|
|
541
566
|
* side-channel (not a part author's calling surface).
|
|
542
567
|
*/
|
|
543
568
|
import(name: string): Solid;
|
|
569
|
+
/**
|
|
570
|
+
* A depth map as a relief solid. `nameOrGrid` is a name declared in the part's
|
|
571
|
+
* `images` field, or an inline grid — the name path is registered pre-build by
|
|
572
|
+
* the framework via the underscore-prefixed `_registerImage` side-channel (not
|
|
573
|
+
* a part author's calling surface).
|
|
574
|
+
*/
|
|
575
|
+
heightfield(nameOrGrid: string | HeightfieldGrid, opts: HeightfieldOptions): Solid;
|
|
544
576
|
|
|
545
577
|
// Backend-optional: the sub-part cache brackets and WASM lifetime hooks. Every
|
|
546
578
|
// framework caller reaches these through `?.`, so a third-party backend may
|
package/types/part.d.ts
CHANGED
|
@@ -257,6 +257,21 @@ export type FontSource =
|
|
|
257
257
|
|
|
258
258
|
type FontSourceValue = string | ArrayBuffer | ArrayBufferView | { default: string };
|
|
259
259
|
|
|
260
|
+
// --- images -----------------------------------------------------------------
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* One entry of a part's `images` map: raw bytes, a URL string, or a thunk
|
|
264
|
+
* returning either (a Vite `() => import("./x.png")` resolves to
|
|
265
|
+
* `{ default: url }`). Resolved to a decoded luminance grid before the
|
|
266
|
+
* synchronous `build` runs — the source `k.heightfield()` samples.
|
|
267
|
+
*/
|
|
268
|
+
export type ImageSource =
|
|
269
|
+
| string
|
|
270
|
+
| ArrayBuffer
|
|
271
|
+
| ArrayBufferView
|
|
272
|
+
| (() => ImageSourceValue | Promise<ImageSourceValue>);
|
|
273
|
+
|
|
274
|
+
type ImageSourceValue = string | ArrayBuffer | ArrayBufferView | { default: string };
|
|
260
275
|
// --- imports and vectors ------------------------------------------------------
|
|
261
276
|
|
|
262
277
|
/**
|
|
@@ -604,6 +619,12 @@ export interface PartDefinition<P = ResolvedParams, D = Derived> {
|
|
|
604
619
|
defaults: Defaults;
|
|
605
620
|
/** Outline fonts a part's `k.text2d()` calls need, as `{ name: source }`. */
|
|
606
621
|
fonts?: Record<string, FontSource>;
|
|
622
|
+
/**
|
|
623
|
+
* Depth-map images a part's `k.heightfield()` calls need, as
|
|
624
|
+
* `{ name: source }` — or a function of the resolved params returning that
|
|
625
|
+
* map, which is what lets a `type: "image"` control drive the source.
|
|
626
|
+
*/
|
|
627
|
+
images?: Record<string, ImageSource> | ((p: P) => Record<string, ImageSource>);
|
|
607
628
|
/** STEP/STL/3MF files a part's `k.import()` calls need, as `{ name: source }`. */
|
|
608
629
|
imports?: Record<string, ImportSource>;
|
|
609
630
|
/** Vector artwork a part's `k.vector2d()` calls place, as `{ name: source }`. */
|