Introduction
Why TSL?
Creating shaders has always been an advanced step for most developers, many game creators have never created GLSL code from scratch. The shader graph solution adopted today by the industry has allowed developers more focused on dynamics to create the necessary graphic effects to meet the demands of their projects.
The aim of the project is to create an easytouse, even if for this we need to create complexity behind, this happened initially with Renderer
and now with the TSL
.
Other benefits that TSL brings besides simplifying shading creation is keeping the renderer agnostic
, while all the complexity of a material can be imported into different modules and use tree shaking
without breaking during the process.
Example
A detail map
makes things look more real in games. It adds tiny details like cracks or bumps to surfaces, like walls. In this example we will scale uv to improve details when seen up close and multiply with a base texture.
Old
This is how we would achieve that using .onBeforeCompile()
:
With TSL
the code would look like this:
import { texture, uv } from 'three/tsl' const detail = texture( detailMap, uv().mul( 10 ) ); const material = new MeshStandardNodeMaterial(); material.colorNode = texture( colorMap ).mul( detail );
TSL
is also capable of encoding code into different outputs such as WGSL
/GLSL
– WebGPU
/WebGL
, in addition to optimizing the shader graph automatically and through codes that can be inserted within each Node
. This allows the developer to focus on productivity and leave the graphical management part to the Node System
.
Another important feature of a graph shader is that we will no longer need to care about the sequence in which components are created, because the Node System
will only declare and include it once.
Let’s say that you import positionWorld
into your code, even if another component uses it, the calculations performed to obtain position world
will only be performed once, as is the case with any other renderer component such as: normalWorld
, modelPosition
, etc.
Architeture
All TSL
component is created from a Node
. The Node
allows it to communicate with any other, value conversions can be automatic or manual, a Node
can receive the output value expected by the parent Node
and modify its own output snippet.
Since they are all components are extended from the Node
class, it is possible to modulate them using tree shaking
. In the shader construction process, the Node
will have important information such as geometry
, material
, renderer
as well as the backend
, which can influence the type and value of output.
The build process is based on three pillars: setup
, analyze
and generate
.
setup 
Use TSL to create a completely customized code for the Node output. The Node can use many others within itself, have countless inputs, but there will always be a single output. 
analyze 
This proccess will check the nodes that were created in order to create useful information for generate the snippet, such as the need to create or not a cache/variable for optimizing a node. 
generate 
An output of string will be sent to each node independently, the node will also be able to create code in the flow, supporting multiple lines. 
Node
also have a native update process invoked by the update()
function, these events be called by frame
, render call
and object draw
.
It is also possible to serialize or deserialize a Node
using serialize()
and deserialize()
functions.
Constants and explicit conversions
Input functions can be used to create contants and do explicit conversions.
Conversions are also performed automatically if the output and input are of different types.
Name  Returns a constant or convertion of type: 

float( node  number ) 
float 
int( node  number ) 
int 
uint( node  number ) 
uint 
bool( node  value ) 
boolean 
color( node  hex  r,g,b ) 
color 
vec2( node  Vector2  x,y ) 
vec2 
vec3( node  Vector3  x,y,z ) 
vec3 
vec4( node  Vector4  x,y,z,w ) 
vec4 
mat2( node  Matrix2  a,b,c,d ) 
mat2 
mat3( node  Matrix3  a,b,c,d,e,f,g,h,i ) 
mat3 
mat4( node  Matrix4  a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p ) 
mat4 
Advanced  
ivec2( node  x,y ) 
ivec2 
ivec3( node  x,y,z ) 
ivec3 
ivec4( node  x,y,z,w ) 
ivec4 
uvec2( node  x,y ) 
uvec2 
uvec3( node  x,y,z ) 
uvec3 
uvec4( node  x,y,z,w ) 
uvec4 
bvec2( node  x,y ) 
bvec2 
bvec3( node  x,y,z ) 
bvec3 
bvec4( node  x,y,z,w ) 
bvec4 
imat2( node  Matrix2  a,b,c,d ) 
imat2 
imat3( node  Matrix3  a,b,c,d,e,f,g,h,i) 
imat3 
imat4( node  Matrix4  a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p ) 
imat4 
umat2( node  Matrix2  a,b,c,d ) 
umat2 
umat3( node  Matrix3  a,b,c,d,e,f,g,h,i ) 
umat3 
umat4( node  Matrix4  a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p ) 
umat4 
bmat2( node  Matrix2  a,b,c,d ) 
bmat2 
bmat3( node  Matrix3  a,b,c,d,e,f,g,h,i ) 
bmat3 
bmat4( node  Matrix4  a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p ) 
bmat4 
Example:
import { color, vec2, positionWorld } from 'three/tsl'; // constant material.colorNode = color( 0x0066ff ); // conversion material.colorNode = vec2( positionWorld ); // result positionWorld.xy
Conversions
It is also possible to perform conversions using the method chain
:
Name  Returns a constant or conversion of type: 

