@vgpu/renderAdvanced29 symbolsView source ↗

Symbols in this topic

@vgpu/render/edit — Mesh Editing

CPU-side triangle mesh editing built on the render package's half-edge kernel. Use this entrypoint to convert render meshes into EditableMesh, select topology, run edit operators, and bake back to render meshes after the edit pipeline.

Index

All imports in this file use the public edit entrypoint:

TypeScript
1
import { EditableMesh } from "@vgpu/render/edit";

EditableMesh

Factory object for creating and baking EditableMeshValue instances. Use fromArrays when you already have typed geometry arrays; use EditableMesh.toRenderMesh or mesh.toRenderMesh only after the final edit step.

Import

TypeScript
1
import { EditableMesh } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import type { Device } from "@vgpu/core";
import type { EditableMeshValue } from "@vgpu/render/edit";
 
declare const EditableMesh: {
  fromArrays(opts: {
    readonly positions: Float32Array;
    readonly normals?: Float32Array;
    readonly uvs?: Float32Array;
    readonly colors?: Float32Array;
    readonly indices?: Uint16Array | Uint32Array;
    readonly sharpEdges?: Uint8Array;
    readonly useSmooth?: Uint8Array;
    readonly creaseAngle?: number;
  }): EditableMeshValue;
  toRenderMesh(em: EditableMeshValue, opts: { readonly device: Device }): unknown;
};

Parameters

ParamTypeRequiredDefaultNotes
opts.positionsFloat32ArrayXYZ triples. Vertices with identical XYZ are welded by position during kernel build.
opts.indicesUint16Array | Uint32Arraysequential 0..positions.length / 3 - 1Triangle indices; length must represent triangles.
opts.normalsFloat32ArrayomittedPreserved only as hasNormals; edit operators recompute face topology.
opts.uvsFloat32ArrayomittedPreserved only as hasUVs; operators may drop seams.
opts.colorsFloat32ArrayomittedPreserved only as hasVertexColors.
opts.sharpEdgesUint8Arrayauto from creaseAnglePer-edge sharp mask in kernel edge order; if present it overrides auto-sharp detection.
opts.useSmoothUint8Arrayall faces smooth (1)Per-face smoothing flags.
opts.creaseAnglenumberMath.PI / 6Radians used to auto-mark sharp edges when sharpEdges is omitted.
emEditableMeshValueMesh to bake for static EditableMesh.toRenderMesh.
opts.deviceDeviceDevice used to create the render mesh buffers.

Returns: EditableMeshValue from fromArrays; render Mesh from toRenderMesh. Throws: — no MeshEditError is thrown directly. Invalid or mismatched raw arrays can still produce invalid geometry at JavaScript/WebGPU boundaries.

Examples

TypeScript
1
2
3
4
5
6
7
8
import { EditableMesh } from "@vgpu/render/edit";
 
const editableMeshExample = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
  indices: new Uint32Array([0, 1, 2]),
});
 
const editableFaceCount: number = editableMeshExample.faceCount;

Notes

toEditable

Converts a render Mesh into an editable half-edge mesh and discards diagnostics. Use when warnings are not important; otherwise call toEditableWithDiagnostics.

Import

TypeScript
1
import { toEditable } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
import { toEditable } from "@vgpu/render/edit";
import type { EditableMeshValue } from "@vgpu/render/edit";
 
type EditableInputMesh = Parameters<typeof toEditable>[0];
declare function toEditableSignature(mesh: EditableInputMesh, opts?: { readonly creaseAngle?: number }): EditableMeshValue;

Parameters

ParamTypeRequiredDefaultNotes
meshMeshRender mesh-like object with attributes and bounds. Source arrays are used when available; otherwise a bbox box fallback is built.
opts.creaseAnglenumberMath.PI / 6 through EditableMesh.fromArraysRadians for auto-sharp edge detection.

Returns: EditableMeshValue — editable mesh ready for selections/operators. Throws: — no MeshEditError is thrown directly.

Examples

TypeScript
1
2
3
4
5
6
7
8
9
import { toEditable } from "@vgpu/render/edit";
 
const renderMeshForEdit = {
  vertexBuffer: {},
  vertexCount: 3,
  attributes: { stride: 12, position: { offset: 0, format: "float32x3" as const } },
  bbox: { min: new Float32Array([0, 0, 0]), max: new Float32Array([1, 1, 1]) },
} as unknown as Parameters<typeof toEditable>[0];
const toEditableMesh = toEditable(renderMeshForEdit, { creaseAngle: Math.PI / 4 });

Notes

toEditableWithDiagnostics

Converts a render Mesh and returns warnings such as stripped tangents. Use this at import/conversion boundaries so LLM-generated pipelines do not silently lose render-layer data.

Import

TypeScript
1
import { toEditableWithDiagnostics } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
import { toEditableWithDiagnostics } from "@vgpu/render/edit";
import type { EditableMeshValue, MeshEditWarning } from "@vgpu/render/edit";
 
type DiagnosticInputMesh = Parameters<typeof toEditableWithDiagnostics>[0];
declare function toEditableWithDiagnosticsSignature(
  mesh: DiagnosticInputMesh,
  opts?: { readonly creaseAngle?: number },
): { readonly mesh: EditableMeshValue; readonly warnings: readonly MeshEditWarning[] };

Parameters

ParamTypeRequiredDefaultNotes
meshMeshRender mesh-like object. If edit-source arrays are absent, bbox fallback arrays are generated.
opts.creaseAnglenumberMath.PI / 6 through EditableMesh.fromArraysRadians for auto-sharp edge detection.

Returns: { mesh, warnings }warnings is an array of MeshEditWarning objects. Throws: — no MeshEditError is thrown directly.

Examples

TypeScript
1
2
3
4
5
6
7
8
9
10
import { toEditableWithDiagnostics } from "@vgpu/render/edit";
 
