Skip to content

pfx

pfx’s path tracer on its neutral sample shot: a grey disc and a grey ring turning back and forth over a dark floor, in soft key, fill and rim light

pfx is a game and render engine in Rust, part of PITO MD: a live renderer for 60 fps at 4K, an offline path tracer with its own denoiser, physics, sound, input, mods and a scene editor, with scenes kept as plain TOML files. It is built to be fast, light and simple, and every number below was measured on this repository’s code.

Measured
Live renderer, 4K, neutral room 4.4 ms GPU a frame (p50), 4.8 ms p99, 0 dropped frames in 1,200
2D pass, 4K, 2,000 shots + 20,301 particles 0.39 ms GPU a frame
Path tracer, desk scene, 4K final, denoised 11.2 s, down from 40.4 s in v0.26.0
Denoiser, 4K 287 ms on the GPU
Empty game, stripped release binary 34.7 MB against Bevy’s 106.6 MB
Empty game, dependency crates 290 against Bevy’s 392

How each was measured is under The numbers.

Install it and make a first game: Install. Every command of the pfx tool: The pfx tool.

The live renderer drawing the engine’s neutral desk scene while the camera sways around it: a wooden desk with a lamp, a colour chart, a chrome ball, a red box and a white card, with shadows, reflections in the ball and steam rising.

The live renderer keeps 60 fps at 4K with shadows, baked light, TAA, text drawn from vector outlines, effects and dynamic resolution (Live renderer design). On the neutral room at 3840x2160 a frame costs 4.4 ms of GPU time at the median and 4.8 ms at p99, about a quarter of the 16.7 ms a 60 fps frame allows, and the CPU’s simulate-and-submit takes 1.8 ms at the median. It draws frames on demand: when only the camera drifts a desk frame costs 0.50 ms, and an idle scene costs nothing.

Bar chart, live frame time at 4K on the neutral room, lower is better: GPU p50 4.4 ms, p99 4.8 ms; CPU p50 1.8 ms, p99 10.5 ms; the 60 fps budget 16.7 ms.

The flat 2D pass draws sprites, text and particles for 2D games and overlays (The flat pass). At 4K, 2,000 shots and 20,301 particles cost 0.39 ms of GPU time a frame.

The flat 2D pass on a dark background: two long diagonal streams of orange, red and pale blue particles, about twenty thousand in all.

The engine’s neutral desk scene, path traced and denoised: a wooden desk in a beige room with a white lamp column, a colour chart, a chrome ball, a red box and a white card labelled Plate, a shelf on the wall above casting a soft shadow.

pfx-trace renders stills, clips and the light bake on the GPU (Tracer cameras and staging, Probe baking). It traces with hardware ray queries wherever the device offers them (Vulkan, DX12, Metal on Apple Silicon) and with its own BVH elsewhere, samples with Cycles’ tabulated Sobol sequence, and stops each pixel when it has converged. The desk above, at 4K, takes 11.2 s as a final and 2.8 s as a draft, denoising included.

Bar chart, path tracer on the desk scene at 4K, wall time in seconds, lower is better. Final: v0.26.0 40.4 s, v0.27.0 15.0 s, v0.32.0 11.2 s. Draft: v0.26.0 5.9 s, v0.27.0 2.5 s, v0.32.0 2.8 s.

The desk scene split down the middle: on the left, labelled 8 SPP, RAW, the path tracer’s grainy output after 8 samples a pixel; on the right, labelled PFX-DENOISE, the same frame clean.

pfx-denoise is Intel Open Image Denoise 2.5.1’s RT filter ported to wgpu compute: a traced colour with its albedo and normal go in, the clean colour comes out, equal to OIDN’s own output to about 1e-5 (The denoiser). A 4K frame takes 287 ms on the GPU. It runs on every pfx render final and draft, so a few samples a pixel are enough.

pfx edit on a new game made by pfx new: the outliner on the left lists the scene’s objects, lights and materials; the viewport in the middle shows the pfx mark and wordmark standing on a grid with the move gizmo on them; the inspector on the right shows the selected group’s position, rotation and scale; the log at the bottom says the scene opened with 4 objects, 10 materials and 1 light.

pfx edit and <game> edit open a scene in the editor, with an outliner, an inspector, gizmos, play in the viewport and live gameplay modules (pfx edit). Every edit is written back into the scene’s TOML in place, so a scene stays a text file you can diff and review. Its egui crates are reusable on their own (The editor crates):

