csscss-houdinicss-paint-api

Can the PaintWorklet be inlined?


The idiomatic way to use the CSS Paint API seems to be:

  1. Create a xyz.js file
    • Populate with a class containing a paint(ctx, geom, properties) function
    • Call registerPaint, passing the class as an argument
  2. Call CSS.paintWorklet.addModule('xyz.js') from your index.html
  3. Apply the paint worklet in CSS like background-image: paint(myPaintWorklet);

More details on that here: https://developers.google.com/web/updates/2018/01/paintapi

But having to load a separate .js file is a performance hit.

Is there a way to inline the PaintWorklet so that a separate .js file is not needed?


Solution

  • One way to do it is using Data URLs. Demo: (works for me atleast on chrome 73). Example taken from here

    <style>
      textarea {
        background-image: paint(checkerboard);
      }
    </style>
    <textarea></textarea>
    <script>
      CSS.paintWorklet.addModule(`data:application/javascript;charset=utf8,${encodeURIComponent(`
        // checkerboard.js
        class CheckerboardPainter {
          paint(ctx, geom, properties) {
            // Use "ctx" as if it was a normal canvas
            const colors = ['red', 'green', 'blue'];
            const size = 32;
            for(let y = 0; y < geom.height/size; y++) {
              for(let x = 0; x < geom.width/size; x++) {
                const color = colors[(x + y) % colors.length];
                ctx.beginPath();
                ctx.fillStyle = color;
                ctx.rect(x * size, y * size, size, size);
                ctx.fill();
              }
            }
          }
        }
      
        // Register our class under a specific name
        registerPaint('checkerboard', CheckerboardPainter);
      `)}`)
    </script>

    Another method would be to make a Blob and pass the blob URL to the addModule function. This looks less hackish. Demo:

    <style>
      textarea {
        background-image: paint(checkerboard);
      }
    </style>
    <textarea></textarea>
    <script>
      CSS.paintWorklet.addModule(URL.createObjectURL(new Blob([`
        // checkerboard.js
        class CheckerboardPainter {
          paint(ctx, geom, properties) {
            // Use "ctx" as if it was a normal canvas
            const colors = ['red', 'green', 'blue'];
            const size = 32;
            for(let y = 0; y < geom.height/size; y++) {
              for(let x = 0; x < geom.width/size; x++) {
                const color = colors[(x + y) % colors.length];
                ctx.beginPath();
                ctx.fillStyle = color;
                ctx.rect(x * size, y * size, size, size);
                ctx.fill();
              }
            }
          }
        }
      
        // Register our class under a specific name
        registerPaint('checkerboard', CheckerboardPainter);
      `], {type: "application/javascript"})))
    </script>