šŸ‘½ Lee Tusman

← Nosebook šŸ‘ƒšŸ““

L5: a New Creative Coding Library in Lua, in the family of Processing/p5 Languages

13 Dec 2025

16-minute read

L5, my creative coding library in the family of Processing-like languages has been out in early alpha for a couple weeks now. I haven’t even announced it here yet, so this post is where I’ll do so, as well as put some (very) early feedback notes.

I began the codebase for L5 in July 2025. I have been programming art with code starting with Processing around 2012. I enjoyed that so much and got deeper and deeper into it, even as I found I wasn’t so drawn to the language it’s implemented in, Java, which I grew to dislike even as my skills in programming grew. I just didn’t appreciate things like static typing or access levels.

When p5.js was announced, I was pretty excited. I had been periodically using Processing.js, a discontinued port of Processing to JavaScript, to share my work on the web, whose syntax mostly allowed writing Processing code with a couple modifications. With p5.js, not only was this a native implementation, but I found I preferred the JavaScript language a lot more to Java. I found it easier to understand as a relative beginner to programming, and I just plain liked that it was so fault-tolerant as a scripting language for a browser that prioritized that, versus a more rigorous compiled language.

I basically mostly jumped ship to p5.js for about a decade, working with it as the main tool I make art with. I continued to teach Processing and p5.js in my classes. I created hundreds, maybe a thousand works for web and even exhibitions in p5.js over a decade. p5.js got me into JavaScript, where I learned much of its large ecosystem, both its pros and cons. Especially as ā€œcoming out of the pandemicā€ I was starting to create more works to be presented in gallery and irl exhibition spaces, I was feeling the limitations of JavaScript.

To name several of these negatives: JavaScript as a language, and particularly the community of frameworks and development changes at lightning speed. From year to year favored environments, paradigms, code editors, packages rise and fall, grow in popularity, and most alarmingly, their APIs change. While p5.js doesn’t have this problem as much, as it’s hooked into browsers which do, I experienced a few of these changes, such as the requirement for a user event to trigger audio (which wiped out the full functioning of a bunch of my older deployed works), as just one example. As I began using p5.js along with other JavaScript frameworks (web audio, opencv, voice detection, and others), things would break, not due to p5.js so much but due to JavaScript.

And the browser environment began to be a hindrance at times. I tried going back to Processing, using it for several projects (an experimental film made with it, for example). At one point, as I struggled to get the video camera library to work with some of my students’ computers, due to Apple restrictions and changes, at some point I found I was dealing with similar issues as I had in JavaScript. And for my own artwork, I didn’t love the language syntax.

At this point I was making more of my own games, particularly small experimental ones and game-jam-style projects. During summer 2020 in the pandemic I began using Pico-8, a retro-inspired but modern game engine for making 2d games. It’s a comprehensive environment that includes a sprite drawing module, digital sound editor, code editor, even a way to browse others’ games and examine or fork their games. As much as I loved it, and made many games in it, it is a constrained environment. You are limited to 128 by 128 pixels, its digital sound synthesis (no samples), and code length limitations. This was fine for many things, and I absolutely loved the Lua language with Pico-8’s API. It produces cool retro-style games. But it’s not great as a general tool for making my artwork: the constraints don’t allow for my own typical art aesthetic nor way of using collaged and layered photographs and sound samples.

Aside from the syntax, I also found I really liked the speed of projects written in Lua. As a library with a C API, tight syntax, and simple, flexible features, I found it was just so, so fast, to use and to run, a result of its 2-step process where the language is compiled to bytecode and interpreted at runtime.

I began using LƖVE/Love2d in 2022 to make experimental game-like projects. Like Pico-8 it also uses Lua under the hood, and has a similar though many times more extensive API. Ideas I learned in Processing and p5.js for the most part carried over. I started using it more and more and began teaching an intro to programming class through making games.

But the idea of sculpting Love2d into more of a Processing-like creative coding framework lodged in the back of my mind as I wanted to use the same language for creative coding as the one I made games in. Love2d is great, has a long-running community, lots of resources, is well-documented. But despite using it for several years, it didn’t feel quite as free, improvisatory and sketch-like as my open-ended experimentation with p5.js had felt. The API was just a bit too big and frankly, not as Processing-like as I wished all the time. (I am working collaboratively on an academic article on this topic as well! Stay tuned.)

