@huukhanhnguyen/model / core/ModelScope
core/ModelScope
ModelScope
Runtime scope holder for a parametric model. Carries the node graph, unit configuration, static asset lanes, and the cross-lane resolver hooks (Model.ts wires them, avoiding a circular import) every isolated scope (components[]/textures[]) reaches through.
Extends
Constructors
Constructor
new ModelScope(
name?):ModelScope
Parameters
name?
string = "Model"
Returns
Overrides
animations
animations:
Chain[] =[]
Animation chains (track nodes) — evaluateAnimations folds to clips.
annotationStyles
annotationStyles:
Operation[] =[]
Annotation styles lane — annotationStyle operation nodes (arrow and extension-line geometry, measurement formatting). Resolved via collectAnnotationStyles() into AnnotationStyle records consumed by-name from every dimension/leader node. Kept SEPARATE from textStyles for DXF's reason — see schema/lanes.ts.
assets?
optionalassets?:Store
attributes
attributes:
Record<string,unknown> ={}
Inherited from
blockKeys
blockKeys:
Set<string>
Authored BlockNode keys — evaluate wraps each child as its own object.
cameras
cameras:
CameraNode[] =[]
Named camera poses (camera method). A view3d head may reference by key. NOT product: never enters the data stream. A LIGHT is an ordinary object whose data is LightData, not a lane node at all; axes and a floor grid are a VIEWER setting, not a lane either (the helpers[] lane was deleted 2026-08-16).
collection
collection:
BaseCollection
Inherited from
components
components:
Component[] =[]
Component lane (named reusable 2D/3D definitions) — on the scope for the same UI-reachability reason as textures (Model.components = accessor).
evaluateRoot?
optionalevaluateRoot?: () =>void
Returns
void
flat?
optionalflat?:boolean
Chain-level flat declaration (ModelJSON.flat) — when true, every root scene step is flat-declared (DataNode._flatDeclared reads this).
id
id:
string
Inherited from
imageUrlOf?
optionalimageUrlOf?: (name) =>string
Resolve an attached-image reference to its url (wired by Model) — imageData's own scope hook: a url-method parameter KEY resolves to that parameter's literal url; anything else (a raw https:/data: URI) passes through unchanged.
Parameters
name
string
Returns
string
laneHeaders?
optionallaneHeaders?: (lane) =>Record<string,unknown>[]
One lane's entries reduced to their HEADER fields (key/title/label), in order — wired by Model to a CollectionNode, so reading this registers a membership edge PLUS one edge per entry. Never touches an entry's body, which is what lets a sheet place a table listing every sheet without closing a cycle. Throws on a lane with no collection.
Parameters
lane
string
Returns
Record<string, unknown>[]
layers
layers:
Operation[] =[]
Layers lane — layer operation nodes (expression args name/color/ lineWidth/lineStyle). Resolved via evaluateLayers() / collectLayers() into Layer records consumed by-name.
listAnimationClips?
optionallistAnimationClips?: () =>AnimationClip[]
All resolved animation clips for the renderer (lane + baked component clips).
Returns
listAnnotationStyles?
optionallistAnnotationStyles?: () =>AnnotationStyle[]
Returns
listPatterns?
optionallistPatterns?: () =>Pattern[]
The RESOLVED patterns[] records (wired by Model). A hatch names one and cannot be drawn without it; reading the lane through a hook is what makes editing a pattern re-draw every hatch that names it.
Returns
Pattern[]
listSkeletons?
optionallistSkeletons?: () => {data:SkeletonData;key:string; }[]
All resolved skeletons for the renderer (skeleton objects in objects[]). The key rides along: it is the skeleton's only identity.
Returns
{ data: SkeletonData; key: string; }[]
listTextStyles?
optionallistTextStyles?: () =>TextStyle[]
The RESOLVED textStyles[] / annotationStyles[] records (wired by Model). A drafting-mark producer reads these through the compute context to build its drawn form — see nodesRegistry/wiring.ts's STYLE_AWARE_METHODS. Hooks rather than stored arrays, for the same reason resolveMaterial is one: reading the lane is what makes it a dependency, so editing a style rebuilds the marks that name it.
Returns
listTracks?
optionallistTracks?: () =>Track[]
The full evaluated Track pool a renderer resolves clip/joint/mesh references against — see evaluate/animation.ts's header (consumer-holds-the-reference: an AnimationClip only lists member track KEYS, a BoneEntity's *Track field is a key too; this is where those keys resolve to actual times/values/interpolation).
Returns
Track[]
materials
materials:
Operation[] =[]
Materials lane — material operation nodes (expression args for every Material field). Resolved via evaluateMaterials() / collectMaterialNodes() into Material records consumed by-name.
name
name:
string
nodes?
optionalnodes?:NodesLike
owningModel?
optionalowningModel?:Model
The Model that owns this scope — wired by Model's constructor (root scope only; an isolated component/texture scope has none). Read by commandRegistry/laneEdit.ts so a panel holding only a scope can still reach the Model-level views lane and settings. Never serialized.
parent?
optionalparent?:any
Inherited from
patterns
patterns:
Operation[] =[]
Patterns lane — pattern operation nodes (expression args name/ lines/lengthSpace). Resolved via evaluatePatterns() / collectPatterns() into Pattern records consumed by-name from a hatch's pattern arg.
refreshTextures?
optionalrefreshTextures?: () =>void
Re-resolve material textureData from the current chains and notify the render sync (wired by Model) — the builder panel's "push texture edits to the 3D scene" hook.
Returns
void
registry?
optionalregistry?:Registry
resolveMaterial?
optionalresolveMaterial?: (name) =>unknown
Resolve one materials[] record by name (wired by Model) — Material.get() expression hook. Returns null on miss (fail-soft). Reading registers a materials-lane dependency edge via evaluateMaterials.
Parameters
name
string
Returns
unknown
resolvePlacedComponentBody?
optionalresolvePlacedComponentBody?: (key,argsOverride?) => {data:ObjectData;flat:boolean;opening:BrepData[]; }
3D-mode placeComponent hook (wired by Model, root scope) — raw (untransformed) body + opening volumes for one components[] entry, NO flatness gate (see components.ts's FlatLaneExtras.resolvePlacedComponentBody doc — the SAME hook name/shape is also wired onto a component's own isolated "component"-lane scope, for nested 3D placement). flat (the component's own Component.flat declaration) rides along so a flat-declared CHAIN reaching this hook from a 3D lane can splice the body as-is instead of force-flattening it.
Parameters
key
string
argsOverride?
Record<string, string>
Returns
{ data: ObjectData; flat: boolean; opening: BrepData[]; }
data
data:
ObjectData
flat
flat:
boolean
opening
opening:
BrepData[]
resolvePlacedPart?
optionalresolvePlacedPart?: (key,argsOverride?,angles?) =>ObjectData|undefined
placePart's ROOT-scope hook (wired by Model's constructor) — folds one components[] entry's attributes.pattern content into 3D and returns the grouped placement (see Model._resolvePlacedPart; a part is a components[] entry with attributes.pattern content + consumer-side parameters — tmp/ui-redesign/view-spec.md). argsOverride carries the placement's own parameter overrides (placePart's args arg — same contract as placeComponent's); angles is the per-bend angle override map. Throws a named error on an unknown key / missing pattern content (caught by the calling DataNode's per-step fail-soft).
Parameters
key
string
argsOverride?
Record<string, string>
angles?
Record<string, number>
Returns
ObjectData | undefined
resolvePlacedTable?
optionalresolvePlacedTable?: (key) =>ObjectData|undefined
Parameters
key
string
Returns
ObjectData | undefined
resolvePlacedView?
optionalresolvePlacedView?: (key) =>ObjectData|undefined
viewport/tableEntity's ROOT-scope hooks (wired by Model, 2026-07-18 — one-graph law: cross-lane reads are free, cycles rejected by detection, never by a blanket lane-placement ban). Resolve one views[]/tables[] entry into flat, positioned data documents — a narrow-scope tableEntity (explicit entities) never touches the root fold at all; a whole-scene read (a view; a tableSource with no explicit entities) that reaches back into THIS same fold throws a named "Circular dependency" error instead (see Model.ts's sceneFrame / fold-depth guard), caught by the reading node's own per-step fail-soft.
Parameters
key
string
Returns
ObjectData | undefined
resolveSkeleton?
optionalresolveSkeleton?: (key) =>SkeletonData|undefined
Resolve a skeleton object key to its SkeletonData (wired by Model for faceSkeleton). The object IS the skeleton — its key is the identity.
Parameters
key
string
Returns
SkeletonData | undefined
resolveTable?
optionalresolveTable?: (key,operationCount?) =>unknown
Resolve one tables[] entry by key (wired by Model) — the Table.get() expression function's hook (see nodes/ExpressionNode.ts). Throws on unknown key. operationCount truncates the body fold (TablesSection verb step preview — same idea as resolveTexture).
Parameters
key
string
operationCount?
number
Returns
unknown
resolveTexture?
optionalresolveTexture?: (key,args?,operationCount?) =>unknown
Full-chain resolver (wired by Model): evaluate one textures[] entry with optional own-parameter overrides — the builder panel's preview entry. operationCount truncates the chain to its first N steps (per-step thumbnails). Returns an ImageBuffer; throws on unknown key.
Parameters
key
string
args?
Record<string, string>
operationCount?
number
Returns
unknown
sampleTexture?
optionalsampleTexture?: (key) =>unknown
Texture-lane field resolver (wired by Model): lets a geometry op — displace — consume a math->image chain by key. Cross-stream by design, but one-way: geometry reads pixels, never the reverse.
Parameters
key
string
Returns
unknown
sceneData?
optionalsceneData?: () =>ObjectData[]
Whole-scene data list for Scene.entities() (wired by Model — flattens sceneFrame() leaves). A root-fold re-entry throws a named "Circular dependency" error (see Model.sceneFrame).
Returns
settings?
optionalsettings?:ModelSettings
Model-level settings (units/activeView/cameraTour) — lives here (like unit) so free functions reach it via node.owner?.settings the same way they already reach unit.
sheets
sheets:
Sheet[] =[]
Sheet lane (construction drawing sheets) — carried on the scope like the other document lanes, so doc-wide edits that only hold a scope (e.g. a material rename rewriting every by-name reference) reach a sheet's ad hoc operations too.
sourceId
sourceId:
string=""
Inherited from
styles
styles:
Operation[] =[]
Styles lane — style operation nodes (expression args name/ background/shading/exposure/sun/environment). Resolved via evaluateStyles() / collectStyleNodes() into Style records consumed by-name from a views[] viewStyle step.
tables
tables:
TableChain[] =[]
Table lane (reporting streams) — carried on the scope like the other document lanes, so UI panels + Table.get() reach it through the owner chain (scopeOf(owner)), same as materials/layers/fonts/textures.
templates
templates:
Template[] =[]
textStyles
textStyles:
Operation[] =[]
Text styles lane — textStyle operation nodes (font/height/ widthFactor/oblique). Resolved via collectTextStyles() into TextStyle records consumed by-name from a text node and from every annotation style.
textures
textures:
Chain[] =[]
Texture lane (math->image chains) — carried on the scope like the other document lanes, so UI panels reach it through the owner chain (scopeOf(owner)), same as materials/layers/fonts. Storage key is textures[] on ModelJSON.
unit?
optionalunit?:UnitConfig
urlParameterRows?
optionalurlParameterRows?: () => {key:string;url:string; }[]
The CURRENT url-method parameter rows ({ key, url } — url = the parameter's literal url, see urlInputLiteral in schema/model.ts), wired by Model and read FRESH on every fonts/images access below — the two views can never go stale, and there is no stored lane state for a UI to write.
Returns
{ key: string; url: string; }[]
Accessors
fonts
Get Signature
get fonts():
AssetFile[]
COMPUTED view over the url-method parameters: one { name: paramKey, url } entry per parameter whose url classifies as a font (assetTypeOf). Read-only — an attached font is edited by editing its parameter.
Returns
images
Get Signature
get images():
AssetFile[]
COMPUTED view over the url-method parameters: one { name: paramKey, url } entry per parameter whose url classifies as an image (assetTypeOf) — consumed by sheet placements, the pattern image source, and the imageData generator. Read-only.
Returns
model
Get Signature
get model():
any
Returns
any
Inherited from
Methods
_dispose()
_dispose():
void
Returns
void
Inherited from
addListener()
addListener(
event,listener): () =>void
Parameters
event
string
listener
Returns
() => void
Inherited from
bakeValue()
bakeValue(
value):ObjectData[]
Bake a chain value (ONE ObjectData, which may be a blockData — clone/array-over-a-group/looseToBlock/makeBlock all produce one) into flat leaf data documents. A node's .model getter resolves to its owning ModelScope, so any node-tree consumer (e.g. a hover preview) reaches this the same way Model.bakeValue does.
Parameters
value
ObjectData | undefined
Returns
evaluate()
evaluate():
void
Pull the root fold fresh (see evaluateRoot) — a no-op if this scope was constructed standalone (not via new Model(...), which always wires evaluateRoot).
Returns
void
fromJSON()
staticfromJSON(json):ModelScope
Parameters
json
Returns
notify()
notify(
event, ...args):void
Parameters
event
string
args
...unknown[]
Returns
void
Inherited from
remove()
remove():
void
Returns
void
Inherited from
removeListener()
removeListener(
event,listener):void
Parameters
event
string
listener
Returns
void
Inherited from
setName()
setName(
name):void
Parameters
name
string
Returns
void
toJSON()
toJSON():
RawModel
Returns
Overrides
resolveImageUrl()
resolveImageUrl(
images,ref):string
Resolve an attached-image reference against the computed url-parameter entries (ModelScope.images): ref may be a url-method parameter KEY (the by-key consumption sheet placements / the pattern image source use) or a literal URI already — a key lookup miss passes ref through unchanged.
Parameters
images
AssetFile[] | undefined
ref
string
Returns
string