Post

Fury3D: a WIP, vibe-friendly 3D engine

Fury3D: a WIP, vibe-friendly 3D engine

I’m picking up Fury3D again — the small C++17/OpenGL engine I started almost a decade ago. The goal this time is narrower and more honest: a WIP, vibe-friendly engine for making small 3D games, one where most of the heavy lifting is done by an AI CLI and I stay in the loop as the reviewer.

Tank fleet rendered with HDR PBR + cascaded shadow maps + the full postprocess chain. Editor on the right: Scene Inspector, Node Properties, Settings (per-effect toggles), Profiler, Content Browser.

The idea

Take a study-grade renderer (deferred light-pre-pass, shadows, glTF, post-FX) and bolt on the things a vibe workflow actually needs: a JSON-described pipeline, a Lua-scripted editor with ImGui, an offline CLI for headless asset conversion, and a text-driven scene format you can diff and review. No 200k-line runtime, no editor-as-product, no hidden state — just enough engine that an AI can read it end-to-end and an AI (or I) can author content for it.

SSR reflection of trees and a wooden fence on a wet outdoor ground — postprocess chain visible to the right.

Sponza HDR scene rendered with the full postprocess chain (SSAO, SSR, ACES, FXAA, CRT).

James skinned character with the joint-debug overlay and the Animator state inspector.

Features

  • C++17 + OpenGL 3.3+ core profile, with explicit per-draw state so passes don’t leak GL_BLEND into each other.
  • JSON-configurable render pipeline — every pass, shader variant, and uniform lives in a .json next to the runtime.
  • HDR pipeline with RGBA16F composite + ACES tonemap, plus a data-driven post-process chain (SSAO, SSR, FXAA, CRT, ACES) that orders itself by stage.
  • Deferred light-pre-pass renderer with cascaded shadow maps for the sun and 2D / cubemap shadow maps for spot & point lights.
  • glTF 2.0 importer (vendored tinygltf) with PBR→Lambert mapping, skins, animations; FBX routed through FBX2glTF so the engine never links the FBX SDK.
  • Skinned meshes + Animator — joint-driven bone matrices, state weights/speeds/wraps/cross-fades, console overlay for joint debugging.
  • Transparent rendering — back-to-front alpha base + per-light additive draws, depth-write off, premultiplied-alpha forward shader.
  • OcTree spatial structure with default-cube auto-wrap and a Profiler spatial section.
  • ImGui + ImGuizmo editor — Scene Inspector, Content Browser, Node Properties, viewport gizmo, native file dialogs, persisted dock layout.
  • Offline fury CLIfury convert gltf|fbx|scene, fury info, fury exec (headless Lua), fury render-mesh; the editor’s default save form is LZ4-compressed .bin, with .json for human diffs.
  • Lua 5.4 + sol2 scripting bridge, with a deliberately small binding surface (only what the editor exercises) so the engine API can keep refactoring.

Full architecture rundown lives in docs/ARCHITECTURE.md.

The vibe-coding bit

I’m writing it with M3 and GLM to get the bones down, then mostly K3 — it’s multimodal, easier to buy than GLM, and surprisingly powerful. K3 drives the bulk of the work; M3/GLM still help when I want a second opinion on a refactor.

That said: code is vibed and reviewed by me. Even with a strong model, code review is essential — I still have to keep an eye on the machine-made decisions. The KISS-by-default style, the openspec workflow under openspec/changes/, and the “spec first, then code” loop exist precisely so I can diff a change against intent instead of vibes. Specs that pass verification get carried over; reproductions live in the agent’s scratchpad, not in the repo.

WIP. Things will move, things will break, things will get renamed. If you want to peek under the hood, it’s all there → github.com/sindney/fury3d.

This post is licensed under CC BY 4.0 by the author.