Jet README

The project's README from github.com/CubeCoders/Jet. As one markdown file: README.md.

Jet logo

Jet

Jet is a dependency-free, fixed-function 3D software rasteriser written in C++17. It targets embedded hardware with limited CPU and memory, including ESP32 and STM32, and also runs on desktop PCs and Raspberry Pi.

Jet uses integer arithmetic in the rasterisation hot path and native 16-bit RGB565 colour for output to embedded displays. It supports flat-shaded, lit and textured geometry for low-poly games and visualisations.

On an ESP32-S3, Jet reaches a peak throughput of 70,000 triangles/second (flat-shaded). The demo below runs at a 480×320 output resolution and 60 FPS using half-width, interlaced field buffers. Throughput varies with scene complexity, triangle size and enabled rendering features.

Community

Share projects and get help on the Discord server.

Demo

A Wipeout-style game running on an ESP32-S3 at 60 FPS:

Jet on ESP32-S3: 60 FPS Wipeout-style demo

Feature highlights

Compile-time switches in JetConfig.hpp let you disable features to reduce CPU, RAM and flash usage. See src/JetConfig.example.hpp for the available options.

Rendering

Lighting

Post-FX

Tooling

2D Sprites

Sprite2D draws overlays after render(). It supports textured or solid-colour fills, colour-key transparency, alpha and additive blending, integer upscaling, and zOrder-based draw order. On HALF_WIDTH_BUFFERS builds, sprites are composited at full output resolution during display scanout.

Particles

ParticleSystem uses a fixed pool and renders through the rasteriser after scene->render(). It includes spark and water-splash emitters, distance culling, and configurable emitter counts and particle lifetimes.

Lens flare

LensFlare projects a directional light source to screen space and positions a sprite chain along the axis between the sun and screen centre. Fade speed, per-element axis offset (axisT), alpha, blend mode and integer scale are configurable. It can use a pick slot for sun occlusion testing; with MAX_PICK_QUERIES = 0, the sun is treated as unobstructed.

Getting started

Your application provides the framebuffer, display driver and main loop. Add Jet as a CMake subdirectory or ESP-IDF component, provide a JetConfig.hpp on your include path (copy and customise src/JetConfig.example.hpp), then call scene->render() once per frame.

For ESP-IDF, depend on it as you would any other component:

# main/idf_component.yml
dependencies:
  jet: "*"

Minimal example

Allocate colour and depth buffers, add a camera, lights and a cube, then render each frame:

#include "Jet.hpp"
using namespace Renderer;

// 320x240 RGB565 colour buffer + matching Z-buffer.
constexpr int W = 320, H = 240;
uint16_t color[W * H];
uint16_t depth[ZBUFFER_STRIDE(W) * H];

int main() {
    Scene  scene(color, depth, W, H);
    scene.setBackcolor(0x0000);          // RGB565 clear colour (black)
    scene.setClearBuffer(true);

    Camera camera;
    camera.setPosition(0, 0, -500);      // world units
    camera.setFOV(75, W);
    camera.nearPlane = 16;
    camera.farPlane  = 8192;
    scene.setCamera(&camera);

    DirectionalLight sun(Vector3{45, 35, 0}, Color{255, 245, 220}, 220);
    AmbientLight     amb(Color{40, 48, 64});
    scene.setDirectionalLight(&sun);
    scene.setAmbientLight(&amb);

    Material red(0xF800);                // RGB565: bright red
    red.shadingMode = ShadingMode::GOURAUD;

    Object* cube = Primitives::createCube(200, 200, 200, &red);
    cube->setPosition(0, 0, 200);
    scene.addObject(cube);

    // Per-frame: rotate, render, push the buffer to your display.
    for (;;) {
        cube->rotate(0, 1, 0);           // 1 degree per frame around Y
        scene.render();                  // colour buffer now contains the frame
        // pushToDisplay(color, W, H);   // <-- you provide this
    }
}

Documentation

The API reference is generated from the Doxygen comments in src/.

To build the docs locally (requires doxygen and optionally graphviz):

cd components/Jet/src
doxygen Doxyfile
# output: components/Jet/src/docs/html/index.html

GitHub Actions publishes the documentation on pushes to the default branch.

Licensing

Jet is distributed under the MIT License. The full text is in LICENSE.

You can use, modify and distribute Jet in open-source or closed-source projects, including commercial products, without a separate licence or fee. Include the copyright and permission notices as required by the MIT License.

Contributing

Submit bug reports, fixes, examples and documentation improvements through issues or pull requests on the official repository.

Before your first contribution, please read CONTRIBUTING.md. Contributions are accepted under the MIT License; no separate Contributor Licence Agreement is required.


Jet is a CubeCoders project.

Jet (CubeCoders/Jet)

Searching Database…

537 ·GitHub
What is this?Jet is a tiny, dependency-free, fixed-function 3D software rasteriser in C++17, built for embedded chips with little CPU and RAM like the ESP32 and STM32; it also runs on desktop PCs and Raspberry Pi.
Is it a ready-made game engine, or a library I build my own renderer on?It's a library, not an engine: your application supplies the framebuffer, display driver and main loop, and each frame you just call scene->render() to draw the scene.
How do I add it to my project?Add Jet as a CMake subdirectory or an ESP-IDF component, copy src/JetConfig.example.hpp to JetConfig.hpp on your include path and tweak it, then call scene->render() from your own loop.
What's the catch — will it replace a GPU?No — Jet renders on the CPU through a fixed-function pipeline with no hardware acceleration, so real throughput depends on your scene complexity, triangle sizes and which features you enable.
Can I use it in a commercial project?Yes — Jet is MIT licensed, so you can use it in open-source or closed-source projects, including commercial products, with no separate licence or fee; just keep the copyright and permission notices.
Why integer math and 16-bit RGB565 instead of floats?Because the target is microcontrollers and small embedded displays: Jet does integer arithmetic in the rasterisation hot path and outputs native 16-bit RGB565, which suits the limited CPU and memory of chips like the ESP32.
Does it support post-processing effects?Yes — CRT scanlines and cell-shading run without an extra buffer, while FXAA, bloom, motion blur, chromatic aberration and pixelation are available as buffered effects on targets with more RAM.
Is the pipeline fully fixed, or can I add my own effects?It's fixed-function, but there is a custom shader entry point for extending the pipeline, plus special modes like WATERREFLECT for animated water and ADDITIVE for neon signs and explosion halos.
Can I strip it down for a really tiny device?Yes — compile-time switches in JetConfig.hpp let you disable features to reduce CPU, RAM and flash usage; copy src/JetConfig.example.hpp and switch off what your board cannot afford.
What are similar projects?NoGraphicsAPI, Marlin, bgfx, raylib, mongoose, coyopedal, assimp, WoWee
Creator
CubeCoders
Size
8.2 MB
Stars
537
Updated
CommitSep 25
Age
5mo
Commits · 90 Days