---
title: Create Components
description: Learn how to write custom TypeScript and JavaScript components for Needle Engine. Create interactive behaviors, use the @serializable decorator for editor integration, and leverage lifecycle methods like start() and update() for game logic.
---

# Create Components

Learn how to create interactive components for Needle Engine using TypeScript or JavaScript.

:::tip Prerequisites
New to TypeScript? Start here:
- [TypeScript Essentials](../../tutorials/fundamentals/typescript-essentials) - Language fundamentals
- [Needle Engine for Unity Developers](../../tutorials/fundamentals/for-unity-developers) - Unity to web workflow
:::

:::details 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.

<video-embed src="https://www.youtube.com/watch?v=uf5UK0bLHlY" limit_height />
:::

---

## 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 here
```

**Benefits:**
- Simple and direct
- Perfect for small projects
- Automatic hot reload

### Unity - NPM Definition Approach

Organize code into reusable npm packages using NPM Definition files:

1. In Unity: `Create > NPM Definition`
2. Right-click the NpmDef: `Create > TypeScript`
3. Write your component

**Benefits:**
- Modular code organization
- Share code between projects
- Standard npm package format

[Learn more about NPM Definitions](../../explanation/core-concepts/npm-modules)

---

## Your First Component

Create `src/scripts/Rotate.ts`:

```ts twoslash
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

```ts twoslash
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:

```ts
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)`

:::warning 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 = true` again
- To hide visually without affecting components, disable the `Renderer` component 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()`:

```ts twoslash
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**:

```ts twoslash
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:

```ts twoslash
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**:

```ts twoslash
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[] = [];
}
```

:::tip Reference
See the complete [@serializable decorator reference](../../reference/typescript-decorators#serializable) 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](./use-lifecycle-hooks) - awake, start, update methods
- [Handle User Input](./handle-input) - Mouse, touch, keyboard
- [Find Components](./find-components) - Query the scene graph
- [Use Coroutines](./use-coroutines) - Sequenced operations
- [Component Lifecycle Reference](../../reference/api/lifecycle-methods) - Complete API

---

## Need Help?

- [TypeScript Essentials](../../tutorials/fundamentals/typescript-essentials)
- [Scripting Examples](../../reference/scripting-examples)
- [API Documentation](https://engine.needle.tools/docs/api/latest)
- [Discord Community](https://discord.needle.tools)
