Needle Engine
  • README
  • Code Of Conduct
  • HOW TO
  • documentation
    • SUMMARY
    • _backlog-mermaid
    • _backlog
    • _meta-test
    • Automatic Component Generation
    • Needle Core Components
    • How To Debug
    • Deployment and Optimization
    • embedding
    • Everywhere Actions
    • Example Projects ✨
    • Exporting Assets, Animations, Prefabs, Materials, Lightmaps...
    • Questions and Answers (FAQ) 💡
    • Feature Overview
    • This page has been moved: continue here
    • getting-started
    • Frameworks, Bundlers, HTML
    • index
    • Additional Modules
    • Networking
    • Needle Engine Project Structure
    • Samples Projects
    • Scripting Examples
    • Creating and using Components
    • Live
    • Live
    • About
    • Live
    • Live
    • Live
    • Live
    • Support, Community & AI
    • Technical Overview
    • Testimonials
    • Testing on local devices
    • Using Needle Engine directly from HTML
    • vision
    • VR & AR (WebXR)
    • blender
      • Needle Engine for Blender
    • cloud
      • Needle Cloud
    • custom-integrations
      • index
    • getting-started
      • Scripting Introduction for Unity Developers
      • Getting Started & Installation
      • Scripting in Needle Engine
    • reference
      • needle.config.json
      • <needle-engine> Configuration
      • @serializable and other decorators
    • three
      • index
    • unity
      • Editor Sync
      • Needle Engine for Unity
    • lang
      • de
        • 404
        • SUMMARY
        • Automatische Komponenten-Generierung
        • Needle-Kernkomponenten
        • Debugging
        • Bereitstellung und Optimierung
        • embedding
        • Everywhere Actions
        • Beispielprojekte ✨
        • Assets, Animationen, Prefabs, Materialien, Lightmaps exportieren...
        • Fragen und Antworten (FAQ) 💡
        • Funktionsübersicht
        • Diese Seite wurde verschoben: hier fortfahren
        • getting-started
        • Frameworks, Bundler, HTML
        • index
        • Zusätzliche Module
        • Netzwerkfunktionen
        • Needle Engine Projektstruktur
        • Beispielprojekte
        • Scripting Beispiele
        • Erstellen und Verwenden von Komponenten
        • Live
        • Live
        • Über
        • Live
        • Live
        • Live
        • Live
        • Support und Community
        • Technischer Überblick
        • Erfahrungsberichte
        • Testen auf lokalen Geräten
        • Needle Engine direkt aus HTML verwenden
        • vision
        • VR & AR (WebXR)
        • blender
          • Needle Engine für Blender
        • cloud
          • Needle Cloud
        • custom-integrations
          • index
        • getting-started
          • Einführung in das Scripting für Unity-Entwickler
          • Erste Schritte & Installation
          • Scripting in Needle Engine
        • reference
          • needle.config.json
          • <needle-engine> Konfiguration
          • @serializable und andere Decorators
        • three
          • index
        • unity
          • Editor Synchronisierung
          • Needle Engine für Unity
      • es
        • SUMMARY
        • Generación Automática de Componentes
        • Componentes principales de Needle
        • Cómo Depurar
        • Despliegue y optimización
        • embedding
        • Acciones Everywhere
        • Proyectos de Ejemplo ✨
        • Exportación de Assets, Animaciones, Prefabs, Materiales, Lightmaps...
        • Preguntas Frecuentes (FAQ) 💡
        • Resumen de Características
        • Esta página ha sido movida: continúe aquí
        • getting-started
        • Frameworks, Bundlers, HTML
        • index
        • Módulos Adicionales
        • Redes
        • Estructura de Proyecto de Needle Engine
        • Proyectos de ejemplo
        • Ejemplos de scripting
        • Crear y usar Components
        • En vivo
        • En Vivo
        • Acerca de
        • En vivo
        • En vivo
        • En vivo
        • En vivo
        • Soporte y Comunidad
        • Resumen técnico
        • Testimonios
        • Testing on local devices
        • Usando Needle Engine directamente desde HTML
        • vision
        • VR & AR (WebXR)
        • blender
          • Needle Engine para Blender
        • cloud
          • Needle Cloud
        • custom-integrations
          • index
        • getting-started
          • Introducción al Scripting para Desarrolladores de Unity
          • Primeros pasos e instalación
          • Scripting in Needle Engine
        • reference
          • needle.config.json
          • Configuración de <needle-engine>
          • @serializable y otros decoradores
        • three
          • index
        • unity
          • Editor Sync
          • Needle Engine para Unity
      • fr
        • SUMMARY
        • Génération automatique de composants
        • Composants principaux de Needle
        • Comment déboguer
        • Déploiement et Optimisation
        • embedding
        • Everywhere Actions
        • Exemples de Projets ✨
        • Exporter des Assets, des Animations, des Prefabs, des Matériaux, des Lightmaps...
        • Questions et Réponses (FAQ) 💡
        • Aperçu des fonctionnalités
        • Cette page a été déplacée : continuez ici
        • getting-started
        • Frameworks, Bundlers, HTML
        • index
        • Modules supplémentaires
        • Réseau
        • Structure du projet Needle Engine
        • Projets d'exemples
        • Exemples de Scripting
        • Créer et utiliser des Components
        • showcase-bike
        • En direct
        • À propos
        • En direct
        • Jouer
        • En direct
        • En direct
        • Support et Communauté
        • Vue d'ensemble technique
        • Témoignages
        • Tester sur les appareils locaux
        • Utiliser Needle Engine directement depuis HTML
        • vision
        • VR & AR (WebXR)
        • blender
          • Needle Engine pour Blender
        • cloud
          • Needle Cloud
        • custom-integrations
          • index
        • getting-started
          • Introduction au Scripting pour les Développeurs Unity
          • Premiers pas et installation
          • Scripting in Needle Engine
        • reference
          • needle.config.json
          • <needle-engine> Configuration
          • @serializable et autres décorateurs
        • three
          • index
        • unity
          • Synchronisation de l'Editor (Editor Sync)
          • Needle Engine pour Unity
      • hi
        • SUMMARY
        • कंपोनेंट का स्वतः जनरेशन
        • नीडल कोर कंपोनेंट्स
        • How To Debug
        • Deployment and Optimization
        • embedding
        • Everywhere Actions
        • उदाहरण प्रोजेक्ट ✨
        • एसेट, एनिमेशन, प्रीफैब, मटेरियल, लाइटमैप्स... को एक्सपोर्ट करना
        • प्रश्न और उत्तर (FAQ) 💡
        • सुविधा अवलोकन
        • यह पृष्ठ स्थानांतरित कर दिया गया है: यहां जारी रखें
        • getting-started
        • Frameworks, Bundlers, HTML
        • index
        • अतिरिक्त मॉड्यूल
        • नेटवर्किंग
        • Needle Engine प्रोजेक्ट स्ट्रक्चर
        • samples-and-modules
        • स्क्रिप्टिंग उदाहरण
        • कंपोनेंट बनाना और उपयोग करना
        • लाइव
        • लाइव
        • परिचय
        • लाइव
        • लाइव
        • लाइव
        • लाइव
        • समर्थन और समुदाय
        • तकनीकी अवलोकन
        • प्रशंसापत्र
        • Testing on local devices
        • HTML से सीधे Needle Engine का उपयोग करना
        • vision
        • VR & AR (WebXR)
        • blender
          • Needle Engine for Blender
        • cloud
          • Needle Cloud
        • custom-integrations
          • index
        • getting-started
          • Unity डेवलपर्स के लिए स्क्रिप्टिंग परिचय
          • आरंभ करना और इंस्टॉलेशन
          • Needle Engine में स्क्रिप्टिंग
        • reference
          • needle.config.json
          • <needle-engine> कॉन्फ़िगरेशन
          • @serializable and other decorators
        • three
          • index
        • unity
          • Editor Sync
          • Unity के लिए Needle Engine
      • ja
        • SUMMARY
        • 自動コンポーネント生成
        • Needleコアコンポーネント
        • デバッグの方法
        • デプロイと最適化
        • embedding
        • Everywhere Actions
        • サンプルプロジェクト ✨
        • アセット、アニメーション、Prefab、マテリアル、ライトマップなどのエクスポート
        • よくある質問(FAQ)💡
        • 機能概要
        • このページは移動しました: こちらからどうぞ
        • getting-started
        • フレームワーク、バンドラー、HTML
        • index
        • 追加モジュール
        • ネットワーキング
        • Needle Engineプロジェクトの構造
        • サンプルプロジェクト
        • スクリプティング例
        • Creating and using Components
        • ライブ
        • showcase-castle
        • 概要
        • ライブ
        • ライブ
        • ライブ
        • ライブ
        • サポートとコミュニティ
        • 技術概要
        • お客様の声
        • ローカルデバイスでのテスト
        • HTMLからNeedle Engineを直接使用する
        • vision
        • VR & AR (WebXR)
        • blender
          • Blender 用 Needle Engine
        • cloud
          • Needle Cloud
        • custom-integrations
          • index
        • getting-started
          • Scripting Introduction for Unity Developers
          • はじめに & インストール
          • Needle Engineでのスクリプティング
        • reference
          • needle.config.json
          • <needle-engine> 設定
          • @serializable およびその他のデコレーター
        • three
          • index
        • unity
          • Editor Sync
          • Unity用Needle Engine
      • pt
        • SUMMARY
        • Automatic Component Generation
        • Componentes Principais do Needle
        • Como Depurar
        • Implementação e Otimização
        • embedding
        • Everywhere Actions
        • Projetos de Exemplo ✨
        • Exportar Recursos, Animações, Prefabs, Materiais, Lightmaps...
        • Perguntas e Respostas (FAQ) 💡
        • Visão Geral dos Recursos
        • Esta página foi movida: continue aqui
        • getting-started
        • Frameworks, Bundlers, HTML
        • index
        • Módulos Adicionais
        • Redes
        • Estrutura do Projeto Needle Engine
        • Projetos de Exemplo
        • Exemplos de Scripting
        • Criar e usar Componentes
        • Ao Vivo
        • Ao Vivo
        • Sobre
        • Ao Vivo
        • Ao Vivo
        • Ao Vivo
        • Ao Vivo
        • Suporte e Comunidade
        • Visão Geral Técnica
        • Depoimentos
        • Testar em dispositivos locais
        • vanilla-js
        • vision
        • VR & AR (WebXR)
        • blender
          • Needle Engine para Blender
        • cloud
          • Needle Cloud
        • custom-integrations
          • index
        • getting-started
          • Introdução à Scripting para Developers Unity
          • Começar e Instalação
          • Scripting no Needle Engine
        • reference
          • needle.config.json
          • needle-engine-attributes
          • @serializable e outros decorators
        • three
          • index
        • unity
          • Sincronização do Editor
          • Needle Engine para Unity
      • vn
        • 404
        • SUMMARY
        • Automatic Component Generation
        • Các Component Cốt lõi của Needle
        • Cách gỡ lỗi
        • Triển khai và Tối ưu hóa
        • embedding
        • Hành động ở mọi nơi (Everywhere Actions)
        • Các Dự Án Ví Dụ ✨
        • Xuất Tài sản, Hoạt ảnh, Prefab, Vật liệu, Lightmap...
        • Câu hỏi thường gặp (FAQ) 💡
        • Tổng quan tính năng
        • Trang này đã được di chuyển: tiếp tục tại đây
        • getting-started
        • Frameworks, Bundlers, HTML
        • index
        • Các Module Bổ Sung
        • Kết nối mạng
        • Cấu trúc dự án Needle Engine
        • samples-and-modules
        • Ví dụ về Scripting
        • Tạo và sử dụng Component
        • Trực tiếp
        • Trực tiếp
        • Giới thiệu
        • Trực tiếp
        • Chơi thử
        • Trực tiếp
        • Demo trực tiếp
        • Hỗ trợ và Cộng đồng
        • Tổng quan kỹ thuật
        • Lời chứng thực
        • Testing on local devices
        • Sử dụng Needle Engine trực tiếp từ HTML
        • vision
        • VR & AR (WebXR)
        • blender
          • Needle Engine cho Blender
        • cloud
          • Needle Cloud
        • custom-integrations
          • index
        • getting-started
          • Giới thiệu về Scripting cho các nhà phát triển Unity
          • Getting Started & Installation
          • Scripting trong Needle Engine
        • reference
          • needle.config.json
          • Cấu hình <needle-engine>
          • @serializable và các decorator khác
        • three
          • index
        • unity
          • Editor Sync
          • Needle Engine cho Unity
      • zh
        • SUMMARY
        • 自动生成组件
        • Needle 核心组件
        • 如何调试
        • 部署与优化
        • embedding
        • Everywhere Actions
        • 示例项目 ✨
        • 导出资源、动画、预制体、材质、光照贴图...
        • 常见问题 (FAQ) 💡
        • 功能概览
        • 此页面已移动:请在此处继续
        • getting-started
        • 框架、打包器、HTML
        • index
        • 附加模块
        • 网络
        • Needle Engine 项目结构
        • 示例项目
        • Scripting Examples
        • Creating and using Components
        • 实时示例
        • 实时
        • 关于
        • 实时演示
        • 在线试玩
        • 实时演示
        • 现场演示
        • 支持与社区
        • 技术概述
        • 用户评价
        • Testing on local devices
        • 使用 Needle Engine 直接从 HTML
        • vision
        • VR & AR (WebXR)
        • blender
          • Needle Engine for Blender
        • cloud
          • Needle Cloud
        • custom-integrations
          • index
        • getting-started
          • Scripting Introduction for Unity Developers
          • 入门与安装
          • 在 Needle Engine 中编写脚本
        • reference
          • needle.config.json
          • <needle-engine> 配置
          • @serializable and other decorators
        • three
          • index
        • unity
          • 编辑器同步
          • Unity 版 Needle Engine
