verekia-model-container
SKILL.md
Model Container
Capture Three.js object references on entities using a wrapper component, allowing systems to manipulate objects directly.
Entity vs Model Pattern
Similar to the Redux container/component pattern:
*Entitycomponents are smart wrappers that connect entity data to the view*Modelcomponents are dumb and only responsible for rendering
┌─────────────────────────────────────────┐
│ PlayerEntity (smart) │
│ - Wraps with ModelContainer │
│ - Passes entity data as props │
│ │
│ ┌─────────────────────────────────┐ │
│ │ PlayerModel (dumb) │ │
│ │ - Pure rendering │ │
│ │ - Receives props │ │
│ │ - No knowledge of entities │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
Usage
type Entity = {
three?: Object3D
}
const ModelContainer = ({ children, entity }: { children: ReactNode; entity: Entity }) => (
<group
ref={ref => {
if (!ref) return
entity.three = ref
return () => {
entity.three = undefined
}
}}
>
{children}
</group>
)
// Dumb component - only renders, receives props
const PlayerModel = ({ color, scale }: { color: string; scale: number }) => (
<mesh scale={scale}>
<boxGeometry />
<meshBasicMaterial color={color} />
</mesh>
)
// Smart wrapper - connects entity to model
const PlayerEntity = ({ entity }: { entity: PlayerData }) => (
<ModelContainer entity={entity}>
<PlayerModel color={entity.team === 'red' ? 'red' : 'blue'} scale={entity.size} />
</ModelContainer>
)
// System manipulates entity.three directly
const MovementSystem = () => {
useFrame(() => {
if (player.three) {
player.three.position.x = player.x
player.three.rotation.y += 0.01
}
})
return null
}
Key Concepts
- Ref callback stores the Three.js object on the entity
- Cleanup function removes the reference when unmounted
- Systems access
entity.threedirectly inuseFrame - Models are reusable and testable in isolation
- Entities handle the bridge between game state and visuals
Benefits
- Clear separation of concerns
- Models can be developed/tested independently
- Entity logic stays with entity components
- Systems don't need to know about React component structure
- Works with any entity system (ECS, Zustand, plain objects)
Related Skills
verekia-architecture- Broader architecture principles (Systems vs Views, headless-first)verekia-miniplex- Using this pattern with Miniplex ECS
This skill is part of verekia's r3f-gamedev.
Weekly Installs
2
Repository
verekia/r3f-gamedevGitHub Stars
26
First Seen
Jan 21, 2026
Installed on
claude-code2