docs
Getting Started
Tutorials
How-To Guides
Explanation
Reference
Help
Getting Started
Tutorials
How-To Guides
Explanation
Reference
Help

Load 3D Web Assets at Runtime

Needle Engine has four ways to load GLB / glTF / VRM files at runtime, and all of them accept any HTTPS URL — bundled paths, Needle Cloud links, AWS S3, Cloudflare R2, your own CDN, or any web server.

This guide covers when to use each loading API, plus what you need in place to host assets externally (CORS, content types) so you can keep your build small and load assets on demand.

When to use this

  • Build is too large because you're shipping many GLB files
  • You want to update assets without rebuilding the website
  • Users only need a subset of available models per session
  • Assets are user-generated or change frequently
  • You're embedding Needle Engine into React/Vue/Svelte and want to load scenes dynamically

Four Ways to Load Assets from a URL

Every loading API in Needle Engine accepts a full URL — there is no separate "remote" path. The four options below cover every common use case.

1. Set the root scene with <needle-engine src="…">

The simplest case — point the web component directly at a hosted GLB.

<needle-engine src="https://cloud.needle.tools/-/assets/Z23hmXBZ21QnG-latest-world/file"></needle-engine>

This works with any URL — Needle Cloud, S3, your CDN, GitHub raw, anywhere. Use this when you have one root scene to display.

See needle-engine attributes for the full list of HTML options (camera-controls, environment-image, etc.).

2. SceneSwitcher.addScene(url) — many scenes, on demand

Best for galleries, configurators, and multi-scene experiences. Keep a minimal root scene with just a SceneSwitcher, then add URLs at runtime.

import { addComponent, SceneSwitcher } from "@needle-tools/engine";

const sceneSwitcher = addComponent(scene, SceneSwitcher, {
    autoLoadFirstScene: false,
    createMenuButtons: true,
    clamp: false,
    preloadNext: 1,
    preloadPrevious: 1,
});

sceneSwitcher.addScene("https://cloud.needle.tools/-/assets/Z23hmXBZ21QnG-latest-world/file");
sceneSwitcher.addScene("https://cloud.needle.tools/-/assets/Z23hmXBzvPW9-latest-product/file");
sceneSwitcher.addScene("https://cloud.needle.tools/-/assets/Z23hmXBZvGGVp-latest-product/file");
sceneSwitcher.addScene("https://your-bucket.s3.amazonaws.com/products/chair-red.glb");
sceneSwitcher.addScene("https://your-bucket.s3.amazonaws.com/products/chair-blue.glb");

sceneSwitcher.select(0);

Each loaded GLB is fully interactive — components, scripts, animations, and physics inside the loaded scene all activate. You can mix URLs from different hosts in the same list.

SceneSwitcher brings two extras that are especially valuable when loading from a CDN:

  • Preloading — set preloadNext and preloadPrevious to download neighbouring scenes in the background while the user views the current one. Transitions then feel instant even over a slow connection. preloadConcurrent caps how many downloads run in parallel. You can also preload manually with sceneSwitcher.preload(index).
  • Browser history & deep links — scene changes sync to a URL parameter (?scene=chair-red), so users can bookmark a specific scene, share a direct link, and use the browser back/forward buttons to navigate between scenes. Configure with queryParameterName, useSceneName, and useHistory.

See SceneSwitcher guide for full navigation, preloading, and lifecycle event details.

3. AssetReference — caching, instancing, prefabs

AssetReference is the right choice when you want to load once and spawn many copies, or when you want a stable handle to an asset across your code.

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

export class SpawnFromCDN extends Behaviour {
    async start() {
        // Create (or reuse) a reference to a URL.
        // getOrCreate caches by URL — multiple calls return the same reference.
        const ref = AssetReference.getOrCreate(
            this.context.domElement.baseURI,
            "https://your-cdn.com/models/tree.glb"
        );

        // Spawn three independent copies
        await ref.instantiate({ parent: this.gameObject });
        await ref.instantiate({ parent: this.gameObject });
        await ref.instantiate({ parent: this.gameObject });

        // Or load once and add the original (no copy):
        // const obj = await ref.loadAssetAsync();
        // this.gameObject.add(obj);
    }
}

AssetReference is also what gets serialized when you assign a Prefab or Scene asset in Unity/Blender — so the same API works whether the asset comes from your editor export or a runtime URL.

See Reference and Load a Prefab and the AssetReference API.

4. loadAsset(url) — one-line direct loading

The simplest option — load a file and add it to the scene in two lines:

import { loadAsset } from "@needle-tools/engine";

const model = await loadAsset("https://your-cdn.com/models/room.glb");
this.context.scene.add(model.scene);

loadAsset returns a wrapper with .scene, .animations, etc. — works the same for GLB, FBX, OBJ, and USDZ inputs.