const renderMeshWithDiagnostics = {
  vertexBuffer: {},
  vertexCount: 3,
  attributes: { stride: 12, position: { offset: 0, format: "float32x3" as const } },
  bbox: { min: new Float32Array([0, 0, 0]), max: new Float32Array([1, 1, 1]) },
} as unknown as Parameters<typeof toEditableWithDiagnostics>[0];
const diagnostics = toEditableWithDiagnostics(renderMeshWithDiagnostics);
const diagnosticsWarnings = diagnostics.warnings.map((warning) => warning.code);

Notes

EditableMeshValue

Runtime shape of an editable mesh. It exposes counts, bounds, typed element sets, material/topology flags, hard-edge selection, an opaque kernel handle, and toRenderMesh.

Import

TypeScript
1
import type { EditableMeshValue } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import type { Device } from "@vgpu/core";
import type { ElementSelection, ElementSet, KernelHandle } from "@vgpu/render/edit";
 
type Vec3 = Float32Array;
 
declare interface EditableMeshValue {
  readonly vertexCount: number;
  readonly edgeCount: number;
  readonly faceCount: number;
  readonly bounds: { readonly min: Vec3; readonly max: Vec3 };
  readonly vertices: ElementSet<"vertex">;
  readonly edges: ElementSet<"edge">;
  readonly faces: ElementSet<"face">;
  readonly isManifold: boolean;
  readonly hasUVs: boolean;
  readonly hasNormals: boolean;
  readonly hasVertexColors: boolean;
  readonly hardEdges: ElementSelection;
  readonly gpu: { readonly halfEdgeKernel: KernelHandle };
  toRenderMesh(opts: { readonly device: Device }): unknown;
}

Parameters

FieldTypeRequiredDefaultNotes
vertexCount / edgeCount / faceCountnumberCounts in the current immutable editable mesh value.
bounds.min / bounds.maxVec3Axis-aligned bounds computed from positions.
vertices / edges / facesElementSetSelection factories and traversal helpers for each domain.
isManifoldbooleantrue only when every edge has two incident faces in the current kernel.
hasUVs / hasNormals / hasVertexColorsbooleanFlags copied from input arrays; most operators rebuild topology arrays.
hardEdgesElementSelectionEdge selection where the kernel isSharp mask is nonzero.
gpu.halfEdgeKernelKernelHandleOpaque handle; do not construct or mutate directly.
toRenderMeshfunctionBakes the editable mesh with { device }.

Returns: N/A — this is an interface/type export. Throws: N/A — toRenderMesh can fail at render/WebGPU boundaries if passed an invalid Device.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, type EditableMeshValue } from "@vgpu/render/edit";
 
const editableValueExample: EditableMeshValue = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const editableBoundsMin = editableValueExample.bounds.min;

Notes

ElementDomain

String union naming the selectable topology domains.

Import

TypeScript
1
import type { ElementDomain } from "@vgpu/render/edit";

Signature

TypeScript
1
export type ElementDomain = "vertex" | "edge" | "face" | "loop";

Parameters

VariantTypeRequiredDefaultNotes
"vertex"ElementDomainVertex selections and VertexView.
"edge"ElementDomainEdge selections, loops, rings, bridge/fill boundaries.
"face"ElementDomainFace selections for extrusion/inset/dissolve.
"loop"ElementDomainDeclared domain variant; public element sets currently operate on vertex/edge/face.

Returns: N/A — type alias. Throws: N/A.

Examples

TypeScript
1
2
3
import type { ElementDomain } from "@vgpu/render/edit";
 
const selectedDomain: ElementDomain = "edge";

Notes

  • Operator validation is strict: passing a selection with the wrong domain throws WRONG_DOMAIN.
  • See also: ElementSelection, ElementSet.

ElementSelection

Immutable selection object passed to operators. Use ElementSet helpers (mesh.faces.byIndex, mesh.edges.loop, etc.) instead of hand-building selections unless you need an ordered boundary loop.

Import

TypeScript
1
import type { ElementSelection } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
import type { ElementDomain } from "@vgpu/render/edit";
 
declare interface ElementSelection {
  readonly domain: ElementDomain;
  readonly indices: ReadonlyArray<number>;
  readonly count: number;
  readonly ordered?: boolean;
}

Parameters

FieldTypeRequiredDefaultNotes
domainElementDomainMust match the operator target domain.
indicesReadonlyArray<number>Element indices in the mesh that owns the selection.
countnumberUsually indices.length; operators check count === 0 for empty selections.
orderedbooleanomitted / falseRequired as true for loop-boundary operators (bridge, fillHole, gridFill).

Returns: N/A — interface. Throws: N/A.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, type ElementSelection } from "@vgpu/render/edit";
 
const selectionMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const oneFaceSelection: ElementSelection = selectionMesh.faces.byIndex([0]);

Notes

  • Selections are mesh-local. Do not reuse a selection from the input mesh against an operator result unless the operator returned that selection for the new mesh.
  • See also: ElementSet, ScoredSelection, MeshEditError.

ElementSet

Domain-specific helper collection available as mesh.vertices, mesh.edges, and mesh.faces. Use it to create validated selections and compute simple adjacency expansions.

Import

TypeScript
1
import type { ElementSet } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import type { ElementDomain, ElementSelection, EdgeView, FaceView, ScoredSelection, VertexView } from "@vgpu/render/edit";
 
type ElementView<D extends ElementDomain> = D extends "vertex" ? VertexView : D extends "edge" ? EdgeView : D extends "face" ? FaceView : never;
 
