ecs-entity
Create ECS entities for breathe-together-v2 with complete Koota traits, systems, React components, and Triplex annotations. Scaffolds index.tsx, traits.tsx, systems.tsx, and registers in providers.tsx. Handles visual entities (Three.js meshes) and state-only entities (breath, controller). Supports marker, stateful, and complex trait configurations. Generates JSDoc annotations with @min/@max/@step/@default directives for Triplex compatibility.
When & Why to Use This Skill
This Claude skill automates the scaffolding of ECS (Entity-Component-System) entities for React and Three.js applications using the Koota library. It streamlines the development workflow by generating boilerplate for traits, systems, and components, while ensuring seamless integration with the Triplex visual editor through automated JSDoc annotations and centralized default management.
Use Cases
- Rapidly scaffolding visual 3D entities with Three.js meshes, including automated setup of position, scale, and material traits.
- Creating 'State-Only' logic entities to manage background processes, global game state, or complex calculations without visual rendering.
- Automating the registration of new systems into a multi-phase execution pipeline to ensure correct update logic and performance.
- Generating Triplex-compatible JSDoc annotations (e.g., @min, @max, @step) to enable real-time property tuning for designers in a visual editor.
- Implementing standardized prop-drilling patterns and centralized configuration to maintain consistency across complex 3D scene hierarchies.
| name | ecs-entity |
|---|---|
| description | Create ECS entities for breathe-together-v2 with complete Koota traits, systems, React components, and Triplex annotations. Scaffolds index.tsx, traits.tsx, systems.tsx, and registers in providers.tsx. Handles visual entities (Three.js meshes) and state-only entities (breath, controller). Supports marker, stateful, and complex trait configurations. Generates JSDoc annotations with @min/@max/@step/@default directives for Triplex compatibility. |
| allowed-tools | [Read, Write, Edit, Glob, Grep, Bash(ls:*)] |
Create ECS Entity for breathe-together-v2
Overview
The breathe-together-v2 project uses a Koota-based ECS (Entity-Component-System) architecture where React components spawn themselves as entities with traits (data) and systems (pure functions) handle updates.
This skill scaffolds complete entities with:
- ✅ React component in
src/entities/[name]/index.tsx - ✅ Trait definitions in
src/entities/[name]/traits.tsx - ✅ System functions in
src/entities/[name]/systems.tsx(optional) - ✅ Auto-registration in
src/providers.tsx - ✅ Triplex annotations for visual components
Quick Start: Guided Interview
To create a new entity, I need to understand a few things:
1. Entity Name (PascalCase)
Example: Particle, Enemy, Portal, Controller
2. Entity Type
Choose one:
Marker Entity - Minimal, just existence flag
- Example:
Land,Camera - Features: One trait only, no systems
- Example:
Stateful Entity with Props - Customizable visual/logical entity
- Example:
ParticleSystem,BreathingSphere,Character - Features: Props interface, multiple traits, optional systems
- Example:
State-Only Entity - Pure logic, no visual rendering (returns null)
- Example:
Breath,GameController,TimeManager - Features: Hidden entity, provides global state via traits
- Example:
3. Visual or Non-Visual?
- Visual: Renders Three.js meshes/groups (use
<group ref={meshRef}>) - Non-visual: Returns
null, purely logic
4. Which Traits to Include?
Common traits from src/shared/traits.tsx:
- Position - 3D position (x, y, z)
- Velocity - 3D velocity for movement
- Mesh - Reference to Three.js object
- Scale - Size/scale factor
Custom traits can be defined with:
- Marker traits (just existence)
- Value traits (single number)
- Vector3 traits (x, y, z)
- RGB color traits
- Complex config traits (nested properties)
5. Props Interface (if Stateful)
What parameters should the component accept?
Examples:
interface Props {
position?: [x: number, y: number, z: number];
scale?: number;
color?: string;
particleCount?: number;
}
6. System Functions Needed?
Does this entity need update logic? (Most do!)
Examples:
- Physics System - Applies forces, updates velocity/position
- Animation System - Updates scale/rotation over time
- Behavior System - State machine, decision logic
- Rendering System - Syncs ECS state to Three.js
7. System Placement (Execution Order)
Where should this system run in the 7-phase pipeline?
See reference.md for the complete system execution order.
Three Entity Patterns
Pattern A: Marker Entity (Minimal)
Simple entity with just existence flag. Example: Land, Camera
See: templates/marker-entity-template.tsx
Pattern B: Stateful Entity with Props
Visual or logical entity with configuration. Example: BreathingSphere, ParticleSystem
See: templates/stateful-entity-template.tsx
Pattern C: State-Only Entity
Pure logic, no 3D rendering. Example: Breath, GameController
See: templates/state-only-entity-template.tsx
Trait Definitions
See: templates/traits-template.tsx
Common patterns: marker traits, value traits, Vector3 traits, RGB colors, complex configs
System Functions
See: templates/system-template.tsx
Two patterns:
- Direct:
export function mySystem(world: World, delta: number) - Closure:
export function mySystem(world: World) { return (delta, time) => { ... } }
System Registration in providers.tsx
Import and add to KootaSystems:
import { mySystem } from "./entities/myEntity/systems";
export function KootaSystems({ mySystemEnabled = true }) {
const world = useWorld();
const mySys = useMemo(() => mySystem(world), [world]);
useFrame((state, delta) => {
if (mySystemEnabled) {
mySystem(world, delta); // or mySys(delta, state.clock.elapsedTime);
}
});
}
JSDoc Template for Props
All entity props follow this format for Triplex integration:
See: templates/jsdoc-template.md for comprehensive guidelines with real examples
Quick template:
/**
* [One-line technical description]
*
* **When to adjust:** [Contextual scenarios]
* **Typical range:** [Visual landmarks, e.g., "Dim (0.2) → Standard (0.4) → Bright (0.6)"]
* **Interacts with:** [Related props]
*
* @min X @max Y @step Z @default value
*/
propertyName?: type;
Scene Threading Pattern
Entities should be integrated into the 3-level scene hierarchy:
Scene Structure
src/levels/
├── breathing.tsx # Production scene (minimal props)
├── breathing.scene.tsx # Experimental scene (preset exploration)
└── breathing.debug.scene.tsx # Debug scene (all controls, manual phase)
Transparent Pass-Through Pattern
Key principle: Scene-level components should NOT redefine entity defaults.
Good Pattern:
// breathing.tsx (Production Scene)
export function BreathingLevel({
backgroundColor = '#0a0f1a', // Scene-owned (rendered by scene)
bloom = 'subtle', // Scene-owned (scene-level post-processing)
// Pass-through (no defaults!) - let entities use their own
sphereColorExhale,
lightingPreset,
environmentPreset,
}: Partial<BreathingLevelProps> = {}) {
return (
<>
<color attach="background" args={[backgroundColor]} />
{/* Entity components use their own defaults */}
<BreathingSphere colorExhale={sphereColorExhale} />
<Lighting preset={lightingPreset} />
<Environment preset={environmentPreset} />
</>
);
}
Why this works:
- Single source of truth for each entity's defaults
- No conflicts between scene and entity layers
- Triplex changes flow correctly
- Easy to reason about ownership
Prop Flow
Entity (BreathingSphere):
export function BreathingSphere({
colorExhale = '#4A8A9A', // Entity owns its default
colorInhale = '#D4A574',
// ...
}: BreathingSphereProps = {}) {
// Implementation
}
Scene (BreathingLevel):
export function BreathingLevel({
sphereColorExhale, // undefined, passes through to entity
// ...
}) {
return <BreathingSphere colorExhale={sphereColorExhale} />;
}
Result: Entity default is used unless explicitly overridden at scene level.
Centralized Defaults System
Entity defaults should reference centralized configuration for consistency.
sceneDefaults.ts Structure
Location: src/config/sceneDefaults.ts
export const VISUAL_DEFAULTS = {
backgroundColor: {
value: '#0a0f1a' as const,
when: 'Base scene background color. Deep space aesthetic for meditation.',
typical: 'Deep Space (#0a0f1a) → Medium (#1a2030) → Light (#2a3040)',
interacts: ['ambientIntensity', 'keyIntensity', 'fillIntensity'],
performance: 'No impact; static color',
},
sphereColorExhale: {
value: '#4A8A9A' as const,
when: 'Cooler blues/teals for meditation, warmer tones for energy',
typical: 'Cool Teal (#4A8A9A, default) → Neutral → Warm Orange',
interacts: ['sphereColorInhale'],
performance: 'No impact; computed per-frame',
},
// ...
};
export const getDefaultValues = () => ({
backgroundColor: VISUAL_DEFAULTS.backgroundColor.value,
sphereColorExhale: VISUAL_DEFAULTS.sphereColorExhale.value,
// ...
});
Usage in Entity Components
Import defaults:
import { VISUAL_DEFAULTS } from '../../config/sceneDefaults';
export function BreathingSphere({
colorExhale = VISUAL_DEFAULTS.sphereColorExhale.value,
colorInhale = VISUAL_DEFAULTS.sphereColorInhale.value,
// ...
}: BreathingSphereProps = {}) {
// Implementation
}
Benefits:
- Single source of truth for defaults
- Metadata enables AI suggestions
- Centralized validation
- Easy to maintain consistency
Prop Documentation Inventory
The codebase maintains 171+ documented props across entities:
- 17 visual props -
src/entities/breathingSphere/index.tsx(colorExhale, opacity, scaleRange, etc.) - 9 lighting props -
src/entities/lighting/index.tsx(ambientIntensity, keyIntensity, etc.) - 13 environment props -
src/entities/environment/index.tsx(enableStars, starsCount, preset, etc.) - 7 particle config props -
src/entities/particle/config.ts(geometry, material, size categories)
All props follow the standardized JSDoc template with complete contextual guidance.
Triplex Annotations (for Tunable Props)
If your component will be edited in Triplex visual editor:
interface MyEntityProps {
/**
* Position in 3D space (x, y, z coordinates).
*
* Triplex renders as three separate number inputs.
*
* **When to adjust**: Move entity around the scene
* **Typical range**: Depends on scene scale (e.g., ±10 for 20-unit scene)
* **Interacts with**: Camera position, scale
*
* @default [0, 0, 0]
*/
position?: [x: number, y: number, z: number];
/**
* Component scale (uniform or per-axis).
*
* Use single number for uniform scaling, or tuple for per-axis control.
* Triplex lets you switch between formats with "Switch Prop Type" action.
*
* **When to adjust**: Increase to make entity larger, decrease for smaller
* **Typical range**: 0.1 (tiny) → 1.0 (normal) → 5.0 (huge)
* **Interacts with**: position (scaled objects may need position adjustment)
*
* @default 1 (uniform) or [1, 1, 1] (per-axis)
*/
scale?: number | [x: number, y: number, z: number];
/**
* Base color in multiple formats (hex, number, or RGB tuple).
*
* Triplex lets you switch between formats with "Switch Prop Type" action.
*
* @default "#ffffff"
*/
color?: string | number | [r: number, g: number, b: number];
}
File Structure After Creation
src/entities/[MyEntity]/
├── index.tsx # React component + entity spawning
├── traits.tsx # Koota trait definitions
└── systems.tsx # Update logic (optional)
Each entity is self-contained and follows the same pattern.
Complete Reference
For detailed specifications, patterns, and real-world examples, see:
reference.md - Complete ECS patterns from codebase exploration
- All three entity types with full code
- Trait definition patterns (20+ examples)
- System query patterns (common combinations)
- System execution order explanation
examples.md - Real examples from breathe-together-v2
src/entities/breath/- State-only entitysrc/entities/particle/- Complex stateful entitysrc/entities/breathingSphere/- Triplex-tunable entity- Side-by-side before/after code
Next Steps
After I generate your entity files, you'll need to:
- Add entity to your scene in
src/levels/breathing.tsxor debug scene - Test in Triplex by running
npm run dev - Add to README if it's a major system component
Questions?
If anything is unclear, ask for details about:
- Specific trait patterns you need
- System execution order placement
- Triplex annotation requirements
- How to integrate with existing systems
Let's build your entity! 🚀