cd /news/developer-tools/halfspace-is-an-ide-for-solid-modeli… · home › topics › developer-tools › article
[ARTICLE · art-141192] src=mattkeeter.com ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Halfspace is an IDE for solid modeling with distance fields

Matt Keeter released Halfspace, an experimental IDE for solid modeling with distance fields, as a showcase app for the Fidget kernel used for rasterization and meshing. Halfspace rasterizes images in real(ish)-time and exports models as images or triangle meshes, and Keeter said he has worked on it since April 2025 without using LLM-generated code, with Fidget dating back to 2022. The IDE combines a small standard library of shapes and transformations with incremental model building, splitting complex models into parameterized, individually visualized pieces.

read7 min views1 publishedSep 28, 2026
Halfspace is an IDE for solid modeling with distance fields
Image: source

Introduction #

Halfspace is an experimental IDE for solid modeling with distance fields.

(The demo is best experienced on a computer; mobile Safari has some WebGPU issues, and pan / tilt / zoom interactions are not yet designed for multitouch)

Halfspace is a showcase app for the [Fidget kernel](../fidget), which is used
for rasterization and meshing.  Within the GUI, images are rasterized in
real(ish)-time; models can be exported as either images or triangle meshes:

Since it's 2026, let me note at the outset that this is not vibe-coded. I've been working on it since April 2025 and am writing the code using my human brain, for various reasons (and Fidget dates back to

2022). Now, the rest of this writeup assumes some knowledge of implicit surfaces;

please [see](../libfive) [many](../fidget) [previous](../ao)
[writeups](../antimony) [for](../kokopelli) [details](../solver) for more

