A simple, template literals-based preprocessor for WGSL shaders

Overview

WGSL Preprocessor

This library provides a dirt-simple way of adding simple preprocessor macros to your WGSL shaders via tagged templates. It supports:

  • #if
  • #elif
  • #else
  • #endif

Most other typical preprocessor functionality can be supported via JavaScript's template literals.

Installation

You can install from npm:

npm install wgls-preprocessor

And then import into your code as a standard ES6 module:

import { wgsl } from './node-modules/wgsl-preprocessor/wgsl-preprocessor.js';

Or use without an install step by loading it from a CDN like jsdelivr:

import { wgsl } from 'https://cdn.jsdelivr.net/npm/[email protected]/wgsl-preprocessor.js';

Or, you know, just copy and paste the contents of wgsl-preprocessor.js where ever is convenient for you. It's less than a 100 lines of code, we really don't need to overthink it!

Usage

Import the wgsl symbol from wherever you've installed wgsl-preprocessor.js and use it as a tag for a template literal string:

import { wgsl } from 'https://cdn.jsdelivr.net/npm/[email protected]/wgsl-preprocessor.js';

function getDebugShader(sRGB = false) {
  return wgsl`
  @stage(fragment)
  fn main() -> @location(0) vec4<f32> {
    let color = vec4(1.0, 0.0, 0.0, 1.0);
  #if ${sRGB}
    let rgb = pow(color.rgb, vec3(1.0 / 2.2));
    return vec4(rgb, color.a);
  #else
    return color;
  #endif
  }`;
}
`

When using #if or #elif the preprocessor symbol must be followed by a substitution expression that will be evaluated as a boolean.

wgsl`
  #if ${someVar}         // Valid
  #endif

  #if ${x > 5}           // Valid
  #endif

  #if ${someFunction()}  // Valid
  #endif

  #if true               // Invalid
  #endif

  #if 1                  // Invalid
  #endif
`;

If the result of the expression is truthy then the string contents between the opening and closing tags will be returned as part of the string, otherwise it will be omitted.

const x = 1;
const source = wgsl`
#if ${x < 3}
  let a = 1;
#endif

#if ${x > 3}
  let b = 2;
#endif

#if ${x == 3}
  let c = 3;
#else
  let c = 0;
#endif

#if ${x == 4}
  let d = 4;
#elif ${x == 1}
  let d = 1;
#else
  let d = 0;
#endif
`;

// source will be:
// let a = 1
//
//
// let c = 0;
//
// let d = 1;

#if/#elif statements may be nested any number of levels deep:

wgsl`
#if ${shadowsEnabled}
  #if ${lightType == 'point'}
    let shadowAmount = computePointLightShadow();
  #elif ${lightType == 'spot'}
    let shadowAmount = computeSpotLightShadow();
  #else
    let shadowAmount = computeDirectionalShadow();
  #endif
  lightFactor = lightFactor - shadowAmount;
#endif
`;

And any number of #elifs may be chained:

wgsl`
#if ${sampleCount == 1}
  var sampleOffsets : array<vec2<f32>, 1> = array<vec2<f32>, 1>(
    vec2(0.0, 0.0)
  );
#elif ${sampleCount == 2}
  var sampleOffsets : array<vec2<f32>, 2> = array<vec2<f32>, 2>(
    vec2(-0.5, -0.5), vec2(0.5, 0.5)
  );
#elif ${sampleCount == 4}
  var sampleOffsets : array<vec2<f32>, 4> = array<vec2<f32>, 4>(
    vec2(-0.5, -0.5), vec2(-0.5, 0.5), vec2(0.5, -0.5), vec2(0.5, 0.5),
  );
#elif ${sampleCount == 8}
  // Etc...
#endif
`;

Why no #define?

If you need something to approximate a #define statement from other preprocessors, simply use JavaScript's built-in substitution expressions! You don't even need the wgsl tag!

const ambientFactor = 1.0;
const sampleCount = 2;

const source = `
  let ambientFactor = f32(${ambientFactor});

  for (var i = 0u; i < ${sampleCount}u; i = i + 1u) {
    // Etc...
  }