declare interface ElementSet<D extends ElementDomain> {
  readonly domain: D;
  readonly count: number;
  where(pred: (e: ElementView<D>) => boolean): ElementSelection;
  scoreBy(score: (e: ElementView<D>) => number): ScoredSelection;
  byIndex(indices: readonly number[]): ElementSelection;
  all(): ElementSelection;
  none(): ElementSelection;
  loop(seedEdge: number): D extends "edge" ? ElementSelection : never;
  ring(seedEdge: number): D extends "edge" ? ElementSelection : never;
  grow(sel: ElementSelection, layers?: number): ElementSelection;
  shrink(sel: ElementSelection, layers?: number): ElementSelection;
  boundaryOf(sel: ElementSelection): ElementSelection;
  connectedComponentOf(seed: number): ElementSelection;
}

Parameters

Method/FieldTypeRequiredDefaultNotes
domainD"vertex", "edge", or "face" for the owning set.
countnumberNumber of elements in the owning domain.
where.predfunctionCalled with VertexView, EdgeView, or FaceView; returned indices are sorted/deduped.
scoreBy.scorefunctionProduces a ScoredSelection sorted by score descending.
byIndex.indicesreadonly number[]Out-of-range indices are filtered out.
loop.seedEdge / ring.seedEdgenumberFor edge sets only; current implementation returns connected edge walk with ordered: true.
grow.layers / shrink.layersnumber1Number of adjacency layers to expand or contract.
boundaryOf.selElementSelectionReturns an edge selection around face/vertex selections; edge input returns itself.
connectedComponentOf.seednumberFlood-fills adjacent elements in the same domain.

Returns: ElementSelection or ScoredSelection depending on the method. Throws: — no MeshEditError is thrown directly by the public methods.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh } from "@vgpu/render/edit";
 
const elementSetMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const longEdges = elementSetMesh.edges.where((edge) => edge.length > 0.5);

Notes

ScoredSelection

Ranked selection helper returned by ElementSet.scoreBy. Use it to pick strongest or weakest candidates without manually sorting indices.

Import

TypeScript
1
import type { ScoredSelection } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
import type { ElementDomain, ElementSelection } from "@vgpu/render/edit";
 
declare interface ScoredSelection {
  readonly domain: ElementDomain;
  readonly entries: ReadonlyArray<{ readonly index: number; readonly score: number }>;
  top(): ElementSelection;
  topN(n: number): ElementSelection;
  threshold(min: number): ElementSelection;
  bottom(): ElementSelection;
  bottomN(n: number): ElementSelection;
}

Parameters

Method/FieldTypeRequiredDefaultNotes
domainElementDomainDomain of all ranked entries.
entriesReadonlyArraySorted by score descending, then index ascending.
top / bottomfunctionEquivalent to topN(1) / bottomN(1).
topN.n / bottomN.nnumberNegative values clamp to 0.
threshold.minnumberKeeps entries with score >= min.

Returns: ElementSelection from ranking methods. Throws: — no MeshEditError is thrown directly.

Examples

TypeScript
1
2
3
4
5
6
7
import { EditableMesh, type ScoredSelection } from "@vgpu/render/edit";
 
const scoredMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 2, 0, 0, 0, 1, 0]),
});
const scoredEdges: ScoredSelection = scoredMesh.edges.scoreBy((edge) => edge.length);
const longestEdge = scoredEdges.top();

Notes

VertexView

Read-only per-vertex data passed to vertex where/scoreBy callbacks.

Import

TypeScript
1
import type { VertexView } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
type Vec3 = Float32Array;
 
declare interface VertexView {
  readonly index: number;
  readonly position: Vec3;
  readonly normal: Vec3;
  readonly valence: number;
  readonly isBoundary: boolean;
  readonly isManifold: boolean;
}

Parameters

FieldTypeRequiredDefaultNotes
indexnumberVertex index in the current mesh.
positionVec3XYZ position.
normalVec3Kernel-computed vertex normal.
valencenumberNumber of incident edges.
isBoundarybooleanTrue if any incident edge is boundary.
isManifoldbooleanTrue when local incident topology is manifold.

Returns: N/A — interface. Throws: N/A.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, type VertexView } from "@vgpu/render/edit";
 
const vertexViewMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const boundaryVertices = vertexViewMesh.vertices.where((vertex: VertexView) => vertex.isBoundary);

Notes

  • Views are snapshots produced by callbacks; do not store them as stable handles across edits.
  • See also: ElementSet, EdgeView, FaceView.

EdgeView

Read-only per-edge data passed to edge where/scoreBy callbacks.

Import

TypeScript
1
import type { EdgeView } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type Vec3 = Float32Array;
 
declare interface EdgeView {
  readonly index: number;
  readonly midpoint: Vec3;
  readonly length: number;
  readonly direction: Vec3;
  readonly vertexA: number;
  readonly vertexB: number;
  readonly faceA: number | null;
  readonly faceB: number | null;
  readonly isBoundary: boolean;
  readonly isManifold: boolean;
  readonly isSharp: boolean;
}

Parameters

FieldTypeRequiredDefaultNotes
indexnumberEdge index in current mesh.
midpoint / directionVec3Derived from endpoints.
lengthnumberEuclidean length.
vertexA / vertexBnumberEndpoint vertex indices.
faceA / faceBnumber | nullIncident faces; faceB === null indicates boundary.
isBoundarybooleanTrue for one-sided edges.
isManifoldbooleanTrue when the edge has manifold incidence.
isSharpbooleanTrue when the kernel sharp mask is set.

Returns: N/A — interface. Throws: N/A.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, type EdgeView } from "@vgpu/render/edit";
 
const edgeViewMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const sharpEdges = edgeViewMesh.edges.where((edge: EdgeView) => edge.isSharp);

Notes

FaceView

Read-only per-face data passed to face where/scoreBy callbacks.

Import

TypeScript
1
import type { FaceView } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
type Vec3 = Float32Array;
 
declare interface FaceView {
  readonly index: number;
  readonly center: Vec3;
  readonly normal: Vec3;
  readonly area: number;
  readonly vertexCount: number;
  readonly vertexIndices: ReadonlyArray<number>;
  readonly edgeIndices: ReadonlyArray<number>;
  readonly useSmooth: boolean;
}

