three-d: one Rust crate with three layers, from raw context calls to a few lines of drawing
2D/3D renderer - makes it simple to draw stuff across platforms (including web)
At a glance
- What is it?
- three-d is an MIT licensed Rust renderer over OpenGL, WebGL and OpenGL ES that lets you start in a high level drawing module and drop down to a context module when you need your own shaders, with a web target built on wasm-bindgen. It fits programmers who want graphics without a game engine, and the layering is the reason it can serve both a first triangle and a custom pipeline.
- Who is it for?
- Adopt three-d if you are writing Rust and want direct OpenGL or WebGL control without adopting a scene graph, a physics engine or an asset pipeline you did not ask for. Do not adopt it expecting engine features, text or a GUI unless you turn on the right features, since text needs the text feature and the immediate mode GUI needs egui-gui.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 121 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Three modules that map to how much graphics you actually know
The module split is the whole idea, and the README states it as a table with an explicit skill requirement attached to each row.
`renderer` is the high level module, described as requiring no knowledge of graphics concepts. It renders standard objects with different types of shading, and it is the layer you use if you just want to draw something. `core` is the middle: use it when you want to write your own shaders but do not want to spend your time on setup and error handling, and it combines with the low level module. `context` is the bottom, requiring a solid understanding of graphics concepts, and it gives you complete control over both setup and rendering. The optional `window` module sits beside them for getting a window up quickly.
Because the layers combine rather than replace each other, the migration path is the interesting part. You can write a first scene in `renderer`, find a material you cannot express there, drop the same objects down into `core` with your own shader, and go further into `context` when you need to control setup itself. The stated design goal is that there is no hidden magic, which in practice means more of the pipeline is visible to you than in an engine that hides it behind a scene graph.
The listed use cases match that audience: data visualization, image processing, UI rendering, 2D or 3D tools, and 2D or 3D games. The point is deliberately not a game engine. That boundary is a feature for tooling, and a limit for anyone who wants a complete engine.
One dependency on glow means OpenGL, WebGL and OpenGL ES for free
The dependency list in Cargo.toml is short and explains the platform reach. The manifest lists glow 0.17, cgmath 0.18, three-d-asset 0.10, thiserror 2 and open-enum 0.5 among its dependencies.
The manifest lists glow as a dependency, while the project description and README identify OpenGL, WebGL, OpenGL ES, desktop, web and mobile as targets. That is not a portability layer the project bolted on afterwards; it falls out of choosing the binding. Topics on the repository list graphics, rust, wasm, webassembly and webgl, and the keyword list adds gamedev, webassembly, opengl and webgl.
The wasm path is spelled out in the manifest. On wasm32 the optional dependencies are wasm-bindgen at 0.2, serde and serde-wasm-bindgen, enabled by the window feature, and web-sys sits in that same feature list. On native platforms the window feature instead pulls in glutin at 0.32 and raw-window-handle at 0.6, and an optional image dependency at 0.25 with only the png feature enabled.
Documentation is built with all features on, and the docs.rs metadata lists four targets: x86_64-apple-darwin, x86_64-unknown-linux-gnu, x86_64-pc-windows-msvc and wasm32-unknown-unknown. So the published API reference covers desktop and web, which is the honest test of whether a cross-platform claim holds.
Features are opt-in, and window is on by default
The feature table is where the trade-offs hide. The default feature set is just window, which expands to glutin, winit, raw-window-handle, wasm-bindgen, serde, serde-wasm-bindgen and web-sys. That default is generous: it means a plain cargo build drags in a windowing stack even if you already have your own surface to render into.
Two optional features add real capability. The text feature enables swash at 0.2 and lyon at 1 for text mesh generation, which is the feature to turn on if you need labels in a data visualization and expect to pay for the dependency. The optional egui-gui feature enables egui 0.34 and egui_glow 0.34. Both are off unless you ask.
The README is explicit that the window module can be replaced. It describes using it to get started while noting that in some cases it is desirable to replace the default, which lines up with the manifest: drop default features and you get the rendering modules without the windowing stack.
Version note worth pausing on. Cargo.toml reads version 0.20.0 with a comment reminding the author to update example links, while the visible release history stops at 0.10.0 from 2022-01-16, with 0.9.0 and 0.8.0 before it. The repository's last push was on 2026-06-24. The gap between the manifest version and the tag list is a fact to check against crates.io before you pin a dependency, not something the README explains.
The examples directory is the real documentation
The examples tree is broad enough to tell you what the renderer covers, and it is organised by topic rather than by difficulty. Directories exist for animation, lighting, lights, pbr, normals, effect, environment, imposters, sprites, particles, point_cloud, picking, instanced_shapes, instanced_draw_order, shapes, shapes2d, screen, mandelbrot, logo, statues, multisample, multiwindow, image and assets.
Several of these answer questions the module table leaves open. instanced_shapes and instanced_draw_order tell you instanced drawing is supported and that ordering is something you control. picking indicates screen-space picking. shapes2d sits next to shapes, so the 2D claim has concrete backing. mandelbrot and image point at offscreen work, and multiwindow shows the window module is not single-surface only. A separate examples/README.md exists, so start there rather than guessing filenames.
For a first use, the practical path is short. Add the crate to a Cargo.toml, read the examples README, run one example that matches what you intend to build, then copy it and strip it. Because the default window feature is on, a desktop example needs no setup beyond the dependency. For the web target, compile to wasm32-unknown-unknown and the window feature pulls in wasm-bindgen and web-sys for the browser side.
The manifest currently declares version 0.20.0. Confirm that version in the crates.io listing before choosing a dependency constraint. The README does not document a crate install command or a set of cargo invocations, so the examples directory is the documented entry point.
Where three-d is the wrong choice
Being explicit about limits is more useful than another feature list.
If you want a game engine, this is not it. There is no scene graph with the usual conveniences, no physics, no animation curve editor, no asset pipeline and no editor. The README positions three-d as avoiding a fully fledged game engine, and that framing comes from users quoted in it who needed something between a raw binding and an engine. If your project needs engine services, you will write them.
If you need text out of the box, you need a feature flag. Text mesh generation sits behind the text feature, so a default build will not render labels.
If you need a GUI, that is also opt-in through egui-gui. And if you already have a windowing stack, the default window feature means you are paying for winit and glutin whether you want them or not.
If you are on a platform outside the four docs.rs targets, expect to verify the build yourself. The manifest lists those four targets for documentation; it does not claim a mobile or iOS story, even though the README lists mobile among the platforms targeted. Nothing in the manifest makes a mobile target easy.
Finally, the release numbering deserves scepticism. The newest visible release is 0.10.0 while the manifest is at 0.20.0, so the available release history and repository head may tell different stories.
How it differs from raw glow and from a full engine
The comparison that matters is with writing glow yourself, because three-d is a thin, opinionated layer over exactly that binding. Direct use of glow would require a separate assessment of the setup and rendering work involved. three-d keeps the same underlying API while removing the setup work, which is why the README distinguishes `context` from `core`: `context` provides low-level setup and rendering control, `core` supports custom shaders while reducing setup and error handling work, and `renderer` is the high-level drawing option.
Against an engine, the difference is what you keep. An engine gives you a scene graph, material system, asset loaders, animation and tooling, and takes abstraction as the price. three-d gives you the drawing pipeline and leaves the rest to you, which is the right trade for a plotting tool, an image processor or a one-off visualisation, and the wrong one for a game with a hundred entities and an artist in the loop.
The licence reinforces that framing. MIT is permissive, with attribution and notice obligations and no copyleft requirement on code that merely links the crate. For commercial embedding of a renderer, that makes adoption a paperwork question rather than an architectural one.
Editorial conclusion
Adopt three-d if you are writing Rust and want direct OpenGL or WebGL control without adopting a scene graph, a physics engine or an asset pipeline you did not ask for. Do not adopt it expecting engine features, text or a GUI unless you turn on the right features, since text needs the text feature and the immediate mode GUI needs egui-gui. Verify first that the version you pin matches your project: the Cargo.toml reads 0.20.0 while the newest visible release is 0.10.0 from 2022-01-16, and the last push was on 2026-06-24, so check the changelog across that gap before assuming the crates.io release matches the repository head.
Frequently asked questions
How do I add three-d to a Rust project?
Use version 0.20.0 as the manifest's current version reference, after confirming its availability in the crates.io listing. The default feature set is window, which on native platforms pulls in glutin, winit and raw-window-handle, and on wasm32 pulls in wasm-bindgen and web-sys.
What is the difference between the context, core and renderer modules?
The README describes renderer as the high level module requiring no knowledge of graphics concepts, core as the mid level module for writing your own shaders without doing setup and error handling, and context as the low level module giving complete control over setup and rendering. They can be combined within one program.
Can three-d render text and GUI elements?
Yes, with the right features. The text feature enables swash and lyon for text mesh generation, and the egui-gui feature enables egui and egui_glow. Both are optional and are not part of the default feature set, which contains only window.
Does three-d compile to WebAssembly?
The manifest and docs.rs metadata include wasm32-unknown-unknown as a documented target, and the window feature pulls in wasm-bindgen, serde-wasm-bindgen and web-sys for wasm32. The window module is documented as working on cross-platform native and web.
What licence is three-d released under?
MIT, as recorded in the license field of Cargo.toml and in the LICENSE file at the repository root.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/asny-three-d)Was this useful?