.toFloat() 
float 
.toInt() 
int 
.toUint() 
uint 
.toBool() 
boolean 
.toColor() 
color 
.toVec2() 
vec2 
.toVec3() 
vec3 
.toVec4() 
vec4 
.toMat2() 
mat2 
.toMat3() 
mat3 
.toMat4() 
mat4 
Advanced  
.toIvec2() 
ivec2 
.toIvec3() 
ivec3 
.toIvec4() 
ivec4 
.toUvec2() 
uvec2 
.toUvec3() 
uvec3 
.toUvec4() 
uvec4 
.toBvec2() 
bvec2 
.toBvec3() 
bvec3 
.toBvec4() 
bvec4 
.toImat2() 
imat2 
.toImat3() 
imat3 
.toImat4() 
imat4 
.toUmat2() 
umat2 
.toUmat3() 
umat3 
.toUmat4() 
umat4 
.toBmat2() 
bmat2 
.toBmat3() 
bmat3 
.toBmat4() 
bmat4 
Example:
import { positionWorld } from 'three/tsl'; // conversion material.colorNode = positionWorld.toVec2(); // result positionWorld.xy
Method chaining
Method chaining
will only be including operators, converters, math and some core functions. These functions, however, can be used on any node
.
Example:
// it will invert the texture color material.colorNode = texture( map ).rgb.oneMinus();
Swizzle
Swizzling is the technique that allows you to access, reorder, or duplicate the components of a vector using a specific notation within TSL. This is done by combining the identifiers:
const original = vec3( 1.0, 2.0, 3.0 ); // (x, y, z) const swizzled = original.zyx; // swizzled = (3.0, 2.0, 1.0)
It’s possible use xyzw
, rgba
or stpq
.
Operators
Name  Description 

.add( node  value, ... ) 
Return the addition of two or more value. 
.sub( node  value ) 
Return the subraction of two or more value. 
.mul( node  value ) 
Return the multiplication of two or more value. 
.div( node  value ) 
Return the division of two or more value. 
.assign( node  value ) 
Assign one or more value to a and return the same. 
.remainder( node  value ) 
Computes the remainder of dividing the first node by the second. 
.equal( node  value ) 
Checks if two nodes are equal. 
.notEqual( node  value ) 
Checks if two nodes are not equal. 
.lessThan( node  value ) 
Checks if the first node is less than the second. 
.greaterThan( node  value ) 
Checks if the first node is greater than the second. 
.lessThanEqual( node  value ) 
Checks if the first node is less than or equal to the second. 
.greaterThanEqual( node  value ) 
Checks if the first node is greater than or equal to the second. 
.and( node  value ) 
Performs logical AND on two nodes. 
.or( node  value ) 
Performs logical OR on two nodes. 
.not( node  value ) 
Performs logical NOT on a node. 
.xor( node  value ) 
Performs logical XOR on two nodes. 
.bitAnd( node  value ) 
Performs bitwise AND on two nodes. 
.bitNot( node  value ) 
Performs bitwise NOT on a node. 
.bitOr( node  value ) 
Performs bitwise OR on two nodes. 
.bitXor( node  value ) 
Performs bitwise XOR on two nodes. 
.shiftLeft( node  value ) 
Shifts a node to the left. 
.shiftRight( node  value ) 
Shifts a node to the right. 
const a = float( 1 ); const b = float( 2 ); const result = a.add( b ); // output: 3
Functions
tslFn( function )
It is possible to use classic JS functions or a tslFn()
interface. The main difference is that tslFn()
creates a controllable environment, allowing the use of stack
where you can use assign
and conditional
, while the classic function only allows inline approaches.
Example:
return timer.add( 0.75 ).mul( Math.PI * 2 ).sin().mul( 0.5 ).add( 0.5 );
} );
const value = oscSine( { timer: value } );”>
const oscSine = tslFn( ( { timer = timerGlobal } ) => { return timer.add( 0.75 ).mul( Math.PI * 2 ).sin().mul( 0.5 ).add( 0.5 ); } ); const value = oscSine( { timer: value } );
If you want to use an export function compatible with
tree shaking
, remember to use/*@__PURE__*/
Name  Description 