Powered by GitBook
On this page
  • Creating custom components
  • When you don't need to write code
  • Creating a new component
  • Component architecture
  • Special Lifecycle hooks
  • Finding, adding and removing components
  • Three.js and the HTML DOM
  • Accessing Needle Engine and components from anywhere
  • Gizmos
  • Serialization / Components in glTF files
  • Loading Scenes
  • Next Steps
Edit on GitHub
  1. documentation

Creating and using Components

PreviousScripting ExamplesNextLive

Last updated 1 month ago

Creating custom components

If you are new to scripting we highly recommend reading the following guides first:

If you know what you're doing, feel free to jump right into the .


Runtime code for Needle Engine is written in (recommended) or . We automatically generate C# stub components out of that, which you can add to GameObjects in the editor. The C# components and their data are recreated by the runtime as JavaScript components with the same data and attached to three.js objects.

Both custom components as well as built-in Unity components can be mapped to JavaScript components in this way. For example, mappings for many built-in components related to animation, rendering or physics are already .

If you want to code-along with the following examples without having to install anything you just click the following link:

  • .


Our web runtime engine adopts a component model similar to Unity and thus provides a lot of functionality that will feel familiar. Components attached to three's Object3D objects have lifecycle methods like awake, start, onEnable, onDisable, update and lateUpdate that you can implement. You can also use .


