---
title: Tile-Based Optimization for 2D SDF Ray Tracing
description: How SDF-2D used signed distance fields, dynamic shaders, and tile-based rendering ideas to make 2D ray tracing run well in the browser.
date: 2026-05-08
projectPeriod: 'Autumn-Winter 2020'
thumbnail:
  src: ./_assets/sdf2d.png
  alt: SDF-2D browser demo with soft lighting effects.
tags: ['graphics', 'web', 'systems']
selected: true
featuredOrder: 2
project: sdf-2d
role: Library author
stack: ['TypeScript', 'WebGL', 'WebGL2', 'Signed distance fields']
scale: Browser library with mobile-oriented real-time rendering and reusable demos
outcome: Reusable NPM package and thesis project for efficient 2D SDF rendering
audience: recruiter-relevant
links:
  - label: NPM package
    type: package
    url: https://www.npmjs.com/package/sdf-2d
  - label: Demo
    type: demo
    url: https://sdf2d.schmelczer.dev
  - label: Video
    type: video
    url: https://www.youtube.com/watch?v=K3cEtnZUNR0
  - label: BSc thesis
    type: thesis
    url: /media/downloads/sdf2d-andras-schmelczer.pdf
    download: true
media:
  - type: image
    src: ./_assets/sdf2d.png
    alt: Browser demo page showing SDF-2D scenes rendered with soft lighting effects.
    caption: SDF-2D was built as a reusable TypeScript library rather than a single demo.
---

SDF-2D was my attempt to make a small, reusable browser library for 2D scenes rendered with ray-tracing techniques. The rendering is based on signed distance fields, where geometry can be represented as functions that return the distance to the nearest surface.

The interesting part was not the basic idea. Signed distance fields are a known technique. The interesting part was making the approach fast and reusable enough for browser demos, including on mobile devices.

The project became one half of my BSc thesis, together with the multiplayer game `decla.red`, which used the rendering library in a real interactive setting.

## The Problem

Ray tracing and distance-field rendering can produce appealing 2D lighting and reflections, but a straightforward implementation spends too much work per pixel. A browser library also has to deal with device variation: WebGL capabilities, shader limits, mobile GPUs, and the overhead of generating scenes dynamically.

The goal was not to render one hand-tuned scene. The goal was a library with a simple API, reusable scene definitions, and real-time behavior.

## Constraints

The library had to support both WebGL and WebGL2. It had to run acceptably on phones. It had to avoid shipping scene-specific shader code by hand. And it had to expose an API that felt like a rendering library rather than a shader experiment.

Those constraints pushed the implementation toward generated shaders and capability-aware rendering paths.

## Design

The main optimization was inspired by tiled renderers. Instead of treating the entire screen uniformly, the renderer could reason about groups of pixels and avoid unnecessary work where possible.

That was paired with deferred shading and dynamic shader generation. Dynamic generation mattered because scenes and devices differ. If a feature or operation was not needed for a given scene or device, the generated shader could avoid carrying that cost.

The API was deliberately kept in TypeScript. That made the library easier to package, document, and reuse in projects that were already browser-first.

## What Worked

The project worked best when the library boundary was respected. A good demo can hide a messy implementation. A reusable package cannot. The API had to explain the rendering model without making every user think like a shader compiler.

The mobile constraint also improved the design. It forced performance work to be structural rather than cosmetic. When a technique works only on a powerful desktop GPU, it is easy to mistake headroom for good architecture.

## What I Would Change

Today I would write more instrumentation around shader variants and device behavior. The project had many optimizations, but stronger profiling output would have made tradeoffs easier to explain and compare.

I would also document the rendering pipeline with diagrams. The ideas are visual, and the explanation should be too.