PI 
The value of π (pi). 
PI2 
The value of 2π (two pi). 
EPSION 
A small value used to handle floatingpoint precision errors. 
INFINITY 
Represent infinity. 
abs( x ) 
Return the absolute value of the parameter. 
acos( x ) 
Return the arccosine of the parameter. 
all( x ) 
Return true if all components of x are true. 
any( x ) 
Return true if any component of x is true. 
asin( x ) 
Return the arcsine of the parameter. 
atan( x ) 
Return the arctangent of the parameters. 
atan2( y, x ) 
Return the arctangent of the quotient of its arguments. 
bitcast( x, y ) 
Reinterpret the bits of a value as a different type. 
cbrt( x ) 
Return the cube root of the parameter. 
ceil( x ) 
Find the nearest integer that is greater than or equal to the parameter. 
clamp( x, min, max ) 
Constrain a value to lie between two further values. 
cos( x ) 
Return the cosine of the parameter. 
cross( x, y ) 
Calculate the cross product of two vectors. 
dFdx( p ) 
Return the partial derivative of an argument with respect to x. 
dFdy( p ) 
Return the partial derivative of an argument with respect to y. 
degrees( radians ) 
Convert a quantity in radians to degrees. 
difference( x, y ) 
Calculate the absolute difference between two values. 
distance( x, y ) 
Calculate the distance between two points. 
dot( x, y ) 
Calculate the dot product of two vectors. 
equals( x, y ) 
Return true if x equals y. 
exp( x ) 
Return the natural exponentiation of the parameter. 
exp2( x ) 
Return 2 raised to the power of the parameter. 
faceforward( N, I, Nref ) 
Return a vector pointing in the same direction as another. 
floor( x ) 
Find the nearest integer less than or equal to the parameter. 
fract( x ) 
Compute the fractional part of the argument. 
fwidth( x ) 
Return the sum of the absolute derivatives in x and y. 
inverseSqrt( x ) 
Return the inverse of the square root of the parameter. 
invert( x ) 
Invert an alpha parameter ( 1. – x ). 
length( x ) 
Calculate the length of a vector. 
lengthSq( x ) 
Calculate the squared length of a vector. 
log( x ) 
Return the natural logarithm of the parameter. 
log2( x ) 
Return the base 2 logarithm of the parameter. 
max( x, y ) 
Return the greater of two values. 
min( x, y ) 
Return the lesser of two values. 
mix( x, y, a ) 
Linearly interpolate between two values. 
negate( x ) 
Negate the value of the parameter ( x ). 
normalize( x ) 
Calculate the unit vector in the same direction as the original vector. 
oneMinus( x ) 
Return 1 minus the parameter. 
pow( x, y ) 
Return the value of the first parameter raised to the power of the second. 
pow2( x ) 
Return the square of the parameter. 
pow3( x ) 
Return the cube of the parameter. 
pow4( x ) 
Return the fourth power of the parameter. 
radians( degrees ) 
Convert a quantity in degrees to radians. 
reciprocal( x ) 
Return the reciprocal of the parameter (1/x). 
reflect( I, N ) 
Calculate the reflection direction for an incident vector. 
refract( I, N, eta ) 
Calculate the refraction direction for an incident vector. 
round( x ) 
Round the parameter to the nearest integer. 
saturate( x ) 
Constrain a value between 0 and 1. 
sign( x ) 
Extract the sign of the parameter. 
sin( x ) 
Return the sine of the parameter. 
smoothstep( e0, e1, x ) 
Perform Hermite interpolation between two values. 
sqrt( x ) 
Return the square root of the parameter. 
step( edge, x ) 
Generate a step function by comparing two values. 
tan( x ) 
Return the tangent of the parameter. 
transformDirection( dir, matrix ) 
Transform the direction of a vector by a matrix and then normalize the result. 
trunc( x ) 
Truncate the parameter, removing the fractional part. 
const value = float( 1 ); // It's possible use `value.abs()` too. const positiveValue = abs( value ); // output: 1
Inputs
Attributes
Name  Description  Type 

