shaderkit

0.5.0 • Public • Published

Size Version Downloads

shaderkit

Tools and IntelliSense for GLSL and WGSL.

Table of Contents

Installation

To install, use your preferred package manager:

npm install shaderkit
yarn add shaderkit
pnpm add shaderkit

Or, use a CDN:

<script type="module">
  import * as shaderkit from 'https://unpkg.com/shaderkit'
</script>

Tokenize

Tokenizes a string of GLSL or WGSL code, returning an array of Token objects, where each Token object represents a single syntax feature in the input code.

interface Token {
  type: 'whitespace' | 'comment' | 'symbol' | 'bool' | 'float' | 'int' | 'identifier' | 'keyword'
  value: string
}
GLSL Example
import { tokenize } from 'shaderkit'

const code = 'void main() { gl_Position = vec4(0, 0, 0, 1); }'
const tokens = tokenize(code)

console.log(tokens)

The output of the above code will be:

[
  { "type": "keyword", "value": "void" },
  { "type": "whitespace", "value": " " },
  { "type": "identifier", "value": "main" },
  { "type": "symbol", "value": "(" },
  { "type": "symbol", "value": ")" },
  { "type": "whitespace", "value": " " },
  { "type": "symbol", "value": "{" },
  { "type": "whitespace", "value": " " },
  { "type": "keyword", "value": "gl_Position" },
  { "type": "whitespace", "value": " " },
  { "type": "symbol", "value": "=" },
  { "type": "whitespace", "value": " " },
  { "type": "keyword", "value": "vec4" },
  { "type": "symbol", "value": "(" },
  { "type": "int", "value": "0" },
  { "type": "symbol", "value": "," },
  { "type": "whitespace", "value": " " },
  { "type": "int", "value": "0" },
  { "type": "symbol", "value": "," },
  { "type": "whitespace", "value": " " },
  { "type": "int", "value": "0" },
  { "type": "symbol", "value": "," },
  { "type": "whitespace", "value": " " },
  { "type": "int", "value": "1" },
  { "type": "symbol", "value": ")" },
  { "type": "symbol", "value": ";" },
  { "type": "whitespace", "value": " " },
  { "type": "symbol", "value": "}" }
]
WGSL Example
import { tokenize } from 'shaderkit'

const code = '@vertex fn main() -> @builtin(position) vec4<f32> { return vec4(0, 0, 0, 1); }'
const tokens = tokenize(code)

console.log(tokens)

The output of the above code will be:

[
  { "type": "symbol", "value": "@" },
  { "type": "keyword", "value": "vertex" },
  { "type": "whitespace", "value": " " },
  { "type": "keyword", "value": "fn" },
  { "type": "whitespace", "value": " " },
  { "type": "identifier", "value": "main" },
  { "type": "symbol", "value": "(" },
  { "type": "symbol", "value": ")" },
  { "type": "whitespace", "value": " " },
  { "type": "symbol", "value": "->" },
  { "type": "whitespace", "value": " " },
  { "type": "symbol", "value": "@" },
  { "type": "keyword", "value": "builtin" },
  { "type": "symbol", "value": "(" },
  { "type": "keyword", "value": "position" },
  { "type": "symbol", "value": ")" },
  { "type": "whitespace", "value": " " },
  { "type": "keyword", "value": "vec4" },
  { "type": "symbol", "value": "<" },
  { "type": "keyword", "value": "f32" },
  { "type": "symbol", "value": ">" },
  { "type": "whitespace", "value": " " },
  { "type": "symbol", "value": "{" },
  { "type": "whitespace", "value": " " },
  { "type": "keyword", "value": "return" },
  { "type": "whitespace", "value": " " },
  { "type": "keyword", "value": "vec4" },
  { "type": "symbol", "value": "(" },
  { "type": "int", "value": "0" },
  { "type": "symbol", "value": "," },
  { "type": "whitespace", "value": " " },
  { "type": "int", "value": "0" },
  { "type": "symbol", "value": "," },
  { "type": "whitespace", "value": " " },
  { "type": "int", "value": "0" },
  { "type": "symbol", "value": "," },
  { "type": "whitespace", "value": " " },
  { "type": "int", "value": "1" },
  { "type": "symbol", "value": ")" },
  { "type": "symbol", "value": ";" },
  { "type": "whitespace", "value": " " },
  { "type": "symbol", "value": "}" }
]

The following are the supported token types and their descriptions:

Type Description
whitespace A sequence of one or more whitespace characters.
comment A single-line or multi-line comment.
symbol A symbol, such as an operator or punctuation mark.
bool A boolean value, either true or false.
float A floating-point number, represented by a sequence of digits and symbols.
int An integer number, represented by a sequence of digits.
identifier A user-defined identifier, such as a variable name or function name.
keyword A keyword reserved by the language, such as if, else, for, etc.

Minify

Minifies a string of GLSL or WGSL code, returning a minified version of the input code.

