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

  1. useQuery — returns an array of entities matching certain traits.
  2. useQueryFirst — returns the first matching entity (or undefined).
  3. useTrait — returns the current value of a given trait on an entity (or undefined if missing).
  4. useTraitEffect — runs a side effect whenever the trait is added, removed, or changed.
  5. useWorld — returns the current ECS world from context.
  6. 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

  1. Memoize expensive sub-components if they always render the same geometry.
  2. Instancing (in R3F) for large numbers of identical objects.
  3. 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.