Parameters

FieldTypeRequiredDefaultNotes
indexnumberFace index in current mesh.
center / normalVec3Derived from triangle vertices and face normal.
areanumberTriangle area.
vertexCountnumberAlways 3 for the triangle-only editable kernel.
vertexIndices / edgeIndicesReadonlyArray<number>Triangle vertex/edge indices.
useSmoothbooleanPer-face smoothing flag.

Returns: N/A — interface. Throws: N/A.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, type FaceView } from "@vgpu/render/edit";
 
const faceViewMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const upwardFaces = faceViewMesh.faces.where((face: FaceView) => face.normal[2] > 0);

Notes

KernelHandle

Opaque branded handle to the internal half-edge kernel. It exists so editable values can carry kernel data without exposing mutation APIs.

Import

TypeScript
1
import type { KernelHandle } from "@vgpu/render/edit";

Signature

TypeScript
1
2
declare const kernelBrand: unique symbol;
export type KernelHandle = { readonly [kernelBrand]: never };

Parameters

FieldTypeRequiredDefaultNotes
branded propertyunique symbolCompile-time brand only; not constructible through public API.

Returns: N/A — type alias. Throws: N/A.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, type KernelHandle } from "@vgpu/render/edit";
 
const kernelHandleMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const kernelHandle: KernelHandle = kernelHandleMesh.gpu.halfEdgeKernel;

Notes

extrude

Extrudes selected faces along their face normals or an explicit direction. Use it for raised panels, shells, and block-out modeling.

Import

TypeScript
1
import { extrude } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import type { EditableMeshValue, ElementSelection, MeshEditWarning } from "@vgpu/render/edit";
 
declare interface ExtrudeOptions {
  readonly distance: number;
  readonly inset?: number;
  readonly direction?: readonly [number, number, number];
  readonly mode?: "region" | "individual";
}
 
declare interface ExtrudeResult {
  readonly mesh: EditableMeshValue;
  readonly sideFaces: ElementSelection;
  readonly capFaces: ElementSelection;
  readonly boundaryEdges: ElementSelection;
  readonly warnings?: readonly MeshEditWarning[];
}
 
declare function extrude(em: EditableMeshValue, faces: ElementSelection, opts: ExtrudeOptions): ExtrudeResult;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh.
facesElementSelectionMust be a non-empty face selection from em.
opts.distancenumberOffset distance along selected face normal or normalized direction.
opts.insetnumber0Fraction toward each face center before lifting. No clamp is applied.
opts.direction[number, number, number]selected face normalNormalized internally; zero vector behaves as length 1 denominator.
opts.mode"region" | "individual"accepted but not used in v1Current implementation extrudes each selected triangle independently.

Returns: ExtrudeResult — edited mesh plus side, cap, and boundary-edge selections on the result mesh. Throws: MeshEditError WRONG_DOMAIN if faces.domain !== "face"; EMPTY_SELECTION if faces.count === 0.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, extrude } from "@vgpu/render/edit";
 
const extrudeMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const extruded = extrude(extrudeMesh, extrudeMesh.faces.byIndex([0]), { distance: 0.2, inset: 0.1 });

Notes

  • Source faces are removed; new side and cap faces are returned for highlighting/chaining.
  • See also: inset, bevel, recomputeNormals.

bevel

Bevels selected edges by shrinking incident faces and inserting strip faces. Use it to soften hard edges; v1 supports a single segment.

Import

TypeScript
1
import { bevel } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import type { EditableMeshValue, ElementSelection, MeshEditWarning } from "@vgpu/render/edit";
 
declare interface BevelOptions {
  readonly offset: number;
  readonly segments?: number;
  readonly profile?: number;
  readonly affect?: "edges" | "vertices";
  readonly markSharp?: boolean;
}
 
declare interface BevelResult {
  readonly mesh: EditableMeshValue;
  readonly newFaces: ElementSelection;
  readonly originalFaces: ElementSelection;
  readonly profileLoops: readonly ElementSelection[];
  readonly warnings?: readonly MeshEditWarning[];
}
 
declare function bevel(em: EditableMeshValue, edges: ElementSelection, opts: BevelOptions): BevelResult;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh.
edgesElementSelectionMust be a non-empty edge selection.
opts.offsetnumberFraction toward each incident face center; clamped to [0, 0.49].
opts.segmentsnumber1Any value other than 1 emits BEVEL_SEGMENTS_CLAMPED; geometry remains one segment.
opts.profilenumberaccepted but not used in v1Present in type for future bevel profiles.
opts.affect"edges" | "vertices"accepted but not used in v1Current implementation bevels selected edges/incident faces.
opts.markSharpbooleantrueMarks selected original/profile edges sharp when true.

Returns: BevelResult — edited mesh, strip faces, shrunken original faces, and profile loop edge selections. Throws: MeshEditError WRONG_DOMAIN if edges.domain !== "edge"; EMPTY_SELECTION if edges.count === 0.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, bevel } from "@vgpu/render/edit";
 
const bevelMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const beveled = bevel(bevelMesh, bevelMesh.edges.byIndex([0]), { offset: 0.05 });

Notes

  • Boundary edges are processed on their one incident face and reported with NON_MANIFOLD_EDGE_SKIPPED warnings.
  • See also: extrude, inset, EdgeView.

inset

Insets selected faces by adding an inner triangle and boundary rim faces. Use it before extrude for panel-like forms.

Import

TypeScript
1
import { inset } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import type { EditableMeshValue, ElementSelection, MeshEditWarning } from "@vgpu/render/edit";
 
declare interface InsetOptions {
  readonly thickness: number;
  readonly depth?: number;
  readonly individual?: boolean;
}
 