const minified: string = minify(code: string, {
  /** Whether to rename variables. Will call a MangleMatcher if specified. Default is `false`. */
  mangle: boolean | ((token: Token, index: number, tokens: Token[]) => boolean)
  /** A map to read and write renamed variables to when mangling. */
  mangleMap: Map<string, string>
  /** Whether to rename external variables such as uniforms or varyings. Default is `false`. */
  mangleExternals: boolean
})

To shared mangled interfaces when using mangleExternal, declare and re-use a mangleMap between shaders:

const options = { mangle: true, mangleExternals: true, mangleMap: new Map() }

// #version 300 es\nin vec2 a;out vec2 b;void main(){b=a;}
minify(`#version 300 es\nin vec2 sstt;out vec2 c;void main(){c=sstt;}`, options)

// #version 300 es\nin vec2 b;out vec4 a[gl_MaxDrawBuffers];void main(){a[0]=b.sstt;}
minify(`#version 300 es\nin vec2 c;out vec4 data[gl_MaxDrawBuffers];void main(){data[0]=c.sstt;}`, options)

Parse

Parses a string of GLSL (WGSL is WIP) code into an AST.

const ast: Program = parse(code: string)

Generate

Generates a string of GLSL (WGSL is WIP) code from an AST.

const code: string = generate(program: Program, {
  target: 'GLSL' // | 'WGSL'
})

Visit

Recurses through an AST, calling a visitor object on matching nodes.

visit(
  program: Program,
  visitors: {
    Program: {
      enter(node, ancestors) {
        // Called before any descendant nodes are processed
      },
      exit(node, ancestors) {
        // Called after all nodes are processed
      }
    },
    Identifier(node, ancestors) {
      // Called before any descendant nodes are processed (alias to enter)
    }
  } satisfies Visitors
)

AST

An Abstract Syntax Tree loosely based on ESTree for GLSL and WGSL grammars.

Node Objects

AST nodes extend Node objects which implement the following abstract interface:

interface Node {
  type: string
}

The type field is a string representing the AST variant type which can determine the interface a node implements.

Identifier

A variable identifier.

interface Identifier extends Node {
  type: 'Identifier'
  name: string
}

Literal

A shader literal representing a bool, float, int, or uint type.

interface Literal extends Node {
  type: 'Literal'
  value: string
}

ArraySpecifier

An array and its dimensions.

interface ArraySpecifier extends Node {
  type: 'ArraySpecifier'
  typeSpecifier: Identifier
  dimensions: (Literal | Identifier | null)[]
}

Program

Represents the root of an AST.

interface Program extends Node {
  type: 'Program'
  body: Statement[]
}

ExpressionStatement

An expression as a standalone statement.

interface ExpressionStatement extends Node {
  type: 'ExpressionStatement'
  expression: Expression
}

BlockStatement

A block statement.

interface BlockStatement extends Node {
  type: 'BlockStatement'
  body: Statement[]
}

DiscardStatement

A discard statement in fragment shaders.

interface DiscardStatement extends Node {
  type: 'DiscardStatement'
}

PreprocessorStatement

A GLSL preprocessor statement with an optional value.

interface PreprocessorStatement extends Node {
  type: 'PreprocessorStatement'
  name: string
  value: Expression[] | null
}

PrecisionQualifierStatement

A GLSL precision qualifier statement.

interface PrecisionQualifierStatement extends Node {
  type: 'PrecisionQualifierStatement'
  precision: PrecisionQualifier
  typeSpecifier: Identifier
}

InvariantQualifierStatement

A GLSL invariant qualifier statement.

interface InvariantQualifierStatement extends Node {
  type: 'InvariantQualifierStatement'
  typeSpecifier: Identifier
}

LayoutQualifierStatement

A layout qualifier statement.

interface LayoutQualifierStatement extends Node {
  type: 'LayoutQualifierStatement'
  layout: Record<string, string | boolean>
  qualifier: StorageQualifier
}

ReturnStatement

A return statement with an optional argument.

interface ReturnStatement extends Node {
  type: 'ReturnStatement'
  argument: Expression | null
}

BreakStatement

A break statement.

interface BreakStatement extends Node {
  type: 'BreakStatement'
}

ContinueStatement

A continue statement.

interface ContinueStatement extends Node {
  type: 'ContinueStatement'
}

IfStatement

An if-else statement.

interface IfStatement extends Node {
  type: 'IfStatement'
  test: Expression
  consequent: Statement
  alternate: Statement | null
}

SwitchStatement

A switch statement.

interface SwitchStatement extends Node {
  type: 'SwitchStatement'
  discriminant: Expression
  cases: SwitchCase[]
}

SwitchCase

A switch-case statement. test is null for a default case.

interface SwitchCase extends Node {
  type: 'SwitchCase'
  test: Expression | null
  consequent: Statement[]
}

WhileStatement

A while statement.

interface WhileStatement extends Node {
  type: 'WhileStatement'
  test: Expression
  body: Statement
}

