Hacker News new | past | comments | ask | show | jobs | submit login
Pixie – A full-featured 2D graphics library for Nim (github.com/treeform)
200 points by elcritch 8 days ago | hide | past | favorite | 75 comments





For those using Python, we just got our Python bindings for Pixie up onto pip. Repo here https://github.com/treeform/pixie-python

It's extremely fresh but our tests are working so consider giving it a try.

For those interested in Nim's meta-programming, we're generating those Python bindings for Pixie from our Nim code using https://github.com/treeform/genny here https://github.com/treeform/pixie/blob/master/bindings/bindi... More languages in the works.


Unreal - I pip-installed the library, ran the demos, and it just worked! After years of mucking about with pyCairo this is a very pleasant surprise!

This has a high risk of being confused with PixiJS, which is often just referred to as pixi, and is a popular 2D WebGL renderer.

https://github.com/pixijs/pixijs

This project is likely to get drowned out by pixi search results when its users try to Google anything related to it.


It's almost impossible to come up with names these days due to the massive amount of software released every year. It's so bad that I automatically include the language name as well as the framework name in any search I do.

In this instance the Nim and JS libraries have different names (and even different spellings of the common subset) so I don't see an issue.


I explained the issue. In case you need to see it, here's a screenshot of me googling for something pixie related (that shows up in its README.md), but getting pixi.js results.

https://i.imgur.com/9pJuaJO.png


> I explained the issue. In case you need to see it

That's an awful lot of sass from someone who didn't bother to read my post:

1. You're not using the language name in your search query like I suggested one should. So your example is moot.

2. You're still being highly critical about something that is awfully hard to get right. Naming projects is one of the hardest things you can do to a project. Firefox went through 2 naming collisions before they landed on Firefox. As an open source contributor myself I frequently get people say "Your name is used by this thing over here too" despite me spending literally hours going through multiple different name options and Googling them to see if they have a presence (search engines aren't always good for checking this stuff by the way).

When there are hundreds of thousands of people creating software each month, you quickly run out of phonetics to use. While naming might seem like an infinitely large namespace, in practice there's only a finite number of names out there yet a literal infinity of projects due to new ones popping up all the time. So collisions aren't just inevitable, they're going to become more frequent too.

This is why open source frameworks for different languages where the spellings differ is fine in my opinion because you should always include the language you're targeting in your search query for more accurate results anyway.

Sometimes I think people just like to throw namespace collisions as a criticism on HN because they're too lazy to research the framework properly but still want to appear knowledgeable to everyone else. It's literally the lowest effort critique one can make on a project.


I pointed this out because pixi.js was the first thing I thought off when I read the title of this post. Others have pointed out they made the same association.

Do you really want to pretend with all your might that naming your graphics library after the same creature as another graphics library is a good idea? Really?

Coincidentally I just named a rendering library for WebGL a few days ago and it's already the first result on google.

Naming projects isn't that hard if you don't want a 3-6 letter name. There's only so many possible combinations of five characters. You'd think software developers of all people would understand that and maybe stop giving their projects short names that look like acronyms and convey literally no meaning.

The easiest way is to pick a longer descriptive name with a good acronym. If your project becomes popular, it'll become known by that acronym. Most 2 word combinations aren't taken either.


> I pointed this out because pixi.js was the first thing I thought off when I read the title of this post. Others have pointed out they made the same association.

People make associations all the time with often unrelated things. That's exactly how our brains are wired to operate. The fact is the names in question are still different.

> Coincidentally I just named a rendering library for WebGL a few days ago and it's already the first result on google.

Google tailors results. And I bet if you shared the name of your library I'd find some similar project that I have an association with when I hear your name.

> Naming projects isn't that hard

Naming things is incredibly hard!

> There's only so many possible combinations of five characters. You'd think software developers of all people would understand that and maybe stop giving their projects short names that look like acronyms and convey literally no meaning.

Love the contradiction of how you start out by saying naming things isn't hard and then go on to explain why naming things is hard. It's also worth noting that adding more characters creates might create more entropy but there's still only so many phonetic phrases available before you drift into the realm of stupidly long names.