The editor example: dragging a crate along x with the move gizmo in a 3D viewport, the scene’s TOML beside it with the crate’s table marked, its at value updating when the drag is released.

Rigid bodies, characters and world queries (Physics); mixing, streams and music (pfx-sound); keyboard, mouse and controllers behind one action map (Input); shots, emitters, a spawn director and input journals for arcade games (pfx_core::sim::shots: projectiles, emitters and followers, pfx_core::sim::director: what to spawn and when, from data, pfx_core::sim journal: a compact input log and headless verify); sandboxed WASM mods (pfx-mod: sandboxed, deterministic mods); and Steam (Steam). The same scene, inputs and seed give the same frames on the same GPU and driver, and a game’s rules run bit for bit from their seed (pfx_core::sim: simulation math that replays bit for bit).

Each of these costs a small slice of a frame:

Bar chart, game systems’ cost per tick in microseconds, lower is better: spawn director with 20 phases and 500 alive 11.5; 2,000 shots step and boxes 22.4; 2,000 shots against 400 targets at 4K, overlaps 32.0; resolve 1,079 hits 5.0; journal snapshot after 25 minutes of input 23.4; save a churned arena of 205 live shots 63.7; 20 sine tones 239; 20 jittered hits mixed 495. A 60 fps frame is 16,667 microseconds.

An empty game made by pfx new, against an empty Bevy app with its default plugins, both built cold with cargo build --release on the same machine:

Bar chart, stripped release binary of an empty game, lower is better: pfx 34.7 MB, Bevy 106.6 MB, 3.1 times smaller. Bar chart, dependency crates of an empty game, lower is better: pfx 290, Bevy 392. Bar chart, cold release build of an empty game in seconds, lower is better: pfx 366.8, Bevy 472.0. That pfx game carries the editor; built without it (--no-default-features, what a Steam build ships) it is 25.3 MB stripped with 251 dependency crates. Bevy’s starter brings its full renderer, UI and audio, so this compares the two starters as they ship, not equal features. The engine is 30 crates and about 278,000 lines of Rust, and the domain code it needs (the denoiser, the Sobol sampler, the resampler) is ported into it rather than linked.

