Actor

An Actor is any renderable entity you place in a scene. Every actor shares a common set of transform and event props, but the type field determines what gets rendered:

TypeWhat it renders
"model"A 3D model loaded from a .glb / .gltf file
"sprite"A flat 2D image (static or animated spritesheet)
"primitive"A code-generated geometric shape (box, sphere, etc.)
tsx
import { Actor } from "@carverjs/core/components";

Choosing an Actor Type #

Not sure which type to use? Here's a guide.

Model (type: "model") #

Loads a pre-made 3D model file (.glb / .gltf) created in tools like Blender, Maya, or downloaded from asset stores.

Use for: Complex, detailed 3D objects — characters, buildings, vehicles, weapons, furniture. Anything that has detailed geometry, textures, and potentially skeletal animations baked into the file.

tsx
<Actor type="model" src="/character.glb" animationName="idle" />

Sprite (type: "sprite") #

A flat 2D image (.png, .jpg) rendered in the 3D/2D world. Sprites come in three flavours:

Use for: 2D games, UI elements in 3D space, particle-like effects, trees/foliage in retro-style games, health bars, damage numbers. Think classic 2D game characters or "billboard" elements that always face the camera.

tsx
// Static image
<Actor type="sprite" src="/tree.png" />

// Grid-based animated spritesheet (image only, no JSON needed)
<Actor
  type="sprite"
  src="/character-run.png"
  spriteAnimation={{ numberOfFrames: 10, fps: 8, loop: true }}
/>

// Atlas-based animated spritesheet (image + JSON atlas)
<Actor
  type="sprite"
  src="/player.png"
  atlasUrl="/player.json"
  spriteAnimation={{ fps: 12, loop: true }}
/>

Primitive (type: "primitive") #

A basic geometric shape (box, sphere, cylinder, etc.) generated entirely by code — no external files needed.

Use for: Prototyping, debug visuals, simple game objects (platforms, walls, collectible orbs, ground planes), placeholder art during development, or minimalist/abstract game styles.

tsx
<Actor type="primitive" shape="sphere" color="red" />
<Actor type="primitive" shape="box" wireframe color="lime" />

At a Glance #

ModelSpritePrimitive
DimensionsFull 3D2D flat3D geometric
Assets needed.glb/.gltf file.png/.jpg imageNone
AnimationSkeletal (walk, idle...)Spritesheet frames (grid or atlas)None
ComplexityHigh (detailed meshes)Low (flat image)Minimal (basic shape)
Best forCharacters, props, buildings2D games, billboards, UIPrototyping, platforms, debug

Quick Start #

A few copy-paste examples to get you going.

Primitive — a red box #

tsx
<Actor type="primitive" shape="box" color="#ff0000" position={[0, 1, 0]} castShadow />

Model — a character with an animation #

tsx
<Actor type="model" src="/models/character.glb" animationName="Idle" position={[0, 0, 0]} />

Sprite — a billboard tree #

tsx
<Actor type="sprite" src="/textures/tree.png" position={[3, 1, 0]} billboard />

Sprite — grid-based animated spritesheet #

If your spritesheet is a single image with frames arranged in a grid, just pass spriteAnimation with a numberOfFrames count. CarverJS automatically calculates the rows and columns from the image dimensions.

tsx
<Actor
  type="sprite"
  src="/sprites/hero-run.png"
  spriteAnimation={{ numberOfFrames: 10, fps: 8, loop: true }}
/>

Sprite — atlas-based animated spritesheet #

If you have a JSON atlas file (exported from tools like TexturePacker or Aseprite), pass it via atlasUrl alongside the spritesheet image.

tsx
<Actor
  type="sprite"
  src="/sprites/hero.png"
  atlasUrl="/sprites/hero.json"
  spriteAnimation={{ fps: 12, loop: true, autoPlay: true }}
/>

Props Reference #

Actor is a discriminated union on the type field. All three variants share a common base of transform, visibility, and event props.

Common Props #

These apply to every actor regardless of type.

PropTypeDefaultDescription
type"model" | "sprite" | "primitive"—Required. Determines the renderer used
namestring—Name assigned to the group
positionVector3—World position [x, y, z]
rotationEuler—Rotation [x, y, z]
scaleVector3—Scale [x, y, z] or uniform number. Overrides size if both are set
sizenumber—Uniform scale factor — preserves aspect ratio. size={2} doubles the actor in all axes
visiblebooleantrueToggle visibility
castShadowbooleanfalseWhether meshes cast shadows
receiveShadowbooleanfalseWhether meshes receive shadows
renderOrdernumber—Render order override
physicsActorPhysicsProps—Rapier physics body config. Only active when parent World has physics.
userDataRecord<string, unknown>—Arbitrary user data on the group
childrenReactNode—Additional children inside the group

Event Props #

All R3F pointer, click, and wheel events are supported:

onClick, onDoubleClick, onContextMenu, onPointerUp, onPointerDown, onPointerOver, onPointerOut, onPointerEnter, onPointerLeave, onPointerMove, onPointerMissed, onWheel


Model Props #

Additional props when type is "model".