So this was the ultimate reason I finally in July 2025 decided to try a little experiment to build out drawing functions in a mini library that wrapped around Love2d’s native functions. Within a week that experiment had proven successful. It was flexible, intuitive to me, and fun to use. So I kept going and ran into my first roadblock: p5.js and Processing allow drawing graphics from anywhere, any event. You could draw graphics in setup. You could of course draw graphics in draw(). But you can also draw graphics in mouse events, key presses, etc. Love2d out of the box could not.

An acquaintance on social media pointed out that Love2d allows modifying and overwriting its basic event loop, and with that clue I was off. It turned into a much more extensive project and I went down rabbit holes debugging as this seemingly-minor change caused graphic irregularities like flickering if no background() color was being drawn for example. So I learned some more and had to add in double buffering. I had to rewrite the event detection to make it more Processing-like. And I started to have make bigger decisions: when to match Processing’s API versus p5.js’s? When to rewrite Love2d’s built-in methods to match Processing/p5’s versus keeping its native utility? And how to deal with the inevitable bugs this would cause?

I took consistent notes each day I worked on the codebase, which I wrote frequently on my project log. I sometimes asked friends in my circle for tips, but mostly just kept plugging away. I had a list of the API I wanted to emulate, which started at just under 200 main functions. And I kept a TODO list as I tried to implement them and found bugs to fix.

All of this work was only possible at the speed I took because I was on sabbatical, and an artist-in-resident at ZK/U in Berlin. I worked for up to (and sometimes more than) a dozen hours in a day. I was so motivated and excited by the work, which I was simultaneously dogfooding, using the library as I went to make my own art projects.

In fact, this is a big takeaway or teaching moment I would say. I started doing L5 Studies. This naming scheme of a studies I learned from doing Teletype Studies several years ago, also at the start of the pandemic. A studies as I understand and practice it is when you dive deep into using a tool regularly, and iteratively building more projects with it, documenting as you go, as a way to understand the tool better and to gradually use it with more of a sense of growing mastery. It’s a way of scaffolding more advanced projects and knowledge of using that tool, be it an instrument, software framework, or something else.

In winter 2021 - 2022 I organized my own PuzzleScript Studies, in my own home studio and in residency at Plexus Projects in Brooklyn. This resulted in a month of mostly one-a-day creative coding projects and games and prototypes written in the consrained, unique PuzzleScript game engine by Increpare. I loved how flexible and interestingly-constrained PuzzleScript was. And the studies method had been so useful. Years earlier I had begun Everyday code sketching as a way to produce lots of rapid small projects (several hundred), some of which turned into major projects and commissions, primarily though not exclusively in p5.js.

Now creating projects with this early form of what I was starting calling L5, I found so many bugs as I built projects, or needed parameters that I had failed to implement. I took to checking out the p5.js and Processing reference, then triangulating an implementation in Love2d/Lua on the backend of L5. Some were super easy, and quite minimal. Others required much more serious re-engineering of the Love2d codebase. And I had to make judgement calls.

An early decision I made, within the first week, was to consider accessibility. p5.js’s describe() function creates a screen-readable description of the canvas. It is part of what grew to be a fundamental commitment to access that underlies p5.js and its community and contributors, and Processing to a growing degree.

What would or could that look like in L5? While I don’t at all think I have anything like a comprehensive answer, I knew I needed to consider it from the beginning. I decided to start with what I knew, and try something, even if not perfect, deciding it was better to start somewhere and make corrections and gather feedback as I can. As L5 and Love2d are often launched through a terminal, in order to get error and printed output, it made sense to piggyback on this environment. In fact, see Accessibility of Command Line Interfaces and a number of blog posts for more on this topic.

At its simplest, right now the describe() feature outputs a provided text description of a sketch, which could then be piped to espeak-ng or other text-to-speech tool. The website for L5, of which I will write more later, was designed for many use cases, including accesibility, with attention paid to the underlying framework, the sizes and loading of images, semantic HTML, and use/ability to use without JavaScript.

I will continue to evaluate accessibility in L5 and hope to grow this and build out a way to gather useful feedback on progress here.

New ā€œfeaturesā€/focus: I wanted to also pause here and talk about another big priority of L5. Aside from the fact that the syntax is closer to a simplified JavaScript than Java, and the fact that it works on desktop, friends of mine know I have been very obviously been growing concerned with sustainability and consumption in art-making, computing and new media/media art/digital media, along with (somewhat mentioned above) interest in longterm resiliency of digital media and creative coding projects. (See for example, Trash Rules Everything Around Me, Linux on Low Powered Laptops, Intro and Design Goals of Archiving Artist-Run Spaces, Command line alternatives to cloud products and platforms, Old Computer Challenge and Permacomputing, Funeral for an E-reader, and my recent Some Permacomputing Links.)