declare interface InsetResult {
  readonly mesh: EditableMeshValue;
  readonly insetFaces: ElementSelection;
  readonly boundaryFaces: ElementSelection;
  readonly rimEdges: ElementSelection;
  readonly warnings?: readonly MeshEditWarning[];
}
 
declare function inset(em: EditableMeshValue, faces: ElementSelection, opts: InsetOptions): InsetResult;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh.
facesElementSelectionMust be a non-empty face selection.
opts.thicknessnumberFraction toward face center; clamped to [0, 0.49]. Clamp emits INSET_OVERLAP_CLAMPED.
opts.depthnumber0Offset along each face normal after insetting.
opts.individualbooleanaccepted but not used in v1Current implementation processes selected triangles individually.

Returns: InsetResult — edited mesh plus inner faces, rim/boundary faces, and rim edges on the result mesh. Throws: MeshEditError WRONG_DOMAIN if faces.domain !== "face"; EMPTY_SELECTION if faces.count === 0.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, inset } from "@vgpu/render/edit";
 
const insetMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const insetResult = inset(insetMesh, insetMesh.faces.all(), { thickness: 0.2, depth: 0.05 });

Notes

  • Follow with extrude(result.mesh, result.insetFaces, ...) for raised or recessed panels.
  • See also: extrude, bevel, FaceView.

subdivideEdges

Splits selected edges and retriangulates incident triangles. Use it to add local resolution before detailed edits.

Import

TypeScript
1
import { subdivideEdges } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
import type { EditableMeshValue, ElementSelection } from "@vgpu/render/edit";
 
declare interface SubdivideEdgesOptions { readonly cuts?: number }
declare interface SubdivideEdgesResult {
  readonly mesh: EditableMeshValue;
  readonly newVertices: ElementSelection;
  readonly newEdges: ElementSelection;
}
 
declare function subdivideEdges(em: EditableMeshValue, edges: ElementSelection, opts?: SubdivideEdgesOptions): SubdivideEdgesResult;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh.
edgesElementSelectionMust be a non-empty edge selection.
optsSubdivideEdgesOptions{}Options object may be omitted.
opts.cutsnumber1Floored and clamped to minimum 1; inserts this many points per selected edge.

Returns: SubdivideEdgesResult — edited mesh with selections for inserted vertices and child edges. Throws: MeshEditError WRONG_DOMAIN if edges.domain !== "edge"; EMPTY_SELECTION if edges.count === 0.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, subdivideEdges } from "@vgpu/render/edit";
 
const subdivideEdgesMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const edgeSubdivision = subdivideEdges(subdivideEdgesMesh, subdivideEdgesMesh.edges.byIndex([0]), { cuts: 2 });

Notes

subdivideFaces

Subdivides selected triangles into four triangles per cut iteration using edge midpoints.

Import

TypeScript
1
import { subdivideFaces } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
import type { EditableMeshValue, ElementSelection } from "@vgpu/render/edit";
 
declare interface SubdivideFacesOptions { readonly cuts?: number }
declare interface SubdivideFacesResult {
  readonly mesh: EditableMeshValue;
  readonly newFaces: ElementSelection;
  readonly newEdges: ElementSelection;
}
 
declare function subdivideFaces(em: EditableMeshValue, faces: ElementSelection, opts?: SubdivideFacesOptions): SubdivideFacesResult;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh.
facesElementSelectionMust be a non-empty face selection.
optsSubdivideFacesOptions{}Options object may be omitted.
opts.cutsnumber1Floored and clamped to minimum 1; repeated cut iterations apply to newly-created faces.

Returns: SubdivideFacesResult — edited mesh with selections for descendant faces and new edges. Throws: MeshEditError WRONG_DOMAIN if faces.domain !== "face"; EMPTY_SELECTION if faces.count === 0.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, subdivideFaces } from "@vgpu/render/edit";
 
const subdivideFacesMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const faceSubdivision = subdivideFaces(subdivideFacesMesh, subdivideFacesMesh.faces.all(), { cuts: 1 });

Notes

loopCut

Attempts to cut an edge loop/ring through coplanar triangle pairs. Falls back to cutting only the seed edge when continuation is ambiguous.

Import

TypeScript
1
import { loopCut } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import type { EditableMeshValue, ElementSelection, MeshEditWarning } from "@vgpu/render/edit";
 
declare interface LoopCutOptions {
  readonly cuts?: number;
  readonly slide?: number;
  readonly markSharp?: boolean;
}
 
declare interface LoopCutResult {
  readonly mesh: EditableMeshValue;
  readonly insertedLoop: ElementSelection;
  readonly warnings?: readonly MeshEditWarning[];
}
 
declare function loopCut(em: EditableMeshValue, seedEdge: number, opts?: LoopCutOptions): LoopCutResult;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh.
seedEdgenumberEdge index; must be 0 <= seedEdge < em.edgeCount.
optsLoopCutOptions{}Options object may be omitted.
opts.cutsnumber1 in fallback onlyUsed only when ambiguous continuation falls back to subdivideEdges.
opts.slidenumber0Maps to split factor 0.5 + slide * 0.5, clamped to [0.001, 0.999].
opts.markSharpbooleanfalseMarks inserted loop edges sharp only in successful ring cuts.

Returns: LoopCutResult — edited mesh plus ordered inserted-loop edge selection. Throws: MeshEditError EMPTY_SELECTION when seedEdge is out of range.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, loopCut } from "@vgpu/render/edit";
 
const loopCutMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const loopCutResult = loopCut(loopCutMesh, 0, { slide: 0.25 });

Notes

bridge

Creates faces between two ordered edge loops in one selection. Use for connecting holes or separated boundary rings.

Import

TypeScript
1
import { bridge } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import type { EditableMeshValue, ElementSelection, MeshEditWarning } from "@vgpu/render/edit";
 
declare interface BridgeOptions {
  readonly twist?: number;
  readonly mode?: "faces" | "merge";
}
 