PropTypeDefaultDescription
srcstring—Required. URL to a .glb/.gltf file
useDracoboolean | string—Enable Draco decompression (pass true or a decoder path)
useMeshoptboolean—Enable Meshopt decompression
animationNamestring—Name of the animation clip to play
animationPausedbooleanfalsePause the active animation
animationSpeednumber1Playback speed multiplier
animationLoopbooleantrueWhether the animation loops

Sprite Props #

Additional props when type is "sprite".

PropTypeDefaultDescription
srcstring—Required. URL to the texture image
atlasUrlstring—URL to a spritesheet JSON atlas (for atlas-based animation)
billboardbooleantrueAuto-face the camera
billboardLockXboolean—Lock billboard rotation on X axis
billboardLockYboolean—Lock billboard rotation on Y axis
billboardLockZboolean—Lock billboard rotation on Z axis
spriteAnimationobject—Animation settings (see below). When provided without atlasUrl, enables grid-based animation. When provided with atlasUrl, enables atlas-based animation

How Sprites Render #

The combination of atlasUrl and spriteAnimation determines what gets rendered:

atlasUrlspriteAnimationResult
——Static sprite — a single image
—ProvidedGrid-based animation — frames are auto-detected from the image grid
ProvidedProvidedAtlas-based animation — frames are read from the JSON atlas

spriteAnimation Fields #

FieldTypeDefaultGridAtlasDescription
numberOfFramesnumber1RequiredOptionalTotal number of frames in the spritesheet
fpsnumber10YesYesFrames per second
loopbooleantrueYesYesLoop the animation
startFramenumber0YesYesFirst frame index
endFramenumberlast frameYesYesLast frame index
autoPlaybooleantrueYesYesStart playing immediately
flipXbooleanfalseYesYesMirror horizontally
frameNamestring——YesNamed frame to display
playboolean——YesStart playback
pauseboolean——YesPause playback
alphaTestnumber——YesAlpha threshold for transparency
playBackwardsboolean——YesReverse playback direction
resetOnEndboolean——YesReset to first frame when done
animationNamesstring[]——YesAvailable animation names in the atlas
onStartfunction——YesCallback when animation starts
onEndfunction——YesCallback when animation ends
onLoopEndfunction——YesCallback when a loop cycle ends
onFramefunction——YesCallback on each frame change

Primitive Props #

Additional props when type is "primitive".

PropTypeDefaultDescription
shapePrimitiveShape"box"Geometry type
geometryArgsnumber[]per-shape defaultsConstructor arguments for the geometry
materialTypePrimitiveMaterialType"standard"Material type
colorColorRepresentation"#6366f1"Material color
materialPropsPartial<MeshStandardMaterial>—Additional material properties
wireframeboolean—Render as wireframe

Available Shapes #

ShapeDefault geometryArgs
box[1, 1, 1]
sphere[0.5, 32, 32]
cylinder[0.5, 0.5, 1, 32]
cone[0.5, 1, 32]
torus[0.5, 0.2, 16, 32]
plane[1, 1]
circle[0.5, 32]
capsule[0.5, 1, 4, 16]
ring[0.3, 0.5, 32]

Available Material Types #

TypeDescription
"standard"Physically-based material (default) — responds to lighting realistically
"basic"Flat shading, not affected by lights — good for UI or unlit objects
"phong"Shiny specular highlights — good for glossy surfaces
"lambert"Soft diffuse shading — good for matte surfaces
"toon"Cel-shaded / cartoon look — hard-edged lighting bands

Physics Props #

When the parent World has a physics prop, you can add physics to individual Actors via the physics prop. The Actor is wrapped in a Rapier <RigidBody>.

FieldTypeDefaultDescription
bodyTypeRigidBodyType"dynamic""dynamic", "fixed", "kinematicPosition", or "kinematicVelocity"
colliderPhysicsColliderType"auto""cuboid", "ball", "capsule", "trimesh", "convexHull", or "auto"
massnumber1Mass of the body
restitutionnumber0Bounciness (0-1)
frictionnumber0.5Friction coefficient
sensorbooleanfalseTrigger volume (detects overlap, no physics response)
gravityScalenumber1Per-body gravity multiplier. 0 = no gravity
linearDampingnumber0Linear velocity damping
angularDampingnumber0Angular velocity damping
ccdbooleanfalseContinuous collision detection for fast-moving objects
enabledTranslations[boolean, boolean, boolean]—Lock/unlock translation per axis. In 2D, Z is auto-locked
enabledRotations[boolean, boolean, boolean]—Lock/unlock rotation per axis. In 2D, X/Y are auto-locked
onCollisionEnterCollisionCallback—Called when another body starts touching
onCollisionExitCollisionCallback—Called when another body stops touching
tsx
<Actor
  type="primitive" shape="box" color="red" position={[0, 5, 0]}
  physics={{ bodyType: "dynamic", mass: 2, restitution: 0.5 }}
/>

Ref #

Actor forwards a ref to its root <group>, giving you direct access to the Three.js object for imperative control:

tsx
const actorRef = useRef<Group>(null);
<Actor ref={actorRef} type="primitive" shape="sphere" />

Type Definitions #

See Types for all type definitions including ActorProps, ModelActorProps, SpriteActorProps, PrimitiveActorProps, ActorTransformProps, ActorEventProps, ActorPhysicsProps, PrimitiveShape, and PrimitiveMaterialType.