Measured once on 2026-10-14 at commit 637c352 (v0.32.0), on an AMD Radeon RX 9060 XT with an AMD Ryzen 9 9950X (32 threads) under Linux, each GPU run through the machine’s GPU queue, which other jobs shared:

  • Live, 4K: pfx bench <room>.scene.toml --seconds 20 --size 3840x2160 on the neutral bench room (crates/load/tests/scenes, with a falling ball and a turning pillar), 1,200 frames. The CPU p99 (10.5 ms) is skewed: the queue held the job for part of the run.
  • Frames on demand: crates/live/examples/frames.rs, the desk at 4K: every frame 4.9 ms GPU at the median, a drifting camera 0.50 ms, idle 0.
  • 2D pass: the swarm test in crates/live/tests/flat/, 2,000 shots and 20,301 particles at 4K, GPU p50 0.39 ms, p99 0.61 ms.
  • Path tracer: crates/denoise/examples/rt_bench.rs time desk final|draft 3840 2160, the desk scene in crates/bake/tests/plates/, adaptive 16-64 samples a pixel for a final and 6-12 for a draft, denoise included. The final’s 11.2 s is the queue’s run time: the bench’s own clock also counted 2 min 4 s it waited for the GPU. v0.26.0 and v0.27.0 were measured with the same bench at their tags, with the PCG sampler at 32-128 and 8-16 samples, which Sobol matches in noise since v0.28.0.
  • Denoiser: crates/denoise/examples/compare.rs bench 3840 2160, median texture to texture (623 ms with upload and readback, 673 ms on a first call that builds the pipelines).
  • Game systems: the bench tests in pfx-core and pfx-sound (cargo test --release -p pfx-core --features serde --lib -- --ignored bench_, cargo test --release -p pfx-sound --test bench -- --ignored), one thread. A sound tick is 800 frames at 48 kHz, with cubic resampling, the default for short sounds.
  • Size: pfx v0.32.0’s scaffold and Bevy 0.20.0 with DefaultPlugins, cargo’s default release profile, 4 build jobs, one cold build each in turn; binaries measured after strip; dependency crates counted with cargo tree -e normal, the game itself excluded. Lines of Rust counted with wc -l over crates/*/src and src.

Nothing here was run twice for a better number. Hardware ray queries on Windows are built but untested on NVIDIA, Intel and AMD Windows machines.

Each is a package in this workspace that a game or app can link by tag; its name links to its API reference (all crates):

Package What it does
pfx-core springs, easings and tweens (Easings and tweens); daylight and the sun; camera rigs and animation; deterministic maths, shots, the spawn director, journals, numbers and words
pfx-geom levels of detail, analytic shapes as meshes, deformable surfaces, SVG marks as bevelled solids
pfx-gpu the wgpu device, offscreen targets, readback and uploads, GPU timing and pacing; windows and screens behind window
pfx-materials one physically based material for both renderers, with ageing and a WGSL BSDF library
pfx-text glyphs from vector outlines (coverage and MSDF atlases), laid along any baseline
pfx-post the finish chain (tone map, bloom, grade, vignette, grain, dither) and image styles
pfx-load meshes, images, HDR skies and fonts, scenes in pfx-scene’s format with in-place edits, and a content-addressed cache
pfx-physics rigid bodies, character controllers and world queries, fluid, ripples, rope, flocks and wind
pfx-sound live mixing, decoded streams and deterministic mixdown
pfx-input keyboard, mouse and controllers behind one action map, glyphs, keycaps in the player’s layout, rumble and recording
pfx-steam achievements, stats, Cloud saves, the overlay, rich presence, leaderboards, lobbies and Steam Input
pfx-live the live renderer: shadows, baked light, TAA, text, effects, the flat 2D pass, frames on demand, dynamic resolution and the dev HUD
pfx-trace the offline path tracer
pfx-denoise Intel Open Image Denoise’s RT filter ported to wgpu compute
pfx-bake path-traced light the live renderer shows at raster cost: probe grids, lightmaps and plates
pfx-play play mode: a game run live over a runtime copy of a scene, with pause, step and an exact stop
pfx-game the game runtime and its command-line launcher
pfx-project a game’s project.toml, scenes and content folders, and pfx new’s scaffold
pfx-mod the mod host: sandboxed, deterministic WASM components, metered by fuel and capped in memory
pfx-editor pfx edit and <game> edit: the scene editor, with play in the viewport and live gameplay modules
pfx-editor-style, -shell, -doc, -toml, -viewport the egui crates editors on pfx share: a theme and its widgets, a window host with an offscreen shot harness, document edits on one undo history, a TOML source panel and a 3D scene viewport with picking and a gizmo
pfx-theme the colours, fonts and type the editor and the dev HUD paint with
pfx-bench pfx bench
pfx-assets path-traced renders of logos, icons and scenes from SVG masters and small specs
pfx-run the pfx tool’s process plumbing: GPU queueing, ending children cleanly and the system ffmpeg

The pfx tool’s commands:

pfx new <game> scaffold a game
pfx edit <scene.toml | project folder> the scene editor
pfx bench <scene.toml> --seconds 10 a repeatable headless load with frame stats
pfx bake --scene <dir> path-traced probes, lightmaps and plates
pfx render --scene <shot> --product <product> --still
pfx steam stage --manifest <game>/steam.toml --out tmp/steam
pfx scene migrate|fix <scene.toml>
pfx --help

Every command and flag: The pfx tool.

pfx is the engine under the PITO MD games and apps. It is generic: no game keeps its names, values or assets in it; each game owns its content and uses the engine (The agnostic check). It works with:

  • pfx-scene, the TOML scene format pfx reads and the editor writes in place.
  • Manfred, which builds and views scenes on pfx’s renderers.
  • prec, pconv and pito-compare, which recorded, encoded and charted this page.

Issues and pull requests are welcome at github.com/gmrdad82/pfx. Keep bin/gate green, keep game-specific names, values and assets out of the engine, and follow the code of conduct. Report a vulnerability privately, as SECURITY.md says.

The code is MIT licensed, © Catalin Ilinca (LICENSE). The MIT licence covers the code only: the PITO MD name, every app and game name and their logos are © Catalin Ilinca, all rights reserved (TRADEMARKS.md). Fonts and other media keep their own licences (NOTICE.md).