import { defineModelKit, Model, useModel, useTexture, useTextureState } from "@apricot/react/model";
import type { ClipInput, JointInput, JointPart, KitPart, ModelKit, PartPressEvent } from "@apricot/react/model";Everything on this page comes from the @apricot/react/model entry point, not @apricot/react. It carries three's glTF loader (about 146 KB), which apps without models do not need.
Model#
Shows a .glb file. Renders nothing, children included, until it has loaded.
| Prop | Type | Default | Description |
|---|---|---|---|
src |
number | string |
A bundled asset (require("./car.glb")) or a URL. Or give kit |
|
kit |
ModelKit |
A model plus names for its parts (defineModelKit). Its names autocomplete in materials, joints and onPartPress |
|
materials |
{ [part or selector]: MaterialInput } |
Material per part: a preset name, a preset with options, or a three.js material. Colour changes animate. A key matching nothing logs a warning | |
joints |
{ [joint or selector]: JointInput } |
Moving parts, 0 (rest) to 1 (open). Plain numbers animate; shared values are followed exactly | |
animations |
{ [clip name]: ClipInput } |
Blender animation clips: progress 0–1, "once" or "loop" |
|
morphs |
{ [shape key]: number or shared value } |
Shape keys, 0 (off) to 1 (full). Plain numbers animate over 0.4 s | |
onPartPress |
(event: PartPressEvent) => void |
A part was tapped | |
inspect |
boolean | false |
Development aid: tap parts to highlight them and see their names and materials |
ground |
boolean | false |
Stands the model on the floor: its lowest point at y = 0, measured once at rest |
castShadow, receiveShadow |
boolean | automatic | Overrides for every mesh, with <Scene shadows> |
ref |
Ref<SceneObject> |
The model's root group | |
onLoad |
(object: THREE.Group) => void |
Loaded and shown | |
onError |
(error: Error) => void |
logs | Failed to load |
children |
ReactNode |
Placed in the model's space; shown once it has loaded (a <CameraRig>, a <Label>) |
Plus transform props (position, rotation, scale; plain or shared values).
A model used by several components loads once and is shared. Each <Model> gets its own copy of the scene graph, so materials, joints and animations apply per copy. Copies of rigged models get their own skeleton. Unmounting restores the shared file's original materials.
defineModelKit(src, parts)#
const sedan = defineModelKit(require("./sedan.glb"), {
paint: "material:vernice",
wheels: "ruota_*",
doorLeft: { select: "porta_ant_sx", hinge: "front", axis: "y", range: [0, -65] },
});Returns a ModelKit<P> ({ src, parts }) where P is the union of your part names. A part (KitPart) is a selector or a JointPart.
Selectors (PartSelector)#
| Selector | Picks |
|---|---|
"wheel_*" |
Parts (nodes) or materials whose name matches. * any characters, ? one. Case-insensitive |
"node:Lid" |
Nodes with that name, and everything under them |
"material:car_paint*" |
Only material slots with that name (the name in the file, even after a preset replaced it) |
"tag:door" |
Nodes with the Blender custom property apricot = door (glTF extras, so userData.apricot) |
["glass", "window_*"] |
Any of several |
Find names with npx apricot-models inspect file.glb or <Model inspect>.
JointPart#
| Field | Type | Default | Description |
|---|---|---|---|
select |
PartSelector |
required | The part(s) that move together |
hinge |
words or Vec3 |
"center" |
Where it turns: an edge or corner of the part's bounds at rest (front, back, top, bottom, left, right, center, combined as "bottom-back"), or an exact point in the part's parent space |
axis |
"x" | "y" | "z" | Vec3 |
"y" |
Rotation or slide axis, in the parent's space |
range |
[at0, at1] degrees |
[0, 90] |
Angle at value 0 and at value 1 |
slide |
[at0, at1] units |
Slide along the axis instead of turning | |
transition |
seconds | 0.6 |
How long a plain value change takes |
The model faces +z: front is +z, top is +y, left is +x.
JointInput#
A value (number or shared value), or an InlineJoint that describes the joint where it is used: { value, select?, hinge?, axis?, range?, slide?, transition? }. select defaults to the key.
<Model src={box} joints={{ "node:Lid": { value: open ? 1 : 0, hinge: "bottom-back", axis: "x", range: [0, -110] } }} />ClipInput#
number | SharedValue<number> | "once" | "loop". A number shows that point of the clip (plain numbers animate there over 0.6 s; shared values scrub exactly).
PartPressEvent#
| Field | Type | Description |
|---|---|---|
part |
P | undefined |
The kit name: a joint that includes the mesh, else the most specific kit name. undefined without a kit or for unnamed parts |
parts |
P[] |
Every kit name whose selector includes the mesh |
name |
string |
The tapped mesh's name in the file |
material |
string |
The tapped material's name in the file |
wearing |
string | undefined |
The preset it wears now, if replaced |
mesh |
THREE.Mesh |
|
point |
THREE.Vector3 |
World-space point hit |
useModel(src)#
Loads a model without showing it. Returns { object, animations, error }: object is a THREE.Group (or null while loading), animations its clips. The file loads once per app; object is this component's own copy of it (geometries and materials stay shared, so do not dispose them). The model is freed when its last user unmounts. Pass object to <Instances object> for many copies, or to <Primitive object>.
useTexture(src, options?) and useTextureState(src, options?)#
useTexture loads a PNG or JPEG (a require or a URL) and returns a THREE.Texture, or null while it loads (and on error, which it logs). useTextureState returns { texture, error }. Textures are shared between components and freed when the last user unmounts.
TextureOptions#
| Option | Default | Description |
|---|---|---|
colorSpace |
SRGBColorSpace |
NoColorSpace (from three) for data such as masks and normal maps |
flipY |
true |
Image rows top to bottom map to v = 1 … 0, as three expects |
repeat |
false |
Tile instead of clamping at the edges |
premultiplyAlpha |
true |
Keep colours premultiplied (what phone decoders produce). Pass false only for your own three.js materials that expect straight colour |
Lower level#
| Export | Description |
|---|---|
loadModelBytes(src) |
Promise<ArrayBuffer> of a bundled asset or URL |
modelCache |
The shared ModelCache behind useModel and <Model> |
textureCache |
The shared cache behind useTexture |
ModelSource |
number | string |
Related#
- Loading models.
- Textures.
- Tooling:
apricot-models.