Description
An inverted drawing experience.
Created on 30 Oct 2025
Code
<style>
html, button {
color-scheme: light dark;
font: 1rem ui-sans-serif, sans-serif;
accent-color: #f0f;
}
canvas {
z-index: -1;
position: fixed;
left: 0;
top: 0;
body:has(#flip:checked) & {
transform: rotate(180deg);
}
}
label {
margin-right: 1rem;
}
p {
margin: 0;
padding: 0;
opacity: 50%;
z-index: -2;
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
</style>
<canvas></canvas>
<label><input id="flip" type="checkbox"> Flip</label>
<label><input id="color" type="color" value="#ff00ff"> Colour</label>
<button id="clear">Clear</button>
<p>Draw a picture, then check the flip option and try drawing again.</p>
<script>
"use strict";
const canvas = document.querySelector("canvas"),
color = document.getElementById("color"),
clear = document.getElementById("clear"),
ctx = canvas.getContext("2d"),
startPath = (x, y) => {
ctx.beginPath();
ctx.moveTo(x, y);
},
continuePath = (x, y) => {
ctx.lineTo(x, y);
ctx.strokeStyle = color.value;
ctx.lineWidth = 2;
ctx.stroke();
},
mouseMove = ev => continuePath(ev.x, ev.y);
color.oninput = () => document.body.style.accentColor = color.value;
clear.onclick = () => ctx.clearRect(0, 0, canvas.width, canvas.height);
canvas.ontouchstart = ev => startPath(ev.touches[0].clientX, ev.touches[0].clientY);
window.ontouchmove = ev => continuePath(ev.touches[0].clientX, ev.touches[0].clientY);
window.ontouchend = () => ctx.stroke();
canvas.onmousedown = ev => {
startPath(ev.x, ev.y);
addEventListener("mousemove", mouseMove);
}
canvas.onmouseup = () => removeEventListener("mousemove", mouseMove);
(onresize = () => {
canvas.width = innerWidth;
canvas.height = innerHeight;
})();
</script>