> The easiest way is to pick a longer descriptive name with a good acronym. If your project becomes popular, it'll become known by that acronym. Most 2 word combinations aren't taken either.

Please no. Acronyms are almost as bad for names as stupid pseudo-words (like SPDY and NGINX). A name doesn't have to be English, but it should at least be a word. Otherwise you're making things artificially hard for anyone who isn't a native English speaker or who has reading difficulties (like dyslexia).

Like I keep saying, naming things is incredibly hard.


I guess we'll have to agree to disagree.

> In this instance the Nim and JS libraries have different names

They're both named "Pixie" and they're both graphics libraries. I assume you meant something else than what you literally said, but I'm not sure what


"Pixi" != "Pixie"

But "Pixi" == "Pixie" when evaluated by humans

It's called PixiJS though.

The namespace is pixi which is what people will be searching.

Then they're searching wrong because that's not the name of the package. Plus, as I opened with, people should be including their language name as part of the search query by default regardless of the framework's name.

It seems absurd to me that developers are too lazy to add one extra keyword to their search to ensure they get specific results, yet are happy to moan about maintainers not putting enough effort in to avoid namespace collisions in a finite pool of usable project names (and particularly when the project names here are literally different). This strikes me as bad workmen blaming their tools; you have a bad search etiquette and are then passing the buck onto the maintainers to fix.

Sorry if that seams harsh but naming things is really hard but adding `nim` into your search query is really easy. To me it is pretty clear cut where this problem should be solved.


The levenshtein distance is still just 1 insertion so search results will likely be mixed.

Its not a real HN library thread without unjustified irl-namespace collision claims.

Yes, I also just came here to ask a question about pixijs ...

I read the title, and thought pixijs had moved to nim + webassembly.

Nim is such a breath of fresh air when I read it. This library looks great.

I've been trying to learn it / grok its documentation for awhile. Any suggestions on how to learn it better? I've given Exercism.IO a try (disclaimer: satisfied learner from there but not trying to shill) but I've had difficulty adopting the language from a Python background.


Nim's a pleasant language to read/write! Out of curiosity, what aspects have you found challenging to learn? One caveat of imitating Python's syntax is that the semantics are not the same as in Python and are closer to Pascal/Ada in many ways.

If you haven't read through the Nim-for-Pythoners [1] it'd be good. I read the "nim manual" [2] constantly and just use ctrl-f. Though Nim Basics by narimiran is a nice tutorial form [3].

There's a few standard links: 1: https://github.com/nim-lang/Nim/wiki/Nim-for-Python-Programm... 2: https://nim-lang.org/docs/manual.html 3: https://narimiran.github.io/nim-basics/


I just read through a bit of their documentation. So, I only have all of five minutes of experience with Nim. But it looks like a pleasant language to work with. I could see this becoming popular and it looks like something I could figure out pretty easily.

I did not see any allocs/de-allocs, which suggests some kind of garbage collector is being used? I guess a lot of that is straightforward with stack allocated data structures going out of scope. But that would put this language in the same realm as Go and not Rust/C/C++, which don't rely on garbage collectors.

I'm mainly doing Kotlin currently, which also has a multi platform compiler (with native, js, and jvm compilers). Though particularly the native compiler is a bit a work in progress. But, Nim could be considered similar to that as well. Though obviously the languages are very different, what is similar though is a focus on programmer convenience. It's something I really appreciate in Kotlin and it seems this language has a lot of that too.

It will be interesting to see how this language grows and evolves. Looking at Rust and Go in recent years, there are a bunch of gnarly topics that inevitably come up like how to deal with asynchronous stuff and co-routines, generics, error handling, etc. Kotlin also had its fair share of that. That's when languages get more complicated. I think Rust is a good example of a language that has a pretty high level of complexity at this point.

Just a first impression. But mostly a good one.