The effect of all this, is I have fallen more in deep appreciation for Lua and its emphasis on longevity, compactness, and efficiency. Not only is it a tight language, built for embedding, flexible, but it’s extremely slow to change, with only small point changes from the release of Lua 5.0 in 2000 to 5.4 in 2020. The Masterminds of Programming interview with the developers of Lua was illuminating and reinforced my appreciation for their work and emphasis.

Likewise, LƖVE/Love2d, which I’ve thrown my lot in as the underlying framework for L5, shares much in common and intertwined with Lua’s strengths. It’s open source, few dependencies, it’s tiny (a couple megabytes), multi-platform and device, clear API, well-maintained and friendly development team, and easy to port. It’s been maintained since 2008, with continuity even through changes in leadership, and it benefits from a strong community. These are upstream of L5 and strengths. Still, it will be important to monitor development of Love to maintain L5’s library.

As I’ve grown more insistent with concerns of sustainability in computing culture and with software tools artists working with computing, I’ve looked to ideas such as Potential and Limits of Constraints in Computational Art, Design and Culture (PDF), I am trying to put my money where my mouth is, and build L5 to work on older computers and devices, in addition to working super-efficiently on modern computers. And this takes serious and sustained effort.

As an early example, I followed the work of a programmer implementing their own little stack-based language on top of L5. They pointed out they had a problem with loading L5 as several of the filter()s fail on load, even when not being used. The filters are implemented with shader code, and with my relative inexperience in shaders, I am learning more about different eras of shaders and what works or doesn’t work on different eras. So this programmer had had to comment out the shader portion of L5 and made a suggestion to optionally turn them off at runtime, something I’m considering along with some other options, and hope to survey the community. Interestingly, I learned their laptop is from 2009! So rather than say ā€œsorry, it’s too oldā€, which I think would likely be a common response elsewhere, I’m digging in and trying to reckon with how we can make L5 resilient, long-lasting, and useful here. I think it can be done. Frankly, the easily commented out shader code and then using the rest of the library as-is is a first step, but much more can be done. We could add fallback algorithms, an option to turn them off, or another option. I’m excited to put more effort to this in the months ahead, even as I acknowledge this will take longterm care as well. I also want to note that the programmer noted how easily it was to pull in Love2d for functionality they wanted that L5 didn’t provide (though I believe I’ve now patched the missing feature). This is theoretically an advantage, much like how in p5.js one can piggyback off the browser and JavaScript API if one needs additional functionality not built into the Processing/p5 core.

Seeing the first posts of L5 programs on social media has been gratifying, and getting excited feedback has been as well. L5 is already a useful tool for me, it’s become my primary way of making my own artwork. It’s just now starting to be useful for others. Seeing it get adopted by others is heart-warming.

I should take an aside here and acknowledge in addition to building on the foundation of Love2d just how much L5 is indebted to Processing/p5 and its strong community and caretaking by the Processing Foundation. I’ve had so much useful discussion with the current Processing Communitiy and Project Leads Raph and Moon, and p5.js Project lead Kit. They and many other members of the Processing community, as well as early mentorship from Processing co-founder Casey and p5.js creator Lauren that have been so helpful over the years have really helped set a guiding path for building and caretaking for this new tool and coding library. While this has been independently-organized, their ā€˜putting in the work’ over so many years (and decades!), along with the educational and foundation work of Daniel Shiffman, and other leadership in the community, has been so instrumental.

L5 benefits from the entire open source community, and the creative commons licensed materials of others, particularly for its documentation. Most of the reference, some examples and tutorials are adapted from Processing and p5.js (see these pages for full details). There is now a new tutorial A Complete Introduction to Programming with L5, from the creative commons licensed tutorials of Happy Coding. Presently install instructions are adapted from the Love2d wiki. Many more details are in the works, and it is a goal to develop a new L5 mode for the Processing IDE this winter, that should make L5 even more accessible to beginners for a wider community. All of this couldn’t happen without a strong open source and community-focused healthy art and code community. Hopefully L5 can be another contributor to this ecosystem.

This is the first post on L5 I’ve made and will likely be one of a number of posts. To be clear, the library/language is in its infancy, it’s at an alpha status now, and things can and will change. It would benefit from other contributors, bug reports, tutorials, more documentation, more eyes on the codebase, testing, and clean-up and refactoring! Its success will come as a result of this community in addition to my own caretaking. It’s an inspiring time, and an important moment in its life. Thanks to friends and acquaintances and all present and future collaborators for their help and feedback so far.