When you don't need to write code

Often, interactive scenes can be realized using Events in Unity and calling methods on built-in components. A typical example is playing an animation on button click - you create a button, add a Click event in the inspector, and have that call Animator.SetTrigger or similar to play a specific animation.

Needle Engine translates Unity Events into JavaScript method calls, which makes this a very fast and flexible workflow - set up your events as usual and when they're called they'll work the same as in Unity.

An example of a Button Click Event that is working out-of-the-box in Needle Engine — no code needed.

Creating a new component

Scripts are written in TypeScript (recommended) or JavaScript. There are two ways to add custom scripts to your project:

  • Simply add a file with an .ts or .js extension inside src/scripts/ in your generated project directory, for example src/scripts/MyFirstScript.ts

In both approaches, source directories are watched for changes and C# stub components or Blender panels are regenerated whenever a change is detected. Changes to the source files also result in a hot reload of the running website – you don't have to wait for Unity to recompile the C# components. This makes iterating on code pretty much instant.

You can even have multiple component types inside one file (e.g. you can declare export class MyComponent1 and export class MyOtherComponent in the same Typescript file).

:::details Example: Creating a Component that rotates an object

  • Create a component that rotates an object Create src/scripts/Rotate.ts and add the following code:

import { Behaviour, serializable } from "@needle-tools/engine";