> I did not see any allocs/de-allocs, which suggests some kind of garbage collector is being used? I guess a lot of that is straightforward with stack allocated data structures going out of scope. But that would put this language in the same realm as Go and not Rust/C/C++, which don't rely on garbage collectors.

Nim use a new GC they call ARC, which is just a clever combination of non-atomic/locking reference counting and move semantics. That combination enables the GC to be realtime capable and deterministic. It's also doesn't have GC pauses or issues with enormous heaps, but it requires more work when multi-threading. In theory Nim sounds be more similar to Go than Rust/C/C++, but with ARC you can use Nim where you'd use C/C++ (or turn off GC entirely). I'm using it on embedded RTOS'es and routinely getting exactly the same memory allocations with only a single integer add/sub overhead. Actually, many larger Rust programs end up using `Rc<mystruct>` a lot, which should result in an almost one-to-one correspondence on generated code to what Nim+ARC produces.

> I'm mainly doing Kotlin currently, which also has a multi platform compiler (with native, js, and jvm compilers). Though particularly the native compiler is a bit a work in progress. But, Nim could be considered similar to that as well.

Probably not a bad comparison. Kotlin sounds like a pragmatic language with just enough "functional concepts" to make it more productive but not type/theory heavy.

> It will be interesting to see how this language grows and evolves. Looking at Rust and Go in recent years, there are a bunch of gnarly topics that inevitably come up like how to deal with asynchronous stuff and co-routines, generics, error handling, etc.

Ouch, those are tough topics. I avoid Nim's async because it requires cycle detection (ARC w/ cycle detection) on embedded. Rust has difficulty with closures and async for similar reasons IIRC. Luckily Nim's error handling/async/co-routines are all pretty standard otherwise. There's some work to be done in Nim for improving modules and removing nill'able types from the standard library. But nothing that should cause the gnarly topics Rust/Go have been facing (:fingers-crossed:).


There is a choice of garbage collectors (including none at all, although a lot of the stdlib breaks in that case). The "main" one the language is moving to is ARC/ORC. See here for more info: https://nim-lang.org/blog/2020/10/15/introduction-to-arc-orc...

> I think Rust is a good example of a language that has a pretty high level of complexity at this point.

I'd say the opposite. Just look at how it compares to C++. Even Swift is a rather complex language when compared to Rust.


two resources i enjoyed:

"nim in action" by dom96 https://www.manning.com/books/nim-in-action

nim days by xmonader https://xmonader.github.io/nimdays/


To learn any new language or framework I just recommend diving in and doing things. Have some goal and mind that you want to create and work at it. Its usually hard to start at first but once you get going its just a little bit of progress at a time.

Despite completely disagreeing with you on the first point, I've had some of the same experience too.

Some years ago when I was going through languages frequently, I was pretty interested in it for a bit, but found it kind of hard to get into and my interest ultimately wandered.

I thought a large part of that was due to my unusually strong dislike of the syntax, and that that was why I found it unusually difficult to grok. Maybe it wasn't. Interesting.


I’d recommend looking into Nim in Action [1] by Dominik Picheta. Really good book overall and helps get you up and running with Nim concepts. Dominik is core Nim team and author of Nimble.

1: https://www.manning.com/books/nim-in-action


This was the final presentation at NimConf in June and I was blown away, as I am sure many others were. The fact that this library exists makes the task of creating a high quality retained-mode UI library in Nim much easier. You don't have to try and wrangle Pango/Cairo/Skia to act as your foundation.

Thank you for watching our pixie presentation!

Sure. I think they saved the best for the last, but I am biased as someone who has developed a lot of UI frameworks. The other presentations were great as well.

(Off topic.) What are your thoughts on a UI framework having a tightly bound language, like tcl/tk, js/html, etc...?

Reminds me of BGRABitmap from Lazarus/FreePascal.

https://github.com/bgrabitmap/bgracontrols

(BGRAControls contains the BGRABitmap components).

It's sad Lazarus/FreePascal doesn't get much play, because high quality libraries like this have existed for years for it and it seems to not get much traction.


