# Is there a description of the tsl commands?

**URL:** <https://discourse.threejs.org/t/is-there-a-description-of-the-tsl-commands/54171>\
**Category:** Questions\
**Tags:** threejs-shader-language\
**Created:** [July 21, 2023, 9:24pm UTC](https://discourse.threejs.org/t/is-there-a-description-of-the-tsl-commands/54171 "2023-07-21T21:24:46Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Attila\_Schroeder](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/attila_schroeder/32/36097_2.png) [@Attila\_Schroeder](https://discourse.threejs.org/u/Attila_Schroeder)\
**Post date:** [July 21, 2023, 9:24pm UTC](https://discourse.threejs.org/t/is-there-a-description-of-the-tsl-commands/54171/1 "2023-07-21T21:24:46Z")

</div>

Is there a description of how mathematical commands look like in tslFn functions?

When I use Math.sin(x) or sin(x) I get a black screen. Instead of \* I have to use mul and instead of + add.  
For more complex formulas I imagine this to be less practical.

I want to translate this glsl code into a tslFn code.

```javascript
ivec2 texSize = textureSize(vertexTexture, 0);
float texWidth = float(texSize.x);
float texHeight = float(texSize.y);
int colIdx = int(floor(idx / texWidth));
int rowIdx = int(mod(idx, texHeight));
vec3 posData = texelFetch(vertexTexture, ivec2(rowIdx, colIdx), 0).rgb;

```

I understand how to use uniforms and attributes. Now all I need is a description of the three-shader-language

```javascript
this.customShaderParams = {
   vertexTexture: texture( DataTextureVertices ),
   time: uniform(this.dt),
   position: attribute('position'),
}

const ShaderNodePosition = tslFn((params) => {

//what is the tsl command for textureSize?
//what is the tsl command for floor?
//what is the tsl command for mod?
//what is the tsl command for texelFetch?

});

const material = new MeshBasicNodeMaterial();
material.positionNode = ShaderNodePosition(this.customShaderParams);				

```

---

<div class="post-metadata">

**Author:** ![mjurczyk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mjurczyk/32/10995_2.png) [@mjurczyk](https://discourse.threejs.org/u/mjurczyk)\
**Post date:** [July 21, 2023, 10:28pm UTC](https://discourse.threejs.org/t/is-there-a-description-of-the-tsl-commands/54171/2 "2023-07-21T22:28:46Z")

</div>

Slight off-topic - but is it just me who’s absolutely out of sync, or is `three-shader-language` something experimental / custom / new / hidden within source? First time I hear a reference to it, nothing in here / docs / source I could find about it 👀

---

<div class="post-metadata">

**Author:** ![Attila\_Schroeder](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/attila_schroeder/32/36097_2.png) [@Attila\_Schroeder](https://discourse.threejs.org/u/Attila_Schroeder)\
**Post date:** [July 21, 2023, 10:43pm UTC](https://discourse.threejs.org/t/is-there-a-description-of-the-tsl-commands/54171/3 "2023-07-21T22:43:42Z")

</div>

tsl = three shader language  
or am I wrong?

In r155 “func” was replaced by “tslFn” or “wgslFn” depending on whether you want to work in tsl or wgsl language. I decided to get more involved with tsl, because if 3js is already trying so hard to develop an optimized node system with its own language, I would also like to understand it.

Hm… 🤔 but now that I had to think about wgslFn because of you, I could do it with that too, since there is enough documentation on wgsl.

But it would be nice to learn more about tsl

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [September 22, 2023, 7:00pm UTC](https://discourse.threejs.org/t/is-there-a-description-of-the-tsl-commands/54171/4 "2023-09-22T19:00:20Z")

</div>

There aren’t any docs yet, it’s all in this example:

[https://threejs.org/examples/#webgpu\_tsl\_editor](https://threejs.org/examples/#webgpu_tsl_editor)

Basically a way of writing WebGPU shaders with JavaScript instead of WGSL directly.

---

<div class="post-metadata">

**Author:** ![Attila\_Schroeder](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/attila_schroeder/32/36097_2.png) [@Attila\_Schroeder](https://discourse.threejs.org/u/Attila_Schroeder)\
**Post date:** [September 22, 2023, 7:27pm UTC](https://discourse.threejs.org/t/is-there-a-description-of-the-tsl-commands/54171/5 "2023-09-22T19:27:14Z")

</div>

I have now found out how the node system works and I can recreate everything I have done so far in WebGL in WGSL. I think it’s great. As for TSL, I’m just curious.  
I will close this point so that it no longer appears as an open question. The node system is really a very good thing, I like it.  
I think if I wanted I could also transfer my WGSL shaders to TSL as long as the corresponding functionality already exists in TSL. But I like wgsl and for very mathematical shaders I find \* instead of mul() and + instead of add() and so on more convenient.

---

<div class="post-metadata">

**Author:** ![trusktr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/trusktr/32/13726_2.png) [@trusktr](https://discourse.threejs.org/u/trusktr)\
**Post date:** [September 22, 2023, 7:51pm UTC](https://discourse.threejs.org/t/is-there-a-description-of-the-tsl-commands/54171/6 "2023-09-22T19:51:28Z")

</div>

> [@Attila\_Schroeder](#):
>
> I can recreate everything I have done so far in WebGL in WGSL

Interesting to know. Do the nodes cover every aspect of WGSL? Or do you write custom nodes using WGSL as well? Seems like TSL would be an alternative “syntax” for cases where you might write a new node.

I see how the operators are terser and less verbose. I wonder though, if the following would be of a substantial value that outweighs writing code in plain WGSL (thinking along the lines of glslify and reusable libs, but in this case JS code):

> [@Why TSL (three.js shading language) is so interesting!](https://discourse.threejs.org/t/why-tsl-three-js-shading-language-is-so-interesting/56306):
>
> TSL is a way of writing WebGPU shaders with JavaScript instead of WGSL directly. Example: [https://threejs.org/examples/#webgpu\_tsl\_editor](https://threejs.org/examples/#webgpu_tsl_editor) What I find interesting, which is not shown yet in any example, is the possibility of shipping “shader code” in the form of JavaScript modules and publishing them on NPM, then being able to import shader libs with standard JavaScript import syntax. f.e. import {someSpecialAnimationOrSomething} from 'my-cool-shader-lib' const finalColor = someSpecialAnimat…

---

<div class="post-metadata">

**Author:** ![Attila\_Schroeder](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/attila_schroeder/32/36097_2.png) [@Attila\_Schroeder](https://discourse.threejs.org/u/Attila_Schroeder)\
**Post date:** [September 22, 2023, 9:50pm UTC](https://discourse.threejs.org/t/is-there-a-description-of-the-tsl-commands/54171/7 "2023-09-22T21:50:41Z")

</div>

The nodes certainly do not cover the entire range of functions of WGSL. The “textureStore” node came with r156. Sunag kindly developed this when I asked for it and merged it into r156. But now with r157 there will be something else that will improve the work with it, the StorageTexture class. That’s really great. In my opinion, this makes DataTextures obsolete. With the node system as it currently is, I can do everything I did before in glsl.

Here is a wgsl example in r156 from me. But I will adapt that with r157, because the StorageTexture class that comes with r157 will be more practical than the THREE.Texture()

```javascript
const butterflyWGSL = wgslFn(`  

  fn computeWGSL(
      storageTex: texture_storage_2d<rgba8unorm, write>,
      index: u32,
      resolution: f32,
  ) -> void {

      var posX = index % u32(log2(resolution));
      var posY = index / u32(resolution);
      let indexUV = vec2u( posX, posY );
      let N: f32 = resolution;

      var k: f32 = (f32(posY) * N/pow(2, f32(posX) + 1)) % N;
      var twiddle: vec2<f32> = vec2<f32>(cos(2 * PI * k / N), sin(2 * PI * k / N));
      var butterflyspan: f32 = pow(2, f32(posX));
      var butterflywing: u32 = 0;

      if(f32(posY) % pow(2, f32(posX) + 1 ) < pow(2, f32(posX))){
        butterflywing = 1;
      }
      else{
        butterflywing = 0;
      }
      if(u32(posX) == 0){
         if(butterflywing == 1){
            textureStore(storageTex, indexUV, vec4f(twiddle.x, twiddle.y, f32(bitReverse(posY)), f32(bitReverse(posY + 1))));
         }
         else{
            textureStore(storageTex, indexUV, vec4f(twiddle.x, twiddle.y, f32(bitReverse(posY - 1)), f32(bitReverse(posY)) ));
         }
      }
      else{
         if(butterflywing == 1){
            textureStore(storageTex, indexUV, vec4f(twiddle.x, twiddle.y, f32(posY), f32(posY) + butterflyspan ));
         }
         else{
            textureStore(storageTex, indexUV, vec4f(twiddle.x, twiddle.y, f32(posY) - butterflyspan, f32(posY) ));
         }
      }
   }

   const PI: f32 = 3.141592653;

   fn bitReverse(value: u32) -> u32 {
      var numBits: u32 = 32u;
      var result: u32 = 0u;

      for(var i: u32 = 0u; i < numBits; i = i + 1u){
         result = result | (((value >> i) & 1u) << (numBits - 1u - i));  
      }
      return result;
   }    
`);

this.butterflyParams = {
	resolution: 512,
	workgroup_size: [1, 16, 1],
}

this.butterflyTexture = new THREE.Texture();
this.butterflyTexture.image = {width: Math.log2(this.butterflyParams.resolution), height: this.butterflyParams.resolution};
this.butterflyTexture.magFilter = this.butterflyTexture.minFilter = THREE.NearestFilter;

this.butterflyCall = butterflyWGSL({
	storageTex: textureStore(this.butterflyTexture),
	index: instanceIndex,
	resolution: this.butterflyParams.resolution,
});

this.computeButterfly = this.butterflyCall.compute(this.butterflyParams.resolution * this.butterflyParams.resolution);
this.renderer.compute(this.computeButterfly, this.butterflyParams.workgroup_size);

```

If you want to change uniforms as usual in glsl, you have to define them as such. In my case here, the “resolution: 512” in the params are a constant that cannot be changed.

Here I have a simple example of where I use the time. I can then use this as a uniform as usual:

https://codepen.io/Spiri0/embed/preview/vYQzMpL?default-tabs=js%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=vYQzMpL

The node system is already very advanced. And it is very well thought out. The developers have done a very good job 👍