background info (or just keep reading, you'll be fine).

Why?

I've spent a bunch of time writing implicit kernels, slightly less time writing GUIs on those kernels, and even less time actually modeling with those tools.

In practice, I don't actually need to do much solid modeling in my daily life, so most of the stuff that I create is a demo or an example of how to use a particular kernel.

Still, I've noticed a particular tension when working with implicit surfaces. Working with low-level implicit surfaces is a bit like writing assembly: it's low-level, powerful, and annoying. If all you're given is x, y, z variables – and it's your responsibility to combine them into all the shapes of your dreams – that can be a painful experience.

When faced with the pain of writing assembly, most people build abstractions on top of it: high-level languages and libraries that compile down to a low-level representation. The equivalent here is a standard library of shapes and transformations: sphere, box, translate, scale, etc.

There's also a less common approach to the pain of assembly: making assembly itself less painful to write.

My favorite project along those lines is Kartik Agaram's Mu, which wraps emulation, tracing, and time-travel debugging around a subset of x86 assembly language.

Halfspace takes both paths. It includes a (small but growing) standard library, but also makes it easy to build up models incrementally: a complex model can be split into smaller pieces, which can be parameterized and visualized individually.

Given that justification, let's unpack the description a bit farther.

Solid modeling #

First off, "solid modeling" means that we're focusing on objects with a definitive inside and outside; you should be able to pick any point in space and say whether it's inside or outside the model.

This seems obvious, but there's plenty of modeling that doesn't care about that property: pull up any video game model viewer and you'll see plenty of infinitely-thin textured walls, built from a single fan of triangles. Since my background is in CAD/CAM software (with an emphasis on 3D printing), I want models that can be physically realized.

There are a bunch of ways to do solid modeling. In most CAD software, a

[boundary-representation](https://en.wikipedia.org/wiki/Boundary_representation)
[geometry kernel](https://en.wikipedia.org/wiki/Geometric_modeling_kernel)

is responsible for stitching a bunch of individual surfaces together into a solid body. This is a tremendously hard problem – for example, the intersection of two NURBS surfaces may not have a closed-form solution!

Dating back to my Master's thesis, I've been working on geometry kernels based on implicit surfaces. These have the advantage that they can conceivably be written and fully understood by a single person or small team, so they're a good fit for personal-scale fabrication software.

This continues in Halfspace: it's a GUI wrapped around the Fidget geometry kernel. Models can be designed using some combination of pre-defined primitives and hand-written scripts, and exported as either images or triangle meshes.

An IDE for distance fields #

We could use the Fidget kernel purely at the constructive solid geometry (CSG) layer, building shapes (spheres, cubes, cylinders, etc) and combining them with logical operations (union, intersection, difference). Halfspace instead make the decision to put the underlying distance fields in the foreground.

Let me give you an example of why this matters. Here are two distance fields for a sawtooth wave, which have the same signs at every point in space, but different values: In this visualization, the sign (which defines inside versus outside) is shown by color (blue versus orange), with the boundary of the shape shown in white (corresponding to a value of 0). The field values are shown by the fainter lines, which are spaced at regular intervals (like a topographic map).

Despite having identical signs everywhere, the first field is very poorly behaved. Look at the vertical edge of the sawtooth: there's a transition from inside (blue) to outside (orange) without a crossing through zero.

This is a C0 or "jump" discontinuity, and it's bad news! Fidget uses automatic differentiation to compute normals, so the normals across this boundary don't point in the correct direction (compare the field lines between top and bottom images). In 3D, where we use normals for shading, this produces incorrect shading in the cabin's shingles:

(If this looks familiar, it's because it's extracted from

an earlier blog post) Putting distance fields front-and-center makes it easy to diagnose these kind of issues. In fact, it suggests a further improvement on the sawtooth field: we can tweak the gradient so that it's 1 everywhere, instead of being bunched up on the diagonals. Here's a before / after comparison:

Having uniform gradients makes various algorithms better-behaved; Fidget doesn't require it for correctness, but it may (for example) improve mesh quality.

Halfspace is experimental and cross-platform #

Right now, it would be a very bold decision to use Halfspace in any load-bearing capacity. In the Fidget writeup, here's one of the project goals:

Finding the "right" APIs for implicit kernels, with the possibility of making substantial compatibility breaks

Halfspace is similar; it doesn't present APIs to end-users, but I'm flexing my software architecture skills by building a substantial cross-platform application, and I'm willing to aggresively iterate and break things as we go.

Speaking of cross-platform, I'm making my life harder by targeting both the web and native platforms. In the era of supply-chain attacks, being able to share a web link – instead of asking someone to compile and run your code – is great for onboarding and casual usage.

To that end, I've been collecting the "Halfspace stack": a set of libraries and patterns which let me ship a combined native + web application with a minimum of pain. Right now, here are the core pieces:

- Rust for the application (and all dependencies)
- [`egui`](https://github.com/emilk/egui) for the GUI
  - [`egui_dock`](https://docs.rs/egui_dock/latest/egui_dock/) for the core
window-and-tab abstraction
- [`wgpu`](https://wgpu.rs/) for both rendering the UI**and** GPU compute (!)
- [Rhai](https://rhai.rs) for scripting
- [Rayon](https://docs.rs/rayon/) and[`wasm-bindgen-rayon`](https://docs.rs/wasm-bindgen-rayon/latest/wasm_bindgen_rayon/) ,

used for two purposes:

  • Speeding up parallel algorithms by distributing work over many workers; this is a "typical" usage of the library
  • A thread pool for short-lived background tasks; this is a more unusual usage, but we can't spawn threads on the web.
  • ...and a long tail of other libraries and shenanigans
    • web-time for cross-platform time support

    • A homebrew worker pool for off-thread (async ) GPU rendering This all deserves a dedicated writeup, and I have complaints about every single layer of the stack, but overall, it's incredible that everything Just Works™.

Driving Fidget improvements #

Another goal of Halfspace is to drive improvements in the Fidget kernel, by using it in a non-trivial application.

The biggest victory on this front has been ongoing work on fidget-wgpu. This was motivated by performance on the web: the native build was pleasantly fast, but doing rasterization on the CPU was awfully slow ("non-interactive speeds") when running through a layer of WebAssembly.

After a lot of work on the Fidget side, both rasterization and post-processing (e.g. shading) can be run purely on the GPU, without any roundtrips to the CPU.

This was both a performance and architectural win:

  • We now have native rendering speed on both native and web targets
  • Rendering logic is no longer spread between Fidget (on the CPU) and Halfspace (with a mix of CPU and GPU code):
    • Fidget implements the canonical rendering logic
    • Halfspace has thin shaders which draw an RGBA texture

(The 2D rendering pipeline is also now fully GPU-accelerated, although it has slightly fancier shaders in Halfspace, for reasons)

Wrapping up #

Halfspace is a thing that exists!

You should try it out, and should probably not use it for critical applications! If you encounter problems, please file an issue or open a discussion on Github.

Like most of my work, I plan to keep working on it until I have run out of things to learn from the project. Also like most of my work, it's

[open-source](https://github.com/mkeeter/halfspace/)
under [the MPLv2 license](https://github.com/mkeeter/halfspace/blob/main/LICENSE.txt).
── more in #developer-tools 4 stories · sorted by recency
── more on @halfspace 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/halfspace-is-an-ide-…] indexed:0 read:7min 2026-09-28 · —