PartHistory Reference
PartHistory lives in src/PartHistory.js and is the core modeling history manager. It owns the feature list, the shared Three.js scene, the expression scratchpad, PMI views, metadata, and the assembly constraint history. It can rebuild geometry deterministically by replaying feature entries, serialize and restore part state, and maintain undo/redo via JSON snapshots.
Live Demos
- Examples hub: https://BREP.io/apiExamples/index.html
- Embeded CAD: https://BREP.io/apiExamples/Embeded_CAD.html
- Embeded CAD Integration Test: https://BREP.io/apiExamples/Embeded_CAD_Integration_Test.html
Responsibilities
- Manage the ordered list of modeling features (
features). - Own and mutate the shared Three.js
scene. - Evaluate parameter expressions via a user-defined expression script.
- Run the history to (re)build geometry from feature inputs.
- Persist and restore feature history, PMI views, metadata, and assembly constraints.
- Track and apply undo/redo snapshots.
- Sync and update assembly component data.
Constructor
new PartHistory()
Creates a new history manager and initializes:
features: empty arrayscene:new THREE.Scene()featureRegistry:new FeatureRegistry()assemblyConstraintRegistry:new AssemblyConstraintRegistry()assemblyConstraintHistory:new AssemblyConstraintHistory(this, registry)pmiViewsManager:new PMIViewsManager(this)metadataManager:new MetadataManager()expressions: default example script stringcallbacks: empty bag for optional hooks- Undo/redo state in
_historyUndo
The constructor also soft-overrides scene.remove and scene.add to aid debugging and to block removal of objects with userData.preventRemove.
Data model
Feature entry shape
Each entry in features is a plain object with at least:
{
type: string, // Feature type string (registry key)
inputParams: Object, // User inputs; includes an id
persistentData: Object, // Saved outputs from previous runs
timestamp?: number, // Last run time (ms epoch)
dirty?: boolean, // Marks entry for re-run
lastRunInputParams?: string, // JSON string for dirty detection
lastRun?: { // Execution metadata
ok: boolean,
startedAt: number,
endedAt: number,
durationMs: number,
error: { name, message, stack } | null
},
effects?: { added: [], removed: [] },
previouseExpressions?: Object // Cached evaluated numeric inputs
}IDs are normalized and kept in sync:
feature.inputParams.idandfeature.idare strings.- A non-enumerable
feature.inputParams.featureIDproperty is defined as an alias ofidfor legacy compatibility.
Feature class contract
A feature class (from FeatureRegistry) is expected to provide:
static inputParamsSchemadescribing inputs and defaults.run(partHistory)which returns{ added, removed }.- Optional
longName,shortName,namefor display. - (Sketch only)
hasSketchChanged(feature)for dirty detection.
Result artifacts
run() should return an object with:
added: array of objects to add to the sceneremoved: array of objects to remove from the scene
Objects are expected to be compatible with Three.js scene nodes. If they implement free() and/or visualize(), those are called automatically.
Expressions
expressions is a user-editable script string. Numeric inputs can reference it.
- Static helper:
PartHistory.evaluateExpression(expressionsSource, equation) - Instance helper:
partHistory.evaluateExpression(equation)
evaluateExpression uses Function() to execute the script and return an evaluated value. It returns null on error. Treat expression input as code (do not evaluate untrusted content).
Execution flow
runHistory()
Rebuilds the scene by replaying features in order.
High-level flow:
- Clear the scene and dispose resources, preserving lights, cameras, and transform gizmos.
- Iterate features in order:
- Run assembly constraints.
- Call optional callbacks.
- Normalize ID linkage for each feature. - Stop after currentHistoryStepId (if set) but keep later features in the list. - Resolve the feature class from the registry; if missing, mark lastRun with a MissingFeature error and continue. - Copy persistentData into the feature instance. - Remove any existing scene children with owningFeatureID === featureId (rerun case). - Compute dirty state based on: - changed input params - feature timestamps vs. upstream features - newer referenced objects - expression evaluation changes - Sketch change detection - If dirty: - call run() - record lastRun, timestamp, effects, lastRunInputParams - Apply effects via applyFeatureEffects().
Notes:
currentHistoryStepIdis not cleared insiderunHistory().- Any feature error stops the run and logs the error.
runHistory()returnsthis.
Scene integration and selection
When adding objects:
applyFeatureEffects()callsfree()andvisualize()if present.- Each added object and its descendants get
timestampandowningFeatureID. - Each object gets an
onClickhandler that usesSelectionFilter.toggleSelection.
Objects with userData.preventRemove are not removed when the scene is cleared.
Serialization
toJSON()
Returns a pretty-printed JSON string containing:
features(type, inputParams, persistentData, timestamp)idCounterexpressionspmiViews(viaPMIViewsManager)metadata(fromMetadataManager)assemblyConstraintsandassemblyConstraintIdCounter
Before export, assembly component transforms are synced into feature input params.
fromJSON(jsonString, options)
Restores state from a JSON string. Behavior:
- Migrates legacy
featureIDfields toid. - Rehydrates PMI views and metadata.
- Loads assembly constraints into
AssemblyConstraintHistory. - Resets undo/redo history unless
options.skipUndoResetistrue.
Undo / redo
PartHistory maintains a JSON snapshot stack:
_historyUndo.undoStackand_historyUndo.redoStack- Debounced snapshot capture (
debounceMs, default 350ms) - Max snapshot count (
max, default 50)
Key methods:
queueHistorySnapshot({ debounceMs, force })flushHistorySnapshot({ force })undoFeatureHistory()redoFeatureHistory()canUndoFeatureHistory()canRedoFeatureHistory()
Undo/redo restores by calling fromJSON() and re-running runHistory().
Assembly components and constraints
assemblyConstraintHistoryowns constraints and runs the solver.runAssemblyConstraints()delegates toAssemblyConstraintHistory.runAll().
Assembly component utilities:
hasAssemblyComponents(): returns true if any feature is an assembly component.syncAssemblyComponentTransforms(): copies scene transforms into feature input params.getOutdatedAssemblyComponentCount(): counts components whose source data changed.updateAssemblyComponents({ rerun = true }): refreshes component data and optionally re-runs history.
Public properties
features: Array<Object>scene: THREE.SceneidCounter: numberfeatureRegistry: FeatureRegistryassemblyConstraintRegistry: AssemblyConstraintRegistryassemblyConstraintHistory: AssemblyConstraintHistorypmiViewsManager: PMIViewsManagermetadataManager: MetadataManagerexpressions: string
- currentHistoryStepId: string | null
callbacks: Object(optional hooks)_historyUndo: Object(internal state)
Callbacks
callbacks is a simple bag of optional functions:
callbacks.run(featureId)- called before each feature runs (awaited).callbacks.reset()- called afterreset()clears scene (awaited).callbacks.afterRunHistory()- called afterrunHistory()completes.callbacks.afterReset()- called afterreset()finishes.
API reference
Static
#### PartHistory.evaluateExpression(expressionsSource, equation): any | null
Evaluates equation using expressionsSource as the preamble. Returns null on error.
Instance
#### evaluateExpression(equation): any | null
Same as static helper but uses this.expressions.
#### getObjectByName(name): Object3D | null
Delegates to scene.getObjectByName.
reset(): Promise<void>
Clears features, resets managers, clears the scene, and resets undo/redo. Calls callbacks.reset and callbacks.afterReset.
runHistory(): Promise<PartHistory>
Replays features, rebuilds the scene, runs constraints, and calls callbacks.afterRunHistory.
applyFeatureEffects(effects, featureId, feature): Promise<void>
Applies added/removed artifacts to the scene, sets timestamps/ownership, and attaches selection handlers.
toJSON(): Promise<string>
Serializes the full part history and related state.
fromJSON(jsonString, options?): Promise<void>
Restores from a serialized history string.
generateId(prefix): Promise<string>
Increments idCounter and returns ${prefix}${idCounter}.
sanitizeInputParams(schema, inputParams): Promise<Object>
Normalizes and evaluates input params based on schema types:
number: evaluates expressionsreference_selection: resolves object names to scene objectsboolean_operation: normalizes op and target list, optional bias/offsettransform: evaluates position/rotation/scale arraysvec3: evaluates 3-vector entriesboolean: normalizes to boolean- default: pass-through
newFeature(featureType): Promise<Object>
Creates a new feature entry, seeds defaults from schema, assigns an ID, and appends it to features.
removeFeature(featureId): Promise<void>
Removes any feature with matching ID.
resetHistoryUndo(): void
Clears undo/redo stacks and internal flags.
queueHistorySnapshot(options?): void
Debounced snapshot capture.
flushHistorySnapshot(options?): Promise<void>
Forces a snapshot immediately.
undoFeatureHistory(): Promise<boolean>
Restores the previous snapshot if available.
redoFeatureHistory(): Promise<boolean>
Reapplies the next snapshot if available.
runAssemblyConstraints(): Promise<Array>
Runs the assembly constraint solver.
hasAssemblyComponents(): boolean
Checks if any feature is an assembly component.
syncAssemblyComponentTransforms(): void
Writes current scene transforms into feature input params.
getOutdatedAssemblyComponentCount(): number
Returns number of outdated components.
updateAssemblyComponents(options?): Promise<{ updatedCount, reran }>
Refreshes assembly component data; optionally re-runs history.
Internal helpers
These methods are intended for internal use:
_coerceRunEffects,_attachSelectionHandlers,_safeRemove_commitHistorySnapshot,_applyHistorySnapshot_sanitizePersistentDataForExport,_collectAssemblyComponentUpdates#runFeatureEntryMigrations,#linkFeatureParams,#prepareFeatureEntry,#prepareFeatureList#disposeSceneObjects,#disposeObjectResources,#disposeMaterialResources
Related helper
extractDefaultValues(schema)
Exported alongside PartHistory. Returns a deep-cloned object of default_value for each schema key.
Usage examples
Basic feature run
import { PartHistory } from './PartHistory.js';
const history = new PartHistory();
const feature = await history.newFeature('Sketch');
// set feature.inputParams as needed
await history.runHistory();Expressions
history.expressions = "x = 10; y = x * 2;";
feature.inputParams.depth = "y + 5";
await history.runHistory();Save / load
const json = await history.toJSON();
const restored = new PartHistory();
await restored.fromJSON(json);
await restored.runHistory();Undo / redo
history.queueHistorySnapshot();
await history.undoFeatureHistory();
await history.redoFeatureHistory();