declare interface BridgeResult {
  readonly mesh: EditableMeshValue;
  readonly bridgeFaces: ElementSelection;
  readonly chosenTwist: number;
  readonly warnings?: readonly MeshEditWarning[];
}
 
declare function bridge(em: EditableMeshValue, sel: ElementSelection, opts?: BridgeOptions): BridgeResult;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh.
selElementSelectionMust be a non-empty ordered edge selection containing two loops.
optsBridgeOptions{}Options object may be omitted.
opts.twistnumberauto by shortest squared endpoint distanceShift applied to second loop correspondence; returned as positive modulo loop length.
opts.mode"faces" | "merge""faces""merge" throws UNSUPPORTED_INPUT in the triangle-only kernel.

Returns: BridgeResult — edited mesh, bridge face selection, chosen twist, optional length-mismatch warnings. Throws: MeshEditError WRONG_DOMAIN, EMPTY_SELECTION, or NOT_ORDERED from loop validation; AMBIGUOUS_TOPOLOGY when two loops cannot be split; UNSUPPORTED_INPUT for mode: "merge"; DEGENERATE_RESULT can propagate from invalid loop vertices.

Examples

TypeScript
1
2
3
4
5
6
7
8
import { EditableMesh, bridge, type ElementSelection } from "@vgpu/render/edit";
 
const bridgeMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1]),
  indices: new Uint32Array([0, 1, 2, 3, 4, 5]),
});
const twoTriangleLoops: ElementSelection = { domain: "edge", indices: [0, 1, 2, 3, 4, 5], count: 6, ordered: true };
const bridged = bridge(bridgeMesh, twoTriangleLoops, { twist: 0 });

Notes

fillHole

Fills an ordered boundary loop with a triangle fan.

Import

TypeScript
1
import { fillHole } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
import type { EditableMeshValue, ElementSelection, MeshEditWarning } from "@vgpu/render/edit";
 
declare interface FillHoleOptions { readonly method?: "triangulate" | "ngon" | "beautify" }
declare interface FillHoleResult {
  readonly mesh: EditableMeshValue;
  readonly newFaces: ElementSelection;
  readonly warnings?: readonly MeshEditWarning[];
}
 
declare function fillHole(em: EditableMeshValue, boundary: ElementSelection, opts?: FillHoleOptions): FillHoleResult;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh.
boundaryElementSelectionMust be a non-empty ordered edge loop.
optsFillHoleOptions{}Options object may be omitted.
opts.method"triangulate" | "ngon" | "beautify""triangulate"Non-triangulate methods still emit a triangle fan and warn FILL_HOLE_TRIANGULATED.

Returns: FillHoleResult — edited mesh and newly-created faces. Throws: MeshEditError WRONG_DOMAIN, EMPTY_SELECTION, or NOT_ORDERED from loop validation; AMBIGUOUS_TOPOLOGY/DEGENERATE_RESULT can propagate from invalid loop vertices.

Examples

TypeScript
1
2
3
4
5
6
7
import { EditableMesh, fillHole, type ElementSelection } from "@vgpu/render/edit";
 
const fillHoleMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const triangleBoundary: ElementSelection = { domain: "edge", indices: [0, 1, 2], count: 3, ordered: true };
const filledHole = fillHole(fillHoleMesh, triangleBoundary);

Notes

  • Non-planar loops warn FILL_NON_PLANAR_BOUNDARY and are still triangulated.
  • See also: gridFill, bridge, ElementSet.boundaryOf.

gridFill

Deterministically represents a grid fill as triangles around the boundary center. Use it when callers request grid-fill semantics but the triangle-only kernel is acceptable.

Import

TypeScript
1
import { gridFill } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
import type { EditableMeshValue, ElementSelection, MeshEditWarning } from "@vgpu/render/edit";
 
declare interface GridFillOptions { readonly spanMode?: "auto" | number }
declare interface GridFillResult {
  readonly mesh: EditableMeshValue;
  readonly newFaces: ElementSelection;
  readonly warnings?: readonly MeshEditWarning[];
}
 
declare function gridFill(em: EditableMeshValue, boundary: ElementSelection, opts?: GridFillOptions): GridFillResult;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh.
boundaryElementSelectionMust be a non-empty ordered edge loop.
optsGridFillOptions{}Options object may be omitted.
opts.spanMode"auto" | number"auto" for warning textNumeric values < 1 throw DEGENERATE_RESULT; all modes triangulate.

Returns: GridFillResult — edited mesh, new fan faces, and warnings. Throws: MeshEditError WRONG_DOMAIN, EMPTY_SELECTION, or NOT_ORDERED from loop validation; DEGENERATE_RESULT for numeric spanMode < 1; AMBIGUOUS_TOPOLOGY can propagate from invalid loop vertices.

Examples

TypeScript
1
2
3
4
5
6
7
import { EditableMesh, gridFill, type ElementSelection } from "@vgpu/render/edit";
 
const gridFillMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const gridBoundary: ElementSelection = { domain: "edge", indices: [0, 1, 2], count: 3, ordered: true };
const gridFilled = gridFill(gridFillMesh, gridBoundary, { spanMode: "auto" });

Notes

  • Always emits GRID_FILL_TRIANGULATED; odd loop lengths also warn with FILL_NON_PLANAR_BOUNDARY wording.
  • See also: fillHole, bridge, MeshEditWarning.

dissolveVertices

Dissolves selected non-boundary vertices by dissolving their surrounding faces.

Import

TypeScript
1
import { dissolveVertices } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import type { EditableMeshValue, ElementSelection, MeshEditWarning } from "@vgpu/render/edit";
 
declare interface DissolveVerticesOptions {
  readonly useFaceSplit?: boolean;
  readonly useBoundaryTear?: boolean;
}
 
declare interface DissolveVerticesResult {
  readonly mesh: EditableMeshValue;
  readonly surroundingFaces: ElementSelection;
  readonly warnings?: readonly MeshEditWarning[];
}
 
