23 comments

[ 0.23 ms ] story [ 58.0 ms ] thread
Very cool, would love to see transparency for the brushes overlay.
How wonderful. I’ll make some art in it.
Does not work with Brave 1.8.86 (current) with Shields Up - JS errors for localstorage and precision. Works with Shields down. Would be nice to either still have it work but show a message maybe? Very nice otherwise!
Nice! This reminds me of Deluxe Paint on my IBM XT with a monochrome monitor. It's astounding how beautiful 1-bit art can be.

A related tool: Pixilart -- a web based tool for drawing pixel art (favicons, etc.)

https://www.pixilart.com

Fill tool reveals that it's not really painting with 1-bit but the dithered colors are actually "colors" that are rendered as dithered.
It’s also made obvious if you use the “Move view” button (the four-way arrow) and drag the image around; the image is continously re-rendered, and the pixels shows Moiré-like patterns as the image moves.
Which is a good thing. Since you'll be able to change fill.
How is it 1-bit? Each pixel can be one of 16 different shades of grey. That's 4-bit, isn't it?
Each of those "greys" are actually dithered 1-bit patterns
I think that's just how it's rendered by default - but really the greys are stored at every resolution, so you need 4-bits per pixel.

Plus the app also preserves the difference between 'not drawn' and 'actively drawn in black', so that's another bit needed for 5-bits.

Notice that when you save the image you really get shades of grey and transparent - not dithering.

(comment deleted)
Weird. Better to screenshot than
The greys are stored at every resolution? What do you mean?

The web page states:

16-'color' palette via dither patterns. Each pattern is treated as a separate color for fill tool

However, I suspect this is the bit (no pun intended) you're missing:

save images as a 16-color greyscale (which will import back into Strike with all patterns intact), or as 1-bit black and white image

> The greys are stored at every resolution? What do you mean?

Try it for yourself. Draw one single pixel in one of the middle greys.

Now zoom in.

You can see the dithering pattern now matter how far you zoom in.

How does it know what dithering pattern to keep drawing? There are sixteen to choose from. That requires 4 bits. But we drew just one pixel, so we have just 1 bit of information.

How do you think they're getting 4 bits of information from 1 bit? They can't be - that's impossible. It must be storing the colour you chose for each pixel and then be drawing the dither pattern each time.

> save images as a 16-color greyscale (which will import back into Strike with all patterns intact)

I'm not missing anything. Again - try this as a thought experiment. Draw a single pixel in a mid grey. Export as an image. You'll see a grey colour. How do you think it's recreated that grey from the dither pattern... when the dither 'pattern' is just one single pixel either on or off as that's all we drew? It can't possibly be doing that, can it? That's nonsense. It must be storing each colour per pixel when drawing.

I'm not missing anything

I think you are missing something or perhaps you're interpreting this in a very pedantic fashion.

If you actually use the tool and ask it to export a 1-bit image you'll get a png file. If you zoom in after opening that png file in a editor like Affinity Photo or GIMP, you'll see exactly what the editor describes -- simple pixels that are either black or white.

The argument seems to be that it's not a 1-bit editor because it doesn't have a 1:1 representation between the individual "pixels" in the editor and the output.

However, I would argue it is a 1-bit editor because that's the final output -- a 1-bit image.

The fact that it maps each of the 16 'colors' to a 1-bit dithering pattern seems like an innovative way to provide 1-bit results.

The implementation of grid based dithering is "bad", it's inconsistent at 1 pixel draw size since you can actually draw nothing if you are on a wrong line!
Not often you find a web app that’s more powerful with a touch interface, but the ability to drag multiple fingers simultaneously is pretty cool.
For me it treats every touch point as if it's the same finger, yielding lines between them. A fun effect, but probably not what is expected.
I love this, but it suffers from an issue I've observed in my own attempts to make mouse-based drawing tools in the browser with JavaScript. If you move your mouse too quickly, the low polling rate of events becomes evident because rather than showing a smooth curve, you see straight lines that are drawn between the two points that were captured for each event.

This is my white whale.

I don't currently have the math chops to fix this in my own implementations, but there are others who have succeeded where I have failed. For example, the web client/controller thingy for the game Drawful 2 by Jackbox has addressed this. Since you can't increase the polling rate in the browser and you can't arbitrarily read the mouse position during things like requestAnimationFrame, you're forced to interpolate the movement of the mouse given the past few events. They're using curves in Drawful 2 instead of straight bitmap-style canvas drawing like in the first Drawful.

But beware, this has a downside. It's very easy to incorrectly interpolate the movement and exaggerate the curve, making it curvier than the actual movement of the mouse.

I guess the web browser just wasn't designed with precision input capture in mind. But that doesn't mean we can't still aim for improvement. For a game like Drawful, more options are probably overkill. (They don't allow you to erase by design.) But for an art tool like this, it might be worth adding an option for input smoothing along with knobs to tweak to adjust the smoothing amount. Or not. I certainly can't fault you for not implementing such a feature given that I can't seem to get it to work.

I did a little research into this. This website [1] mentions something I'd never heard of before. That some browsers "collapse" real mouse events into fewer "fake" events that tie the event poll rate to your monitor's refresh rate. Even though I'm using Firefox and not Chrome like they mention, I'm seeing that exact phenomenon. The highest number of mouse events I can seem to generate is 60 per second.

However, this other website [2] is showing me events on the order of up to 124 Hz. Either that site is doing something special or it's lying. The JavaScript there is decently obfuscated. I'm going to spend a few minutes trying to deobfuscate it and see what I can find out.

[1] https://www.vsynctester.com/testing/mouse.html

[2] https://zowie.benq.com/en/support/mouse-rate-checker.html