Which one should I use?

  • One root scene → <needle-engine src="…">
  • Switch between many scenes → SceneSwitcher.addScene(url)
  • Reusable asset spawned multiple times, or editor-assigned prefab → AssetReference
  • Quick one-off load → loadAsset(url)

React, Vue, Svelte Integration

The same APIs work inside any framework. A typical pattern with React:

import { useEffect, useRef } from "react";
import "@needle-tools/engine";

export function ProductViewer({ productUrl }: { productUrl: string }) {
    const ref = useRef<HTMLElement>(null);

    useEffect(() => {
        if (ref.current) ref.current.setAttribute("src", productUrl);
    }, [productUrl]);

    return <needle-engine ref={ref} camera-controls />;
}

For a SceneSwitcher-based dynamic loader, mount once and call addScene() / select() when the user picks a model — no remount needed.

Hosting Options

Needle Cloud — the perfect fit for runtime asset loading

Needle Cloud is built for exactly this use case. Upload a GLB, get a URL, and you immediately get everything a production CDN setup would need:

  • Progressive loading — small preview textures and low-poly meshes stream first, full quality streams on demand. Typically ~90% less bandwidth than loading raw GLB from S3.
  • Automatic compression — KTX2 textures and Draco/meshopt meshes generated on upload, no toktx setup, no build pipeline.
  • Global CDN — assets served from edge locations close to your users.
  • Correct CORS and Content-Type headers out of the box — no S3 policy tuning.
  • Versioning + labels (see below) — update assets without redeploying your app.

Upload your GLB and copy the Progressive-World or Progressive-Product download link from the asset's Edit page — then drop that URL into addScene(), loadAsset(), AssetReference.getOrCreate(), or <needle-engine src>.

Update assets without redeploying your app — labels

This is the killer feature for the "load 20-30 models from the cloud" pattern: each cloud asset has moveable labels (latest, main) that act as stable URLs pointing at whichever version you choose.

LabelURL patternWhat it does
Pinned versioncloud.needle.tools/-/assets/<id>-<version>/fileAlways serves that exact upload. Never changes.
latestcloud.needle.tools/-/assets/<id>-latest-<name>/fileAuto-updates to the most recent upload.
maincloud.needle.tools/-/assets/<id>-main-<name>/fileYou manually promote a version to main — your production users see it.

Workflow:

  1. Hard-code the main-labeled URL in your app: sceneSwitcher.addScene("https://cloud.needle.tools/-/assets/Z23h…-main-chair/file").
  2. Iterate on the GLB in Unity / Blender and upload a new version. It immediately becomes latest (preview / staging).
  3. When you're happy, click ⋮ → Set main label on the new version in the Needle Cloud dashboard.
  4. All users now load the new asset — no code change, no rebuild, no redeploy. Roll back the same way by moving the main label back.

This is impossible with a plain S3 bucket without writing your own version-resolution layer. See Needle Cloud: Version Control & Sharing for details.

Tips

Use pinned URLs in your tests and demos so they don't break when you ship a new version. Use the main label in your production app so you can ship updates without touching code.

Amazon S3, Cloudflare R2, Google Cloud Storage

Any object store works as long as it serves the file over HTTPS with the right headers (see CORS below). You'll be responsible for compression, progressive LOD generation, and versioning yourself.

Your own server, GitHub, or any static host

If the URL returns the GLB bytes with a permissive CORS policy, Needle Engine will load it.

CORS & Content-Type

Because the browser fetches the GLB cross-origin, the host must allow your site's origin. For an S3 bucket the CORS rule looks like this:

[
  {
    "AllowedOrigins": ["https://your-site.com"],
    "AllowedMethods": ["GET", "HEAD"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": ["Content-Length"]
  }
]

Recommended response headers:

  • Content-Type: model/gltf-binary for .glb (or application/octet-stream as a fallback)
  • Content-Type: model/gltf+json for .gltf
  • Access-Control-Allow-Origin matching your site origin (or * for public assets)
  • Cache-Control: public, max-age=… for CDN caching

If a load fails, open the browser DevTools Network tab — most external-URL issues come down to a missing CORS header or a redirect that strips it.

Live Example

Try it in your browser — the example below uses SceneSwitcher.addScene() with several Needle Cloud URLs. Swap them for your own to test:

Open on Stackblitz — uses SceneSwitcher.addScene() with several Needle Cloud URLs.

Related

  • SceneSwitcher Component — full guide to multi-scene loading
  • Needle Cloud — managed asset hosting with progressive loading
  • Progressive Loading & LODs — how big assets stream
  • Reference Assets in Scripts — AssetReference patterns
  • needle-engine HTML attributes — src, camera-controls, and more
Suggest changes
Last Updated: 5/14/26, 10:19 AM

Extras

Needle AI Ask Needle AI
Copy Markdown

Navigation

  • Getting Started
  • Tutorials
  • How-To Guides
  • Explanation
  • Reference
  • Help

Extras

Needle AI Ask Needle AI
Copy Markdown