I think you might want to give the CJK and Hangul sections a separate approach pass with slightly different opacity settings, they're so dense that they end up too saturated!
Also, technically speaking drawing the last symbol with opacity 0.01 on top of all previous symbols doesn't result in a proper average. Think about it this way: first we draw one character. Then we draw the second character on top of it with 0.01 opacity. This has the result of reducting the opacity of the first by 0.99. This repeats for each character. So if we draw N characters on top of each other, the first character drawn will have opacity 0.01 * 0.99**(N-1), the second 0.01 * 0.99**(N-2).
Basically, we end up with exponential smoothing: https://en.wikipedia.org/wiki/Exponential_smoothing
There's a number of methods to avoid it. One would be to make a binary tree of canvases, with each leaf two different characters drawn at 0.5 opacity on top of each other, then recursively draw the two child nodes together at 0.5 opacity. Another option would be to load the pixels per character, add all of the pixel values in an "accumulator" Uint32Array (we can safely add up to 2**24 characters this way without overflowing the accumulator), then divide the values by the total number of characters added to get back our 8-bit average.
Good point--I've been spending too much in webgl land lately where you can just add up. Fixed this to use an accumulator for each range. For CJK, I'm just adding something to bail on any range after 1024 characters, even though that's not quite right.
Nice! I started tweaking it and optimizing it, it's different enough that I'm no longer sure if my results match your original intent:
https://observablehq.com/d/3672da74ac4f2aa2
The main difference output wise is that instead of averaging it normalizes, so the end result is more likely to have a high contrast. I also had to find a workaround for the missing character glyph for Firefox
I like the normalization, adopting that over here. But yeah, the missing character issues are really weirdly hard--it's odd that's there no way to test.
And even if that worked, the dotted circles used to position diacritics in Brahmic scripts are frustrating; I surprised they seem to be different sizes for, say, Bengali and Gujarati. A better version of this would figure out some way to drop just the dots portions of those. At least it serves the purpose I had in making this, though, which is to understand a little more about Unicode.