Getting started

Getting started

TinyFX programs use the .tfx extension. The native CLI compiles source and opens a winit window; the browser package exposes the same compiler and a WebGPU runner for a canvas.

Native CLI

Build the debug CLI from the repository root:

cargo build -p tinyfx-cli
 
# Type-check without opening a window.
./target/debug/tfx check examples/fundamentals/cube/main.cube.tfx
 
# Run a program. --watch recompiles source changes.
./target/debug/tfx run examples/fundamentals/cube/main.cube.tfx --watch
 
# Format source, or make formatting part of CI.
./target/debug/tfx fmt std examples
./target/debug/tfx fmt std examples --check

tfx run accepts source or a compiled .tfxb program. Asset paths in a native program are resolved relative to that entry file, rather than the shell working directory. With .tfxb --watch, replacing the artifact reloads its bytecode directly; source watch mode instead recompiles the entry and imports.

First program

Create hello.tfx:

UV gradient

A small example embedded directly in this guide.
fn loop() {
draw(shader {
  frag {
    out.color = (in.uv.x, in.uv.y, 0.7, 1.0);
  }
});
}
Preview

Then run it:

./target/debug/tfx run hello.tfx

setup() is optional and runs once before the first frame. loop() is also optional: a program that draws in setup or global initialization can make a static image. Read runtime lifecycle before building stateful applications.

Inspecting compiler output

# Write WGSL modules for shaders and compute kernels.
./target/debug/tfx build hello.tfx --emit-wgsl out/wgsl
 
# Write a versioned bytecode program for the Rust VM.
./target/debug/tfx build hello.tfx -o hello.tfxb
 
# Write readable generated TypeScript/ESM CPU code.
./target/debug/tfx build hello.tfx --emit-typescript out/hello.ts
 
# Write compiler-authored physical WebGPU pass modules.
./target/debug/tfx build hello.tfx --emit-webgpu out/webgpu
 
# Explain static lowering decisions without acquiring a GPU.
./target/debug/tfx check hello.tfx --explain-passes
./target/debug/tfx build hello.tfx --explain-passes=json

The emitted TypeScript is a separate execution target, not a decompilation of VM bytecode. It depends on @tinyfx-lang/runtime; see compilation targets and artifact reference.

Browser playground

The workspace uses pnpm:

pnpm install
pnpm --filter tinyfx build:wasm
pnpm --dir apps/playground dev

The browser build is split deliberately. The compiler/editor artifact provides checking and editor features; the runner artifact is dynamically loaded only after valid source has compiled to .tfxb. The playground's development command builds missing artifacts as needed.

For an embedding, the tinyfx package accepts source, optional imported files, assets, and a canvas. It owns canvas backing-store sizing, so CSS should size the canvas and application code should not set canvas.width or canvas.height while it is running:

import { run } from "tinyfx";
 
await run(canvas, source, {
  imports: { "lib/palette.tfx": paletteSource },
  assets: { "assets/photo.png": photoBytes },
});

See assets in browser embeddings for the resolver contract.

For an application build, install the facade directly or add the Vite plugin when .tfx files should be importable modules:

npm install tinyfx
npm install tinyfx @tinyfx-lang/vite

Generated TypeScript/ESM consumers install @tinyfx-lang/runtime instead of the WASM facade. All three packages share the 0.1.x alpha release line, while generated-core/platform API 1.0, physical pass blueprint 1.0, and .tfxb format v1 remain independently versioned contracts.

Where to go next

The shortest route into real work is language, then GPU programming. The examples directory is intentionally useful documentation too: feedback, fluid, hybrid_depth, buffers, volumetric_clouds, and webcam_video exercise distinct runtime paths.