export class Rotate extends Behaviour
{
    @serializable()
    speed : number = 1;

    start(){
        // logging this is useful for debugging in the browser. 
        // You can open the developer console (F12) to see what data your component contains
        console.log(this);
    }

    // update will be called every frame
    update(){
        this.gameObject.rotateY(this.context.time.deltaTime * this.speed);
    }
}

Now inside Unity a new script called Rotate.cs will be automatically generated. Add the new Unity component to a Cube and save the scene. The cube is now rotating inside the browser. Open the chrome developer console by F12 to inspect the log from the Rotate.start method. This is a helpful practice to learn and debug what fields are exported and currently assigned. In general all public and serializable fields and all public properties are exported.

Now add a new field public float speed = 5 to your Unity component and save it. The Rotate component inspector now shows a speed field that you can edit. Save the scene (or click the Build button) and note that the javascript component now has the exported speed value assigned. :::

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);
    }
}

:::

:::details Version Control & Unity 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. :::

Component architecture

Components are added to three.js Object3Ds. This is similar to how Components in Unity are added to GameObjects. Therefore when we want to access a three.js Object3D, we can access it as this.gameObject which returns the Object3D that the component is attached to.

Note: Setting visible to false on a Object3D will act like SetActive(false) in Unity - meaning it will also disable all the current components on this object and its children. Update events for inactive components are not being called until visible is set to true again. If you want to hide an object without affecting components you can just disable the Needle Engine Renderer component.