DoWhileStatement

A do-while statement.

interface DoWhileStatement extends Node {
  type: 'DoWhileStatement'
  body: Statement
  test: Expression
}

ForStatement

A for statement.

interface ForStatement extends Node {
  type: 'ForStatement'
  init: VariableDeclaration | Expression | null
  test: Expression | null
  update: Expression | null
  body: Statement
}

FunctionDeclaration

A function declaration. body is null for overloads.

interface FunctionDeclaration extends Node {
  type: 'FunctionDeclaration'
  id: Identifier
  qualifiers: PrecisionQualifier[]
  typeSpecifier: Identifier | ArraySpecifier
  params: FunctionParameter[]
  body: BlockStatement | null
}

FunctionParameter

A function parameter within a function declaration.

interface FunctionParameter extends Node {
  type: 'FunctionParameter'
  id: Identifier | null
  qualifiers: (ConstantQualifier | ParameterQualifier | PrecisionQualifier)[]
  typeSpecifier: Identifier | ArraySpecifier
}

VariableDeclaration

A variable declaration.

interface VariableDeclaration extends Node {
  type: 'VariableDeclaration'
  declarations: VariableDeclarator[]
}

VariableDeclarator

A variable declarator within a variable declaration.

interface VariableDeclarator extends Node {
  type: 'VariableDeclarator'
  id: Identifier
  qualifiers: (ConstantQualifier | InterpolationQualifier | StorageQualifier | PrecisionQualifier)[]
  typeSpecifier: Identifier | ArraySpecifier
  layout: Record<string, string | boolean> | null
  init: Expression | null
}

StructuredBufferDeclaration

A buffer interface declaration with optional layout and qualifiers.

interface StructuredBufferDeclaration extends Node {
  type: 'StructuredBufferDeclaration'
  id: Identifier | null
  qualifiers: (InterfaceStorageQualifier | MemoryQualifier | LayoutQualifier)[]
  typeSpecifier: Identifier | ArraySpecifier
  layout: Record<string, string | boolean> | null
  members: VariableDeclaration[]
}

StructDeclaration

A struct declaration. Can be used as a type or constructor.

interface StructDeclaration extends Node {
  type: 'StructDeclaration'
  id: Identifier
  members: VariableDeclaration[]
}

ArrayExpression

An array initialization expression.

interface ArrayExpression extends Node {
  type: 'ArrayExpression'
  typeSpecifier: ArraySpecifier
  elements: Expression[]
}

UnaryExpression

A unary expression with a left or right handed operator.

interface UnaryExpression extends Node {
  type: 'UnaryExpression'
  operator: UnaryOperator
  prefix: boolean
  argument: Expression
}

UnaryOperator

type UnaryOperator = '-' | '+' | '!' | '~'

UpdateExpression

An update expression with an optionally prefixed operator.

interface UpdateExpression extends Node {
  type: 'UpdateExpression'
  operator: UpdateOperator
  argument: Expression
  prefix: boolean
}

UpdateOperator

type UpdateOperator = '++' | '--'

BinaryExpression

A binary expression with a left and right operand.

interface BinaryExpression extends Node {
  type: 'BinaryExpression'
  operator: BinaryOperator
  left: Expression
  right: Expression
}

BinaryOperator

type BinaryOperator =
  | '=='
  | '!='
  | '<'
  | '<='
  | '>'
  | '>='
  | '<<'
  | '>>'
  | '+'
  | '-'
  | '*'
  | '/'
  | '%'
  | '|'
  | '^'
  | '&'

AssignmentExpression

An assignment expression.

interface AssignmentExpression extends Node {
  type: 'AssignmentExpression'
  operator: AssignmentOperator
  left: Expression
  right: Expression
}

AssignmentOperator

type AssignmentOperator = '=' | '+=' | '-=' | '*=' | '/=' | '%=' | '<<=' | '>>=' | '>>>=' | '|=' | '^=' | '&='

LogicalExpression

A logical operation between two expressions.

interface LogicalExpression extends Node {
  type: 'LogicalExpression'
  operator: LogicalOperator
  left: Expression
  right: Expression
}

LogicalOperator

type LogicalOperator = '||' | '&&' | '^^'

MemberExpression

A member expression.

interface MemberExpression extends Node {
  type: 'MemberExpression'
  object: Expression
  property: Expression
  computed: boolean
}

ConditionalExpression

A conditional expression or ternary.

interface ConditionalExpression extends Node {
  type: 'ConditionalExpression'
  test: Expression
  alternate: Expression
  consequent: Expression
}

CallExpression

A function call expression or struct initialization.

interface CallExpression extends Node {
  type: 'CallExpression'
  callee: Expression
  arguments: Expression[]
}

Package Sidebar

Install

npm i shaderkit

Weekly Downloads

13

Version

0.5.0

License

MIT

Unpacked Size

148 kB

Total Files

17

Last publish

Collaborators

  • codyjasonbennett