attribute( name, type = null, default = null ) 
Getting geometry attribute using name and type.  any 
uv( index = 0 ) 
UV attribute named uv + index . 
vec2 
vertexColor( index = 0 ) 
Vertex color node for the specified index.  color 
Position
Name  Description  Type 

positionGeometry 
Position attribute of geometry.  vec3 
positionLocal 
Local variable for position.  vec3 
positionWorld 
World position.  vec3 
positionWorldDirection 
Normalized world direction.  vec3 
positionView 
View position.  vec3 
positionViewDirection 
Normalized view direction.  vec3 
positionLocal
represents the position after modifications made byskinning
,morpher
, etc.
Normal
Name  Description  Type 

normalGeometry 
Normal attribute of geometry.  vec3 
normalLocal 
Local variable for normal.  vec3 
normalView 
Normalized view normal.  vec3 
normalWorld 
Normalized world normal.  vec3 
transformedNormalView 
Transformed normal in view space.  vec3 
transformedNormalWorld 
Normalized transformed normal in world space.  vec3 
transformedClearcoatNormalView 
Transformed clearcoat normal in view space.  vec3 
transformed*
represents the normal after modifications made byskinning
,morpher
, etc.
Tangent
Name  Description  Type 

tangentGeometry 
Tangent attribute of geometry.  vec4 
tangentLocal 
Local variable for tangent.  vec3 
tangentView 
Normalized view tangent.  vec3 
tangentWorld 
Normalized world tangent.  vec3 
transformedTangentView 
Transformed tangent in view space.  vec3 
transformedTangentWorld 
Normalized transformed tangent in world space.  vec3 
Bitangent
Name  Description  Type 

bitangentGeometry 
Normalized bitangent in geometry space.  vec3 
bitangentLocal 
Normalized bitangent in local space.  vec3 
bitangentView 
Normalized bitangent in view space.  vec3 
bitangentWorld 
Normalized bitangent in world space.  vec3 
transformedBitangentView 
Normalized transformed bitangent in view space.  vec3 
transformedBitangentWorld 
Normalized transformed bitangent in world space.  vec3 
Camera
Name  Description  Type 

cameraNear 
Near plane distance of the camera.  float 
cameraFar 
Far plane distance of the camera.  float 
cameraLogDepth 
Logarithmic depth value for the camera.  float 
cameraProjectionMatrix 
Projection matrix of the camera.  mat4 
cameraProjectionMatrixInverse 
Inverse projection matrix of the camera.  mat4 
cameraViewMatrix 
View matrix of the camera.  mat4 
cameraWorldMatrix 
World matrix of the camera.  mat4 
cameraNormalMatrix 
Normal matrix of the camera.  mat3 
cameraPosition 
World position of the camera.  vec3 
Texture
Name  Description  Type 

texture( texture, uv = uv(), level = null ) 
Retrieves texels from a texture.  vec4 
cubeTexture( texture, uvw = reflectVector, level = null ) 
Retrieves texels from a cube texture.  vec4 
triplanarTexture( textureX, textureY = null, textureZ = null, scale = float( 1 ), position = positionLocal, normal = normalLocal ) 
Computes texture using triplanar mapping based on provided parameters.  vec4 
Model
Name  Description  Type 

