Core Concepts
Components
Your Viber3D game typically uses React + React Three Fiber. Components can query data from the ECS world and render Three.js objects accordingly.
ECS + React
Koota provides React hooks to connect ECS data (traits) to your components. In Viber3D, you’ll often use React Three Fiber (@react-three/fiber) for rendering 3D scenes, and these hooks to sync ECS state with visuals.
Common Hooks
useQuery— returns an array of entities matching certain traits.useQueryFirst— returns the first matching entity (orundefined).useTrait— returns the current value of a given trait on an entity (orundefinedif missing).useTraitEffect— runs a side effect whenever the trait is added, removed, or changed.useWorld— returns the current ECS world from context.useActions— returns a set of centralized actions for mutating the ECS state.
Example: Rendering Entities
import { useQuery, useTrait } from 'koota/react'
import { Transform, IsEnemy } from '../traits'
function EnemyRenderer() {
// get all enemies
const enemies = useQuery(IsEnemy, Transform)
return (
<>
{enemies.map(entity => (
<EnemyView key={entity.id()} entity={entity} />
))}
</>
)
}
function EnemyView({ entity }: { entity: Entity }) {
const transform = useTrait(entity, Transform)
if (!transform) return null
return (
<mesh position={transform.position}>
<boxBufferGeometry />
<meshStandardMaterial color="red" />
</mesh>
)
}
Using useTraitEffect
To react to changes in a trait without causing rerenders, use useTraitEffect. For example, you might want to update a mesh’s position in a ref:
function EnemyView({ entity }: { entity: Entity }) {
const ref = useRef<THREE.Mesh>(null!)
// Subscribe to ECS changes outside of React’s render
useTraitEffect(entity, Transform, (transform) => {
if (!transform || !ref.current) return
ref.current.position.copy(transform.position)
ref.current.rotation.copy(transform.rotation)
})
return (
<mesh ref={ref}>
<boxBufferGeometry />
<meshStandardMaterial color="red" />
</mesh>
)
}
React Three Fiber + ECS
You can also integrate useFrame from R3F for certain updates:
import { useFrame } from '@react-three/fiber'
import { Movement, Transform } from '../traits'
function MovementSystem() {
// This component acts as a "system" in React
const world = useWorld()
useFrame(() => {
const time = world.get(Time)
if (!time) return
const { delta } = time
world.query(Transform, Movement).updateEach(([t, m]) => {
t.position.add(m.velocity.clone().multiplyScalar(delta))
})
})
return null
}
Performance Optimizations
- Memoize expensive sub-components if they always render the same geometry.
- Instancing (in R3F) for large numbers of identical objects.
- Culling & LOD for objects not in view or too far away.
Next Steps
- Explore Actions for centralizing ECS changes in your React components.
- Check out official React Three Fiber docs for advanced rendering.
- Combine with Systems for heavy logic outside of React’s render cycle.