Pre-alpha distance function reference thread

A thread for discussion and updates of the SDF/shader drawing techniques reference pages. (First discussed in this thread.)

This will be a small repository of code and notes for drawing and animating shapes using distance functions in render2D(). There’s no basic tutorial yet - if you’re not familiar with the concepts, there are all kinds of guides and references listed in the thread mentioned above.

I’ll post update notes here until the project gets complete enough to be considered ready for more general use.

Links to the Repository
Toolkit Main Page
2D SDF Reference

Latest Updates:


  • Added many new symbol and marker SDFs. Thanks @scruffynerf!


  • New Shapes! Gear, Diamond, Line Segment, Heart
  • More handy utility fns: mix(), smoothstep(), dot(), dot2()
1 Like

I’ve been on the lookout for additional SDFs beyond the ones from IQ and PixelSpiritDeck

Found some:

Includes card suits, arrows, and more. All worth adding to a library.

Also, not SDFs (they are SVGs), but this idea is awesome and I can imagine a pattern that can be inspired by it… Make items have some relationship points, build items to connect, and suddenly it’s generative art. We’re quite a ways from this, but… it’s also not that far a stretch. Imagine a pattern that just made art all day long… If it’s making art and nobody sees it, is it real?

Added: Another good basic set of algos
Found it thru curv/Shape_Constructors.rst at master · curv3d/curv · GitHub
Which is also good, the entire shape library is actually written in itself.

Good question. I have a large stack of high res fractal prints which are wondering the same thing.

Wow, they need a ‘put this on a t-shirt’ button and an ‘ask GPT-3 to design a religion around this’ button!


I’ve been totally into SDF world… I’m hoping to port all of the bits this can do… it’s a fun playground example.

1 Like

Just updated the SDF toolkit!
Added these shapes:

  • Gear (with arbitrary number and size of teeth)
  • Diamond
  • Line Segment
  • Heart

Also added some utility functions to help with porting:

  • dot(x1,y1,x2,y2) - dot product
  • dot2(x,y) - dot product of a vector with itself
  • mix(low,high,value) - linear interpolation function
  • smoothstep(low,high,value) - threshold function with (cubic) sigmoidal interpolation.

These need some normalizing of size, and optimizing in general.
We could also replace min and max with function names that are clear what they do, since for SDFs, min is a union and max is a difference (or add/remove)

