Create Components
Learn how to create interactive components for Needle Engine using TypeScript or JavaScript.
Prerequisites
New to TypeScript? Start here:
- TypeScript Essentials - Language fundamentals
- Needle Engine for Unity Developers - Unity to web workflow
Video: Creating Custom Components in Unity
This video gives a short introduction to the easiest and fastest way to create custom Needle Engine components in Unity.
Quick Start
Direct File Approach
Add a .ts or .js file to src/scripts/ in your web project:
your-project/
└── src/
└── scripts/
└── MyFirstScript.ts ← Add your component hereBenefits:
- Simple and direct
- Perfect for small projects
- Automatic hot reload
Unity - NPM Definition Approach
Organize code into reusable npm packages using NPM Definition files:
- In Unity:
Create > NPM Definition - Right-click the NpmDef:
Create > TypeScript - Write your component
Benefits:
- Modular code organization
- Share code between projects
- Standard npm package format
Learn more about NPM Definitions
Your First Component
Create src/scripts/Rotate.ts:
import { Behaviour, serializable } from "@needle-tools/engine";
export class Rotate extends Behaviour
{
@serializable()
speed : number = 1;
start(){
// Logging is useful for debugging in the browser
// Open the developer console (F12) to see your component's data
console.log(this);
}
// update will be called every frame
update(){
this.gameObject.rotateY(this.context.time.deltaTime * this.speed);
}
}What happens next:
- 🔄 C# stub (Unity) or Blender panel auto-generates on save
- ⚡ Hot reload in browser—no Unity recompilation needed
- 🚀 Instant iteration—see changes in ~1 second
Component with Custom Function
import { Behaviour } from "@needle-tools/engine";
export class PrintNumberComponent extends Behaviour
{
start(){
this.printNumber(42);
}
private printNumber(myNumber : number){
console.log("My Number is: " + myNumber);
}
}Multiple Components Per File
You can export multiple components from one file:
export class MyComponent1 extends Behaviour { }
export class MyComponent2 extends Behaviour { }Component Architecture
Components attach to three.js Object3D instances:
- Access the Object3D:
this.gameObject - Access the scene:
this.context.scene - Access components:
this.gameObject.getComponent(Type)
Visibility & Active State
Setting visible = false on an Object3D acts like Unity's SetActive(false):
- Disables all components on this object and its children
- No update events called until
visible = trueagain - To hide visually without affecting components, disable the
Renderercomponent instead
Serialization
Use @serializable() to expose properties in the editor (Unity/Blender) and ensure they get saved/loaded correctly.
Basic Types
Primitives (number, string, boolean) only need @serializable():
import { Behaviour, serializable } from "@needle-tools/engine";
export class MyComponent extends Behaviour
{
@serializable()
speed: number = 5;
@serializable()
playerName: string = "Player";
@serializable()
isActive: boolean = true;
}Object References
For object references and complex types, you must specify the type:
import { Behaviour, serializable } from "@needle-tools/engine";
import { Object3D, Light, Camera } from "three";
export class MyComponent extends Behaviour
{
@serializable(Object3D)
myTarget?: Object3D;
@serializable(Light)
targetLight?: Light;
@serializable(Camera)
mainCamera?: Camera;
}Arrays
Primitive arrays don't need a type:
import { Behaviour, serializable } from "@needle-tools/engine";
export class MyComponent extends Behaviour
{
@serializable()
speeds: number[] = [1, 2, 3];
@serializable()
names: string[] = ["Player1", "Player2"];
}Arrays with object references need the type specified:
import { Behaviour, serializable } from "@needle-tools/engine";
import { Object3D, Light } from "three";
export class MyComponent extends Behaviour
{
// Correct: type specified for object references
@serializable(Object3D)
waypoints: Object3D[] = [];
@serializable(Light)
lights: Light[] = [];
// Wrong: will not serialize correctly
// waypoints: Object3D[] = [];
}Reference
See the complete @serializable decorator reference for more details and advanced usage.
Version Control
While generated C# components use the type name to produce stable GUIDs, we recommend checking in generated components in version control as a good practice.
Next Steps
- Use Lifecycle Hooks - awake, start, update methods
- Handle User Input - Mouse, touch, keyboard
- Find Components - Query the scene graph
- Use Coroutines - Sequenced operations
- Component Lifecycle Reference - Complete API