# Using the module in three.js

> Import the exported material, load its textures, drive its uniforms, and match Blender's colours.

Blender to TSL docs · https://tools.ashthornton.dev/blender-to-tsl/docs/threejs/

Each exported file is an ES module with one job: build the material. It imports three.js, exports a factory function, and lists what it needs from your project (textures, attributes and settings). You don't need anything else from the add-on at runtime.

## Requirements

- **`WebGPURenderer` from `three/webgpu`.** It switches to WebGL 2 by itself in browsers without WebGPU. The classic `WebGLRenderer` can't render node materials.
- **three.js r186** is what the add-on is tested with. Newer versions usually work; TSL is still changing, so check the console after you upgrade three.

The module imports from `'three/webgpu'` and `'three/tsl'`. If your project resolves three differently (an import map or an alias), edit those two import lines, or have an [AI agent](https://tools.ashthornton.dev/blender-to-tsl/docs/ai-agents.md) export with your project's specifiers.

## Create the material

```js
import createBrickWallMaterial from './materials/BrickWall.tsl.js';

const { material, uniforms } = createBrickWallMaterial();
mesh.material = material;
```

The factory is the module's default export, and is also exported by name: `create` + the material name + `Material`. Each call returns a new material, plus the uniforms that drive it.

## Textures

A material that uses images exports `TEXTURES`, keyed by image name. Each entry has the `file` name and the sampling settings from Blender. Load every file and pass them in:

```js
import { TextureLoader } from 'three/webgpu';
import createBrickWallMaterial, { TEXTURES } from './materials/BrickWall.tsl.js';

const loader = new TextureLoader();
const textures = {};
for (const [key, { file }] of Object.entries(TEXTURES)) {
  textures[key] = await loader.loadAsync(`/materials/${file}`);
}

const { material } = createBrickWallMaterial({ textures });
```

- **Export .js** with **Copy Images** on puts the images next to the module. Serve them from wherever your project keeps static files, and change the URL above to match.
- The factory configures each texture for you: `flipY`, colour space, wrapping and filtering all come from Blender. Don't set them yourself.
- A texture you don't pass logs `[tsl] missing texture "<key>"` in the console.
- Any loader works, including `KTX2Loader` for compressed textures.

> **Tip**
>
> An agent can export with a texture URL for your project. The module then also exports `loadTextures()`, which loads every image for you: `createBrickWallMaterial({ textures: await loadTextures() })`.

## Uniforms

`uniforms` maps names to TSL uniform nodes. Change `.value` at runtime, with no rebuild:

```js
uniforms.tint.value.set('#ff6a3d');   // an RGB node labelled "Tint"
uniforms.glowStrength.value = 2.5;    // a Value node labelled "Glow Strength"
```

Value and RGB nodes become uniforms (with **Value/RGB as Uniforms** on), named after their node labels in camelCase: *Glow Strength* becomes `glowStrength`. Label the nodes you want to drive in Blender before you export; unlabelled nodes use the node name. Other uniforms come from things Blender knows about the scene and the object:

| Uniform | Comes from | What to do |
|---|---|---|
| `frame` | Keyframed values, e.g. an animated Mapping node | Set it every frame: `seconds × fps + frame_start`, using the .blend's frame rate and start frame. It starts at the frame that was current at export. |
| `objectRandom`, object colour | Object Info | Defaults to Blender's value for this object. Set it per mesh if you reuse the material on several. |
| `ambientLight`, `sunDirection`, `sunColor` | Shader to RGB | Drive them from your scene's lights (below). |

```js
renderer.setAnimationLoop((time) => {
  uniforms.frame.value = (time / 1000) * 24 + 1; // 24 fps, starting at frame 1
  renderer.render(scene, camera);
});
```

Keyframes with linear or constant interpolation play exactly as on Blender's timeline. Eased keys are linear between keys, and F-curve modifiers are ignored; the export notes say so when it happens.

### Shader to RGB lighting

three.js can't feed its lights into a material's node graph the way Blender's Shader to RGB does, so toon-style materials use a simple light from three uniforms:

- `sunDirection`: a world-space unit vector pointing **towards** the light. For a `DirectionalLight`, that's `light.position − light.target.position`, normalised.
- `sunColor`: the light's `color × intensity / π`.
- `ambientLight`: your ambient or world colour.

## Mesh data

If the material reads attributes or vertex colours, the module exports `ATTRIBUTES`, mapping Blender's names to the names it reads on the geometry, e.g. `{ rand: '_rand' }`. [Exporting the mesh](https://tools.ashthornton.dev/blender-to-tsl/docs/exporting.md#exporting-the-mesh) covers getting those into a glTF. Edit the values if your pipeline names attributes differently.

## Transparency and sides

The factory sets `transparent`, `alphaHash` and `side` from the Blender material's render method and backface settings. Don't override them.

## Matching Blender's colours

Colours are scene-linear, the same working space three.js uses. To match Blender, set the renderer's tone mapping to the one that matches your **Color Management ▸ View Transform**:

| Blender view transform | three.js `renderer.toneMapping` |
|---|---|
| Standard | `NoToneMapping` |
| AgX (Blender's default) | `AgXToneMapping` |
| Khronos PBR Neutral | `NeutralToneMapping` |

Other view transforms, such as Filmic, have no three.js equivalent; the export notes tell you. three's AgX lifts dark, saturated colours a little compared with Blender's.

## What the module says about itself

`META` (exported by every module) is the export report as plain data: the material class, the `requirements` (renderer, tone mapping, alpha, double-sided, UV maps, vertex colours, tangents), the uniforms with their roles, the attributes and the conversion notes. It's handy for checking a module in code or tests:

```js
import { META } from './materials/BrickWall.tsl.js';
console.log(META.requirements.tone_mapping); // e.g. "AgXToneMapping"
```

## The code is yours

The modules the add-on generates, including the helper functions copied into them, are yours to use, change and ship under any terms, including in closed-source sites and apps. No attribution is needed.

One exception: code translated from Blender's Cycles renderer (its maths, colour blends, some textures, bump and normal maps) is Apache-2.0. A module that contains any says so in a `/*! … */` notice at the top. Apache-2.0 allows closed-source use; keep that notice with the code when you ship it. Bundlers keep `/*!` comments by default.