Pile of symbols Number 1
// from
function markerT(x,y,size) {
   size = size*2
   r1 = max(abs(x -size/3. + size/3.), abs(x - size/3. - size/3.));
   r2 = max(abs(y - size/3.), abs(y + size/3.));
   r3 = max(abs(x), abs(y));
   r = max(min(r1,r2),r3);
   r -= size/2.;
   return r;

function markerCheck(px,py,size){
    x = -SQRT1_2 * (px - py);
    y =  SQRT1_2 * (px + py);
    size = size*2
    r1 = max(abs(x - 2.*size/3.), abs(x - 1.*size/3.));
    r2 = max(abs(y - 2.*size/3.), abs(y - size/3.));
    r3 = max(abs(x),max(abs(x-size/3.), abs(y)));
    r = max(min(r1,r2),r3);
    r -= size/2;
    return r;

function markerCross(px,py,size){
  x = SQRT1_2 * (px - py);
  y = SQRT1_2 * (px + py);
  size = size/1.5
  r1 = max(abs(x - size), abs(x + size));
  r2 = max(abs(y - size), abs(y + size));
  r3 = max(abs(x), abs(y));
  r = max(min(r1,r2),r3);
  r -= size*1.5;
  return r;

function markerClobber(px,py,size){
   size = size * 2
    c1y = -0.25;
    c2x = 0.216507
    c2y = 0.125;
    r1 = hypot(px, py - c1y*size) - size/3.5;
    r2 = hypot(px - c2x*size, py - c2y*size) - size/3.5;
    r3 = hypot(px + c2x*size, py - c2y*size) - size/3.5;
    return min(min(r1,r2),r3);

function markerAsterisk(px,py,size){
   x = SQRT1_2 * (px - py);
   y = SQRT1_2 * (px + py);
   size = size * 2
   r1 = max(abs(x)- size/2., abs(y)- size/10.);
   r2 = max(abs(y)- size/2., abs(x)- size/10.);
   r3 = max(abs(px)- size/2., abs(py)- size/10.);
   r4 = max(abs(py)- size/2., abs(px)- size/10.);
   return min( min(r1,r2), min(r3,r4));

function markerChevron(px,py,size){
    x = 1/SQRT2 * (px - py);
    y = 1/SQRT2 * (px + py);
    size = size * 2
    r1 = max(abs(x), abs(y)) - size/3;
    r2 = max(abs(x-size/3.), abs(y-size/3.)) - size/3.;
    return max(r1,-r2);

function markerRing(px,py,size){
    r1 = circle(px,py,size);
    r2 = circle(px,py,size/2);
    return max(r1,-r2);

function markerInfinity(px,py,size){
    c1x = .125
    size = size * 5
    r1 = circle(px-c1x*size,py,size/6);
    r2 = circle(px-c1x*size,py,size/14);
    r3 = circle(px+c1x*size,py,size/6);
    r4 = circle(px+c1x*size,py,size/14);
    return min( max(r1,-r2), max(r3,-r4));

function markerTag(px,py,size){
    x = -px;
    y = py;
    size = size * 3
    r1 = max(abs(x)- size/2., abs(y)- size/6.);
    r2 = abs(x-size/1.5)+abs(y)-size;
    return max(r1,.75*r2);

More coming soon…

1 Like

These are great! I just checked them in to the main SDF document. We can normalize and optimize at leisure. (PM me your github email address and I can add you as a contributor to this repository – if we keep working at it, we’ll soon have one of the most complete 2D collections around!)

1 Like

A few more: another heart (unsure which is better, this might be with tuning), and a 7 segment LED for Numbers
(and yeah, we could do a 14 or even 16 segment LED, and have alphanumerics…)

Absolutely need sizing work, so we can use them smaller.

Heart2 and 7SegmentLED
function heart2(x,y,size) {
    // From: by coyote & Fabrice
    size = .4/size
    y += .034;
    x *= size;
    y *= -size;
    return sqrt( x*x + y*y - abs(x) * y ) - .4

function segment(x,y,size){
    return roundedRectangle(x,y,size/6,size/2)

function sevenSegment(x,y,size,num)
	seg= 5.0;
	scale = 2.5
	a = .45 * size * scale
	b = .225 * size * scale
	seg = (num!=-1 && num!=1 && num!=4                    ?min(segment(y+a,x,size),seg):seg);
	seg = (num!=-1 && num!=1 && num!=2 && num!=3 && num!=7?min(segment(x-b,y+b,size),seg):seg);
	seg = (num!=-1 && num!=5 && num!=6                    ?min(segment(x+b,y+b,size),seg):seg);
	seg = (num!=-1 && num!=0 && num!=1 && num!=7          ?min(segment(y,x,size),seg):seg);
	seg = (num==0 || num==2 || num==6 || num==8           ?min(segment(x-b,y-b,size),seg):seg);
	seg = (num!=-1 && num!=2                              ?min(segment(x+b,y-b,size),seg):seg);
	seg = (num!=-1 && num!=1 && num!=4 && num!=7          ?min(segment(y-a,x,size),seg):seg);
	return seg;

Hmm, Would you like to play a game?

Now that’s a pattern… do a WOPR countdown, and then show missles striking… all in ultra low res. Oh, and it’d have to do the DEFCON changes as well

Talk about a countdown pattern… You’d want two keys to turn this on.
Ok, last video:

yes, it had lots of LEDs in multiple panels… so the pattern could sit there and just blink leds calmly… most of the time.