declare function dissolveVertices(em: EditableMeshValue, vertices: ElementSelection, opts?: DissolveVerticesOptions): DissolveVerticesResult;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh.
verticesElementSelectionMust be a non-empty vertex selection.
optsDissolveVerticesOptions{}Options object may be omitted.
opts.useFaceSplitbooleanaccepted but not used in v1Present in type only.
opts.useBoundaryTearbooleanaccepted but not used in v1Boundary vertices are skipped with warnings.

Returns: DissolveVerticesResult — edited mesh and resulting surrounding face selection. Throws: MeshEditError WRONG_DOMAIN if vertices.domain !== "vertex"; EMPTY_SELECTION if vertices.count === 0.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, dissolveVertices } from "@vgpu/render/edit";
 
const dissolveVerticesMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const dissolvedVertices = dissolveVertices(dissolveVerticesMesh, dissolveVerticesMesh.vertices.byIndex([0]));

Notes

dissolveEdges

Removes selected internal edges by merging each adjacent face pair and retriangulating with a deterministic diagonal.

Import

TypeScript
1
import { dissolveEdges } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
import type { EditableMeshValue, ElementSelection, MeshEditWarning } from "@vgpu/render/edit";
 
declare interface DissolveEdgesOptions { readonly useVerts?: boolean }
declare interface DissolveEdgesResult {
  readonly mesh: EditableMeshValue;
  readonly mergedFaces: ElementSelection;
  readonly warnings?: readonly MeshEditWarning[];
}
 
declare function dissolveEdges(em: EditableMeshValue, edges: ElementSelection, opts?: DissolveEdgesOptions): DissolveEdgesResult;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh.
edgesElementSelectionMust be a non-empty edge selection. Boundary/overlapping jobs are skipped with warnings.
optsDissolveEdgesOptions{}Options object may be omitted.
opts.useVertsbooleanaccepted but not used in v1Present in type only.

Returns: DissolveEdgesResult — edited mesh and merged face selection. Throws: MeshEditError WRONG_DOMAIN if edges.domain !== "edge"; EMPTY_SELECTION if edges.count === 0.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, dissolveEdges } from "@vgpu/render/edit";
 
const dissolveEdgesMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const dissolvedEdges = dissolveEdges(dissolveEdgesMesh, dissolveEdgesMesh.edges.byIndex([0]));

Notes

dissolveFaces

Removes selected face regions and retriangulates each region boundary as a fan.

Import

TypeScript
1
import { dissolveFaces } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
import type { EditableMeshValue, ElementSelection, MeshEditWarning } from "@vgpu/render/edit";
 
declare interface DissolveFacesResult {
  readonly mesh: EditableMeshValue;
  readonly resultFace: ElementSelection;
  readonly warnings?: readonly MeshEditWarning[];
}
 
declare function dissolveFaces(em: EditableMeshValue, faces: ElementSelection): DissolveFacesResult;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh.
facesElementSelectionMust be a non-empty face selection. Connected components are dissolved independently.

Returns: DissolveFacesResult — edited mesh and result face selection. Throws: MeshEditError WRONG_DOMAIN if faces.domain !== "face"; EMPTY_SELECTION if faces.count === 0.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, dissolveFaces } from "@vgpu/render/edit";
 
const dissolveFacesMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const dissolvedFaces = dissolveFaces(dissolveFacesMesh, dissolveFacesMesh.faces.all());

Notes

mergeByDistance

Welds vertices whose positions are within a threshold, removes collapsed faces, and returns an old-to-new vertex map.

Import

TypeScript
1
import { mergeByDistance } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import type { EditableMeshValue, ElementSelection, MeshEditWarning } from "@vgpu/render/edit";
 
declare interface MergeByDistanceOptions {
  readonly threshold?: number;
  readonly selection?: ElementSelection;
  readonly key?: "position" | "full-vertex";
}
 
declare interface MergeByDistanceResult {
  readonly mesh: EditableMeshValue;
  readonly mergeMap: ReadonlyMap<number, number>;
  readonly weldedCount: number;
  readonly warnings?: readonly MeshEditWarning[];
}
 
declare function mergeByDistance(em: EditableMeshValue, opts?: MergeByDistanceOptions): MergeByDistanceResult;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh.
optsMergeByDistanceOptions{}Options object may be omitted.
opts.thresholdnumber1e-4Euclidean position distance for clustering.
opts.selectionElementSelectionem.vertices.all()Must be a vertex selection. Only selected vertices are clustered; all faces are remapped.
opts.key"position" | "full-vertex"warning mode equivalent to "full-vertex"Clustering is position-based in v1. "position" emits SEAM_DESTROYED when UV/normal/color flags exist.

Returns: MergeByDistanceResult — welded mesh, old vertex index to new vertex index map (-1 for unused), and welded count. Throws: MeshEditError WRONG_DOMAIN if opts.selection.domain !== "vertex"; EMPTY_SELECTION if opts.selection.count === 0.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, mergeByDistance } from "@vgpu/render/edit";
 
const mergeMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 0.00001, 0, 0, 0, 1, 0]),
});
const merged = mergeByDistance(mergeMesh, { threshold: 0.001 });

Notes

healManifold

Deterministic cleanup pass that removes duplicate, degenerate, and overused-edge faces where possible.

Import

TypeScript
1
import { healManifold } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import type { EditableMeshValue, MeshEditWarning } from "@vgpu/render/edit";
 
declare interface HealManifoldReport {
  readonly nonManifoldEdgesFixed: number;
  readonly nonManifoldVerticesFixed: number;
  readonly holesFixed: number;
  readonly duplicateFacesRemoved: number;
}
 
declare interface HealManifoldResult {
  readonly mesh: EditableMeshValue;
  readonly report: HealManifoldReport;
  readonly warnings?: readonly MeshEditWarning[];
}
 