Why do you think that is? Pascal as a language? The IDE? Is there a lack of success stories or high profile applications?

Stunning. Already supports all popular font types, image types, and SVG.

It’s really great work. The font support is a bit behind the times though, and text shaping is non-existent. I see so many libraries fall at that hurdle, they think they can do it themselves then when they realise it’s hard and requires a team of people they either abandon it or tell you to use harfbuzz without the necessary integration points. Hopefully that won’t be the case here!

Rust managed to get text shaping (https://github.com/RazrFalcon/rustybuzz), you can certainly do it yourself but it's just a lot of work...

I agree shaping is hard. But so is a lot of other things we have done. We will just take it one setup at a time. I am sure with time we will conquer shaping as well.

I don't think treeform and guzba will have much trouble, honestly.

Not to mention operations like "complex blends: Darken, Multiply, Color Dodge, Hue, Luminosity... etc" and many SIMD accelerations. It also has Node, Python, and C interfaces. Though I haven't found an excuse to use it yet. Surely there's got to be some excuse... ;)

If you're looking for a small, fast CPU-based 2D library, you might be interested in https://github.com/RazrFalcon/tiny-skia

Just like Skia, all pixel accesses is SIMD accelerated.

It doesn't have C bindings, but they can be trivially implemented.


Ah, that's the thing.. I don't have a reason/need for using a fast 2d library. It's that Pixie's Nim API makes me want to have a reason. Like maybe it'd be fun to write a modern plotting backend with it! Currently even one of Julia-lang's best plot backends uses a C-based plotting library, GR [1]. It's a pain to use from raw C bindings though. :/ Also while Rust is great, I'm too lazy to program in it. All them `& mut<RC<box<mything>>` things. ;) (Yes I know that's not real Rust code...) Though tiny-skia does look like a well done library!

1: https://gr.readthedocs.io/


Dug into the source for the GIF decoder a bit and it looks like it only supports the most basic features- no windowing, animation, local colortables, or background colors. I suspect many optimized static GIFs won't decode correctly. Still, everything has to start somewhere!

We did not really "need" a GIF decoder but it was a fun thing to make. It can decode many many gifs, but yes its still missing features. I hope to get to them though eventually.

SVG support has been really helpful for me to see a diverse and "real world" set of rendering results when working on Pixie. And for testing it's great to be able to grab huge sets of open source SVG files and check our results.

For example, I have a few "megatests" where I render entire icon sets or emoji sets such as https://raw.githubusercontent.com/treeform/pixie/master/test... and https://raw.githubusercontent.com/treeform/pixie/master/test...

Running these tests helps me feel more confident that changes I'm making are not breaking things.


I'm sure you will be interested in https://github.com/RazrFalcon/resvg-test-suite

From a quick glance, pixie should pass 10-20% of those tests. Yes, SVG is that complex.


I had been using ImageMagick for these types of things. Wondering how pixie improves over it.

Without knowing how much overhead Nim brings in, I still believe it would have been better if this library preliminary was a C or C++ lib and then had binding for all the other languages.


Nim nowadays (with the new ARC/ORC memory management) seems to be similar with C++ in terms of runtime overhead, so I don’t think you need to be too worried about it.

This is correct. Given any C/C++ program one can write an equivalent Nim program. But because you have advanced metaprogramming available to you it will probably be shorter and easier to understand.

I am not sure Pixie improves over ImageMagick. Perhaps it has some more advanced blend modes or other algorithms that ImageMagick hasn't implemented. ImageMagick is really great for pipelines of conversions. I see Pixie being more of a Quartz, Cairo, Skia, etc. for the Nim platform that can serve as the low-level canvas for a lot of higher-level functionality. Sadly, I am not enough of a Nim expert to know the trade-offs between using native code or importing C libraries.

  > Sadly, I am not enough of a Nim expert to know the trade-offs between using native code or importing C libraries.
I'm no expert either but (not sure if this is what you're getting at) Nim is "compiled" to C/C++/JS and you have nearly full control over emitted code.

