Creative coding in Vue with VueXYZ

tldr; VueXYZ is a new open-source collection of composables for Vue 3, providing flexible ways to combine creative coding with the Composition API.

Simon Le Marchant
11 min read · 2024

Creative programming.

Everything’s a canvas

Early in my career I was a full-stack developer, building all sorts of projects from custom PHP and WordPress websites to SaaS apps and marketing funnels. As time went on, I found myself bored with coding the same old thing over-and-over, and started seeking out more creatively challenging projects. I wanted to push the boundaries of traditional web design, and work on things that other developers would shy away from. During this time, I was very lucky to get the chance to partner with some amazing agencies and transition towards creative frontend engineering work now building digital artwork, interactive installations and generative designs for some very reputable clients.

Creative frontend engineering requires a bit of a hacking mentality. You’re pushing the limits of a browser, trying to sift through everything at your disposal to convince it to render something very non-standard. On top of all of that, different browsers have different capabilities (I’m looking at you, Safari). It’s a constant balance between “can I make this look amazing” and “did I just set someone’s GPU on fire?”.

This can get complex fast, which is why I’m not surprised that “creative coding” libraries lean towards simplification. Take p5.js for example. It’s a pretty amazing tool that describes itself as focusing on “…making coding accessible and inclusive for artists, designers, educators, beginners, and anyone else!”. It works by, for the most part, greatly abstracting and simplifying the process of rendering primitive shapes to a HTML5 canvas.

At it’s core, that is what creative coding is — using primitive shapes as the building blocks for constructing complex and intricate visual compositions. Instead of needing to worry about how to define a triangle, you just call triangle() and you get a triangle on the screen. Call it within a loop, with varying parameters, and you can build some interesting visuals.

Creative programming.
A triangle strip, created in p5.js with a little math and shape primitives. Credit: Ira Greenberg.

Thinking outside of the canvas

P5 is a solid choice if your goal is to immediately visualize the output. There are also other options, like Pixi.js that’s described as “the fastest, most flexible 2D WebGL renderer”. And then there’s full-on products like Rive, that provide UIs around this. While they all have their differences, the key here is that they are all working with primitive shape methods, manipulating the data, and eventually they are are rendering something to the screen.

But, what if we don’t want to render anything? What if we need to position something instead?

I can’t tell you how many times for various creative projects I’ve needed to position a DOM element at {x, y, z} using a CSS transform. Browsers make life easy for “box-like” layouts, but the moment you want to position something on a diagonal line; there’s math involved.

Or for a more intricate example, imagine needing to position a series of DOM elements equidistantly across a Bezier curve, and then animate them in and out. The most troublesome task isn’t writing the CSS transformation, it’s calculating what those position values are supposed to be, for each DOM element, for every frame.

Now yes, P5 can manipulate the DOM directly, I’m not discounting it here. But it’s not a full reactivity library. There has to be a better solution for managing reactive state for these primitive shapes in the browser.

Creative programming.
Here I needed to position a unknown number of DOM elements on the edge of a circle. What you don’t see from the still image is the fact that this circle changes size, and these elements animate in by rotating around the circle. Without reactivity, this is a DOM manipulation and math-induced headache.

Based on the title of this article alone, you probably knew where I’m heading. Which incrementally-adoptable frontend framework has a reactive composable data architecture that would lend itself perfect to these sort of on-the-fly calculations, and that could ultimately bind data back to the DOM?

Yep, we’re talking about Vue 3, and the Composition API.

Looking back to p5’s triangle() method. What if, instead of using it to render to a canvas, you have a composable that returns reactive data?

const {vertices, edges, faces} = useTriangle({size: 100})

Sure, you could turn around and render that on a canvas, but you don’t have to. You could instead generate an SVG path from the edges, or you could take a single vertex from vertices and use it to position a different primitive shape. You could modify the data, however you see fit, before ultimately passing it to whatever component needs it - with full reactivity ✨

Introducing VueXYZ

VueXYZ is a collection of Vue composables for creative coding.

After having this in the pipeline in various different forms for years, I’m happy to finally say that VueXYZ is now open-source on GitHub. It features a bunch of 2D primitive shape composables that return various reactive data. It also includes a handful of powerful utility composables that you can use to manipulate and transform the data, turning it into something new.

Creative programming.
The homepage demo on https://vuexyz.org

Remember my challenging DOM example from before, placing DOM elements on an animated Bezier curve? With VueXYZ we can do that with relatively little code:

// assume start, c1, c2, and end are refs()

const bezierCurve = useBezierCurve({start, c1, c2, end})
const position = usePointOnPrimitive(bezierCurve, 0.25) // 25% along the curve
const style = useStyleTransform(position)

// useStyleTransform provides a reactive string you can bind to :style
// position: absolute; top: 0; left: 0; transform: translate3d(100px, 255px, 0px)

On the topic of positioning vs. rendering, VueXYZ actually has you covered for both. In this example we were creating a CSS style tag to position a DOM element using useStyleTransform, but you can actually render primitive data to a canvas or SVG context yourself with the built-in drawToCanvas and svgPath return values, available on every primitive shape. You can read more about rendering in the documentation. And of course, nothing is stopping you from using VueXYZ’s composables and Vue’s reactivity to build something, and then passing that into a p5.js or pixi.js for rendering there.

At the end of the day, this library is not a replacement for p5, Pixi, or anything else. It’s a new approach to looking at creative coding in the Vue ecosystem. It takes Vue’s reactivity and composable architecture and applies it towards some of the more complex UI challenges out there, helping you to think outside the box and to actually be able to code whatever weird and interesting things your project’s designer dreamed up.

I hope you get a chance to play around with it, and let me know what you think. Is it missing something, can it be improved? I’m open and looking forward to feedback.

You can find the full documentation and plenty of demos at https://vuexyz.org.

Thanks for reading, and happy coding!