declare function healManifold(em: EditableMeshValue): HealManifoldResult;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh.

Returns: HealManifoldResult — cleaned mesh plus report. nonManifoldVerticesFixed and holesFixed are currently always 0. Throws: — no MeshEditError is thrown directly.

Examples

TypeScript
1
2
3
4
5
6
7
import { EditableMesh, healManifold } from "@vgpu/render/edit";
 
const healMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
  indices: new Uint32Array([0, 1, 2, 0, 1, 2]),
});
const healed = healManifold(healMesh);

Notes

recomputeNormals

Rebuilds the editable mesh and recomputes face normals using smoothing components and sharp edges or a new crease angle.

Import

TypeScript
1
import { recomputeNormals } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
import type { EditableMeshValue } from "@vgpu/render/edit";
 
declare interface RecomputeNormalsOptions {
  readonly weighting?: "angle" | "area" | "uniform";
  readonly creaseAngle?: number;
}
 
declare function recomputeNormals(em: EditableMeshValue, opts?: RecomputeNormalsOptions): EditableMeshValue;

Parameters

ParamTypeRequiredDefaultNotes
emEditableMeshValueSource mesh. Empty meshes are returned unchanged.
optsRecomputeNormalsOptions{}Options object may be omitted.
opts.weighting"angle" | "area" | "uniform""angle"Weighting mode for smoothing component normals.
opts.creaseAnglenumberpreserve current sharp-edge maskIf provided, rebuilds sharp edges from the crease angle instead of preserving isSharp.

Returns: EditableMeshValue — new mesh with recomputed kernel face normals, or the same mesh when faceCount === 0. Throws: — no MeshEditError is thrown directly.

Examples

TypeScript
1
2
3
4
5
6
import { EditableMesh, recomputeNormals } from "@vgpu/render/edit";
 
const normalsMesh = EditableMesh.fromArrays({
  positions: new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0]),
});
const normalsRecomputed = recomputeNormals(normalsMesh, { weighting: "area" });

Notes

MeshEditError

Error class thrown by validation and topology operators. Catch by instanceof MeshEditError and branch on code.

Import

TypeScript
1
import { MeshEditError } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export type MeshEditErrorCode =
  | "NON_MANIFOLD"
  | "STALE_SELECTION"
  | "EMPTY_SELECTION"
  | "WRONG_DOMAIN"
  | "NOT_ORDERED"
  | "DEGENERATE_RESULT"
  | "AMBIGUOUS_TOPOLOGY"
  | "UNSUPPORTED_INPUT";
 
declare class MeshEditError extends Error {
  readonly code: MeshEditErrorCode;
  readonly suggestion?: string;
  constructor(opts: { readonly code: MeshEditErrorCode; readonly message?: string; readonly suggestion?: string });
}

Parameters

Param/FieldTypeRequiredDefaultNotes
opts.codeMeshEditErrorCodeMachine-readable error code.
opts.messagestringopts.codeError message passed to Error.
opts.suggestionstringomittedOptional recovery hint.
codeMeshEditErrorCodePublic readonly field copied from constructor.
suggestionstringomittedPublic readonly optional field.
namestring"MeshEditError"Set by constructor.

Returns: MeshEditError instance from new MeshEditError(...). Throws: — constructor does not throw.

Examples

TypeScript
1
2
3
4
import { MeshEditError } from "@vgpu/render/edit";
 
const meshEditError = new MeshEditError({ code: "EMPTY_SELECTION", suggestion: "Select at least one face." });
const meshEditErrorCode = meshEditError.code;

Notes

MeshEditWarning

Non-fatal diagnostic emitted in operator result warnings arrays. Use warnings to explain deterministic fallbacks and data loss.

Import

TypeScript
1
import { MeshEditWarning } from "@vgpu/render/edit";

Signature

TypeScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
export type MeshEditWarningCode =
  | "NON_MANIFOLD_EDGE_SKIPPED"
  | "NON_MANIFOLD_VERTEX_SKIPPED"
  | "DEGENERATE_FACE_DROPPED"
  | "TANGENTS_STRIPPED"
  | "BEVEL_ACUTE_CLAMPED"
  | "BEVEL_SEGMENTS_CLAMPED"
  | "INSET_OVERLAP_CLAMPED"
  | "SEAM_DESTROYED"
  | "BRIDGE_LOOP_LENGTH_MISMATCH"
  | "FILL_NON_PLANAR_BOUNDARY"
  | "LOOP_CUT_AMBIGUOUS_CONTINUATION"
  | "FILL_HOLE_TRIANGULATED"
  | "GRID_FILL_TRIANGULATED"
  | "DISSOLVE_FACES_RETRIANGULATED"
  | "MERGE_DEGENERATE_FACES_REMOVED"
  | "HEAL_NON_MANIFOLD_RESIDUE";
 
declare class MeshEditWarning {
  readonly code: MeshEditWarningCode;
  readonly reason: string;
  readonly element?: { readonly domain: "vertex" | "edge" | "face"; readonly index: number };
  constructor(
    code: MeshEditWarningCode,
    reason: string,
    element?: { readonly domain: "vertex" | "edge" | "face"; readonly index: number },
  );
}

Parameters

Param/FieldTypeRequiredDefaultNotes
codeMeshEditWarningCodeMachine-readable warning code.
reasonstringHuman-readable explanation.
element{ domain: "vertex" | "edge" | "face"; index: number }omittedOptional source element associated with the warning.

Returns: MeshEditWarning instance from new MeshEditWarning(...). Throws: — constructor does not throw.

Examples

TypeScript
1
2
3
4
import { MeshEditWarning } from "@vgpu/render/edit";
 
const meshEditWarning = new MeshEditWarning("GRID_FILL_TRIANGULATED", "Triangle-only output was used.");
const warningReason = meshEditWarning.reason;

Notes