modelDirection 
Direction of the model.  vec3 
modelViewMatrix 
View matrix of the model.  mat4 
modelNormalMatrix 
Normal matrix of the model.  mat4 
modelWorldMatrix 
World matrix of the model.  mat4 
modelPosition 
Position of the model.  vec3 
modelScale 
Scale of the model.  vec3 
modelViewPosition 
View position of the model.  vec3 
modelWorldMatrixInverse 
Inverse world matrix of the model.  mat4 
Utils
Reflect
Name  Description  Type 

reflectView 
Computes reflection direction in view space.  vec3 
reflectVector 
Transforms the reflection direction to world space.  vec3 
UV
Name  Description  Type 

matcapUV 
UV coordinates for matcap material computation.  vec2 
rotateUV( uv, rotation, centerNode = vec2( 0.5 ) ) 
Rotates UV coordinates around a center point.  vec2 
spritesheetUV( count, uv = uv(), frame = float( 0 ) ) 
Computes UV coordinates for a sprite sheet based on the number of frames, UV coordinates, and frame index.  vec2 
equirectUV( direction = positionWorldDirection ) 
Computes UV coordinates for equirectangular mapping based on the direction vector.  vec2 
Remap
Variable  Description  Type 

remap 
Remaps a value from one range to another.  any 
remapClamp 
Remaps a value from one range to another, with clamping.  any 
Random
Variable  Description  Type 

hash( seed ) 
Generates a hash value in the range [ 0, 1 ] from the given seed.  float 
range( min, max ) 
Generates a range attribute of values between min and max. 
any 
Oscillators
Variable  Description  Type 

oscSine( timer = timerGlobal ) 
Generates a sine wave oscillation based on a timer.  float 
oscSquare( timer = timerGlobal ) 
Generates a square wave oscillation based on a timer.  float 
oscTriangle( timer = timerGlobal ) 
Generates a triangle wave oscillation based on a timer.  float 
oscSawtooth( timer = timerGlobal ) 
Generates a sawtooth wave oscillation based on a timer.  float 
Packing
Variable  Description  Type 

directionToColor( value ) 
Converts direction vector to color.  color 
colorToDirection( value ) 
Converts color to direction vector.  vec3 
Functions
.toVar( name = null )
To create a variable from a node use .toVar()
.
The first parameter is used to add a name to it, otherwise the node system will name it automatically, it can be useful in debugging or access using wgslFn
.
const uvScaled = uv().mul( 10 ).toVar(); material.colorNode = texture( map, uvScaled );
varying( node, name = null )
Let’s suppose you want to optimize some calculation in the vertex stage
but are using it in a slot like material.colorNode
.
For example:
// multiplication will be executed in vertex stage const normalView = varying( modelNormalMatrix.mul( normalLocal ) ); // normalize will be executed in fragment stage // because .colorNode is fragment stage slot as default material.colorNode = normalView.normalize();
The first parameter of varying
modelNormalMatrix.mul( normalLocal )
will be executed in vertex stage
, and the return from varying()
will be a varying
as we are used in WGSL/GLSL, this can optimize extra calculations in the fragment stage
. The second parameter allows you to add a custom name to varying
.
If varying()
is added only to .positionNode
, it will only return a simple variable and varying will not be created.
Transitioning common GLSL properties to TSL
GLSL  TSL  Type 

position 
positionGeometry 
vec3 
transformed 
positionLocal 
vec3 
transformedNormal 
normalLocal 
vec3 
vWorldPosition 
positionWorld 
vec3 
vColor 
vertexColor() 
vec3 
vUv  uv

uv() 
vec2 
vNormal 
normalView 
vec3 
viewMatrix 
cameraViewMatrix 
mat4 
modelMatrix 
modelWorldMatrix 
mat4 
modelViewMatrix 
modelViewMatrix 
mat4 
projectionMatrix 
cameraProjectionMatrix 
mat4 
diffuseColor 
material.colorNode 
vec4 
gl_FragColor 
material.fragmentNode 
vec4 