Sitemap

ITNEXT

ITNEXT is a platform for IT developers & software engineers to share knowledge, connect, collaborate, learn and experience next-gen technologies.

Controlling Paint Worklet with JSON in CSS

3 min readApr 24, 2019

--

This article is based on my Polish blog post about the same topic.

If you’re following the JavaScript community, you probably know about CSS in JS. It’s a way to put your CSS into your JavaScript file, instead of the separate CSS file. The solution I’m showing in this article is the opposite, it’s a JSON object put into the CSS file that is parsed in JavaScript (you can probably put JS in CSS but I didn’t test it). The reason why we do this is to control JavaScript-based CSS, the API that is part of Houdini.

Press enter or click to view image in full size

Houdini

Houdini is a collection of new APIs created for one purpose. So the developers can be in control of how the CSS engine behaves. To hook up in its internals and make it work as they want. Some of the APIs are already implemented, Some are planned to be implemented, and some are still in a design process so they may change. You can see the status of the Houdini on the site ishoudinireadyyet.com.

Paint Worklet

This worklet is like regular worker (separated thread run in the browser) but it allows to register “paint” class that has access to canvas-like API that can be used inside CSS to render things (e.g. using background-image)

To register the paint worklet you execute this code:

CSS.paintWorklet.addModule('plik.js');

Inside that file you can create special class like the one below:

class Circle {static get inputProperties() {
return ['--pointer-x', '--pointer-y', '--pointer-options'];
}
paint(context, geom, properties) {
var x = properties.get('--pointer-x').value || 0;
var y = properties.get('--pointer-y').value || 0;
const prop = properties.get('--pointer-options');
// destructure object props with defaults
const {
background,
color,
width
} = Object.assign({
color: 'white',
background: 'black',
width: 10
}, JSON.parse(prop.toString()));
// draw circle at point
context.fillStyle = color;
console.log({x,y, color, background, width})
context.beginPath();
const r = Math.floor(width / 2);
context.arc(x, y, r, 0, 2 * Math.PI, false);
context.closePath();
context.fill();
}
}

then you can register this class as paint:

registerPaint('circle', Circle);

JSON in CSS

If you take a look at the previous code of the class you will see this:

const prop = properties.get('--pointer-options');
JSON.parse(prop.toString());

So we get raw data from CSS and parse it as JSON. In CSS it look like this:

div {
height: 100vh;
background-image: paint(circle);
--pointer-x: 20px;
--pointer-y: 10px;
--pointer-options: {
"color": "rebeccapurple",
"width": 20
};
}

Each time you change the custom property (the one with two dashes at the front, also called CSS variable) it will re-render the background.

NOTE: Last time I tested this code, CSS variables required to have dash in the middle, otherwise they were not working with the paint worklet.

When you add custom properties to your CSS, you also need to register them, so they have type:

CSS.registerProperty({
name: '--pointer-x',
syntax: '<length>',
inherits: false,
initialValue: '10px'
});
CSS.registerProperty({
name: '--pointer-y',
syntax: '<length>',
inherits: false,
initialValue: '10px'
});
CSS.registerProperty({
name: '--pointer-options',
inherits: false,
initialValue: '{}'
});

And the last thing you can do is to change the CSS properties on mouse move:

document.querySelector('div').addEventListener('mousemove', (e) => {
const style = e.target.style;
style.setProperty('--pointer-x', event.clientX + 'px');
style.setProperty('--pointer-y', event.clientY + 'px');
});

You can check the whole code in this CodePen demo.

If you like this article you can follow me on Twitter @jcubic.

--

--

ITNEXT
ITNEXT

Published in ITNEXT

ITNEXT is a platform for IT developers & software engineers to share knowledge, connect, collaborate, learn and experience next-gen technologies.

Jakub T. Jankiewicz
Jakub T. Jankiewicz

Written by Jakub T. Jankiewicz

Web developer, technical writer, Open Source programmer and Polish Wikipedia editor. Also not professional photographer and logo designer.

Responses (1)

How does rerendering after calling `style.setProperty` work? Would it be more efficient to set both x and y at once in a single setProperty call?

--