Show HN: Simulating 20M Particles in JavaScript (dgerrells.com)
Had some fun with shared array buffers over many months of free time.
Skip to the end to play around with the final app.
Open to ideas on how to simulate more whilst staying in js land.
Skip to the end to play around with the final app.
Open to ideas on how to simulate more whilst staying in js land.
72 comments
[ 3.2 ms ] story [ 120 ms ] thread(You might want to pick a value that runs reasonably well on old phones, or have it adjust based on frame rate. Alternatively just put a some links at the top of the article.)
See https://ciechanow.ski/ (very popular on this website) for a world-class example of just how cool it is to embed simulations right in the article.
(Obligatory: back in my day, every website used to embed cool interactive stuff!)
--
Also, I think you can run a particle sim on GPU without WebGPU.
e.g. https://news.ycombinator.com/item?id=19963640
That blog is amazing. Each example is so polished. I love it.
edit: I tried adding an embedded version but the required headers didn't play well with other embeds. The older versions are all still stuck in codesandboxes.
Interactive thingywotsits may slow down individuals making posts, but there are a lot of individuals out there.
Are there some frameworks that make interactive simulations like that easier to make, or do you just do it the hard way?
https://jason.today/falling-sand
I'll try to include embedded examples in the future.
You can try out the final version here https://dgerrells.com/sabby
[0] https://dgerrells.com/sabby
kinda joking, kinda not.
[0] https://gws.phd/posts/fortran_wasm/
Which is why the flang port it's about is attempting to compile to the actual primitives.
> I decided to have each particle be represented by 4 numbers an x, y, dx, and dy. These will each be 32-bit floating point numbers.
Would it be possible to encode this data into a single JS number (53-bit number, given that MAX_SAFE_INTEGER is 2^53 - 1 = 9,007,199,254,740,991). Or -3.4e38 to 3.4e38, which is the range of the Float32Array used in the blog.
For example, I understand for the screen position you might have a 1000x1000 canvas, which can be represented with 0-1,000,000 numbers. Even if we add 10 sub-pixel divisions, that's still 100,000,000, which still fits very comfortably within JS.
Similar for speed (dx, dy), I see you are doing "(Math.random()*2-1)*10" for calculating the speed, which should go from -10,+10 with arbitrary decimal accuracy, but I wonder if limiting it to 1 decimal would be enough for the simulation, which would be [-10.0, +10.0] and can also be converted to the -100,+100 range in integers. Which needs 10,000 numbers to represent all of the possible values.
If you put both of those together, that gives 10,000 * 100,000,000 = 1,000,000,000,000 (1T) numbers needed to represent the particles, which still fits within JS' MAX_SAFE_INTEGER. So it seems you might be able to fit all of the data for a single particle within a single MAX_SAFE_INTEGER or a single Float32Array element? Then you don't need the stride and can be a lot more sure about data consistency.
It might be that the encoding/decoding of the data into a single number is slower than the savings in memory and so it's totally not worth it though, which I don't know.
Float16Array would immediately halve your memory requirements
Another possibility would be to have separate precision arrays.
eg. Float16Array for x,y and even Int8Array for dx/dy, but, in both cases you will would get some motion artifacts, especially for Int8 from the clamping and aliasing of dx/dy.
[0]: https://github.com/thi-ng/umbrella/tree/develop/packages/vec...
[1]: https://github.com/thi-ng/umbrella/tree/develop/packages/vec...
[2]: https://github.com/thi-ng/umbrella/tree/develop/packages/bit...
[3]: https://github.com/thi-ng/umbrella/tree/develop/packages/sim...
There's also Structura, which implements a few performant data structures:
[4]: https://github.com/zandaqo/structurae/blob/master/README.md#...
[0]: https://github.com/dleeftink/QuickSet
[1]: https://github.com/dleeftink/QuickSet?tab=readme-ov-file#see...
Of note is FastIntSet, which uses the technique you described, but I think is only able to store 4 unsigned integers as one JS value (I might be wrong).
[2]: https://github.com/TheLucifurry/fast-int-set/blob/main/src/s...
This notebook demonstrate a MVP bitpacking technique using BigInts (see the 'bitpack' and 'pack' cells):
[3]: https://observablehq.com/@dleeftink/array-bitbuffers
SimSIMD offers various similarity measures and quantisation levels for TypedArrays:
[4]: https://github.com/ashvardanian/simsimd#using-simsimd-in-jav...
Not sure I understand. The flicker is not due to sometimes the screen drawn with white(like I assumed) and just because of my mobiles light settings?
Other simulations similar to this, don't have this flicker on my devive.
(still impressive work, genuine question to avoid this effect in my experiements)
And no matter the technical reasons, for some people this might be a serious health issue, so a warming might make sense in the current state.
run and program the simulations https://tinlizzie.org/~ohshima/shadama2/
https://tinlizzie.org/~ohshima/shadama2/live2017/
https://www.youtube.com/watch?v=tqBO_5GMfWw
Does anyone know why/how it maintains state if you tab out? Does Chrome eventually try to clean up the cache or is it locked in?
In the future I will keep everything self hosted to avoid this issue. I appreciate the patience.
https://github.com/google/playground-elements
not sure if, based on the way it works, whether it supports SharedArrayBuffer
The sandbox has a button that's basically "Open a preview in a separate tab". If you click that, the header will be sent, and the demo will work.
If you only use the "in-editor" preview, the proper header will not be sent.
Agree not intuitive. Hope it helps, it was a super cool demo.
My custom engine is built on a very similar solution using SharedArrayBuffers but there are still many things in this article that I'm eager to try, so thanks!
Too bad we cant just rely on JS only and have to involve a bunch of DOM operations, which is usually the slow part of the UIs we create.
No? With WebGL and soon WebGPU, or in this case here with writing to a imagebuffer and just passing that to canvas, you don't have to use the DOM anymore since quite a while.
(but then you don't get all the nice things html offers, like displaying and styling text etc)
In reality, you're right, there are alternatives, but for the basic web documents, it kind of hurts more than help to use them.
However, that's not where the problem starts. A lot of web sites are slow because they simply run too much code that doesn't need running in the first place and allocates objects that don't need to be allocated.
We don't need lower level constructs if we can simply start by removing cruft and be more wary of adding it. Go back to KISS/YAGNI.
I did have a question about this:
> Javascript does support an Atomics API but it uses promises which are gross. Eww sick.
With the exception of waitAsync[1], the Atomics APIs don't appear to use promises. I've used Atomics before and never needed to mess with any async/promise code. Is it using promises behind the scenes or is there something else I'm missing?
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Edit: formatting
I have done a somewhat similar experiment a while ago and achieved to fit quite a lot of particles with a basic physics simulation.
https://github.com/Seb-C/gravity
https://youtu.be/easvMCCBFkQ?t=114
How does one get this good with understanding hardware level details like L1 caches and the software implications?
I graduated as an Electrical Engineer, moved into Software for career. Feel like I’m missing some skills.
Specifically how can I better understand and use:
- the chrome Profiler? It’s scary to me currently. - Graphics programming - Optimisiations?
I'm not super skilled at the chrome profiler either, it seems to be suited better for certain tasks than others, but I might just be doing it wrong ...
Has anyone done similar experimentation and/or benchmarking on using webgpu for neural nets in JS?