So I don't think it's far-fetched to emit C with hand optimizations if you really need them.

That's the weird thing about Nim. It's not really a new language so much as a syntax and front end to several existing languages.

If you compile in "-d:danger" mode turning off all checks and highest optimizations, the C code it spits out is pretty human readable even.


    > That's the weird thing about Nim. It's not really a new language so much as a syntax and front end to several existing languages.
This is a bit of an over-simplification. Nim does a lot of stuff on its own, so you won't be able to convert back from C to Nim for example. The most obvious being of course the macro system that is just normal Nim code but is evaluated at compile-time and generates code for you. In fact you can use the compiler to evaluate Nim without compiling it, so it certainly falls into the language in its own right category.

I actually wrote a small program for batch scaling images using pixie a couple weeks ago and it was a bit faster than ImageMagick, and the results looked the same. The scaling in pixie is a little less flexible though.

I haven't really compared any other features though. Scaling images does appear to be quicker though (when compiled with -d:release -d:danger --opt:speed)


After the conference talk, I rushed to try it out. I remember having quite some difficulty getting the demos to work well on a Mac and eventually gave up.

Can you give us more details on what did not work for you? We would love to fix it.

I've been looking for an alternative to Skia so this looks interesting. Why Nim though? I've never heard of it before.

I chose to write Pixie in Nim because I really like Nim:

* Nim very fast. I can beat any C/C++ program in performance using same tricks as they do. Cleaver Memory management, inlining, static analysis, SIMD. There is no wall that you run where you need to drop into "C".

* Nim is very easy to write, I came from Python/CoffeeScript and it was a very easy transition. Nim feels like Python with Types.

* Nim is very powerful with generics/templates/macros allowing you to write DSLs quickly.

* Nim has very easy interop with C. So its very easy to use existing C libraries or low level operating system APIs.

* Nim works everywhere: From Desktop Windows/Mac/Linux, to mobile iOS/Android to embeaded devices. It even compiles to JavaScript (like CoffeeScript/Typescript or WASM) or GL shader language. It run anywhere.

* Nim has a smaller community that has not been overrun by complexity or apathy. Everything feels green and fresh and everyone helps everyone else. But still big enough that there are libraries for most things.


Looks like a great library, though the name is going to cause some people to think it’s related to pixi.js

That's unfortunate. I did not know about pixi.js when we picked the name. It feels like all of the cool names are taken! When we were thinking of a name we just looked around the Nim community for name collisions.

So, I've been thinking about making a library like yours, and as with most things I think about nothing came of it. However, I did have a name picked out: "Graffiti".

I think it's kinda cool and relevant, and a quick search didn't reveal any other library with the same name. If you're up for rebranding, feel free to use it :)


Is pixi.js pretty big? I haven't heard of it before tonight, and I thought I'd had exposure to most of the bigger JS frameworks via HN (I'm not a JS guy, more Python).

Yup, Pixi is the most popular javascript 2D game engine/renderer, with over 34k stars on github. It’s used all over the place.

As good as pixijs is, I wouldn't call it a gaming engine. Unless things have evolved in that direction. I haven't used it in 3 years or so

Well it’s more than just a renderer, since it also handles interaction… so I wouldn’t say it’s wrong to call it an engine, but you can just call it a framework if you want.

I'll probably take this up for my artistic work (currently using PyGame and p5.js). Thanks!

Is anyone aware of anything like this for Go, Rust, Zig or similar?


You should also check out the femtovg project, a 2D rendering API that sixtyfps relies on.

https://github.com/femtovg/femtovg

It's a decent starting point for trying to build your own toolkit.

I have recently added a wgpu backend but for now it lives in my fork https://github.com/adamnemecek/femtovg run the demo with `cargo run --example wgpu_demo --release`.

Also join the femtovg discord https://discord.gg/V69VdVu


Very cool, thank you! :)


That's super cool, thank you! :)

I for one welcome the butt caps.

I guess some people don’t welcome butt caps. The world is a complex place.

Still stanning for butt caps



Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: