HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
fogleman
primitive
Go2016–2026
fogleman / primitive

primitive

Reproducing images with geometric primitives.

32Distinct people
42Mentions
1Explicit recommenders
13.6KGitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

Reproducing images with geometric primitives.

GitHub

Where it is used

No documented product use was verified in the last source check.

What people are saying

Apparently, he published all of his code (I didn't see any mention of where). Regarding the color -- he mentions being careful with the palette, but I wonder how he gets it to…

anonytrary used a recommendation phrase. One indexed comment matches. This is a phrase match, not a verdict.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

No other repository is repeatedly linked in the same discussions.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 12:54:37 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by year42 dated mentions

Observed mentions: 2016-09-15 03:02:38 UTC to 2026-04-22 23:21:49 UTC.

0510152016-01-01 00:00:00 UTC to 2017-01-01 00:00:00 UTC (exclusive): 13 mentions; 2 submissions, 11 comments20162017-01-01 00:00:00 UTC to 2018-01-01 00:00:00 UTC (exclusive): 7 mentions; 0 submissions, 7 comments2018-01-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 8 mentions; 1 submissions, 7 comments2019-01-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2020-01-01 00:00:00 UTC to 2021-01-01 00:00:00 UTC (exclusive): 5 mentions; 0 submissions, 5 comments2021-01-01 00:00:00 UTC to 2022-01-01 00:00:00 UTC (exclusive): 3 mentions; 1 submissions, 2 comments20212022-01-01 00:00:00 UTC to 2023-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2023-01-01 00:00:00 UTC to 2024-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2024-01-01 00:00:00 UTC to 2025-01-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2025-01-01 00:00:00 UTC to 2026-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2026-01-01 00:00:00 UTC to 2027-01-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments. Incomplete calendar period.2026*

* An incomplete calendar period is marked with an outlined bar. Its count is not directly comparable with a full period.

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
20162016-01-01 00:00:00 UTC2017-01-01 00:00:00 UTC13211
20172017-01-01 00:00:00 UTC2018-01-01 00:00:00 UTC707
20182018-01-01 00:00:00 UTC2019-01-01 00:00:00 UTC817
20192019-01-01 00:00:00 UTC2020-01-01 00:00:00 UTC000
20202020-01-01 00:00:00 UTC2021-01-01 00:00:00 UTC505
20212021-01-01 00:00:00 UTC2022-01-01 00:00:00 UTC312
20222022-01-01 00:00:00 UTC2023-01-01 00:00:00 UTC101
20232023-01-01 00:00:00 UTC2024-01-01 00:00:00 UTC202
20242024-01-01 00:00:00 UTC2025-01-01 00:00:00 UTC101
20252025-01-01 00:00:00 UTC2026-01-01 00:00:00 UTC000
2026 (partial)2026-01-01 00:00:00 UTC2027-01-01 00:00:00 UTC202

From the project README

An excerpt from the repository, fetched Nov 13, 2026.

Read the project’s introduction
Primitive Pictures Reproducing images with geometric primitives. How it Works A target image is provided as input. The algorithm tries to find the single most optimal shape that can be drawn to minimize the error between the target image and the drawn image. It repeats this process, adding one shape at a time. Around 50 to 200 shapes are needed to reach a result that is recognizable yet artistic and abstract. Primitive for macOS Now available as a native Mac application! https://primitive.lol/ Twitter Follow @PrimitivePic on Twitter to see a new primitive picture every 30 minutes! The Twitter bot looks for interesting photos using the Flickr API, runs the algorithm using randomized parameters, and posts the picture using the Twitter API. You can tweet a picture to the bot and it will process it for you. Command-line Usage Run it on your own images! First, install Go. go get -u github.com/fogleman/primitive primitive -i input.png -o output.png -n 100 Small input images should be used (like 256x256px). You don't need the detail anyway and the code will run faster. Flag Default Description i n/a input file o n/a output file n n/a number of shapes m 1 mode: 0=combo, 1=triangle, 2=rect, 3=ellipse, 4=circle, 5=rotatedrect, 6=beziers, 7=rotatedellipse, 8=polygon rep 0 add N extra shapes each iteration with reduced search (mostly good for beziers) nth 1 save every Nth frame (only when %d is in output path) r 256 resize large input images to this size before processing s 1024 output image size a 128 color alpha (use 0 to let the algorithm choose alpha for each shape) bg avg starting background color (hex) j 0 number of parallel workers (default uses all cores) v off verbose output vv off very verbose output Output Formats Depending on the output filename extension provided, you can produce different types of output. PNG: raster output JPG: raster output SVG: vector output GIF: animated output showing shapes being added - requires ImageMagick (specifically the convert command) For PNG and SVG outputs, you can also include %d, %03d, etc. in the filename. In this case, each frame will be saved separately. You can use the -o flag multiple times. This way you can save both a PNG and an SVG, for example. Progression This GIF demonstrates the iterative nature of the algorithm, attempting to minimize the mean squared error by adding one shape at a time. (Use a ".gif" output file to generate one yourself!) Static Animation Since the algorithm has a random component to it, you can run it against the same input image multiple times to bring life to a static image. Creative Constraints If you're willing to dabble in the code, you can enforce constraints on the shapes to produce even more interesting results. Here, the rectangles are constrained to point toward the sun in this picture of a pyramid sunset. Shape and Iteration Comparison Matrix The matrix below shows triangles, ellipses and rectangles at 50, 100 and 200 iterations each. How it Works, Part II Say we have a Target Image. This is what we're working towards recreating. We start with a blank canvas, but we fill it with a single solid color. Currently, this is the average color of the Target Image. We call this new blank canvas the Current Image. Now, we start evaluating shapes. To evaluate a shape, we draw it on top of the Current Image, producing a New Image. This New Image is compared to the Target Image to compute a score. We use the root-mean-square error for the score. Current Image + Shape => New Image RMSE(New Image, Target Image) => Score The shapes are generated randomly. We can generate a random shape and score it. Then we can mutate the shape (by tweaking a triangle vertex, tweaking an ellipse radius or center, etc.) and score it again. If the mutation improved the score, we keep it. Otherwise we rollback to the previous state. Repeating this process is known as hill climbing. Hill climbing is prone to getting stuck in local minima, so we actually do this many different times with several different starting shapes. We can also generate N random shapes and pick the best one before we start hill climbing. Simulated annealing is another good option, but in my tests I found the hill climbing technique just as good and faster, at least for this particular problem. Once we have found a good-scoring shape, we add it to the Current Image, where it will remain unchanged. Then we start the process again to find the next shape to draw. This process is repeated as many times as desired. Primitives The following primitives are supported: Triangle Rectangle (axis-aligned) Ellipse (axis-aligned) Circle Rotated Rectangle Combo (a mix of the above in a single image) More shapes can be added by implementing the following interface: type Shape interface { Rasterize() []Scanline Copy() Shape Mutate() Draw(dc *gg.Context) SVG(attrs string) string } Features Hill Climbing or Simulated Annealing for optimization (hill climbing multiple random shapes is nearly as good as annealing and faster) Scanline rasterization of shapes in pure Go (preferable for implementing the features below) Optimal color computation based on affected pixels for each shape (color is directly computed, not optimized for) Partial image difference for faster scoring (only pixels that change need be considered) Anti-aliased output rendering Inspiration This project was originally inspired by the popular and excellent work of Roger Johansson - Genetic Programming: Evolution of Mona Lisa. Since seeing that article when it was quite new, I've tinkered with this problem here and there over the years. But only now am I satisfied with my results. It should be noted that there are significant differences in my implementation compared to Roger's original work. Mine is not a genetic algorithm. Mine only operates on one shape at a time. Mine is much faster (AFAIK) and supports many types of shapes. Examples Here are more examples from interesting p
Read the full README on GitHub

What Hacker News says

42 sources
I made a simple web UI[1] for generating images like this. It uses a Go library by Michael Fogleman[2] for all the heavy lifting—hat’s off to him. For Bézier curves in particular, iteratively constraining the search around initial matches seems key to retaining detail (see the “rep” argument in Fogleman’s work), for example in the eyes of the Vermeer portrait in the OP. [1]: https://github.com/kevin-hanselman/primitive-web-ui [2]: https://github.com/fogleman/primitive
In Iterative image reconstruction using random cubic bézier strokes
TIL about https://github.com/fogleman/primitive from "Comparison of raster-to-vector conversion software" https://en.wikipedia.org/wiki/Comparison_of_raster-to-vector... which does already list vtracer (2020) visioncortex/vtracer: https://github.com/visioncortex/vtracer Vector graphics https://en.wikipedia.org/wiki/Vector_graphics Rotoscoping: https://en.wikipedia.org/wiki/Rotoscoping Sprite (computer graphics) https://en.wikipedia.org/wiki/Sprite_(computer_graphics) E.g. pygame-web can do SVG sprites; so that you don't have to do pixel art and sprite scaling just works. 2.5D: https://en.wikipedia.org/wiki/2.5D 3D scanning: https://en.wikipedia.org/wiki/3D_scanning "Why Cities: Skylines 2 performs poorly" (2023) ... No AutoLOD Level of Depth https://news.ycombinator.com/item?id=38160089 Wavetale is a 3D game with extensive and visually
Read the rest
impressive vector graphics.
In Vtracer: Next-Gen Raster-to-Vector Conversion
I think the “smallest” is the interesting part of this exercise. I think it needs to aim for lossless, with a sliding scale of quality that loses detail to the point where a human would notice. Consider an SVG from [Primitive](https://github.com/fogleman/primitive) and a mostly-transparent overlay containing the diff against the original image. Tuning Primitive is not entirely deterministic (like your algorithm) and I think a human interface for the front-end would allow a few knobs to erase parts of the diff in order to shrink the detail imperceptively. Seems like a good opportunity for a contest :)
In Experiment in evolving the smallest image file format
I've started work down this path for a project I am working on. I downloaded some footage of satellites flying over the earth from NASA, used FFMPEG to extract each frame of the video, wrote a ruby script which runs over every image in a folder and calls primitive (https://github.com/fogleman/primitive) on each image. The final step is to recombine it into a single video, which I haven't done yet because I haven't yet implemented video playback in the program I'm writing. In the meantime I'm just loading each image on the fly and playing it as a sprite animation. This results in low FPS but it gets the gist across. https://www.youtube.com/watch?v=SBFGqxWYyvI&feature=youtu.be I'm thinking it'd still look pretty choppy even if it was a 60 FPS video though. I'm not yet sure how I'm going to smooth it out. I can share the FFMPEG command I use
Read the rest
d / script I made with you if you want, but I'd have to find it first (this was maybe a year ago). I'm sure the script is garbage. I do not believe the go program that I am using is deterministic. You can run the same command on an image twice and it will produce a different result. It might be possible to make it deterministic, but it's not something I've wanted so I haven't looked into it.
In Geometrize: Turn Images into Geometric Primitives
There's a pretty awesome project that does this with SVGs. https://pkg.go.dev/mod/github.com/fogleman/primitive https://primitive.lol/ I've used it in a project to generate vector thumbnails that are under 1KB that I can just base64 encode and send along with the general text of a page - so the page renders with the text and low-fi images, and then I can load the hi-fi ones as necessary. The lo-fi images are art in themselves, sometimes I preferred them to the actual images :-P
In BlurHash: Algorithm to generate compact representation of an image placeholder
I was just poking through some of the code and noticed that there seem to a lot of open bugfix PRs [1]. Have you thought about going through and upstreaming some of them? Many of them seem like quick reviews. Edit: Also, if you would like some help maintaining it, I imagine plenty of fellow HN-ers (including me) would love to help. [1] https://github.com/fogleman/primitive/pulls?q=is%3Aopen+is%3...
In Primitive – recreate your photos with vector-based geometric primitives

Showing the 15 most recent of 42 sources. Enable JavaScript to search and browse every indexed mention.

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.