
Strike: A web-based, 1-bit paint tool - polm23
https://amorphous.itch.io/strike
======
kyberias
Fill tool reveals that it's not really painting with 1-bit but the dithered
colors are actually "colors" that are rendered as dithered.

~~~
teddyh
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.

------
itsajoke
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.

~~~
itsajoke
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](https://www.vsynctester.com/testing/mouse.html)

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

~~~
itsajoke
I think I sussed out the secret sauce from that Benq website. They're using
the experimental getCoalescedEvents [1] function to uncollapse the mouse
events!

[1] [https://developer.mozilla.org/en-
US/docs/Web/API/PointerEven...](https://developer.mozilla.org/en-
US/docs/Web/API/PointerEvent/getCoalescedEvents)

~~~
codezero
I’ve seen some systems use a Bézier curve to a make a realistic stroke with
limited data points.

------
wenc
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](https://www.pixilart.com)

------
Piko
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!

~~~
leafo
The developer is aware and they're going to make it so the project doesn't
depend on localStorage being available to run the project:
[https://twitter.com/_morphous/status/1256465513611436034](https://twitter.com/_morphous/status/1256465513611436034)

In the meantime, you'll have to grant access

------
macintux
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.

~~~
ygra
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.

------
chrisseaton
How is it 1-bit? Each pixel can be one of 16 different shades of grey. That's
4-bit, isn't it?

~~~
xnxn
Each of those "greys" are actually dithered 1-bit patterns

~~~
chrisseaton
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.

~~~
binarycrusader
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_

~~~
chrisseaton
> 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.

~~~
binarycrusader
_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.

------
emilfihlman
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!

------
epa
Very cool, would love to see transparency for the brushes overlay.

------
onemoresoop
How wonderful. I’ll make some art in it.