Lifecycle methods

Note that lifecycle methods are only being called when they are declared. So only declare update lifecycle methods when they are actually necessary, otherwise it may hurt performance if you have many components with update loops that do nothing.

Method name
Description

awake()

First method being called when a new component is created

onEnable()

Called when a component is enabled (e.g. when enabled changes from false to true)

onDisable()

Called when a component is disabled (e.g. when enabled changes from true to false)

onDestroy()

called when the Object3D or component is being destroyed

start()

Called on the start of the first frame after the component was created

earlyUpdate()

First update event

update()

Default update event

lateUpdate()

Called after update

onBeforeRender()

Last update event before render call

onAfterRender()

Called after render event

Physic event methods

Method name
Description

onCollisionEnter(col : Collision)

onCollisionStay(col : Collision)

onCollisionExit(col : Collision)

onTriggerEnter(col : Collision)

onTriggerStay(col : Collision)

onTriggerExit(col : Collision)

Input event methods

Method name
Description

onPointerEnter(args : PointerEventData)

Called when a cursor starts to hover over an object (or any of it's children)

onPointerMove(args : PointerEventData)

Called when a cursor moves over an object (or any of it's children)

onPointerExit(args : PointerEventData)

Called when a cursor exists (stops hovering) an object

onPointerDown(args : PointerEventData)

Called when a cursor is pressed over an object

onPointerUp(args : PointerEventData)

Called when a cursor is released over an object

onPointerClick(args : PointerEventData)

Called when a cursor is clicked over an object

XR event methods

requires Needle Engine >= 3.32.0

Method name
Description

supportsXR(mode: XRSessionMode)

Optionally implement if you only want to receive XR callbacks for specific XR modes like immersive-vr or immersive-ar. Return true to notify the system that you want callbacks for the passed in mode

onBeforeXR(mode: XRSessionMode, init: XRSessionInit)

Called right before a XRSession is requested and can be used to modify the XRSessionInit object

onEnterXR(args: NeedleXREventArgs)

Callback when this component joins a xr session (or becomes active in a running XR session)

onUpdateXR(args: NeedleXREventArgs)

Callback when a xr session updates (while it is still active in XR session)

onLeaveXR(args: NeedleXREventArgs)

allback when this component exists a xr session (or when it becomes inactive in a running XR session)

onControllerAdded(args: NeedleXRControllerEventArgs)

Callback when a controller is connected/added while in a XR session OR when the component joins a running XR session that has already connected controllers OR when the component becomes active during a running XR session that has already connected controllers

onControllerRemoved(args: NeedleXRControllerEventArgs)

callback when a controller is removed while in a XR session OR when the component becomes inactive during a running XR session

Additional XR events

Method name
Description

window.addEventListener("needle-xrsession-start")

CustomEvent that is invoked when a XRSession starts. details contains the NeedleXRSession

window.addEventListener("needle-xrsession-end")

CustomEvent that is invoked when a XRSession starts. details contains the NeedleXRSession

onXRSessionStart(args: { session:NeedleXRSession } )

global event hook. To unsubscribe use offXRSessionStart

Coroutines

Example

import { Behaviour, FrameEvent } from "@needle-tools/engine";

export class Rotate extends Behaviour {

    start() {
        // the second argument is optional and allows you to specifiy 
        // when it should be called in the current frame loop
        // coroutine events are called after regular component events of the same name
        // for example: Update coroutine events are called after component.update() functions
        this.startCoroutine(this.rotate(), FrameEvent.Update);
    }

    // this method is called every frame until the component is disabled
    *rotate() {
        // keep looping forever
        while (true) {
            yield;
        }
    }
}

To stop a coroutine, either exit the routine by returning from it, or cache the return value of startCoroutine and call this.stopCoroutine(<...>). All Coroutines are stopped at onDisable / when disabling a component.

Special Lifecycle hooks

Needle Engine also exposes a few lifecycle hooks that you can use to hook into the update loop without having to write a full component. Those hooks can be inserted at any point in your web application (for example in toplevel scope or in a svelte component)

Method name
Description

onInitialized(cb, options)

Called when a new context is initialized (before the first frame)

onClear(cb, options)

Register a callback before the engine context is cleared

onDestroy(cb, options)

Register a callback in the engine before the context is destroyed

onStart(cb, options)

Called directly after components start at the beginning of a frame

onUpdate(cb, options)

Called directly after components update

onBeforeRender(cb, options)

called before calling render

onAfterRender(cb, options)

called before calling render

// this can be put into e.g. main.ts or a svelte component (similar to onMount)
import { onStart, onUpdate, onBeforeRender, onAfterRender } from "@needle-tools/engine"

onStart(ctx => console.log("Hello Scene", ctx.scene));

onUpdate(ctx => {
    // do something... e.g. access the frame # or deltatime via ctx.time
    console.log("UPDATE", ctx.time.frame);
});

onBeforeRender(ctx => {
    // this event is only called once because of the { once: true } argument
    console.log("ON BEFORE RENDER", ctx.time.frame);
}, { once: true } );

// Every event hook returns a method to unsubscribe from the event
const unsubscribe = onAfterRender(ctx => {
    console.log("ON AFTER RENDER", ctx.time.frame);
});
// Unsubscribe from the event at any time
setTimeout(()=> unsubscribe(), 1000);

Finding, adding and removing components

To access other components, use the static methods on GameObject or this.gameObject methods. For example, to access a Renderer component in the parent use GameObject.getComponentInParent(this.gameObject, Renderer) or this.gameObject.getComponentInParent(Renderer).

Example:

import { Behaviour, GameObject, Renderer } from "@needle-tools/engine";

export class MyComponent extends Behaviour {

    start() {
        const renderer = GameObject.getComponentInParent(this.gameObject, Renderer);
        console.log(renderer);
    }
}

Some of the available methods:

Method

GameObject.instantiate(Object3D, InstantiateOptions)

creates a new instance of this object including new instances of all its components

GameObject.destroy(Object3D | Component)

destroy a component or Object3D (and its components)

GameObject.addNewComponent(Object3D, Type)

adds (and creates) a new component for a type to the provided object. Note that awake and onEnable is already called when the component is returned

GameObject.addComponent(Object3D, Component)

moves a component instance to the provided object. It is useful if you already have an instance e.g. when you create a component with e.g. new MyComponent() and then attach it to a object

GameObject.removeComponent(Component)

removes a component from a gameObject

GameObject.getComponent(Object3D, Type)

returns the first component matching a type on the provided object.

GameObject.getComponents(Object3D, Type)

returns all components matching a type on the provided object.

GameObject.getComponentInChildren

same as getComponent but also searches in child objects.

GameObject.getComponentsInChildren

same as getComponents but also searches in child objects.

GameObject.getComponentInParent

same as getComponent but also searches in parent objects.

GameObject.getComponentsInParent

same as getComponents but also searches in parent objects.

GameObject.findObjectOfType

searches the whole scene for a type.

GameObject.findObjectsOfType

searches the whole scene for all matching types.

Three.js and the HTML DOM

This architecture allows for potentially having multiple needle WebGL scenes on the same webpage, that can either run on their own or communicate between each other as parts of your webpage.

Access the scene

To access the current scene from a component you use this.scene which is equivalent to this.context.scene, this gives you the root three.js scene object.

To traverse the hierarchy from a component you can either iterate over the children of an object with a for loop:

for(let i = 0; i < this.gameObject.children; i++) 
    console.log(this.gameObject.children[i]);

or you can iterate using the foreach equivalent:

for(const child of this.gameObject.children) {
    console.log(child);
}
import { Object3D } from "three";
this.gameObject.traverse((obj: Object3D) => console.log(obj));

Another option that is quite useful when you just want to iterate objects being renderable you can query all renderer components and iterate over them like so:

import { Renderer } from "@needle-tools/engine";
for(const renderer of this.gameObject.getComponentsInChildren(Renderer))
    console.log(renderer);

For more information about getting components see the next section.

Time

Use this.context.time to get access to time data:

  • this.context.time.time is the time since the application started running

  • this.context.time.deltaTime is the time that has passed since the last frame

  • this.context.time.frameCount is the number of frames that have passed since the application started

  • this.context.time.realtimeSinceStartup is the unscaled time since the application has started running

It is also possible to use this.context.time.timeScale to deliberately slow down time for e.g. slow motion effects.

Input

Receive input data for the object the component is on:

import { Behaviour } from "@needle-tools/engine";
export class MyScript extends Behaviour
{
    onPointerDown() {
        console.log("POINTER DOWN on " + this.gameObject.name);
    }
}

You can also subscribe to global events in the InputEvents enum like so:

import { Behaviour, InputEvents, NEPointerEvent } from "@needle-tools/engine";

export class MyScript extends Behaviour
{
    onEnable() {
        this.context.input.addEventListener(InputEvents.PointerDown, this.inputPointerDown);
    }

    onDisable() {
        // it is recommended to also unsubscribe from events when your component becomes inactive
        this.context.input.removeEventListener(InputEvents.PointerDown, this.inputPointerDown);
    }

    // @nonSerialized
    inputPointerDown = (evt: NEPointerEvent) => { console.log("POINTER DOWN anywhere on the <needle-engine> element"); }
}

Or use this.context.input if you want to poll input state every frame:

import { Behaviour } from "@needle-tools/engine";
export class MyScript extends Behaviour
{
    update() {
        if(this.context.input.getPointerDown(0)){
            console.log("POINTER DOWN anywhere")
        }
    }
}
import { Behaviour } from "@needle-tools/engine";
export class MyScript extends Behaviour
{
    onEnable() {
        window.addEventListener("click", this.windowClick);
    }

    onDisable() {
        // unsubscribe again when the component is disabled
        window.removeEventListener("click", this.windowClick);
    }

    windowClick = () => { console.log("CLICK anywhere on the page, not just on <needle-engine>"); }
}

Note that in this case you have to handle all cases yourself. For example you may need to use different events if your user is visiting your website on desktop vs mobile vs a VR device. These cases are automatically handled by the Needle Engine input events (e.g. PointerDown is raised both for mouse down, touch down and in case of VR on controller button down).

Raycasting

Use this.context.physics.raycast() to perform a raycast and get a list of intersections. If you dont pass in any options the raycast is performed from the mouse position (or first touch position) in screenspace using the currently active mainCamera. You can also pass in a RaycastOptions object that has various settings like maxDistance, the camera to be used or the layers to be tested against.

Note: This type of raycast casts a ray against all visible objects in the scene. No physics engine is needed, which is different to the behaviour in Unity, where you always need colliders to hit objects. If you want to cast against physics colliders only, use physics.engine.raycast methods described below.

Performance considerations

When using default Needle compression settings, simplified versions of meshes are automatically created and used for raycasting as well. Still, some types of meshes are slow – for example, skinned meshes or meshes with blendshapes require expensive calculations to determine exact hits. Consider setting those objects to the Ignore Raycast layer in Unity to avoid raycasting against them.

Physics-based Raycasting

Another option is to use the physics raycast methods which will only return hits with colliders in the scene.

const hit = this.context.physics.engine?.raycast();

Networking

Accessing Needle Engine and components from anywhere

It is possible to access all the functionality described above using regular JavaScript code that is not inside components and lives somewhere else. All the components and functionality of the needle runtime is accessible via the global Needle namespace (you can write console.log(Needle) to get an overview)

For getting callbacks for the initial scene load see the following example:

<needle-engine loadstart="loadingStarted" progress="loadingProgress" loadfinished="loadingFinished"></needle-engine>

<script type="text/javascript">
function loadingStarted() { console.log("START") }
function loadingProgress() { console.log("LOADING...") }
function loadingFinished() { console.log("FINISHED!") }
</script>

You can also subscribe to the globale NeedleEngine (sometimes also referred to as ContextRegistry) to receive a callback when a Needle Engine context has been created or to access all available contexts:

class YourComponentType extends Behaviour {}
//---cut---
import { NeedleEngine, GameObject, Behaviour } from "@needle-tools/engine";

NeedleEngine.addContextCreatedCallback((args) => {
  const context = args.context;
  const scene = context.scene;
  const myInstance = GameObject.getComponentInChildren(scene, YourComponentType);
});

You can also access all available contexts via NeedleEngine.Registered which returns the internal array. (Note that this array should not be modified but can be used to iterate all active contexts to modify settings, e.g. set all contexts to context.isPaused = true)

Below you find a list of available events on the static NeedleEngine type. You can subscribe to those events via NeedleEngine.registerCallback(ContextEvent.ContextCreated, (args) => {})

ContextEvent options

ContextEvent.ContextRegistered

Called when the context is registered to the registry.

ContextEvent.ContextCreationStart

Called before the first glb is loaded and can be used to initialize the physics engine. Can return a promise

ContextEvent.ContextCreated

Called when the context has been created before the first frame

ContextEvent.ContextDestroyed

Called when the context has been destroyed

ContextEvent.MissingCamera

Called when the context could not find a camera, currently only called during creation

ContextEvent.ContextClearing

Called when the context is being cleared: all objects in the scene are being destroyed and internal state is reset

ContextEvent.ContextCleared

Called after the context has been cleared

Gizmos

The static Gizmos class can be used to draw lines, shapes and text which is mostly useful for debugging. All gizmos function have multiple options for e.g. colors or for how long they should be displayed in the scene. Internally they are cached and re-used.

Gizmos

Gizmos.DrawLabel

Draws a label with a background optionally. It can be attached to an object. Returns a Label handle which can be used to update the text.

Gizmos.DrawRay

Takes an origin and direction in worldspace to draw an infinite ray line

Gizmos.DrawDirection

Takes a origin and direction to draw a direction in worldspace

Gizmos.DrawLine

Takes two vec3 worldspace points to draw a line

Gizmos.DrawWireSphere

Draws a wireframe sphere in worldspace

Gizmos.DrawSphere

Draws a solid sphere in worldspace

Gizmos.DrawWireBox

Draws a wireframe box in worldspace

Gizmos.DrawWireBox3

Draws a wireframe box3

Gizmos.DrawArrow

Draws an arrow taking two points in worldspace

Serialization / Components in glTF files

To embed components and recreate components with their correct types in glTF, we also need to save non-primitive types (everything that is not a Number, Boolean or String). You can do so is adding a @serializable(<type>) decorator above your field or property.

To serialize from and to custom formats, it is possible to extend from the TypeSerializer class and create an instance. Use super() in the constructor to register supported types.

Note: In addition to matching fields, matching properties will also be exported when they match to fields in the typescript file.

Loading Scenes

These exported gltf files will be serialized as plain string URIs. To simplify loading these from TypeScript components, we added the concept of AssetReference types. They can be loaded at runtime and thus allow to defer loading parts of your app or loading external content.

AssetReferences are cached by URI, so if you reference the same exported glTF/Prefab in multiple components/scripts it will only be loaded once and then re-used.

Next Steps

Unity specific: Organize your code into NPM Definition Files (npm packages). These help you to modularize and re-use code between projects and if you are familiar with web development they are in fact regular npm packages that are installed locally. In Unity you can create NpmDef files via Create > NPM Definition and then add TypeScript files by right-clicking an NpmDef file and selecting Create > TypeScript. Please see for more information.

If you are new to writing Javascript or Typescript we recommend reading the guide first before continuing with this guide.

:::details Create component with a custom function Refer to the to learn more about the syntax and language.

Coroutines can be declared using the . To start a coroutine, call this.startCoroutine(this.myRoutineName());

For example ()

The context refers to the runtime inside a . The three.js scene lives inside a custom HTML component called <needle-engine> (see the index.html in your project). You can access the <needle-engine> web component using this.context.domElement.

You can also use three.js specific methods to quickly iterate all objects recursively using the method:

or to just traverse visible objects use instead.

If you want to handle inputs yourself you can also subscribe to (there are a ton). For example to subscribe to the browsers click event you can write:

Use this.context.physics.raycastFromRay(your_ray) to perform a raycast using a .

Here is an editable

Networking methods can be accessed via this.context.connection. Please refer to the for further information.

You can find components using Needle.findObjectOfType(Needle.AudioSource) for example. It is recommended to cache those references, as searching the whole scene repeatedly is expensive. See the list for above.

Another option is using the onInitialized(ctx => {})

Example: @

In Unity referenced Prefabs, SceneAssets and AssetReferences (Unity's Addressable System) will automatically be exported as glTF files (please refer to the documentation).

Example: @

Typescript Essentials Guide
Typescript Essentials Guide
JavaScript Generator Syntax
See example on stackblitz
web component
traverse
traverseVisible
all events the browser provides
three.js ray
example for physics raycast
networking docs
code ts twoslash
Export Prefabs
code ts twoslash
finding adding and removing components
lifecycle hook
Typescript Essentials
Needle Engine for Unity Developers
Needle Engine API documentation
TypeScript
JavaScript
Create virtual workspace to code along
Coroutines
included in Needle Engine
this chapter