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
namestringName assigned to the group
positionVector3World position [x, y, z]
rotationEulerRotation [x, y, z]
scaleVector3Scale [x, y, z] or uniform number. Overrides size if both are set
sizenumberUniform scale factor — preserves aspect ratio. size={2} doubles the actor in all axes
visiblebooleantrueToggle visibility
castShadowbooleanfalseWhether meshes cast shadows
receiveShadowbooleanfalseWhether meshes receive shadows
renderOrdernumberRender order override
physicsActorPhysicsPropsRapier physics body config. Only active when parent World has physics.
userDataRecord<string, unknown>Arbitrary user data on the group
childrenReactNodeAdditional 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
srcstringRequired. URL to a .glb/.gltf file
useDracoboolean | stringEnable Draco decompression (pass true or a decoder path)
useMeshoptbooleanEnable Meshopt decompression
animationNamestringName 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
srcstringRequired. URL to the texture image
atlasUrlstringURL to a spritesheet JSON atlas (for atlas-based animation)
billboardbooleantrueAuto-face the camera
billboardLockXbooleanLock billboard rotation on X axis
billboardLockYbooleanLock billboard rotation on Y axis
billboardLockZbooleanLock billboard rotation on Z axis
spriteAnimationobjectAnimation 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
frameNamestringYesNamed frame to display
playbooleanYesStart playback
pausebooleanYesPause playback
alphaTestnumberYesAlpha threshold for transparency
playBackwardsbooleanYesReverse playback direction
resetOnEndbooleanYesReset to first frame when done
animationNamesstring[]YesAvailable animation names in the atlas
onStartfunctionYesCallback when animation starts
onEndfunctionYesCallback when animation ends
onLoopEndfunctionYesCallback when a loop cycle ends
onFramefunctionYesCallback 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
wireframebooleanRender 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
onCollisionEnterCollisionCallbackCalled when another body starts touching
onCollisionExitCollisionCallbackCalled 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.