`;

But of course, they play nicely with the wgsl tag too:

const useApproximateSRGB = true;
const approxGamma = 2.2;

export const colorConversions = wgsl`
  fn linearTosRGB(linear : vec3<f32>) -> vec3<f32> {
    #if ${useApproximateSRGB}
      let INV_GAMMA = 1.0 / ${approxGamma};
      return pow(linear, vec3(INV_GAMMA));
    #else
      if (all(linear <= vec3(0.0031308))) {
        return linear * 12.92;
      }
      return (pow(abs(linear), vec3(1.0/2.4)) * 1.055) - vec3(0.055);
    #endif
  }
`;
You might also like...

This template is for generating a .NET C# wrapper for the RabbitMQ client based on your AsyncAPI document.

This template is for generating a .NET C# wrapper for the RabbitMQ client based on your AsyncAPI document.

.NET C# RabbitMQ template This is a .NET C# RabbitMQ template for the AsyncAPI generator This template is for generating a .NET C# wrapper for the Rab

Dec 21, 2022

Template for generating rust-based native projects

Speedy NAPI-RS template Use this template Click use this template above, then find and replace speedy-sourcemap to your desired naming. Setup Rust too

Jan 21, 2022

A free simple responsive HTML email template

A free simple responsive HTML email template

Free Responsive HTML Email Template Sometimes all you want is a really simple responsive HTML email template with a clear call-to-action button. Here

Dec 30, 2022

Simple NextJS Project Template to write less boilerplate code when starting a new Next JS Project

Simple NextJS Project Template to write less boilerplate code when starting a new Next JS Project

Feb 12, 2022

A simple element template chooser for properties-panel = 1

A simple element template chooser for properties-panel >= 1

A simple element template chooser for properties-panel = 1

May 30, 2022

A simple template to get started with a non-profit website.

A simple template to get started with a non-profit website.

Next.js Non-Profit Website A non-profit website template powered by the Cosmic headless CMS. Uses Next.js, Tailwind CSS, and Stripe for donation payme

Sep 6, 2022

A simple and safe template engine.

A simple and safe template engine.

TagScript A simple and safe template engine. Description TagScript is a drop in easy to use string interpreter that lets you provide users with ways o

Dec 31, 2022

A simple self-use pull template project

A simple self-use pull template project

English | 简体中文 temp_manage A simple self-use pull template project. Supports github, gitlab, Bitbucket If you have an excellent template project, you

Jul 21, 2022

Dashboard skeleton Simple and fast dashboard skeleton template

Dashboard skeleton Simple and fast dashboard skeleton template. Installation npm install --save dashboard-skeleton-compostrap Version 1x built on Boo

Aug 23, 2022
Owner
Brandon Jones
WebGPU/WebXR at Google
Brandon Jones
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
A JavaScript object getter and setter with string literals ⚡

objectio (object + io) A JavaScript object getter and setter with string literals ⚡ Usage import { get, set } from 'objectio'; const obj = { a: 1,

Shiono Yoshihide 2 Sep 14, 2022
A Typescript Hardhat-based template to develop evm-based smart contracts with all the tooling you need.

EVM-based Smart Contract Scaffold A Typescript Hardhat-based template to develop evm-based smart contracts with all the tooling you need. Features Use

Flair 8 Oct 24, 2022
Discord.js bot starter template, Slash Commands only (Raymond forced me to make a bot template)

boat-template Raymond forced me to make a bot template This template is meant is just for stupidness ig Getting Started Rename the config.example.ts t

Drxckzyz tha idiot 3 Jan 5, 2022
A fully-fledged Hardhat project template based on TypeScript.

Fully-Fledged Hardhat Project Template Based on TypeScript Installation It is recommended to install Yarn through the npm package manager, which comes

Pascal Marco Caversaccio 75 Dec 21, 2022
AMP: is a fast admin dashboard template based on FastAPI

AMP: is a fast admin dashboard template based on FastAPI Introduction AMP: is a fast admin dashboard template based on FastAPI. The project uses its o

Denis Bazarnov 17 Jan 1, 2023
Scientific blog template based on theaisummer.com

Scientific blog template based on AI Summer The current template can be used for scientific blogs as it supports a wide variety of necessary component

AI Summer 65 Jan 1, 2023
Titlebar template for Electron-based desktop apps

Electron-Titlebar-Template CSS based MacOs UI Titlebar Template for Electron-based desktop apps Titlebar can: minimize maximize fullscreen close You c

null 3 May 18, 2022