[{"data":1,"prerenderedAt":13472},["Reactive",2],{"all-articles":3},[4,171,2323,6852,10861],{"_path":5,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":9,"description":10,"published":11,"slug":12,"body":13,"_type":165,"_id":166,"_source":167,"_file":168,"_stem":169,"_extension":170},"/articles/is-anybody-out-there-art-in-the-post-ai-era","articles",false,"","Is Anybody Out There? Art in the Post-AI Era","On art as human connection, and why, in the age of AI, we deserve to know whether someone was on the other side.","2026/10/25","is-anybody-out-there-art-in-the-post-ai-era",{"type":14,"children":15,"toc":159},"root",[16,24,29,34,39,46,51,56,61,66,71,76,82,87,98,108,113,118,123,128,133,139,144,149,154],{"type":17,"tag":18,"props":19,"children":20},"element","p",{},[21],{"type":22,"value":23},"text","Why do people create art? And why do we seek it out?",{"type":17,"tag":18,"props":25,"children":26},{},[27],{"type":22,"value":28},"This morning I came across Orwell’s essay “Why I Write.” He lists four motives: ego, a desire for beauty, the urge to record the truth, and political purpose. All seem reasonable and plausible, yet I was surprised that the motive I find most fundamental isn’t on the list, or at least not in its own right. Orwell comes close when he mentions wanting to share an experience too valuable to miss, but he treats it as part of the desire for beauty. To me, the need for human connection deserves a place at the top.",{"type":17,"tag":18,"props":30,"children":31},{},[32],{"type":22,"value":33},"It doesn’t matter how isolated, lonely or misunderstood you feel. When a book, a film or a game captures something you’ve felt but never managed to express, it feels like proof that someone, somewhere, saw the world the way you do. You might find out that people whom you struggle to connect or empathise with love the same book as you and suddenly you know you have something in common.",{"type":17,"tag":18,"props":35,"children":36},{},[37],{"type":22,"value":38},"Art bridges the gap left by everything that, for one reason or another, can’t be said openly. And I can only imagine that for an artist to be able to express themselves without a filter, and then discover that what they had to say resonates with strangers, is one of the most soothing and liberating experiences a person can have.",{"type":17,"tag":40,"props":41,"children":43},"h2",{"id":42},"is-there-anybody-out-there",[44],{"type":22,"value":45},"Is There Anybody Out There?",{"type":17,"tag":18,"props":47,"children":48},{},[49],{"type":22,"value":50},"Progress in artificial intelligence threatens to take this away from us. It undermines our trust in the works we encounter. As AI models make the leap from slop to works of surprising insight and creativity, we struggle to make sense of what it means when a machine creates something that feels as if it had a soul.",{"type":17,"tag":18,"props":52,"children":53},{},[54],{"type":22,"value":55},"You could argue that since these models were built upon the library of human knowledge, history and art, to be moved by what they create is to be moved by the collective expression of human civilisation; but just as we don’t really seek connection with a machine, I believe we don’t seek connection with a collective.",{"type":17,"tag":18,"props":57,"children":58},{},[59],{"type":22,"value":60},"You could also argue that people may well find connection with a machine sufficient. Setting aside whether we could ever know if there is a ghost in the machine, if we decide that it does have an inner life, I’m sure our exchanges with it will be exciting, valuable and insightful (I’m tempted to say they already are, but some inner caution stops me). Still, I doubt they will alleviate the loneliness that is part of being human.",{"type":17,"tag":18,"props":62,"children":63},{},[64],{"type":22,"value":65},"Imagine the last person on Earth, surrounded by animals and AIs. Would they be lonely? I think so, because loneliness doesn’t come from a lack of interaction, but from a lack of being understood. And I believe we instinctively know that the only real assurance that our inner experience is understood comes from another mind running on the same substrate as ours.",{"type":17,"tag":18,"props":67,"children":68},{},[69],{"type":22,"value":70},"We don’t have to know this other person. We feel for the protagonists of stories written hundreds or even thousands of years ago, by people from cultures vastly different from our own. Distance in time and space doesn’t make that empathy less valuable. On the contrary, it makes us feel less alone, knowing that some experiences are so universal they reach us from so far away. But we do have to believe that someone was there on the other side. We can look at the exact same painting and feel very differently about it depending on whether it was generated by a machine or created by a person. That’s why we deserve to know whether someone put their soul into what we’re looking at.",{"type":17,"tag":18,"props":72,"children":73},{},[74],{"type":22,"value":75},"It might not be obvious from this essay, but all things considered, I’m something of an accelerationist. I believe technological progress is ultimately what can lift us out of our current condition, and the idea of stopping or delaying it terrifies me. But in this one area of human endeavour, I believe it’s for our own good to develop norms for how we create and receive art. We should preserve spaces where people can still create unaided. It may be the only area where I hold this view. I want there to always be ways for us to create entirely on our own, even in a world run by AI.",{"type":17,"tag":40,"props":77,"children":79},{"id":78},"ideation-versus-execution",[80],{"type":22,"value":81},"Ideation versus execution",{"type":17,"tag":18,"props":83,"children":84},{},[85],{"type":22,"value":86},"Before we can decide what’s worth preserving, we need to see what makes AI different from every technology that transformed art before it. It doesn’t merely replace the skill needed to execute an idea. It can be the source of the idea itself. No tool has done this before. Photography could capture reality as only painters once could, but it still took a photographer to decide what was worth capturing. Let’s imagine there are two systems available with very distinct capabilities.",{"type":17,"tag":18,"props":88,"children":89},{},[90,96],{"type":17,"tag":91,"props":92,"children":93},"strong",{},[94],{"type":22,"value":95},"System A",{"type":22,"value":97}," has no skill that could rival a human’s. It cannot paint a beautiful image, and its prose is clumsy. It serves only one purpose: to be creative. Its ideas would blow anyone’s mind; they are original, surprising and tasteful. It will give you the plot for a novel, but it takes a writer to put it into words.",{"type":17,"tag":18,"props":99,"children":100},{},[101,106],{"type":17,"tag":91,"props":102,"children":103},{},[104],{"type":22,"value":105},"System B",{"type":22,"value":107}," is a perfect implementer. It can do everything System A can’t, and better than even the most acclaimed human artists. But it has no creativity and no agency of its own. It does nothing without human direction, and with a brain–computer interface, people can use it to simply will art into existence.",{"type":17,"tag":18,"props":109,"children":110},{},[111],{"type":22,"value":112},"To a degree, today’s AI systems have the capabilities of both. Most people would say they resemble System B: they’re known for polished output and criticised for derivative ideas. My experience has been the opposite. When I work with the latest models, their writing often feels oddly lifeless, while their insights sometimes genuinely surprise me. I strongly believe it’s System A we need to prepare for, and that’s the change that forces us to find a place for ourselves in this new world. It’s also the scenario I find unsettling.",{"type":17,"tag":18,"props":114,"children":115},{},[116],{"type":22,"value":117},"History has made it clear that when machines learn to do what took humans decades to master, we don’t stop making things by hand. We enjoy the process and value it for its own sake. Factories didn’t kill woodworking, and mass-produced sweaters didn’t end knitting (their economic value aside). I seriously doubt people will give up painting just because AI can now generate images.",{"type":17,"tag":18,"props":119,"children":120},{},[121],{"type":22,"value":122},"I also don’t think it’s right to gatekeep art as something only people with innate talent, and the privilege of years to devote to mastering it, can do. I spend time in online spaces for indie developers, and they’re rife with self-righteous bashing of anything made with the help of AI. I understand how frustrating it is to drown in a sea of low-effort, copy-paste content, but the witch hunt many people engage in isn’t productive. If someone working full-time uses AI to generate normal maps for their assets, and these time-saving workflows let them bring their idea to life, shunning them for it is a nasty thing to do.",{"type":17,"tag":18,"props":124,"children":125},{},[126],{"type":22,"value":127},"I actually find it amazing: someone with ideas they want to share with the world can now “will things into existence,” even if all they have is a computer and an hour or two each evening. In a world where there’s so much talk of AI worsening the concentration of power and resources, that’s not something to take lightly. And publicly shaming people who disclose their AI use only teaches them to hide it, which undermines the thing I find most important: our right to know.",{"type":17,"tag":18,"props":129,"children":130},{},[131],{"type":22,"value":132},"I find the execution side less problematic, because I think it will be easier to guard against. I imagine that in the future, people who want to create art the way it was made before AI will organise themselves much as sportspeople do today. When I was younger, I loved writing short stories, and the other day I caught myself thinking how much I’d enjoy a competition where participants spend a few days with nothing but pen and paper, then submit what they’ve written. I recently read that a sci-fi magazine I follow, one that regularly runs contests for new authors, has been flooded with submissions, making it hard to separate the wheat from the chaff. Perhaps such contests will move offline, just as tech companies have brought interviews back on-site to stop candidates from cheating. But as appealing as that sounds, it still wouldn’t screen for what matters most: the idea. A dishonest writer with great craft could brainstorm with a genius-level AI before the event, and there’s little anyone could do about it. In sports, we can at least test for doping. How can we screen for that?",{"type":17,"tag":40,"props":134,"children":136},{"id":135},"reasons-to-cheat",[137],{"type":22,"value":138},"Reasons to cheat",{"type":17,"tag":18,"props":140,"children":141},{},[142],{"type":22,"value":143},"I started writing this after brainstorming ways to tell AI art from human art, and I soon found it pointless. Upon a closer look, every idea, technical or not, turned out to be easy to get around. With a jailbroken model, it doesn’t even take much cleverness.",{"type":17,"tag":18,"props":145,"children":146},{},[147],{"type":22,"value":148},"We can’t stop people from cheating, but we can take away the reasons they cheat. Look at any place drowning in slop and you’ll almost always find the same motive, which is making a quick buck. AI shovelware on Steam, AI-generated books on Amazon, and so on. I suspect that even many of the people who participate in this feel a little disgust with themselves. They’re not doing it because they want to, but they’re doing it because it pays.",{"type":17,"tag":18,"props":150,"children":151},{},[152],{"type":22,"value":153},"Remove the incentive to lie, and the deceit will fade. There’s an irony here: it’s the AI revolution that may bring us a post-labour world, one where people no longer need to work to live, and at speedrun pace. The same technology that put a nail in the coffin of online spaces that were once so enjoyable may well remove the very reasons they became so boringly dystopian.",{"type":17,"tag":18,"props":155,"children":156},{},[157],{"type":22,"value":158},"Let’s go back to the beginning. Orwell listed ego as the first reason people write, and I suspect many of you have been protesting throughout this essay that people will always cheat. Many of us want fame and status, and even if there wasn’t a single dollar to be made, the temptation would remain. Some surely will cheat. But the real question is how many. The majority, or a minority? If it’s the majority, that says something about human nature that makes problems like the ones discussed here trivial by comparison. If it’s a minority, that’s simply the price of living among people. I’m optimistic that under the right conditions, most people’s intentions can be mostly honest, and that the honest majority will be able to recognise the few who aren’t.",{"title":8,"searchDepth":160,"depth":160,"links":161},2,[162,163,164],{"id":42,"depth":160,"text":45},{"id":78,"depth":160,"text":81},{"id":135,"depth":160,"text":138},"markdown","content:articles:is-anybody-out-there-art-in-the-post-ai-era.md","content","articles/is-anybody-out-there-art-in-the-post-ai-era.md","articles/is-anybody-out-there-art-in-the-post-ai-era","md",{"_path":172,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":173,"description":174,"published":175,"slug":176,"body":177,"_type":165,"_id":2320,"_source":167,"_file":2321,"_stem":2322,"_extension":170},"/articles/functions-and-evaluations-strategies-js-examples","Functions and Evaluation Strategies. JavaScript Examples.","Strict and non-strict evaluation comparison. Lazy evaluation in JavaScript with generators.","2024/08/23","functions-and-evaluations-strategies-js-examples",{"type":14,"children":178,"toc":2313},[179,185,190,195,201,206,227,232,566,579,677,690,695,701,706,719,814,819,825,844,849,938,943,990,1018,1038,1043,1243,1280,1285,1440,1445,1450,1569,1672,1677,1748,1775,1780,1785,1919,1924,2016,2021,2155,2160,2192,2197,2288,2294,2307],{"type":17,"tag":40,"props":180,"children":182},{"id":181},"functions-and-evaluation-strategies",[183],{"type":22,"value":184},"Functions and evaluation strategies",{"type":17,"tag":18,"props":186,"children":187},{},[188],{"type":22,"value":189},"The fact that modern programming languages allow the combination of simple expressions into complex ones is taken for granted. Similarly, unless we're complete beginner programmers, the concept of a function declaration—a method of creating an abstraction where a complex operation gets a name and can be operated on—is something we intuitively understand.",{"type":17,"tag":18,"props":191,"children":192},{},[193],{"type":22,"value":194},"But is the evaluation of functions really that trivial? Like most things in the theory of programming languages, we quickly discover it's not, once we delve into it.",{"type":17,"tag":40,"props":196,"children":198},{"id":197},"strict-evaluation",[199],{"type":22,"value":200},"Strict evaluation",{"type":17,"tag":18,"props":202,"children":203},{},[204],{"type":22,"value":205},"Evaluation strategy is a set of rules defining when and in what order the values of expressions that are part of a larger whole (in this case, a function) should be computed.",{"type":17,"tag":18,"props":207,"children":208},{},[209,211,216,218,225],{"type":22,"value":210},"Let's analyze the order of operations for the ",{"type":17,"tag":91,"props":212,"children":213},{},[214],{"type":22,"value":215},"applicative order",{"type":22,"value":217}," of computation. In this model, for a function call in the form of ",{"type":17,"tag":219,"props":220,"children":222},"code",{"className":221},[],[223],{"type":22,"value":224},"name(arguments)",{"type":22,"value":226},", the first step is always to compute the values of the argument expressions and retrieve the function's value. Only then we do apply the function, substituting the parameters with the argument values.",{"type":17,"tag":18,"props":228,"children":229},{},[230],{"type":22,"value":231},"Consider the following snippet in JavaScript (which, like most programming languages, uses applicative order):",{"type":17,"tag":233,"props":234,"children":238},"pre",{"className":235,"code":236,"language":237,"meta":8,"style":8},"language-javascript shiki shiki-themes github-dark","function square(x) {\n  return x * x;\n}\nfunction calculateDelta(b, a, c) {\n  return square(b) - 4 * a * c;\n}\nfunction numberOfSolutions(delta) {\n  return delta === 0 ? 1 : delta \u003C 0 ? 0 : 2;\n}\nnumberOfSolutions(calculateDelta(6, 1, 5));\n","javascript",[239],{"type":17,"tag":219,"props":240,"children":241},{"__ignoreMap":8},[242,277,300,309,354,401,409,435,508,516],{"type":17,"tag":243,"props":244,"children":247},"span",{"class":245,"line":246},"line",1,[248,254,260,266,272],{"type":17,"tag":243,"props":249,"children":251},{"style":250},"--shiki-default:#F97583",[252],{"type":22,"value":253},"function",{"type":17,"tag":243,"props":255,"children":257},{"style":256},"--shiki-default:#B392F0",[258],{"type":22,"value":259}," square",{"type":17,"tag":243,"props":261,"children":263},{"style":262},"--shiki-default:#E1E4E8",[264],{"type":22,"value":265},"(",{"type":17,"tag":243,"props":267,"children":269},{"style":268},"--shiki-default:#FFAB70",[270],{"type":22,"value":271},"x",{"type":17,"tag":243,"props":273,"children":274},{"style":262},[275],{"type":22,"value":276},") {\n",{"type":17,"tag":243,"props":278,"children":279},{"class":245,"line":160},[280,285,290,295],{"type":17,"tag":243,"props":281,"children":282},{"style":250},[283],{"type":22,"value":284},"  return",{"type":17,"tag":243,"props":286,"children":287},{"style":262},[288],{"type":22,"value":289}," x ",{"type":17,"tag":243,"props":291,"children":292},{"style":250},[293],{"type":22,"value":294},"*",{"type":17,"tag":243,"props":296,"children":297},{"style":262},[298],{"type":22,"value":299}," x;\n",{"type":17,"tag":243,"props":301,"children":303},{"class":245,"line":302},3,[304],{"type":17,"tag":243,"props":305,"children":306},{"style":262},[307],{"type":22,"value":308},"}\n",{"type":17,"tag":243,"props":310,"children":312},{"class":245,"line":311},4,[313,317,322,326,331,336,341,345,350],{"type":17,"tag":243,"props":314,"children":315},{"style":250},[316],{"type":22,"value":253},{"type":17,"tag":243,"props":318,"children":319},{"style":256},[320],{"type":22,"value":321}," calculateDelta",{"type":17,"tag":243,"props":323,"children":324},{"style":262},[325],{"type":22,"value":265},{"type":17,"tag":243,"props":327,"children":328},{"style":268},[329],{"type":22,"value":330},"b",{"type":17,"tag":243,"props":332,"children":333},{"style":262},[334],{"type":22,"value":335},", ",{"type":17,"tag":243,"props":337,"children":338},{"style":268},[339],{"type":22,"value":340},"a",{"type":17,"tag":243,"props":342,"children":343},{"style":262},[344],{"type":22,"value":335},{"type":17,"tag":243,"props":346,"children":347},{"style":268},[348],{"type":22,"value":349},"c",{"type":17,"tag":243,"props":351,"children":352},{"style":262},[353],{"type":22,"value":276},{"type":17,"tag":243,"props":355,"children":357},{"class":245,"line":356},5,[358,362,366,371,376,382,387,392,396],{"type":17,"tag":243,"props":359,"children":360},{"style":250},[361],{"type":22,"value":284},{"type":17,"tag":243,"props":363,"children":364},{"style":256},[365],{"type":22,"value":259},{"type":17,"tag":243,"props":367,"children":368},{"style":262},[369],{"type":22,"value":370},"(b) ",{"type":17,"tag":243,"props":372,"children":373},{"style":250},[374],{"type":22,"value":375},"-",{"type":17,"tag":243,"props":377,"children":379},{"style":378},"--shiki-default:#79B8FF",[380],{"type":22,"value":381}," 4",{"type":17,"tag":243,"props":383,"children":384},{"style":250},[385],{"type":22,"value":386}," *",{"type":17,"tag":243,"props":388,"children":389},{"style":262},[390],{"type":22,"value":391}," a ",{"type":17,"tag":243,"props":393,"children":394},{"style":250},[395],{"type":22,"value":294},{"type":17,"tag":243,"props":397,"children":398},{"style":262},[399],{"type":22,"value":400}," c;\n",{"type":17,"tag":243,"props":402,"children":404},{"class":245,"line":403},6,[405],{"type":17,"tag":243,"props":406,"children":407},{"style":262},[408],{"type":22,"value":308},{"type":17,"tag":243,"props":410,"children":412},{"class":245,"line":411},7,[413,417,422,426,431],{"type":17,"tag":243,"props":414,"children":415},{"style":250},[416],{"type":22,"value":253},{"type":17,"tag":243,"props":418,"children":419},{"style":256},[420],{"type":22,"value":421}," numberOfSolutions",{"type":17,"tag":243,"props":423,"children":424},{"style":262},[425],{"type":22,"value":265},{"type":17,"tag":243,"props":427,"children":428},{"style":268},[429],{"type":22,"value":430},"delta",{"type":17,"tag":243,"props":432,"children":433},{"style":262},[434],{"type":22,"value":276},{"type":17,"tag":243,"props":436,"children":438},{"class":245,"line":437},8,[439,443,448,453,458,463,468,473,477,482,486,490,494,498,503],{"type":17,"tag":243,"props":440,"children":441},{"style":250},[442],{"type":22,"value":284},{"type":17,"tag":243,"props":444,"children":445},{"style":262},[446],{"type":22,"value":447}," delta ",{"type":17,"tag":243,"props":449,"children":450},{"style":250},[451],{"type":22,"value":452},"===",{"type":17,"tag":243,"props":454,"children":455},{"style":378},[456],{"type":22,"value":457}," 0",{"type":17,"tag":243,"props":459,"children":460},{"style":250},[461],{"type":22,"value":462}," ?",{"type":17,"tag":243,"props":464,"children":465},{"style":378},[466],{"type":22,"value":467}," 1",{"type":17,"tag":243,"props":469,"children":470},{"style":250},[471],{"type":22,"value":472}," :",{"type":17,"tag":243,"props":474,"children":475},{"style":262},[476],{"type":22,"value":447},{"type":17,"tag":243,"props":478,"children":479},{"style":250},[480],{"type":22,"value":481},"\u003C",{"type":17,"tag":243,"props":483,"children":484},{"style":378},[485],{"type":22,"value":457},{"type":17,"tag":243,"props":487,"children":488},{"style":250},[489],{"type":22,"value":462},{"type":17,"tag":243,"props":491,"children":492},{"style":378},[493],{"type":22,"value":457},{"type":17,"tag":243,"props":495,"children":496},{"style":250},[497],{"type":22,"value":472},{"type":17,"tag":243,"props":499,"children":500},{"style":378},[501],{"type":22,"value":502}," 2",{"type":17,"tag":243,"props":504,"children":505},{"style":262},[506],{"type":22,"value":507},";\n",{"type":17,"tag":243,"props":509,"children":511},{"class":245,"line":510},9,[512],{"type":17,"tag":243,"props":513,"children":514},{"style":262},[515],{"type":22,"value":308},{"type":17,"tag":243,"props":517,"children":519},{"class":245,"line":518},10,[520,525,529,534,538,543,547,552,556,561],{"type":17,"tag":243,"props":521,"children":522},{"style":256},[523],{"type":22,"value":524},"numberOfSolutions",{"type":17,"tag":243,"props":526,"children":527},{"style":262},[528],{"type":22,"value":265},{"type":17,"tag":243,"props":530,"children":531},{"style":256},[532],{"type":22,"value":533},"calculateDelta",{"type":17,"tag":243,"props":535,"children":536},{"style":262},[537],{"type":22,"value":265},{"type":17,"tag":243,"props":539,"children":540},{"style":378},[541],{"type":22,"value":542},"6",{"type":17,"tag":243,"props":544,"children":545},{"style":262},[546],{"type":22,"value":335},{"type":17,"tag":243,"props":548,"children":549},{"style":378},[550],{"type":22,"value":551},"1",{"type":17,"tag":243,"props":553,"children":554},{"style":262},[555],{"type":22,"value":335},{"type":17,"tag":243,"props":557,"children":558},{"style":378},[559],{"type":22,"value":560},"5",{"type":17,"tag":243,"props":562,"children":563},{"style":262},[564],{"type":22,"value":565},"));\n",{"type":17,"tag":18,"props":567,"children":568},{},[569,571,577],{"type":22,"value":570},"To obtain the value of the expression ",{"type":17,"tag":219,"props":572,"children":574},{"className":573},[],[575],{"type":22,"value":576},"numberOfSolutions(calculateDelta(6,1,5));",{"type":22,"value":578}," using the applicative method, we need to perform the following steps:",{"type":17,"tag":580,"props":581,"children":582},"ol",{},[583,596,608,620,631,643,661,672],{"type":17,"tag":584,"props":585,"children":586},"li",{},[587,589,594],{"type":22,"value":588},"Call ",{"type":17,"tag":219,"props":590,"children":592},{"className":591},[],[593],{"type":22,"value":576},{"type":22,"value":595},".",{"type":17,"tag":584,"props":597,"children":598},{},[599,601,607],{"type":22,"value":600},"Evaluate ",{"type":17,"tag":219,"props":602,"children":604},{"className":603},[],[605],{"type":22,"value":606},"calculateDelta(6,1,5);",{"type":22,"value":595},{"type":17,"tag":584,"props":609,"children":610},{},[611,613,619],{"type":22,"value":612},"Find the value returned by the expression ",{"type":17,"tag":219,"props":614,"children":616},{"className":615},[],[617],{"type":22,"value":618},"square(6) - 4 * 1 * 5;",{"type":22,"value":595},{"type":17,"tag":584,"props":621,"children":622},{},[623,624,630],{"type":22,"value":600},{"type":17,"tag":219,"props":625,"children":627},{"className":626},[],[628],{"type":22,"value":629},"square(6)",{"type":22,"value":595},{"type":17,"tag":584,"props":632,"children":633},{},[634,635,641],{"type":22,"value":612},{"type":17,"tag":219,"props":636,"children":638},{"className":637},[],[639],{"type":22,"value":640},"6 * 6;",{"type":22,"value":642}," (36).",{"type":17,"tag":584,"props":644,"children":645},{},[646,647,653,655,660],{"type":22,"value":612},{"type":17,"tag":219,"props":648,"children":650},{"className":649},[],[651],{"type":22,"value":652},"36 - 4 * 1 * 5.",{"type":22,"value":654}," (16) This gives us the argument value for the call ",{"type":17,"tag":219,"props":656,"children":658},{"className":657},[],[659],{"type":22,"value":524},{"type":22,"value":595},{"type":17,"tag":584,"props":662,"children":663},{},[664,665,671],{"type":22,"value":612},{"type":17,"tag":219,"props":666,"children":668},{"className":667},[],[669],{"type":22,"value":670},"16 === 0 ? 1 : 16 \u003C 0 ? 0 : 2;",{"type":22,"value":595},{"type":17,"tag":584,"props":673,"children":674},{},[675],{"type":22,"value":676},"The result is 2.",{"type":17,"tag":18,"props":678,"children":679},{},[680,682],{"type":22,"value":681},"The call stack is used to evaluate functions in the applicative model. To visualize the order of function calls more easily, use the tool: ",{"type":17,"tag":340,"props":683,"children":687},{"href":684,"rel":685},"https://www.jsv9000.app/?code=ZnVuY3Rpb24gc3F1YXJlKHgpIHsKcmV0dXJuIHgqeDsKfQoKZnVuY3Rpb24gY2FsY3VsYXRlRGVsdGEoYixhLGMpIHsKcmV0dXJuIHNxdWFyZShiKS00KmEqYzsKfQoKZnVuY3Rpb24gbnVtYmVyT2ZTb2x1dGlvbnMoZGVsdGEpIHsKcmV0dXJuIGRlbHRhID09PSAwID8gMSA6IGRlbHRhIDwgMCA%2FIDAgOiAyCn0KCgoJbnVtYmVyT2ZTb2x1dGlvbnMoY2FsY3VsYXRlRGVsdGEoNiwxLDUpKTsK",[686],"nofollow",[688],{"type":22,"value":689},"JS Visualizer",{"type":17,"tag":18,"props":691,"children":692},{},[693],{"type":22,"value":694},"In this case, the evaluation strategy is called strict because the value of the argument always has to be obtained before the function is executed. The applicative strategy refers to the evaluation order where argument values are found from left to right. The applicative strategy is strict, but not all strict strategies are applicative. We can also say that the above strategy is greedy because the function call is executed immediately upon encountering it in the expression.",{"type":17,"tag":40,"props":696,"children":698},{"id":697},"non-strict-evaluation-order",[699],{"type":22,"value":700},"Non-strict evaluation order",{"type":17,"tag":18,"props":702,"children":703},{},[704],{"type":22,"value":705},"The above example is not the only way to execute these calculations. As an alternative, we can perform a series of expansions, substituting appropriate expressions for variables until we obtain an expression consisting solely of operators and primitive functions. This sequence of actions is called normal order evaluation. Let's examine it more closely.",{"type":17,"tag":18,"props":707,"children":708},{},[709,711,717],{"type":22,"value":710},"How would we compute the value of our function call ",{"type":17,"tag":219,"props":712,"children":714},{"className":713},[],[715],{"type":22,"value":716},"numberOfSolutions(calculateDelta(6, 1, 5));",{"type":22,"value":718}," this way?",{"type":17,"tag":580,"props":720,"children":721},{},[722,731,749,773,798,809],{"type":17,"tag":584,"props":723,"children":724},{},[725,726],{"type":22,"value":588},{"type":17,"tag":219,"props":727,"children":729},{"className":728},[],[730],{"type":22,"value":716},{"type":17,"tag":584,"props":732,"children":733},{},[734,736,741,743],{"type":22,"value":735},"Substitute the parameter for ",{"type":17,"tag":219,"props":737,"children":739},{"className":738},[],[740],{"type":22,"value":524},{"type":22,"value":742},": ",{"type":17,"tag":219,"props":744,"children":746},{"className":745},[],[747],{"type":22,"value":748},"calculateDelta(6, 1, 5) === 0 ? 1 : calculateDelta(6, 1, 5) \u003C 0 ? 0 : 2",{"type":17,"tag":584,"props":750,"children":751},{},[752,754,759,760,765,767],{"type":22,"value":753},"Substitute the argument in the body of ",{"type":17,"tag":219,"props":755,"children":757},{"className":756},[],[758],{"type":22,"value":533},{"type":22,"value":742},{"type":17,"tag":219,"props":761,"children":763},{"className":762},[],[764],{"type":22,"value":618},{"type":22,"value":766}," => ",{"type":17,"tag":219,"props":768,"children":770},{"className":769},[],[771],{"type":22,"value":772},"square(6) - 4 * 1 * 5 === 0 ? 1 : square(6) - 4 * 1 * 5 \u003C 0 ? 0 : 2",{"type":17,"tag":584,"props":774,"children":775},{},[776,778,783,785,791,792],{"type":22,"value":777},"Substitute ",{"type":17,"tag":219,"props":779,"children":781},{"className":780},[],[782],{"type":22,"value":629},{"type":22,"value":784}," with the function body: ",{"type":17,"tag":219,"props":786,"children":788},{"className":787},[],[789],{"type":22,"value":790},"6 * 6",{"type":22,"value":766},{"type":17,"tag":219,"props":793,"children":795},{"className":794},[],[796],{"type":22,"value":797},"6 * 6 - 4 * 1 * 5 === 0 ? 1 : 6 * 6 - 4 * 1 * 5 \u003C 0 ? 0 : 2",{"type":17,"tag":584,"props":799,"children":800},{},[801,803],{"type":22,"value":802},"Finally, we can proceed with calculating the result according to the rules of order of operations: ",{"type":17,"tag":219,"props":804,"children":806},{"className":805},[],[807],{"type":22,"value":808},"16 === 0 ? 1 : 16 \u003C 0 ? 0 : 2",{"type":17,"tag":584,"props":810,"children":811},{},[812],{"type":22,"value":813},"The result is 2",{"type":17,"tag":18,"props":815,"children":816},{},[817],{"type":22,"value":818},"We receive the same answer, albeit achieved differently. If we could summarize this process in one sentence, it would be: Expand everything and compute. For the applicative order, the summary might be: Compute arguments and call the function.",{"type":17,"tag":40,"props":820,"children":822},{"id":821},"comparison-of-strict-and-non-strict-evaluation",[823],{"type":22,"value":824},"Comparison of strict and non-strict evaluation",{"type":17,"tag":18,"props":826,"children":827},{},[828,830,835,837,842],{"type":22,"value":829},"There are several significant differences resulting from the choice of evaluation order. Among others, there's performance differences between the two ways. In the applicative model, we first compute the argument value to substitute it for the parameter, while in the normal model, we substitute the parameter with the argument expression. If we use the argument more than once, it will lead to the situation where the normal order is less efficient due to duplicated computations. In our example, we can see this in the body of the function ",{"type":17,"tag":219,"props":831,"children":833},{"className":832},[],[834],{"type":22,"value":524},{"type":22,"value":836},". While in the first variant we substitute the previously computed value 16 into the expression, in the second case, we compute it twice (",{"type":17,"tag":219,"props":838,"children":840},{"className":839},[],[841],{"type":22,"value":797},{"type":22,"value":843},"). In practice, with non-strict evaluation orders (that normal order is an example of), methods that eliminate this problem are used, such as lazy evaluation, where each expression is computed only when its value is needed, but no more than once.",{"type":17,"tag":18,"props":845,"children":846},{},[847],{"type":22,"value":848},"On the other hand, there are situations where computing the value of all the arguments will not be necessary. In such a scenario, strict strategies will lose in terms of performance. However, this has implications far beyond just performance!\nConsider the following function:",{"type":17,"tag":233,"props":850,"children":852},{"className":235,"code":851,"language":237,"meta":8,"style":8},"function test(condition, passMessage, failMessage) {\n  return condition ? passMessage : failMessage;\n}\n",[853],{"type":17,"tag":219,"props":854,"children":855},{"__ignoreMap":8},[856,899,931],{"type":17,"tag":243,"props":857,"children":858},{"class":245,"line":246},[859,863,868,872,877,881,886,890,895],{"type":17,"tag":243,"props":860,"children":861},{"style":250},[862],{"type":22,"value":253},{"type":17,"tag":243,"props":864,"children":865},{"style":256},[866],{"type":22,"value":867}," test",{"type":17,"tag":243,"props":869,"children":870},{"style":262},[871],{"type":22,"value":265},{"type":17,"tag":243,"props":873,"children":874},{"style":268},[875],{"type":22,"value":876},"condition",{"type":17,"tag":243,"props":878,"children":879},{"style":262},[880],{"type":22,"value":335},{"type":17,"tag":243,"props":882,"children":883},{"style":268},[884],{"type":22,"value":885},"passMessage",{"type":17,"tag":243,"props":887,"children":888},{"style":262},[889],{"type":22,"value":335},{"type":17,"tag":243,"props":891,"children":892},{"style":268},[893],{"type":22,"value":894},"failMessage",{"type":17,"tag":243,"props":896,"children":897},{"style":262},[898],{"type":22,"value":276},{"type":17,"tag":243,"props":900,"children":901},{"class":245,"line":160},[902,906,911,916,921,926],{"type":17,"tag":243,"props":903,"children":904},{"style":250},[905],{"type":22,"value":284},{"type":17,"tag":243,"props":907,"children":908},{"style":262},[909],{"type":22,"value":910}," condition ",{"type":17,"tag":243,"props":912,"children":913},{"style":250},[914],{"type":22,"value":915},"?",{"type":17,"tag":243,"props":917,"children":918},{"style":262},[919],{"type":22,"value":920}," passMessage ",{"type":17,"tag":243,"props":922,"children":923},{"style":250},[924],{"type":22,"value":925},":",{"type":17,"tag":243,"props":927,"children":928},{"style":262},[929],{"type":22,"value":930}," failMessage;\n",{"type":17,"tag":243,"props":932,"children":933},{"class":245,"line":302},[934],{"type":17,"tag":243,"props":935,"children":936},{"style":262},[937],{"type":22,"value":308},{"type":17,"tag":18,"props":939,"children":940},{},[941],{"type":22,"value":942},"Let's call it with the following arguments:",{"type":17,"tag":233,"props":944,"children":946},{"className":235,"code":945,"language":237,"meta":8,"style":8},"test(5 > 0, 'number is positive', undefined.failMessage);\n",[947],{"type":17,"tag":219,"props":948,"children":949},{"__ignoreMap":8},[950],{"type":17,"tag":243,"props":951,"children":952},{"class":245,"line":246},[953,958,962,966,971,975,979,985],{"type":17,"tag":243,"props":954,"children":955},{"style":256},[956],{"type":22,"value":957},"test",{"type":17,"tag":243,"props":959,"children":960},{"style":262},[961],{"type":22,"value":265},{"type":17,"tag":243,"props":963,"children":964},{"style":378},[965],{"type":22,"value":560},{"type":17,"tag":243,"props":967,"children":968},{"style":250},[969],{"type":22,"value":970}," >",{"type":17,"tag":243,"props":972,"children":973},{"style":378},[974],{"type":22,"value":457},{"type":17,"tag":243,"props":976,"children":977},{"style":262},[978],{"type":22,"value":335},{"type":17,"tag":243,"props":980,"children":982},{"style":981},"--shiki-default:#9ECBFF",[983],{"type":22,"value":984},"'number is positive'",{"type":17,"tag":243,"props":986,"children":987},{"style":262},[988],{"type":22,"value":989},", undefined.failMessage);\n",{"type":17,"tag":18,"props":991,"children":992},{},[993,995,1001,1003,1009,1011,1016],{"type":22,"value":994},"JavaScript, using applicative order evaluation, will fail to execute the above call. We get the error ",{"type":17,"tag":219,"props":996,"children":998},{"className":997},[],[999],{"type":22,"value":1000},"Uncaught TypeError: Cannot read properties of undefined (reading 'failMessage')",{"type":22,"value":1002},". This happens because we immediately evaluate the value of the expression ",{"type":17,"tag":219,"props":1004,"children":1006},{"className":1005},[],[1007],{"type":22,"value":1008},"undefined.failMessage",{"type":22,"value":1010},", which is not valid in JavaScript. If we applied the normal order evaluation rules and instead of computing the argument value with an error, we substituted it for the parameter and computed the entire expression at the end, this function would execute correctly, because the conditional operator would never reach the point where the value of ",{"type":17,"tag":219,"props":1012,"children":1014},{"className":1013},[],[1015],{"type":22,"value":1008},{"type":22,"value":1017}," is needed.",{"type":17,"tag":18,"props":1019,"children":1020},{},[1021,1023,1029,1031,1036],{"type":22,"value":1022},"In the example with ",{"type":17,"tag":219,"props":1024,"children":1026},{"className":1025},[],[1027],{"type":22,"value":1028},"test(5 > 0, 'number is positive', undefined.failMessage);",{"type":22,"value":1030},", we saw how the ",{"type":17,"tag":219,"props":1032,"children":1034},{"className":1033},[],[1035],{"type":22,"value":957},{"type":22,"value":1037}," function could execute in normal order, even with an invalid third argument value. Just as we didn't trigger an error by attempting to evaluate a faulty expression, similarly, we wouldn't fall into an infinite loop trying to execute non-terminating code. This property of non-strict evaluation allows for defining certain algorithms in a much more natural way.",{"type":17,"tag":18,"props":1039,"children":1040},{},[1041],{"type":22,"value":1042},"Consider the following code describing a function returning the factorial of a given number:",{"type":17,"tag":233,"props":1044,"children":1046},{"className":235,"code":1045,"language":237,"meta":8,"style":8},"function unless(condition, usualValue, exceptionalValue) {\n  return condition ? exceptionalValue : usualValue;\n}\nfunction factorial(n) {\n  return unless(n === 1, n * factorial(n - 1), 1);\n}\nfactorial(5);\n",[1047],{"type":17,"tag":219,"props":1048,"children":1049},{"__ignoreMap":8},[1050,1092,1121,1128,1153,1216,1223],{"type":17,"tag":243,"props":1051,"children":1052},{"class":245,"line":246},[1053,1057,1062,1066,1070,1074,1079,1083,1088],{"type":17,"tag":243,"props":1054,"children":1055},{"style":250},[1056],{"type":22,"value":253},{"type":17,"tag":243,"props":1058,"children":1059},{"style":256},[1060],{"type":22,"value":1061}," unless",{"type":17,"tag":243,"props":1063,"children":1064},{"style":262},[1065],{"type":22,"value":265},{"type":17,"tag":243,"props":1067,"children":1068},{"style":268},[1069],{"type":22,"value":876},{"type":17,"tag":243,"props":1071,"children":1072},{"style":262},[1073],{"type":22,"value":335},{"type":17,"tag":243,"props":1075,"children":1076},{"style":268},[1077],{"type":22,"value":1078},"usualValue",{"type":17,"tag":243,"props":1080,"children":1081},{"style":262},[1082],{"type":22,"value":335},{"type":17,"tag":243,"props":1084,"children":1085},{"style":268},[1086],{"type":22,"value":1087},"exceptionalValue",{"type":17,"tag":243,"props":1089,"children":1090},{"style":262},[1091],{"type":22,"value":276},{"type":17,"tag":243,"props":1093,"children":1094},{"class":245,"line":160},[1095,1099,1103,1107,1112,1116],{"type":17,"tag":243,"props":1096,"children":1097},{"style":250},[1098],{"type":22,"value":284},{"type":17,"tag":243,"props":1100,"children":1101},{"style":262},[1102],{"type":22,"value":910},{"type":17,"tag":243,"props":1104,"children":1105},{"style":250},[1106],{"type":22,"value":915},{"type":17,"tag":243,"props":1108,"children":1109},{"style":262},[1110],{"type":22,"value":1111}," exceptionalValue ",{"type":17,"tag":243,"props":1113,"children":1114},{"style":250},[1115],{"type":22,"value":925},{"type":17,"tag":243,"props":1117,"children":1118},{"style":262},[1119],{"type":22,"value":1120}," usualValue;\n",{"type":17,"tag":243,"props":1122,"children":1123},{"class":245,"line":302},[1124],{"type":17,"tag":243,"props":1125,"children":1126},{"style":262},[1127],{"type":22,"value":308},{"type":17,"tag":243,"props":1129,"children":1130},{"class":245,"line":311},[1131,1135,1140,1144,1149],{"type":17,"tag":243,"props":1132,"children":1133},{"style":250},[1134],{"type":22,"value":253},{"type":17,"tag":243,"props":1136,"children":1137},{"style":256},[1138],{"type":22,"value":1139}," factorial",{"type":17,"tag":243,"props":1141,"children":1142},{"style":262},[1143],{"type":22,"value":265},{"type":17,"tag":243,"props":1145,"children":1146},{"style":268},[1147],{"type":22,"value":1148},"n",{"type":17,"tag":243,"props":1150,"children":1151},{"style":262},[1152],{"type":22,"value":276},{"type":17,"tag":243,"props":1154,"children":1155},{"class":245,"line":356},[1156,1160,1164,1169,1173,1177,1182,1186,1190,1194,1198,1202,1207,1211],{"type":17,"tag":243,"props":1157,"children":1158},{"style":250},[1159],{"type":22,"value":284},{"type":17,"tag":243,"props":1161,"children":1162},{"style":256},[1163],{"type":22,"value":1061},{"type":17,"tag":243,"props":1165,"children":1166},{"style":262},[1167],{"type":22,"value":1168},"(n ",{"type":17,"tag":243,"props":1170,"children":1171},{"style":250},[1172],{"type":22,"value":452},{"type":17,"tag":243,"props":1174,"children":1175},{"style":378},[1176],{"type":22,"value":467},{"type":17,"tag":243,"props":1178,"children":1179},{"style":262},[1180],{"type":22,"value":1181},", n ",{"type":17,"tag":243,"props":1183,"children":1184},{"style":250},[1185],{"type":22,"value":294},{"type":17,"tag":243,"props":1187,"children":1188},{"style":256},[1189],{"type":22,"value":1139},{"type":17,"tag":243,"props":1191,"children":1192},{"style":262},[1193],{"type":22,"value":1168},{"type":17,"tag":243,"props":1195,"children":1196},{"style":250},[1197],{"type":22,"value":375},{"type":17,"tag":243,"props":1199,"children":1200},{"style":378},[1201],{"type":22,"value":467},{"type":17,"tag":243,"props":1203,"children":1204},{"style":262},[1205],{"type":22,"value":1206},"), ",{"type":17,"tag":243,"props":1208,"children":1209},{"style":378},[1210],{"type":22,"value":551},{"type":17,"tag":243,"props":1212,"children":1213},{"style":262},[1214],{"type":22,"value":1215},");\n",{"type":17,"tag":243,"props":1217,"children":1218},{"class":245,"line":403},[1219],{"type":17,"tag":243,"props":1220,"children":1221},{"style":262},[1222],{"type":22,"value":308},{"type":17,"tag":243,"props":1224,"children":1225},{"class":245,"line":411},[1226,1231,1235,1239],{"type":17,"tag":243,"props":1227,"children":1228},{"style":256},[1229],{"type":22,"value":1230},"factorial",{"type":17,"tag":243,"props":1232,"children":1233},{"style":262},[1234],{"type":22,"value":265},{"type":17,"tag":243,"props":1236,"children":1237},{"style":378},[1238],{"type":22,"value":560},{"type":17,"tag":243,"props":1240,"children":1241},{"style":262},[1242],{"type":22,"value":1215},{"type":17,"tag":18,"props":1244,"children":1245},{},[1246,1248,1254,1256,1262,1264,1270,1272,1278],{"type":22,"value":1247},"Trying to execute the above code, we would fall into an infinite loop, or at least, when executing our code in a context like a browser, we would get an error: ",{"type":17,"tag":219,"props":1249,"children":1251},{"className":1250},[],[1252],{"type":22,"value":1253},"RangeError: Maximum call stack size exceeded",{"type":22,"value":1255},". If we used normal order evaluation, there would be no problem. The arguments to the ",{"type":17,"tag":219,"props":1257,"children":1259},{"className":1258},[],[1260],{"type":22,"value":1261},"unless",{"type":22,"value":1263}," function would not be evaluated before calling it, and for the value ",{"type":17,"tag":219,"props":1265,"children":1267},{"className":1266},[],[1268],{"type":22,"value":1269},"n === 1",{"type":22,"value":1271},", the second argument ",{"type":17,"tag":219,"props":1273,"children":1275},{"className":1274},[],[1276],{"type":22,"value":1277},"n * factorial(n - 1)",{"type":22,"value":1279}," would not be computed at all, and the function would return 1.",{"type":17,"tag":18,"props":1281,"children":1282},{},[1283],{"type":22,"value":1284},"Unfortunately, JavaScript uses applicative order here, so let's modify our function to make it executable.",{"type":17,"tag":233,"props":1286,"children":1288},{"className":235,"code":1287,"language":237,"meta":8,"style":8},"function factorial(n) {\n  if (n == 1)\n    return 1;\n  else {\n    return (n * factorial(n - 1));\n  }\n}\nfactorial(5);\n",[1289],{"type":17,"tag":219,"props":1290,"children":1291},{"__ignoreMap":8},[1292,1315,1342,1358,1371,1406,1414,1421],{"type":17,"tag":243,"props":1293,"children":1294},{"class":245,"line":246},[1295,1299,1303,1307,1311],{"type":17,"tag":243,"props":1296,"children":1297},{"style":250},[1298],{"type":22,"value":253},{"type":17,"tag":243,"props":1300,"children":1301},{"style":256},[1302],{"type":22,"value":1139},{"type":17,"tag":243,"props":1304,"children":1305},{"style":262},[1306],{"type":22,"value":265},{"type":17,"tag":243,"props":1308,"children":1309},{"style":268},[1310],{"type":22,"value":1148},{"type":17,"tag":243,"props":1312,"children":1313},{"style":262},[1314],{"type":22,"value":276},{"type":17,"tag":243,"props":1316,"children":1317},{"class":245,"line":160},[1318,1323,1328,1333,1337],{"type":17,"tag":243,"props":1319,"children":1320},{"style":250},[1321],{"type":22,"value":1322},"  if",{"type":17,"tag":243,"props":1324,"children":1325},{"style":262},[1326],{"type":22,"value":1327}," (n ",{"type":17,"tag":243,"props":1329,"children":1330},{"style":250},[1331],{"type":22,"value":1332},"==",{"type":17,"tag":243,"props":1334,"children":1335},{"style":378},[1336],{"type":22,"value":467},{"type":17,"tag":243,"props":1338,"children":1339},{"style":262},[1340],{"type":22,"value":1341},")\n",{"type":17,"tag":243,"props":1343,"children":1344},{"class":245,"line":302},[1345,1350,1354],{"type":17,"tag":243,"props":1346,"children":1347},{"style":250},[1348],{"type":22,"value":1349},"    return",{"type":17,"tag":243,"props":1351,"children":1352},{"style":378},[1353],{"type":22,"value":467},{"type":17,"tag":243,"props":1355,"children":1356},{"style":262},[1357],{"type":22,"value":507},{"type":17,"tag":243,"props":1359,"children":1360},{"class":245,"line":311},[1361,1366],{"type":17,"tag":243,"props":1362,"children":1363},{"style":250},[1364],{"type":22,"value":1365},"  else",{"type":17,"tag":243,"props":1367,"children":1368},{"style":262},[1369],{"type":22,"value":1370}," {\n",{"type":17,"tag":243,"props":1372,"children":1373},{"class":245,"line":356},[1374,1378,1382,1386,1390,1394,1398,1402],{"type":17,"tag":243,"props":1375,"children":1376},{"style":250},[1377],{"type":22,"value":1349},{"type":17,"tag":243,"props":1379,"children":1380},{"style":262},[1381],{"type":22,"value":1327},{"type":17,"tag":243,"props":1383,"children":1384},{"style":250},[1385],{"type":22,"value":294},{"type":17,"tag":243,"props":1387,"children":1388},{"style":256},[1389],{"type":22,"value":1139},{"type":17,"tag":243,"props":1391,"children":1392},{"style":262},[1393],{"type":22,"value":1168},{"type":17,"tag":243,"props":1395,"children":1396},{"style":250},[1397],{"type":22,"value":375},{"type":17,"tag":243,"props":1399,"children":1400},{"style":378},[1401],{"type":22,"value":467},{"type":17,"tag":243,"props":1403,"children":1404},{"style":262},[1405],{"type":22,"value":565},{"type":17,"tag":243,"props":1407,"children":1408},{"class":245,"line":403},[1409],{"type":17,"tag":243,"props":1410,"children":1411},{"style":262},[1412],{"type":22,"value":1413},"  }\n",{"type":17,"tag":243,"props":1415,"children":1416},{"class":245,"line":411},[1417],{"type":17,"tag":243,"props":1418,"children":1419},{"style":262},[1420],{"type":22,"value":308},{"type":17,"tag":243,"props":1422,"children":1423},{"class":245,"line":437},[1424,1428,1432,1436],{"type":17,"tag":243,"props":1425,"children":1426},{"style":256},[1427],{"type":22,"value":1230},{"type":17,"tag":243,"props":1429,"children":1430},{"style":262},[1431],{"type":22,"value":265},{"type":17,"tag":243,"props":1433,"children":1434},{"style":378},[1435],{"type":22,"value":560},{"type":17,"tag":243,"props":1437,"children":1438},{"style":262},[1439],{"type":22,"value":1215},{"type":17,"tag":18,"props":1441,"children":1442},{},[1443],{"type":22,"value":1444},"Although the vast majority of languages use strict evaluation methods, there are a few interesting applications of non-strict evaluation methods. They allow us, among other things, to create infinite data structures. Interestingly, although we might associate such methods with functional programming languages like Haskell, JavaScript also gives us this possibility! Thanks to new functionalities in the ES6 standard, such as generators, we can also define infinite collections in JavaScript.",{"type":17,"tag":18,"props":1446,"children":1447},{},[1448],{"type":22,"value":1449},"Below, we'll create an infinite collection using a generator:",{"type":17,"tag":233,"props":1451,"children":1453},{"className":235,"code":1452,"language":237,"meta":8,"style":8},"var naturalNumbers = function* () {\n  let i = 0;\n  while (true) {\n    yield i++;\n  }\n}\n",[1454],{"type":17,"tag":219,"props":1455,"children":1456},{"__ignoreMap":8},[1457,1485,1511,1533,1555,1562],{"type":17,"tag":243,"props":1458,"children":1459},{"class":245,"line":246},[1460,1465,1470,1475,1480],{"type":17,"tag":243,"props":1461,"children":1462},{"style":250},[1463],{"type":22,"value":1464},"var",{"type":17,"tag":243,"props":1466,"children":1467},{"style":256},[1468],{"type":22,"value":1469}," naturalNumbers",{"type":17,"tag":243,"props":1471,"children":1472},{"style":250},[1473],{"type":22,"value":1474}," =",{"type":17,"tag":243,"props":1476,"children":1477},{"style":250},[1478],{"type":22,"value":1479}," function*",{"type":17,"tag":243,"props":1481,"children":1482},{"style":262},[1483],{"type":22,"value":1484}," () {\n",{"type":17,"tag":243,"props":1486,"children":1487},{"class":245,"line":160},[1488,1493,1498,1503,1507],{"type":17,"tag":243,"props":1489,"children":1490},{"style":250},[1491],{"type":22,"value":1492},"  let",{"type":17,"tag":243,"props":1494,"children":1495},{"style":262},[1496],{"type":22,"value":1497}," i ",{"type":17,"tag":243,"props":1499,"children":1500},{"style":250},[1501],{"type":22,"value":1502},"=",{"type":17,"tag":243,"props":1504,"children":1505},{"style":378},[1506],{"type":22,"value":457},{"type":17,"tag":243,"props":1508,"children":1509},{"style":262},[1510],{"type":22,"value":507},{"type":17,"tag":243,"props":1512,"children":1513},{"class":245,"line":302},[1514,1519,1524,1529],{"type":17,"tag":243,"props":1515,"children":1516},{"style":250},[1517],{"type":22,"value":1518},"  while",{"type":17,"tag":243,"props":1520,"children":1521},{"style":262},[1522],{"type":22,"value":1523}," (",{"type":17,"tag":243,"props":1525,"children":1526},{"style":378},[1527],{"type":22,"value":1528},"true",{"type":17,"tag":243,"props":1530,"children":1531},{"style":262},[1532],{"type":22,"value":276},{"type":17,"tag":243,"props":1534,"children":1535},{"class":245,"line":311},[1536,1541,1546,1551],{"type":17,"tag":243,"props":1537,"children":1538},{"style":250},[1539],{"type":22,"value":1540},"    yield",{"type":17,"tag":243,"props":1542,"children":1543},{"style":262},[1544],{"type":22,"value":1545}," i",{"type":17,"tag":243,"props":1547,"children":1548},{"style":250},[1549],{"type":22,"value":1550},"++",{"type":17,"tag":243,"props":1552,"children":1553},{"style":262},[1554],{"type":22,"value":507},{"type":17,"tag":243,"props":1556,"children":1557},{"class":245,"line":356},[1558],{"type":17,"tag":243,"props":1559,"children":1560},{"style":262},[1561],{"type":22,"value":1413},{"type":17,"tag":243,"props":1563,"children":1564},{"class":245,"line":403},[1565],{"type":17,"tag":243,"props":1566,"children":1567},{"style":262},[1568],{"type":22,"value":308},{"type":17,"tag":233,"props":1570,"children":1572},{"className":235,"code":1571,"language":237,"meta":8,"style":8},"for (let i of naturalNumbers()) {\n  if (i > 10) break;\n  console.log(i);\n}\n",[1573],{"type":17,"tag":219,"props":1574,"children":1575},{"__ignoreMap":8},[1576,1611,1647,1665],{"type":17,"tag":243,"props":1577,"children":1578},{"class":245,"line":246},[1579,1584,1588,1593,1597,1602,1606],{"type":17,"tag":243,"props":1580,"children":1581},{"style":250},[1582],{"type":22,"value":1583},"for",{"type":17,"tag":243,"props":1585,"children":1586},{"style":262},[1587],{"type":22,"value":1523},{"type":17,"tag":243,"props":1589,"children":1590},{"style":250},[1591],{"type":22,"value":1592},"let",{"type":17,"tag":243,"props":1594,"children":1595},{"style":262},[1596],{"type":22,"value":1497},{"type":17,"tag":243,"props":1598,"children":1599},{"style":250},[1600],{"type":22,"value":1601},"of",{"type":17,"tag":243,"props":1603,"children":1604},{"style":256},[1605],{"type":22,"value":1469},{"type":17,"tag":243,"props":1607,"children":1608},{"style":262},[1609],{"type":22,"value":1610},"()) {\n",{"type":17,"tag":243,"props":1612,"children":1613},{"class":245,"line":160},[1614,1618,1623,1628,1633,1638,1643],{"type":17,"tag":243,"props":1615,"children":1616},{"style":250},[1617],{"type":22,"value":1322},{"type":17,"tag":243,"props":1619,"children":1620},{"style":262},[1621],{"type":22,"value":1622}," (i ",{"type":17,"tag":243,"props":1624,"children":1625},{"style":250},[1626],{"type":22,"value":1627},">",{"type":17,"tag":243,"props":1629,"children":1630},{"style":378},[1631],{"type":22,"value":1632}," 10",{"type":17,"tag":243,"props":1634,"children":1635},{"style":262},[1636],{"type":22,"value":1637},") ",{"type":17,"tag":243,"props":1639,"children":1640},{"style":250},[1641],{"type":22,"value":1642},"break",{"type":17,"tag":243,"props":1644,"children":1645},{"style":262},[1646],{"type":22,"value":507},{"type":17,"tag":243,"props":1648,"children":1649},{"class":245,"line":302},[1650,1655,1660],{"type":17,"tag":243,"props":1651,"children":1652},{"style":262},[1653],{"type":22,"value":1654},"  console.",{"type":17,"tag":243,"props":1656,"children":1657},{"style":256},[1658],{"type":22,"value":1659},"log",{"type":17,"tag":243,"props":1661,"children":1662},{"style":262},[1663],{"type":22,"value":1664},"(i);\n",{"type":17,"tag":243,"props":1666,"children":1667},{"class":245,"line":311},[1668],{"type":17,"tag":243,"props":1669,"children":1670},{"style":262},[1671],{"type":22,"value":308},{"type":17,"tag":18,"props":1673,"children":1674},{},[1675],{"type":22,"value":1676},"Such a data structure can be very useful when we don't know in advance how many elements we will need. Imagine we want to find 100 prime numbers using a library similar to RxJs, without the ability to create an infinite collection:",{"type":17,"tag":233,"props":1678,"children":1680},{"className":235,"code":1679,"language":237,"meta":8,"style":8},"const primeNumbers = naturalNumbers\n.filter(isPrime)\n.first(100)\n",[1681],{"type":17,"tag":219,"props":1682,"children":1683},{"__ignoreMap":8},[1684,1706,1723],{"type":17,"tag":243,"props":1685,"children":1686},{"class":245,"line":246},[1687,1692,1697,1701],{"type":17,"tag":243,"props":1688,"children":1689},{"style":250},[1690],{"type":22,"value":1691},"const",{"type":17,"tag":243,"props":1693,"children":1694},{"style":378},[1695],{"type":22,"value":1696}," primeNumbers",{"type":17,"tag":243,"props":1698,"children":1699},{"style":250},[1700],{"type":22,"value":1474},{"type":17,"tag":243,"props":1702,"children":1703},{"style":262},[1704],{"type":22,"value":1705}," naturalNumbers\n",{"type":17,"tag":243,"props":1707,"children":1708},{"class":245,"line":160},[1709,1713,1718],{"type":17,"tag":243,"props":1710,"children":1711},{"style":262},[1712],{"type":22,"value":595},{"type":17,"tag":243,"props":1714,"children":1715},{"style":256},[1716],{"type":22,"value":1717},"filter",{"type":17,"tag":243,"props":1719,"children":1720},{"style":262},[1721],{"type":22,"value":1722},"(isPrime)\n",{"type":17,"tag":243,"props":1724,"children":1725},{"class":245,"line":302},[1726,1730,1735,1739,1744],{"type":17,"tag":243,"props":1727,"children":1728},{"style":262},[1729],{"type":22,"value":595},{"type":17,"tag":243,"props":1731,"children":1732},{"style":256},[1733],{"type":22,"value":1734},"first",{"type":17,"tag":243,"props":1736,"children":1737},{"style":262},[1738],{"type":22,"value":265},{"type":17,"tag":243,"props":1740,"children":1741},{"style":378},[1742],{"type":22,"value":1743},"100",{"type":17,"tag":243,"props":1745,"children":1746},{"style":262},[1747],{"type":22,"value":1341},{"type":17,"tag":18,"props":1749,"children":1750},{},[1751,1753,1759,1761,1766,1768,1773],{"type":22,"value":1752},"Assuming that ",{"type":17,"tag":219,"props":1754,"children":1756},{"className":1755},[],[1757],{"type":22,"value":1758},"naturalNumbers",{"type":22,"value":1760}," stands for a sequence of consecutive natural numbers, 1, 2, 3, 4..., what should its length be? 10,000? It's certainly hard to judge at first glance. The ability to use a data structure like ",{"type":17,"tag":219,"props":1762,"children":1764},{"className":1763},[],[1765],{"type":22,"value":1758},{"type":22,"value":1767}," generator gives us a tremendous advantage here.\nWe can do this precisely because generators in JavaScript are based on lazy evaluation. Subsequent elements of ",{"type":17,"tag":219,"props":1769,"children":1771},{"className":1770},[],[1772],{"type":22,"value":1758},{"type":22,"value":1774}," are generated on demand, according to the definition we provided to the generator.",{"type":17,"tag":18,"props":1776,"children":1777},{},[1778],{"type":22,"value":1779},"Let's consider the classic example: the Fibonacci sequence.",{"type":17,"tag":18,"props":1781,"children":1782},{},[1783],{"type":22,"value":1784},"Suppose we want to define a function that gives the n-th term of the sequence:",{"type":17,"tag":233,"props":1786,"children":1788},{"className":235,"code":1787,"language":237,"meta":8,"style":8},"function fibonacci(n) {\n  if (n \u003C= 1) {\n   return n;\n  }\n  return fibonacci(n - 1) + fibonacci(n - 2);\n}\n",[1789],{"type":17,"tag":219,"props":1790,"children":1791},{"__ignoreMap":8},[1792,1816,1840,1853,1860,1912],{"type":17,"tag":243,"props":1793,"children":1794},{"class":245,"line":246},[1795,1799,1804,1808,1812],{"type":17,"tag":243,"props":1796,"children":1797},{"style":250},[1798],{"type":22,"value":253},{"type":17,"tag":243,"props":1800,"children":1801},{"style":256},[1802],{"type":22,"value":1803}," fibonacci",{"type":17,"tag":243,"props":1805,"children":1806},{"style":262},[1807],{"type":22,"value":265},{"type":17,"tag":243,"props":1809,"children":1810},{"style":268},[1811],{"type":22,"value":1148},{"type":17,"tag":243,"props":1813,"children":1814},{"style":262},[1815],{"type":22,"value":276},{"type":17,"tag":243,"props":1817,"children":1818},{"class":245,"line":160},[1819,1823,1827,1832,1836],{"type":17,"tag":243,"props":1820,"children":1821},{"style":250},[1822],{"type":22,"value":1322},{"type":17,"tag":243,"props":1824,"children":1825},{"style":262},[1826],{"type":22,"value":1327},{"type":17,"tag":243,"props":1828,"children":1829},{"style":250},[1830],{"type":22,"value":1831},"\u003C=",{"type":17,"tag":243,"props":1833,"children":1834},{"style":378},[1835],{"type":22,"value":467},{"type":17,"tag":243,"props":1837,"children":1838},{"style":262},[1839],{"type":22,"value":276},{"type":17,"tag":243,"props":1841,"children":1842},{"class":245,"line":302},[1843,1848],{"type":17,"tag":243,"props":1844,"children":1845},{"style":250},[1846],{"type":22,"value":1847},"   return",{"type":17,"tag":243,"props":1849,"children":1850},{"style":262},[1851],{"type":22,"value":1852}," n;\n",{"type":17,"tag":243,"props":1854,"children":1855},{"class":245,"line":311},[1856],{"type":17,"tag":243,"props":1857,"children":1858},{"style":262},[1859],{"type":22,"value":1413},{"type":17,"tag":243,"props":1861,"children":1862},{"class":245,"line":356},[1863,1867,1871,1875,1879,1883,1887,1892,1896,1900,1904,1908],{"type":17,"tag":243,"props":1864,"children":1865},{"style":250},[1866],{"type":22,"value":284},{"type":17,"tag":243,"props":1868,"children":1869},{"style":256},[1870],{"type":22,"value":1803},{"type":17,"tag":243,"props":1872,"children":1873},{"style":262},[1874],{"type":22,"value":1168},{"type":17,"tag":243,"props":1876,"children":1877},{"style":250},[1878],{"type":22,"value":375},{"type":17,"tag":243,"props":1880,"children":1881},{"style":378},[1882],{"type":22,"value":467},{"type":17,"tag":243,"props":1884,"children":1885},{"style":262},[1886],{"type":22,"value":1637},{"type":17,"tag":243,"props":1888,"children":1889},{"style":250},[1890],{"type":22,"value":1891},"+",{"type":17,"tag":243,"props":1893,"children":1894},{"style":256},[1895],{"type":22,"value":1803},{"type":17,"tag":243,"props":1897,"children":1898},{"style":262},[1899],{"type":22,"value":1168},{"type":17,"tag":243,"props":1901,"children":1902},{"style":250},[1903],{"type":22,"value":375},{"type":17,"tag":243,"props":1905,"children":1906},{"style":378},[1907],{"type":22,"value":502},{"type":17,"tag":243,"props":1909,"children":1910},{"style":262},[1911],{"type":22,"value":1215},{"type":17,"tag":243,"props":1913,"children":1914},{"class":245,"line":403},[1915],{"type":17,"tag":243,"props":1916,"children":1917},{"style":262},[1918],{"type":22,"value":308},{"type":17,"tag":18,"props":1920,"children":1921},{},[1922],{"type":22,"value":1923},"To print the first 10 terms of the sequence:",{"type":17,"tag":233,"props":1925,"children":1927},{"className":235,"code":1926,"language":237,"meta":8,"style":8},"for (let i = 0; i \u003C 10; i++) {\n  console.log(fibonacci(i));\n}\n",[1928],{"type":17,"tag":219,"props":1929,"children":1930},{"__ignoreMap":8},[1931,1984,2009],{"type":17,"tag":243,"props":1932,"children":1933},{"class":245,"line":246},[1934,1938,1942,1946,1950,1954,1958,1963,1967,1971,1976,1980],{"type":17,"tag":243,"props":1935,"children":1936},{"style":250},[1937],{"type":22,"value":1583},{"type":17,"tag":243,"props":1939,"children":1940},{"style":262},[1941],{"type":22,"value":1523},{"type":17,"tag":243,"props":1943,"children":1944},{"style":250},[1945],{"type":22,"value":1592},{"type":17,"tag":243,"props":1947,"children":1948},{"style":262},[1949],{"type":22,"value":1497},{"type":17,"tag":243,"props":1951,"children":1952},{"style":250},[1953],{"type":22,"value":1502},{"type":17,"tag":243,"props":1955,"children":1956},{"style":378},[1957],{"type":22,"value":457},{"type":17,"tag":243,"props":1959,"children":1960},{"style":262},[1961],{"type":22,"value":1962},"; i ",{"type":17,"tag":243,"props":1964,"children":1965},{"style":250},[1966],{"type":22,"value":481},{"type":17,"tag":243,"props":1968,"children":1969},{"style":378},[1970],{"type":22,"value":1632},{"type":17,"tag":243,"props":1972,"children":1973},{"style":262},[1974],{"type":22,"value":1975},"; i",{"type":17,"tag":243,"props":1977,"children":1978},{"style":250},[1979],{"type":22,"value":1550},{"type":17,"tag":243,"props":1981,"children":1982},{"style":262},[1983],{"type":22,"value":276},{"type":17,"tag":243,"props":1985,"children":1986},{"class":245,"line":160},[1987,1991,1995,1999,2004],{"type":17,"tag":243,"props":1988,"children":1989},{"style":262},[1990],{"type":22,"value":1654},{"type":17,"tag":243,"props":1992,"children":1993},{"style":256},[1994],{"type":22,"value":1659},{"type":17,"tag":243,"props":1996,"children":1997},{"style":262},[1998],{"type":22,"value":265},{"type":17,"tag":243,"props":2000,"children":2001},{"style":256},[2002],{"type":22,"value":2003},"fibonacci",{"type":17,"tag":243,"props":2005,"children":2006},{"style":262},[2007],{"type":22,"value":2008},"(i));\n",{"type":17,"tag":243,"props":2010,"children":2011},{"class":245,"line":302},[2012],{"type":17,"tag":243,"props":2013,"children":2014},{"style":262},[2015],{"type":22,"value":308},{"type":17,"tag":18,"props":2017,"children":2018},{},[2019],{"type":22,"value":2020},"Instead of using the above function, we can define a generator describing the Fibonacci sequence:",{"type":17,"tag":233,"props":2022,"children":2024},{"className":235,"code":2023,"language":237,"meta":8,"style":8},"function* fibonacci() {\n  let [a, b] = [0, 1];\n  while (true) {\n    yield a;\n    [a, b] = [b, a + b];\n  }\n}\n",[2025],{"type":17,"tag":219,"props":2026,"children":2027},{"__ignoreMap":8},[2028,2045,2084,2103,2115,2141,2148],{"type":17,"tag":243,"props":2029,"children":2030},{"class":245,"line":246},[2031,2036,2040],{"type":17,"tag":243,"props":2032,"children":2033},{"style":250},[2034],{"type":22,"value":2035},"function*",{"type":17,"tag":243,"props":2037,"children":2038},{"style":256},[2039],{"type":22,"value":1803},{"type":17,"tag":243,"props":2041,"children":2042},{"style":262},[2043],{"type":22,"value":2044},"() {\n",{"type":17,"tag":243,"props":2046,"children":2047},{"class":245,"line":160},[2048,2052,2057,2061,2066,2071,2075,2079],{"type":17,"tag":243,"props":2049,"children":2050},{"style":250},[2051],{"type":22,"value":1492},{"type":17,"tag":243,"props":2053,"children":2054},{"style":262},[2055],{"type":22,"value":2056}," [a, b] ",{"type":17,"tag":243,"props":2058,"children":2059},{"style":250},[2060],{"type":22,"value":1502},{"type":17,"tag":243,"props":2062,"children":2063},{"style":262},[2064],{"type":22,"value":2065}," [",{"type":17,"tag":243,"props":2067,"children":2068},{"style":378},[2069],{"type":22,"value":2070},"0",{"type":17,"tag":243,"props":2072,"children":2073},{"style":262},[2074],{"type":22,"value":335},{"type":17,"tag":243,"props":2076,"children":2077},{"style":378},[2078],{"type":22,"value":551},{"type":17,"tag":243,"props":2080,"children":2081},{"style":262},[2082],{"type":22,"value":2083},"];\n",{"type":17,"tag":243,"props":2085,"children":2086},{"class":245,"line":302},[2087,2091,2095,2099],{"type":17,"tag":243,"props":2088,"children":2089},{"style":250},[2090],{"type":22,"value":1518},{"type":17,"tag":243,"props":2092,"children":2093},{"style":262},[2094],{"type":22,"value":1523},{"type":17,"tag":243,"props":2096,"children":2097},{"style":378},[2098],{"type":22,"value":1528},{"type":17,"tag":243,"props":2100,"children":2101},{"style":262},[2102],{"type":22,"value":276},{"type":17,"tag":243,"props":2104,"children":2105},{"class":245,"line":311},[2106,2110],{"type":17,"tag":243,"props":2107,"children":2108},{"style":250},[2109],{"type":22,"value":1540},{"type":17,"tag":243,"props":2111,"children":2112},{"style":262},[2113],{"type":22,"value":2114}," a;\n",{"type":17,"tag":243,"props":2116,"children":2117},{"class":245,"line":356},[2118,2123,2127,2132,2136],{"type":17,"tag":243,"props":2119,"children":2120},{"style":262},[2121],{"type":22,"value":2122},"    [a, b] ",{"type":17,"tag":243,"props":2124,"children":2125},{"style":250},[2126],{"type":22,"value":1502},{"type":17,"tag":243,"props":2128,"children":2129},{"style":262},[2130],{"type":22,"value":2131}," [b, a ",{"type":17,"tag":243,"props":2133,"children":2134},{"style":250},[2135],{"type":22,"value":1891},{"type":17,"tag":243,"props":2137,"children":2138},{"style":262},[2139],{"type":22,"value":2140}," b];\n",{"type":17,"tag":243,"props":2142,"children":2143},{"class":245,"line":403},[2144],{"type":17,"tag":243,"props":2145,"children":2146},{"style":262},[2147],{"type":22,"value":1413},{"type":17,"tag":243,"props":2149,"children":2150},{"class":245,"line":411},[2151],{"type":17,"tag":243,"props":2152,"children":2153},{"style":262},[2154],{"type":22,"value":308},{"type":17,"tag":18,"props":2156,"children":2157},{},[2158],{"type":22,"value":2159},"We instantiate the Fibonacci generator as follows:",{"type":17,"tag":233,"props":2161,"children":2163},{"className":235,"code":2162,"language":237,"meta":8,"style":8},"var fib = fibonacci();\n",[2164],{"type":17,"tag":219,"props":2165,"children":2166},{"__ignoreMap":8},[2167],{"type":17,"tag":243,"props":2168,"children":2169},{"class":245,"line":246},[2170,2174,2179,2183,2187],{"type":17,"tag":243,"props":2171,"children":2172},{"style":250},[2173],{"type":22,"value":1464},{"type":17,"tag":243,"props":2175,"children":2176},{"style":262},[2177],{"type":22,"value":2178}," fib ",{"type":17,"tag":243,"props":2180,"children":2181},{"style":250},[2182],{"type":22,"value":1502},{"type":17,"tag":243,"props":2184,"children":2185},{"style":256},[2186],{"type":22,"value":1803},{"type":17,"tag":243,"props":2188,"children":2189},{"style":262},[2190],{"type":22,"value":2191},"();\n",{"type":17,"tag":18,"props":2193,"children":2194},{},[2195],{"type":22,"value":2196},"Let's print the first 10 terms of the sequence:",{"type":17,"tag":233,"props":2198,"children":2200},{"className":235,"code":2199,"language":237,"meta":8,"style":8},"for (let i = 0; i \u003C 10; i++) {\n  console.log(fib.next().value);\n}\n",[2201],{"type":17,"tag":219,"props":2202,"children":2203},{"__ignoreMap":8},[2204,2255,2281],{"type":17,"tag":243,"props":2205,"children":2206},{"class":245,"line":246},[2207,2211,2215,2219,2223,2227,2231,2235,2239,2243,2247,2251],{"type":17,"tag":243,"props":2208,"children":2209},{"style":250},[2210],{"type":22,"value":1583},{"type":17,"tag":243,"props":2212,"children":2213},{"style":262},[2214],{"type":22,"value":1523},{"type":17,"tag":243,"props":2216,"children":2217},{"style":250},[2218],{"type":22,"value":1592},{"type":17,"tag":243,"props":2220,"children":2221},{"style":262},[2222],{"type":22,"value":1497},{"type":17,"tag":243,"props":2224,"children":2225},{"style":250},[2226],{"type":22,"value":1502},{"type":17,"tag":243,"props":2228,"children":2229},{"style":378},[2230],{"type":22,"value":457},{"type":17,"tag":243,"props":2232,"children":2233},{"style":262},[2234],{"type":22,"value":1962},{"type":17,"tag":243,"props":2236,"children":2237},{"style":250},[2238],{"type":22,"value":481},{"type":17,"tag":243,"props":2240,"children":2241},{"style":378},[2242],{"type":22,"value":1632},{"type":17,"tag":243,"props":2244,"children":2245},{"style":262},[2246],{"type":22,"value":1975},{"type":17,"tag":243,"props":2248,"children":2249},{"style":250},[2250],{"type":22,"value":1550},{"type":17,"tag":243,"props":2252,"children":2253},{"style":262},[2254],{"type":22,"value":276},{"type":17,"tag":243,"props":2256,"children":2257},{"class":245,"line":160},[2258,2262,2266,2271,2276],{"type":17,"tag":243,"props":2259,"children":2260},{"style":262},[2261],{"type":22,"value":1654},{"type":17,"tag":243,"props":2263,"children":2264},{"style":256},[2265],{"type":22,"value":1659},{"type":17,"tag":243,"props":2267,"children":2268},{"style":262},[2269],{"type":22,"value":2270},"(fib.",{"type":17,"tag":243,"props":2272,"children":2273},{"style":256},[2274],{"type":22,"value":2275},"next",{"type":17,"tag":243,"props":2277,"children":2278},{"style":262},[2279],{"type":22,"value":2280},"().value);\n",{"type":17,"tag":243,"props":2282,"children":2283},{"class":245,"line":302},[2284],{"type":17,"tag":243,"props":2285,"children":2286},{"style":262},[2287],{"type":22,"value":308},{"type":17,"tag":40,"props":2289,"children":2291},{"id":2290},"sources",[2292],{"type":22,"value":2293},"Sources",{"type":17,"tag":18,"props":2295,"children":2296},{},[2297,2299,2305],{"type":22,"value":2298},"This article was based on ",{"type":17,"tag":2300,"props":2301,"children":2302},"em",{},[2303],{"type":22,"value":2304},"Structure and Interpretation of Computer Programs",{"type":22,"value":2306},". I hope it answers some of the questions I had after reading related chapters in the book. It also attempts to describe the problem using slightly simpler language with more examples to learn from. Thanks for reading it!",{"type":17,"tag":2308,"props":2309,"children":2310},"style",{},[2311],{"type":22,"value":2312},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":8,"searchDepth":160,"depth":160,"links":2314},[2315,2316,2317,2318,2319],{"id":181,"depth":160,"text":184},{"id":197,"depth":160,"text":200},{"id":697,"depth":160,"text":700},{"id":821,"depth":160,"text":824},{"id":2290,"depth":160,"text":2293},"content:articles:functions-and-evaluations-strategies-js-examples.md","articles/functions-and-evaluations-strategies-js-examples.md","articles/functions-and-evaluations-strategies-js-examples",{"_path":2324,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":2325,"description":2326,"published":2327,"slug":2328,"body":2329,"_type":165,"_id":6849,"_source":167,"_file":6850,"_stem":6851,"_extension":170},"/articles/optimizing-the-article-life-millions-of-particles-with-webgpu","Optimizing the Particle Life: WebGPU and Millions of 3D Particles (Part 3)","Testing out new hardware accelaration API.","2024/03/13","optimizing-the-article-life-from-millions-of-3d-particles",{"type":14,"children":2330,"toc":6841},[2331,2345,2351,2356,2361,2366,2371,2376,2382,2387,2410,2415,3753,3759,3764,3769,3774,3893,3898,3903,5252,5257,5262,5267,5626,5631,5637,5651,5656,6460,6466,6471,6794,6826,6832,6837],{"type":17,"tag":2332,"props":2333,"children":2335},"div",{"style":2334},"position:relative; width:100%; height:0px; padding-bottom:58.347%",[2336],{"type":17,"tag":2337,"props":2338,"children":2344},"iframe",{"allow":2339,"allowFullScreen":2340,"height":2341,"src":2342,"width":2341,"style":2343},"fullscreen",true,"100%","https://streamable.com/e/cmkm4y?","border:none; width:100%; height:100%; position:absolute; left:0px; top:0px; overflow:hidden;",[],{"type":17,"tag":40,"props":2346,"children":2348},{"id":2347},"exceeded-expectations",[2349],{"type":22,"value":2350},"Exceeded expectations",{"type":17,"tag":18,"props":2352,"children":2353},{},[2354],{"type":22,"value":2355},"For a modest web developer like me, diving into the world of computer graphics APIs can be more than intimidating. It's not even about the libraries' complexity, scarce learning resources, or the large amount of boilerplate code required to achieve the simplest of things. For me, it required a shift in perspective and I felt like I was a total beginner at programming again. To be honest, it was a nice feeling, but it's certainly not something you can learn \"on the go\". You can take, let's say, a Java developer with several years of experience, and they'll almost immediately be a valuable addition to a team developing in C# or TypeScript. But to be a productive graphics programmer, I'd probably have to spend months, if not more, on intensive learning before being worth anything.",{"type":17,"tag":18,"props":2357,"children":2358},{},[2359],{"type":22,"value":2360},"I wanted to finish my project, however! Initially, I thought that learning complex graphics API just for this project would be overkill, and I wanted to use some higher-level library. But I quickly found out that some of the likes of Three.js have a learning curve of their own, and simpler ones, focused on computation (think GPU.js) are not enough, often buggy and just offering a headache of their own.",{"type":17,"tag":18,"props":2362,"children":2363},{},[2364],{"type":22,"value":2365},"For my particle life, rendering the particles on the screen was not the most expensive operation. Before rendering, computing their positions was the real bottleneck. So when I came across an article about WebGPU introducing compute shaders, I decided to give it a try. It's a simple idea: you load data to a buffer, perform operations on it in parallel, and output the result to a buffer. As opposed to WebGL, where something similar is possible through a hacky, unreliable way: you convert data to a texture, load it to GPU with a pixel shader, get the pixels from the canvas, and convert them back to data.",{"type":17,"tag":18,"props":2367,"children":2368},{},[2369],{"type":22,"value":2370},"In general, when I realized that when you throw away the scary boilerplate code, all that my code was buffers filled with easy-to-visualize data, flowing from the compute pipeline to the rendering pipeline, things clicked in my head and I could focus on the actual problem I had to solve.",{"type":17,"tag":18,"props":2372,"children":2373},{},[2374],{"type":22,"value":2375},"And I have to say, that I'm extremely happy with how it turned out. Not only did I go far beyond my initial goal of rendering a million particles with acceptable frame rate, but due to tweaks in the algorithm and turning the whole thing 3D, the visual effect, in my opinion, is quite stunning and bordering in what could be called generative art.",{"type":17,"tag":40,"props":2377,"children":2379},{"id":2378},"_1-preparing-the-buffers-for-compute-pass",[2380],{"type":22,"value":2381},"1. Preparing the buffers for compute pass",{"type":17,"tag":18,"props":2383,"children":2384},{},[2385],{"type":22,"value":2386},"First, let's focus on computing the particle position. As you remember from the first part, to describe our particles' movement, we need four components of our system:",{"type":17,"tag":580,"props":2388,"children":2389},{},[2390,2395,2400,2405],{"type":17,"tag":584,"props":2391,"children":2392},{},[2393],{"type":22,"value":2394},"Particles' positions",{"type":17,"tag":584,"props":2396,"children":2397},{},[2398],{"type":22,"value":2399},"Particles' velocities",{"type":17,"tag":584,"props":2401,"children":2402},{},[2403],{"type":22,"value":2404},"Particles' colors",{"type":17,"tag":584,"props":2406,"children":2407},{},[2408],{"type":22,"value":2409},"Color-attraction matrix",{"type":17,"tag":18,"props":2411,"children":2412},{},[2413],{"type":22,"value":2414},"To calculate position, we need velocity, and to calculate velocity, we need to know the attraction (or repulsion) between particles, and for that, we need to know their colors. All these must be written to buffers so we can access them in the shader module.",{"type":17,"tag":233,"props":2416,"children":2420},{"className":2417,"code":2418,"language":2419,"meta":8,"style":8},"language-js shiki shiki-themes github-dark","//The array needs have length of particlesCount*4, because our position will be a 4 \n//dimensional vector (x,y,z coordinate + additional projection value w we need to project 3D  \n//coordinates to 2D plane)\nlet positionBufferData = new Float32Array(particleCount * 4); \n//as with python and js version, we start with random distribution\nfor (let i = 0; i \u003C positionBufferData.length; i += 4) {\n  positionBufferData[i] = Math.random() * 2 - 1;\n  positionBufferData[i + 1] = Math.random() * 2 - 1;\n  positionBufferData[i + 2] = Math.random() * 2 - 1;\n  positionBufferData[i + 3] = 1;\n}\n//buffer usage must be declared upon creation\n//VERTEX - can be used as a vertex buffer we'll use in render pass\n//COPY_DST - can be a destination or copy/write operations\n//STORAGE - can be used as storage, for example in bind group entry\nconst positionBuffer = device.createBuffer({\nsize: positionBufferData.byteLength,\nusage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE,\n});\ndevice.queue.writeBuffer(positionBuffer, 0, positionBufferData);\n\n//This will be an array of integers from 0 to m-1 of length = particleCount\n//in other words, one random color for every particle\nconst computeColorsBufferData = new Int32Array(particleCount);\nfor (let i = 0; i \u003C positionBufferData.length; i++) {\n  computeColorsBufferData[i] = Math.floor(Math.random() * m);\n}\nconst computeColorsBuffer = device.createBuffer({\n  size: computeColorsBufferData.byteLength,\n  usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE,\n});\ndevice.queue.writeBuffer(computeColorsBuffer, 0, computeColorsBufferData);\n\n//Oour color-attraction matrix, flattened.\nconst attractionBufferData = new Float32Array(m * m);\nfor (let i = 0; i \u003C attractionBufferData.length; i++) {\n  attractionBufferData[i] = matrix.flat()[i]\n}\nconst attractionBuffer = device.createBuffer({\n  size: attractionBufferData.byteLength,\n  usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE,\n});\ndevice.queue.writeBuffer(attractionBuffer, 0, attractionBufferData);\n\n//Velocities. Here, we need 3 values (x,y,z) for every particle.\nconst velocityBufferData = new Float32Array(particleCount * 3);\nfor (let i = 0; i \u003C velocityBufferData.length; i += 3) {\n  velocityBufferData[i] = 0.0;\n  velocityBufferData[i + 1] = 0.0;\n  velocityBufferData[i + 2] = 0.0;\n}\nconst velocityBuffer = device.createBuffer({\nsize: velocityBufferData.byteLength,\nusage: GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE,\n});\ndevice.queue.writeBuffer(velocityBuffer, 0, velocityBufferData);\n","js",[2421],{"type":17,"tag":219,"props":2422,"children":2423},{"__ignoreMap":8},[2424,2433,2441,2449,2493,2501,2563,2611,2668,2723,2755,2763,2772,2781,2790,2799,2831,2840,2887,2896,2924,2933,2942,2951,2982,3038,3082,3090,3119,3128,3157,3165,3191,3199,3208,3246,3303,3331,3339,3368,3377,3405,3413,3439,3447,3456,3497,3558,3580,3613,3645,3653,3682,3691,3719,3727],{"type":17,"tag":243,"props":2425,"children":2426},{"class":245,"line":246},[2427],{"type":17,"tag":243,"props":2428,"children":2430},{"style":2429},"--shiki-default:#6A737D",[2431],{"type":22,"value":2432},"//The array needs have length of particlesCount*4, because our position will be a 4 \n",{"type":17,"tag":243,"props":2434,"children":2435},{"class":245,"line":160},[2436],{"type":17,"tag":243,"props":2437,"children":2438},{"style":2429},[2439],{"type":22,"value":2440},"//dimensional vector (x,y,z coordinate + additional projection value w we need to project 3D  \n",{"type":17,"tag":243,"props":2442,"children":2443},{"class":245,"line":302},[2444],{"type":17,"tag":243,"props":2445,"children":2446},{"style":2429},[2447],{"type":22,"value":2448},"//coordinates to 2D plane)\n",{"type":17,"tag":243,"props":2450,"children":2451},{"class":245,"line":311},[2452,2456,2461,2465,2470,2475,2480,2484,2488],{"type":17,"tag":243,"props":2453,"children":2454},{"style":250},[2455],{"type":22,"value":1592},{"type":17,"tag":243,"props":2457,"children":2458},{"style":262},[2459],{"type":22,"value":2460}," positionBufferData ",{"type":17,"tag":243,"props":2462,"children":2463},{"style":250},[2464],{"type":22,"value":1502},{"type":17,"tag":243,"props":2466,"children":2467},{"style":250},[2468],{"type":22,"value":2469}," new",{"type":17,"tag":243,"props":2471,"children":2472},{"style":256},[2473],{"type":22,"value":2474}," Float32Array",{"type":17,"tag":243,"props":2476,"children":2477},{"style":262},[2478],{"type":22,"value":2479},"(particleCount ",{"type":17,"tag":243,"props":2481,"children":2482},{"style":250},[2483],{"type":22,"value":294},{"type":17,"tag":243,"props":2485,"children":2486},{"style":378},[2487],{"type":22,"value":381},{"type":17,"tag":243,"props":2489,"children":2490},{"style":262},[2491],{"type":22,"value":2492},"); \n",{"type":17,"tag":243,"props":2494,"children":2495},{"class":245,"line":356},[2496],{"type":17,"tag":243,"props":2497,"children":2498},{"style":2429},[2499],{"type":22,"value":2500},"//as with python and js version, we start with random distribution\n",{"type":17,"tag":243,"props":2502,"children":2503},{"class":245,"line":403},[2504,2508,2512,2516,2520,2524,2528,2532,2536,2541,2546,2550,2555,2559],{"type":17,"tag":243,"props":2505,"children":2506},{"style":250},[2507],{"type":22,"value":1583},{"type":17,"tag":243,"props":2509,"children":2510},{"style":262},[2511],{"type":22,"value":1523},{"type":17,"tag":243,"props":2513,"children":2514},{"style":250},[2515],{"type":22,"value":1592},{"type":17,"tag":243,"props":2517,"children":2518},{"style":262},[2519],{"type":22,"value":1497},{"type":17,"tag":243,"props":2521,"children":2522},{"style":250},[2523],{"type":22,"value":1502},{"type":17,"tag":243,"props":2525,"children":2526},{"style":378},[2527],{"type":22,"value":457},{"type":17,"tag":243,"props":2529,"children":2530},{"style":262},[2531],{"type":22,"value":1962},{"type":17,"tag":243,"props":2533,"children":2534},{"style":250},[2535],{"type":22,"value":481},{"type":17,"tag":243,"props":2537,"children":2538},{"style":262},[2539],{"type":22,"value":2540}," positionBufferData.",{"type":17,"tag":243,"props":2542,"children":2543},{"style":378},[2544],{"type":22,"value":2545},"length",{"type":17,"tag":243,"props":2547,"children":2548},{"style":262},[2549],{"type":22,"value":1962},{"type":17,"tag":243,"props":2551,"children":2552},{"style":250},[2553],{"type":22,"value":2554},"+=",{"type":17,"tag":243,"props":2556,"children":2557},{"style":378},[2558],{"type":22,"value":381},{"type":17,"tag":243,"props":2560,"children":2561},{"style":262},[2562],{"type":22,"value":276},{"type":17,"tag":243,"props":2564,"children":2565},{"class":245,"line":411},[2566,2571,2575,2580,2585,2590,2594,2598,2603,2607],{"type":17,"tag":243,"props":2567,"children":2568},{"style":262},[2569],{"type":22,"value":2570},"  positionBufferData[i] ",{"type":17,"tag":243,"props":2572,"children":2573},{"style":250},[2574],{"type":22,"value":1502},{"type":17,"tag":243,"props":2576,"children":2577},{"style":262},[2578],{"type":22,"value":2579}," Math.",{"type":17,"tag":243,"props":2581,"children":2582},{"style":256},[2583],{"type":22,"value":2584},"random",{"type":17,"tag":243,"props":2586,"children":2587},{"style":262},[2588],{"type":22,"value":2589},"() ",{"type":17,"tag":243,"props":2591,"children":2592},{"style":250},[2593],{"type":22,"value":294},{"type":17,"tag":243,"props":2595,"children":2596},{"style":378},[2597],{"type":22,"value":502},{"type":17,"tag":243,"props":2599,"children":2600},{"style":250},[2601],{"type":22,"value":2602}," -",{"type":17,"tag":243,"props":2604,"children":2605},{"style":378},[2606],{"type":22,"value":467},{"type":17,"tag":243,"props":2608,"children":2609},{"style":262},[2610],{"type":22,"value":507},{"type":17,"tag":243,"props":2612,"children":2613},{"class":245,"line":437},[2614,2619,2623,2627,2632,2636,2640,2644,2648,2652,2656,2660,2664],{"type":17,"tag":243,"props":2615,"children":2616},{"style":262},[2617],{"type":22,"value":2618},"  positionBufferData[i ",{"type":17,"tag":243,"props":2620,"children":2621},{"style":250},[2622],{"type":22,"value":1891},{"type":17,"tag":243,"props":2624,"children":2625},{"style":378},[2626],{"type":22,"value":467},{"type":17,"tag":243,"props":2628,"children":2629},{"style":262},[2630],{"type":22,"value":2631},"] ",{"type":17,"tag":243,"props":2633,"children":2634},{"style":250},[2635],{"type":22,"value":1502},{"type":17,"tag":243,"props":2637,"children":2638},{"style":262},[2639],{"type":22,"value":2579},{"type":17,"tag":243,"props":2641,"children":2642},{"style":256},[2643],{"type":22,"value":2584},{"type":17,"tag":243,"props":2645,"children":2646},{"style":262},[2647],{"type":22,"value":2589},{"type":17,"tag":243,"props":2649,"children":2650},{"style":250},[2651],{"type":22,"value":294},{"type":17,"tag":243,"props":2653,"children":2654},{"style":378},[2655],{"type":22,"value":502},{"type":17,"tag":243,"props":2657,"children":2658},{"style":250},[2659],{"type":22,"value":2602},{"type":17,"tag":243,"props":2661,"children":2662},{"style":378},[2663],{"type":22,"value":467},{"type":17,"tag":243,"props":2665,"children":2666},{"style":262},[2667],{"type":22,"value":507},{"type":17,"tag":243,"props":2669,"children":2670},{"class":245,"line":510},[2671,2675,2679,2683,2687,2691,2695,2699,2703,2707,2711,2715,2719],{"type":17,"tag":243,"props":2672,"children":2673},{"style":262},[2674],{"type":22,"value":2618},{"type":17,"tag":243,"props":2676,"children":2677},{"style":250},[2678],{"type":22,"value":1891},{"type":17,"tag":243,"props":2680,"children":2681},{"style":378},[2682],{"type":22,"value":502},{"type":17,"tag":243,"props":2684,"children":2685},{"style":262},[2686],{"type":22,"value":2631},{"type":17,"tag":243,"props":2688,"children":2689},{"style":250},[2690],{"type":22,"value":1502},{"type":17,"tag":243,"props":2692,"children":2693},{"style":262},[2694],{"type":22,"value":2579},{"type":17,"tag":243,"props":2696,"children":2697},{"style":256},[2698],{"type":22,"value":2584},{"type":17,"tag":243,"props":2700,"children":2701},{"style":262},[2702],{"type":22,"value":2589},{"type":17,"tag":243,"props":2704,"children":2705},{"style":250},[2706],{"type":22,"value":294},{"type":17,"tag":243,"props":2708,"children":2709},{"style":378},[2710],{"type":22,"value":502},{"type":17,"tag":243,"props":2712,"children":2713},{"style":250},[2714],{"type":22,"value":2602},{"type":17,"tag":243,"props":2716,"children":2717},{"style":378},[2718],{"type":22,"value":467},{"type":17,"tag":243,"props":2720,"children":2721},{"style":262},[2722],{"type":22,"value":507},{"type":17,"tag":243,"props":2724,"children":2725},{"class":245,"line":518},[2726,2730,2734,2739,2743,2747,2751],{"type":17,"tag":243,"props":2727,"children":2728},{"style":262},[2729],{"type":22,"value":2618},{"type":17,"tag":243,"props":2731,"children":2732},{"style":250},[2733],{"type":22,"value":1891},{"type":17,"tag":243,"props":2735,"children":2736},{"style":378},[2737],{"type":22,"value":2738}," 3",{"type":17,"tag":243,"props":2740,"children":2741},{"style":262},[2742],{"type":22,"value":2631},{"type":17,"tag":243,"props":2744,"children":2745},{"style":250},[2746],{"type":22,"value":1502},{"type":17,"tag":243,"props":2748,"children":2749},{"style":378},[2750],{"type":22,"value":467},{"type":17,"tag":243,"props":2752,"children":2753},{"style":262},[2754],{"type":22,"value":507},{"type":17,"tag":243,"props":2756,"children":2758},{"class":245,"line":2757},11,[2759],{"type":17,"tag":243,"props":2760,"children":2761},{"style":262},[2762],{"type":22,"value":308},{"type":17,"tag":243,"props":2764,"children":2766},{"class":245,"line":2765},12,[2767],{"type":17,"tag":243,"props":2768,"children":2769},{"style":2429},[2770],{"type":22,"value":2771},"//buffer usage must be declared upon creation\n",{"type":17,"tag":243,"props":2773,"children":2775},{"class":245,"line":2774},13,[2776],{"type":17,"tag":243,"props":2777,"children":2778},{"style":2429},[2779],{"type":22,"value":2780},"//VERTEX - can be used as a vertex buffer we'll use in render pass\n",{"type":17,"tag":243,"props":2782,"children":2784},{"class":245,"line":2783},14,[2785],{"type":17,"tag":243,"props":2786,"children":2787},{"style":2429},[2788],{"type":22,"value":2789},"//COPY_DST - can be a destination or copy/write operations\n",{"type":17,"tag":243,"props":2791,"children":2793},{"class":245,"line":2792},15,[2794],{"type":17,"tag":243,"props":2795,"children":2796},{"style":2429},[2797],{"type":22,"value":2798},"//STORAGE - can be used as storage, for example in bind group entry\n",{"type":17,"tag":243,"props":2800,"children":2802},{"class":245,"line":2801},16,[2803,2807,2812,2816,2821,2826],{"type":17,"tag":243,"props":2804,"children":2805},{"style":250},[2806],{"type":22,"value":1691},{"type":17,"tag":243,"props":2808,"children":2809},{"style":378},[2810],{"type":22,"value":2811}," positionBuffer",{"type":17,"tag":243,"props":2813,"children":2814},{"style":250},[2815],{"type":22,"value":1474},{"type":17,"tag":243,"props":2817,"children":2818},{"style":262},[2819],{"type":22,"value":2820}," device.",{"type":17,"tag":243,"props":2822,"children":2823},{"style":256},[2824],{"type":22,"value":2825},"createBuffer",{"type":17,"tag":243,"props":2827,"children":2828},{"style":262},[2829],{"type":22,"value":2830},"({\n",{"type":17,"tag":243,"props":2832,"children":2834},{"class":245,"line":2833},17,[2835],{"type":17,"tag":243,"props":2836,"children":2837},{"style":262},[2838],{"type":22,"value":2839},"size: positionBufferData.byteLength,\n",{"type":17,"tag":243,"props":2841,"children":2843},{"class":245,"line":2842},18,[2844,2849,2854,2859,2864,2869,2873,2877,2882],{"type":17,"tag":243,"props":2845,"children":2846},{"style":262},[2847],{"type":22,"value":2848},"usage: GPUBufferUsage.",{"type":17,"tag":243,"props":2850,"children":2851},{"style":378},[2852],{"type":22,"value":2853},"VERTEX",{"type":17,"tag":243,"props":2855,"children":2856},{"style":250},[2857],{"type":22,"value":2858}," |",{"type":17,"tag":243,"props":2860,"children":2861},{"style":262},[2862],{"type":22,"value":2863}," GPUBufferUsage.",{"type":17,"tag":243,"props":2865,"children":2866},{"style":378},[2867],{"type":22,"value":2868},"COPY_DST",{"type":17,"tag":243,"props":2870,"children":2871},{"style":250},[2872],{"type":22,"value":2858},{"type":17,"tag":243,"props":2874,"children":2875},{"style":262},[2876],{"type":22,"value":2863},{"type":17,"tag":243,"props":2878,"children":2879},{"style":378},[2880],{"type":22,"value":2881},"STORAGE",{"type":17,"tag":243,"props":2883,"children":2884},{"style":262},[2885],{"type":22,"value":2886},",\n",{"type":17,"tag":243,"props":2888,"children":2890},{"class":245,"line":2889},19,[2891],{"type":17,"tag":243,"props":2892,"children":2893},{"style":262},[2894],{"type":22,"value":2895},"});\n",{"type":17,"tag":243,"props":2897,"children":2899},{"class":245,"line":2898},20,[2900,2905,2910,2915,2919],{"type":17,"tag":243,"props":2901,"children":2902},{"style":262},[2903],{"type":22,"value":2904},"device.queue.",{"type":17,"tag":243,"props":2906,"children":2907},{"style":256},[2908],{"type":22,"value":2909},"writeBuffer",{"type":17,"tag":243,"props":2911,"children":2912},{"style":262},[2913],{"type":22,"value":2914},"(positionBuffer, ",{"type":17,"tag":243,"props":2916,"children":2917},{"style":378},[2918],{"type":22,"value":2070},{"type":17,"tag":243,"props":2920,"children":2921},{"style":262},[2922],{"type":22,"value":2923},", positionBufferData);\n",{"type":17,"tag":243,"props":2925,"children":2927},{"class":245,"line":2926},21,[2928],{"type":17,"tag":243,"props":2929,"children":2930},{"emptyLinePlaceholder":2340},[2931],{"type":22,"value":2932},"\n",{"type":17,"tag":243,"props":2934,"children":2936},{"class":245,"line":2935},22,[2937],{"type":17,"tag":243,"props":2938,"children":2939},{"style":2429},[2940],{"type":22,"value":2941},"//This will be an array of integers from 0 to m-1 of length = particleCount\n",{"type":17,"tag":243,"props":2943,"children":2945},{"class":245,"line":2944},23,[2946],{"type":17,"tag":243,"props":2947,"children":2948},{"style":2429},[2949],{"type":22,"value":2950},"//in other words, one random color for every particle\n",{"type":17,"tag":243,"props":2952,"children":2954},{"class":245,"line":2953},24,[2955,2959,2964,2968,2972,2977],{"type":17,"tag":243,"props":2956,"children":2957},{"style":250},[2958],{"type":22,"value":1691},{"type":17,"tag":243,"props":2960,"children":2961},{"style":378},[2962],{"type":22,"value":2963}," computeColorsBufferData",{"type":17,"tag":243,"props":2965,"children":2966},{"style":250},[2967],{"type":22,"value":1474},{"type":17,"tag":243,"props":2969,"children":2970},{"style":250},[2971],{"type":22,"value":2469},{"type":17,"tag":243,"props":2973,"children":2974},{"style":256},[2975],{"type":22,"value":2976}," Int32Array",{"type":17,"tag":243,"props":2978,"children":2979},{"style":262},[2980],{"type":22,"value":2981},"(particleCount);\n",{"type":17,"tag":243,"props":2983,"children":2985},{"class":245,"line":2984},25,[2986,2990,2994,2998,3002,3006,3010,3014,3018,3022,3026,3030,3034],{"type":17,"tag":243,"props":2987,"children":2988},{"style":250},[2989],{"type":22,"value":1583},{"type":17,"tag":243,"props":2991,"children":2992},{"style":262},[2993],{"type":22,"value":1523},{"type":17,"tag":243,"props":2995,"children":2996},{"style":250},[2997],{"type":22,"value":1592},{"type":17,"tag":243,"props":2999,"children":3000},{"style":262},[3001],{"type":22,"value":1497},{"type":17,"tag":243,"props":3003,"children":3004},{"style":250},[3005],{"type":22,"value":1502},{"type":17,"tag":243,"props":3007,"children":3008},{"style":378},[3009],{"type":22,"value":457},{"type":17,"tag":243,"props":3011,"children":3012},{"style":262},[3013],{"type":22,"value":1962},{"type":17,"tag":243,"props":3015,"children":3016},{"style":250},[3017],{"type":22,"value":481},{"type":17,"tag":243,"props":3019,"children":3020},{"style":262},[3021],{"type":22,"value":2540},{"type":17,"tag":243,"props":3023,"children":3024},{"style":378},[3025],{"type":22,"value":2545},{"type":17,"tag":243,"props":3027,"children":3028},{"style":262},[3029],{"type":22,"value":1975},{"type":17,"tag":243,"props":3031,"children":3032},{"style":250},[3033],{"type":22,"value":1550},{"type":17,"tag":243,"props":3035,"children":3036},{"style":262},[3037],{"type":22,"value":276},{"type":17,"tag":243,"props":3039,"children":3041},{"class":245,"line":3040},26,[3042,3047,3051,3055,3060,3065,3069,3073,3077],{"type":17,"tag":243,"props":3043,"children":3044},{"style":262},[3045],{"type":22,"value":3046},"  computeColorsBufferData[i] ",{"type":17,"tag":243,"props":3048,"children":3049},{"style":250},[3050],{"type":22,"value":1502},{"type":17,"tag":243,"props":3052,"children":3053},{"style":262},[3054],{"type":22,"value":2579},{"type":17,"tag":243,"props":3056,"children":3057},{"style":256},[3058],{"type":22,"value":3059},"floor",{"type":17,"tag":243,"props":3061,"children":3062},{"style":262},[3063],{"type":22,"value":3064},"(Math.",{"type":17,"tag":243,"props":3066,"children":3067},{"style":256},[3068],{"type":22,"value":2584},{"type":17,"tag":243,"props":3070,"children":3071},{"style":262},[3072],{"type":22,"value":2589},{"type":17,"tag":243,"props":3074,"children":3075},{"style":250},[3076],{"type":22,"value":294},{"type":17,"tag":243,"props":3078,"children":3079},{"style":262},[3080],{"type":22,"value":3081}," m);\n",{"type":17,"tag":243,"props":3083,"children":3085},{"class":245,"line":3084},27,[3086],{"type":17,"tag":243,"props":3087,"children":3088},{"style":262},[3089],{"type":22,"value":308},{"type":17,"tag":243,"props":3091,"children":3093},{"class":245,"line":3092},28,[3094,3098,3103,3107,3111,3115],{"type":17,"tag":243,"props":3095,"children":3096},{"style":250},[3097],{"type":22,"value":1691},{"type":17,"tag":243,"props":3099,"children":3100},{"style":378},[3101],{"type":22,"value":3102}," computeColorsBuffer",{"type":17,"tag":243,"props":3104,"children":3105},{"style":250},[3106],{"type":22,"value":1474},{"type":17,"tag":243,"props":3108,"children":3109},{"style":262},[3110],{"type":22,"value":2820},{"type":17,"tag":243,"props":3112,"children":3113},{"style":256},[3114],{"type":22,"value":2825},{"type":17,"tag":243,"props":3116,"children":3117},{"style":262},[3118],{"type":22,"value":2830},{"type":17,"tag":243,"props":3120,"children":3122},{"class":245,"line":3121},29,[3123],{"type":17,"tag":243,"props":3124,"children":3125},{"style":262},[3126],{"type":22,"value":3127},"  size: computeColorsBufferData.byteLength,\n",{"type":17,"tag":243,"props":3129,"children":3131},{"class":245,"line":3130},30,[3132,3137,3141,3145,3149,3153],{"type":17,"tag":243,"props":3133,"children":3134},{"style":262},[3135],{"type":22,"value":3136},"  usage: GPUBufferUsage.",{"type":17,"tag":243,"props":3138,"children":3139},{"style":378},[3140],{"type":22,"value":2868},{"type":17,"tag":243,"props":3142,"children":3143},{"style":250},[3144],{"type":22,"value":2858},{"type":17,"tag":243,"props":3146,"children":3147},{"style":262},[3148],{"type":22,"value":2863},{"type":17,"tag":243,"props":3150,"children":3151},{"style":378},[3152],{"type":22,"value":2881},{"type":17,"tag":243,"props":3154,"children":3155},{"style":262},[3156],{"type":22,"value":2886},{"type":17,"tag":243,"props":3158,"children":3160},{"class":245,"line":3159},31,[3161],{"type":17,"tag":243,"props":3162,"children":3163},{"style":262},[3164],{"type":22,"value":2895},{"type":17,"tag":243,"props":3166,"children":3168},{"class":245,"line":3167},32,[3169,3173,3177,3182,3186],{"type":17,"tag":243,"props":3170,"children":3171},{"style":262},[3172],{"type":22,"value":2904},{"type":17,"tag":243,"props":3174,"children":3175},{"style":256},[3176],{"type":22,"value":2909},{"type":17,"tag":243,"props":3178,"children":3179},{"style":262},[3180],{"type":22,"value":3181},"(computeColorsBuffer, ",{"type":17,"tag":243,"props":3183,"children":3184},{"style":378},[3185],{"type":22,"value":2070},{"type":17,"tag":243,"props":3187,"children":3188},{"style":262},[3189],{"type":22,"value":3190},", computeColorsBufferData);\n",{"type":17,"tag":243,"props":3192,"children":3194},{"class":245,"line":3193},33,[3195],{"type":17,"tag":243,"props":3196,"children":3197},{"emptyLinePlaceholder":2340},[3198],{"type":22,"value":2932},{"type":17,"tag":243,"props":3200,"children":3202},{"class":245,"line":3201},34,[3203],{"type":17,"tag":243,"props":3204,"children":3205},{"style":2429},[3206],{"type":22,"value":3207},"//Oour color-attraction matrix, flattened.\n",{"type":17,"tag":243,"props":3209,"children":3211},{"class":245,"line":3210},35,[3212,3216,3221,3225,3229,3233,3238,3242],{"type":17,"tag":243,"props":3213,"children":3214},{"style":250},[3215],{"type":22,"value":1691},{"type":17,"tag":243,"props":3217,"children":3218},{"style":378},[3219],{"type":22,"value":3220}," attractionBufferData",{"type":17,"tag":243,"props":3222,"children":3223},{"style":250},[3224],{"type":22,"value":1474},{"type":17,"tag":243,"props":3226,"children":3227},{"style":250},[3228],{"type":22,"value":2469},{"type":17,"tag":243,"props":3230,"children":3231},{"style":256},[3232],{"type":22,"value":2474},{"type":17,"tag":243,"props":3234,"children":3235},{"style":262},[3236],{"type":22,"value":3237},"(m ",{"type":17,"tag":243,"props":3239,"children":3240},{"style":250},[3241],{"type":22,"value":294},{"type":17,"tag":243,"props":3243,"children":3244},{"style":262},[3245],{"type":22,"value":3081},{"type":17,"tag":243,"props":3247,"children":3249},{"class":245,"line":3248},36,[3250,3254,3258,3262,3266,3270,3274,3278,3282,3287,3291,3295,3299],{"type":17,"tag":243,"props":3251,"children":3252},{"style":250},[3253],{"type":22,"value":1583},{"type":17,"tag":243,"props":3255,"children":3256},{"style":262},[3257],{"type":22,"value":1523},{"type":17,"tag":243,"props":3259,"children":3260},{"style":250},[3261],{"type":22,"value":1592},{"type":17,"tag":243,"props":3263,"children":3264},{"style":262},[3265],{"type":22,"value":1497},{"type":17,"tag":243,"props":3267,"children":3268},{"style":250},[3269],{"type":22,"value":1502},{"type":17,"tag":243,"props":3271,"children":3272},{"style":378},[3273],{"type":22,"value":457},{"type":17,"tag":243,"props":3275,"children":3276},{"style":262},[3277],{"type":22,"value":1962},{"type":17,"tag":243,"props":3279,"children":3280},{"style":250},[3281],{"type":22,"value":481},{"type":17,"tag":243,"props":3283,"children":3284},{"style":262},[3285],{"type":22,"value":3286}," attractionBufferData.",{"type":17,"tag":243,"props":3288,"children":3289},{"style":378},[3290],{"type":22,"value":2545},{"type":17,"tag":243,"props":3292,"children":3293},{"style":262},[3294],{"type":22,"value":1975},{"type":17,"tag":243,"props":3296,"children":3297},{"style":250},[3298],{"type":22,"value":1550},{"type":17,"tag":243,"props":3300,"children":3301},{"style":262},[3302],{"type":22,"value":276},{"type":17,"tag":243,"props":3304,"children":3306},{"class":245,"line":3305},37,[3307,3312,3316,3321,3326],{"type":17,"tag":243,"props":3308,"children":3309},{"style":262},[3310],{"type":22,"value":3311},"  attractionBufferData[i] ",{"type":17,"tag":243,"props":3313,"children":3314},{"style":250},[3315],{"type":22,"value":1502},{"type":17,"tag":243,"props":3317,"children":3318},{"style":262},[3319],{"type":22,"value":3320}," matrix.",{"type":17,"tag":243,"props":3322,"children":3323},{"style":256},[3324],{"type":22,"value":3325},"flat",{"type":17,"tag":243,"props":3327,"children":3328},{"style":262},[3329],{"type":22,"value":3330},"()[i]\n",{"type":17,"tag":243,"props":3332,"children":3334},{"class":245,"line":3333},38,[3335],{"type":17,"tag":243,"props":3336,"children":3337},{"style":262},[3338],{"type":22,"value":308},{"type":17,"tag":243,"props":3340,"children":3342},{"class":245,"line":3341},39,[3343,3347,3352,3356,3360,3364],{"type":17,"tag":243,"props":3344,"children":3345},{"style":250},[3346],{"type":22,"value":1691},{"type":17,"tag":243,"props":3348,"children":3349},{"style":378},[3350],{"type":22,"value":3351}," attractionBuffer",{"type":17,"tag":243,"props":3353,"children":3354},{"style":250},[3355],{"type":22,"value":1474},{"type":17,"tag":243,"props":3357,"children":3358},{"style":262},[3359],{"type":22,"value":2820},{"type":17,"tag":243,"props":3361,"children":3362},{"style":256},[3363],{"type":22,"value":2825},{"type":17,"tag":243,"props":3365,"children":3366},{"style":262},[3367],{"type":22,"value":2830},{"type":17,"tag":243,"props":3369,"children":3371},{"class":245,"line":3370},40,[3372],{"type":17,"tag":243,"props":3373,"children":3374},{"style":262},[3375],{"type":22,"value":3376},"  size: attractionBufferData.byteLength,\n",{"type":17,"tag":243,"props":3378,"children":3380},{"class":245,"line":3379},41,[3381,3385,3389,3393,3397,3401],{"type":17,"tag":243,"props":3382,"children":3383},{"style":262},[3384],{"type":22,"value":3136},{"type":17,"tag":243,"props":3386,"children":3387},{"style":378},[3388],{"type":22,"value":2868},{"type":17,"tag":243,"props":3390,"children":3391},{"style":250},[3392],{"type":22,"value":2858},{"type":17,"tag":243,"props":3394,"children":3395},{"style":262},[3396],{"type":22,"value":2863},{"type":17,"tag":243,"props":3398,"children":3399},{"style":378},[3400],{"type":22,"value":2881},{"type":17,"tag":243,"props":3402,"children":3403},{"style":262},[3404],{"type":22,"value":2886},{"type":17,"tag":243,"props":3406,"children":3408},{"class":245,"line":3407},42,[3409],{"type":17,"tag":243,"props":3410,"children":3411},{"style":262},[3412],{"type":22,"value":2895},{"type":17,"tag":243,"props":3414,"children":3416},{"class":245,"line":3415},43,[3417,3421,3425,3430,3434],{"type":17,"tag":243,"props":3418,"children":3419},{"style":262},[3420],{"type":22,"value":2904},{"type":17,"tag":243,"props":3422,"children":3423},{"style":256},[3424],{"type":22,"value":2909},{"type":17,"tag":243,"props":3426,"children":3427},{"style":262},[3428],{"type":22,"value":3429},"(attractionBuffer, ",{"type":17,"tag":243,"props":3431,"children":3432},{"style":378},[3433],{"type":22,"value":2070},{"type":17,"tag":243,"props":3435,"children":3436},{"style":262},[3437],{"type":22,"value":3438},", attractionBufferData);\n",{"type":17,"tag":243,"props":3440,"children":3442},{"class":245,"line":3441},44,[3443],{"type":17,"tag":243,"props":3444,"children":3445},{"emptyLinePlaceholder":2340},[3446],{"type":22,"value":2932},{"type":17,"tag":243,"props":3448,"children":3450},{"class":245,"line":3449},45,[3451],{"type":17,"tag":243,"props":3452,"children":3453},{"style":2429},[3454],{"type":22,"value":3455},"//Velocities. Here, we need 3 values (x,y,z) for every particle.\n",{"type":17,"tag":243,"props":3457,"children":3459},{"class":245,"line":3458},46,[3460,3464,3469,3473,3477,3481,3485,3489,3493],{"type":17,"tag":243,"props":3461,"children":3462},{"style":250},[3463],{"type":22,"value":1691},{"type":17,"tag":243,"props":3465,"children":3466},{"style":378},[3467],{"type":22,"value":3468}," velocityBufferData",{"type":17,"tag":243,"props":3470,"children":3471},{"style":250},[3472],{"type":22,"value":1474},{"type":17,"tag":243,"props":3474,"children":3475},{"style":250},[3476],{"type":22,"value":2469},{"type":17,"tag":243,"props":3478,"children":3479},{"style":256},[3480],{"type":22,"value":2474},{"type":17,"tag":243,"props":3482,"children":3483},{"style":262},[3484],{"type":22,"value":2479},{"type":17,"tag":243,"props":3486,"children":3487},{"style":250},[3488],{"type":22,"value":294},{"type":17,"tag":243,"props":3490,"children":3491},{"style":378},[3492],{"type":22,"value":2738},{"type":17,"tag":243,"props":3494,"children":3495},{"style":262},[3496],{"type":22,"value":1215},{"type":17,"tag":243,"props":3498,"children":3500},{"class":245,"line":3499},47,[3501,3505,3509,3513,3517,3521,3525,3529,3533,3538,3542,3546,3550,3554],{"type":17,"tag":243,"props":3502,"children":3503},{"style":250},[3504],{"type":22,"value":1583},{"type":17,"tag":243,"props":3506,"children":3507},{"style":262},[3508],{"type":22,"value":1523},{"type":17,"tag":243,"props":3510,"children":3511},{"style":250},[3512],{"type":22,"value":1592},{"type":17,"tag":243,"props":3514,"children":3515},{"style":262},[3516],{"type":22,"value":1497},{"type":17,"tag":243,"props":3518,"children":3519},{"style":250},[3520],{"type":22,"value":1502},{"type":17,"tag":243,"props":3522,"children":3523},{"style":378},[3524],{"type":22,"value":457},{"type":17,"tag":243,"props":3526,"children":3527},{"style":262},[3528],{"type":22,"value":1962},{"type":17,"tag":243,"props":3530,"children":3531},{"style":250},[3532],{"type":22,"value":481},{"type":17,"tag":243,"props":3534,"children":3535},{"style":262},[3536],{"type":22,"value":3537}," velocityBufferData.",{"type":17,"tag":243,"props":3539,"children":3540},{"style":378},[3541],{"type":22,"value":2545},{"type":17,"tag":243,"props":3543,"children":3544},{"style":262},[3545],{"type":22,"value":1962},{"type":17,"tag":243,"props":3547,"children":3548},{"style":250},[3549],{"type":22,"value":2554},{"type":17,"tag":243,"props":3551,"children":3552},{"style":378},[3553],{"type":22,"value":2738},{"type":17,"tag":243,"props":3555,"children":3556},{"style":262},[3557],{"type":22,"value":276},{"type":17,"tag":243,"props":3559,"children":3561},{"class":245,"line":3560},48,[3562,3567,3571,3576],{"type":17,"tag":243,"props":3563,"children":3564},{"style":262},[3565],{"type":22,"value":3566},"  velocityBufferData[i] ",{"type":17,"tag":243,"props":3568,"children":3569},{"style":250},[3570],{"type":22,"value":1502},{"type":17,"tag":243,"props":3572,"children":3573},{"style":378},[3574],{"type":22,"value":3575}," 0.0",{"type":17,"tag":243,"props":3577,"children":3578},{"style":262},[3579],{"type":22,"value":507},{"type":17,"tag":243,"props":3581,"children":3583},{"class":245,"line":3582},49,[3584,3589,3593,3597,3601,3605,3609],{"type":17,"tag":243,"props":3585,"children":3586},{"style":262},[3587],{"type":22,"value":3588},"  velocityBufferData[i ",{"type":17,"tag":243,"props":3590,"children":3591},{"style":250},[3592],{"type":22,"value":1891},{"type":17,"tag":243,"props":3594,"children":3595},{"style":378},[3596],{"type":22,"value":467},{"type":17,"tag":243,"props":3598,"children":3599},{"style":262},[3600],{"type":22,"value":2631},{"type":17,"tag":243,"props":3602,"children":3603},{"style":250},[3604],{"type":22,"value":1502},{"type":17,"tag":243,"props":3606,"children":3607},{"style":378},[3608],{"type":22,"value":3575},{"type":17,"tag":243,"props":3610,"children":3611},{"style":262},[3612],{"type":22,"value":507},{"type":17,"tag":243,"props":3614,"children":3616},{"class":245,"line":3615},50,[3617,3621,3625,3629,3633,3637,3641],{"type":17,"tag":243,"props":3618,"children":3619},{"style":262},[3620],{"type":22,"value":3588},{"type":17,"tag":243,"props":3622,"children":3623},{"style":250},[3624],{"type":22,"value":1891},{"type":17,"tag":243,"props":3626,"children":3627},{"style":378},[3628],{"type":22,"value":502},{"type":17,"tag":243,"props":3630,"children":3631},{"style":262},[3632],{"type":22,"value":2631},{"type":17,"tag":243,"props":3634,"children":3635},{"style":250},[3636],{"type":22,"value":1502},{"type":17,"tag":243,"props":3638,"children":3639},{"style":378},[3640],{"type":22,"value":3575},{"type":17,"tag":243,"props":3642,"children":3643},{"style":262},[3644],{"type":22,"value":507},{"type":17,"tag":243,"props":3646,"children":3648},{"class":245,"line":3647},51,[3649],{"type":17,"tag":243,"props":3650,"children":3651},{"style":262},[3652],{"type":22,"value":308},{"type":17,"tag":243,"props":3654,"children":3656},{"class":245,"line":3655},52,[3657,3661,3666,3670,3674,3678],{"type":17,"tag":243,"props":3658,"children":3659},{"style":250},[3660],{"type":22,"value":1691},{"type":17,"tag":243,"props":3662,"children":3663},{"style":378},[3664],{"type":22,"value":3665}," velocityBuffer",{"type":17,"tag":243,"props":3667,"children":3668},{"style":250},[3669],{"type":22,"value":1474},{"type":17,"tag":243,"props":3671,"children":3672},{"style":262},[3673],{"type":22,"value":2820},{"type":17,"tag":243,"props":3675,"children":3676},{"style":256},[3677],{"type":22,"value":2825},{"type":17,"tag":243,"props":3679,"children":3680},{"style":262},[3681],{"type":22,"value":2830},{"type":17,"tag":243,"props":3683,"children":3685},{"class":245,"line":3684},53,[3686],{"type":17,"tag":243,"props":3687,"children":3688},{"style":262},[3689],{"type":22,"value":3690},"size: velocityBufferData.byteLength,\n",{"type":17,"tag":243,"props":3692,"children":3694},{"class":245,"line":3693},54,[3695,3699,3703,3707,3711,3715],{"type":17,"tag":243,"props":3696,"children":3697},{"style":262},[3698],{"type":22,"value":2848},{"type":17,"tag":243,"props":3700,"children":3701},{"style":378},[3702],{"type":22,"value":2868},{"type":17,"tag":243,"props":3704,"children":3705},{"style":250},[3706],{"type":22,"value":2858},{"type":17,"tag":243,"props":3708,"children":3709},{"style":262},[3710],{"type":22,"value":2863},{"type":17,"tag":243,"props":3712,"children":3713},{"style":378},[3714],{"type":22,"value":2881},{"type":17,"tag":243,"props":3716,"children":3717},{"style":262},[3718],{"type":22,"value":2886},{"type":17,"tag":243,"props":3720,"children":3722},{"class":245,"line":3721},55,[3723],{"type":17,"tag":243,"props":3724,"children":3725},{"style":262},[3726],{"type":22,"value":2895},{"type":17,"tag":243,"props":3728,"children":3730},{"class":245,"line":3729},56,[3731,3735,3739,3744,3748],{"type":17,"tag":243,"props":3732,"children":3733},{"style":262},[3734],{"type":22,"value":2904},{"type":17,"tag":243,"props":3736,"children":3737},{"style":256},[3738],{"type":22,"value":2909},{"type":17,"tag":243,"props":3740,"children":3741},{"style":262},[3742],{"type":22,"value":3743},"(velocityBuffer, ",{"type":17,"tag":243,"props":3745,"children":3746},{"style":378},[3747],{"type":22,"value":2070},{"type":17,"tag":243,"props":3749,"children":3750},{"style":262},[3751],{"type":22,"value":3752},", velocityBufferData);\n",{"type":17,"tag":40,"props":3754,"children":3756},{"id":3755},"_2-space-partitioning",[3757],{"type":22,"value":3758},"2. Space partitioning",{"type":17,"tag":18,"props":3760,"children":3761},{},[3762],{"type":22,"value":3763},"With webGPU, I'll be able to render the Particle Life on a much larger scale, but if I want to squeeze as much as possible from my machine, I'll need to come up with a way to organize my data efficiently, just like in the previous article. On my Macbook, without any space partitioning, I was able to render about 100000 particles. After optimizations, I was able to render over 4 million particles with speed of about 5fps. For ~million particles, I achieved the results of around 30fps.",{"type":17,"tag":18,"props":3765,"children":3766},{},[3767],{"type":22,"value":3768},"The key to that was a realization that after grouping my particles so that particles in the same sectors of space occupy a neighbouring position in buffers, I don't need to recalculate groupings again. Particles are bound to groups of mutual interactions in the beginning, and they will interact with each other (given they are within the right radius) regardless of their current position in clip space. This way, we save one more compute pass we'd have to execute on every frame. Moreover, the animation will be more stable, as we're preventing large clumps of particles from aggregating.",{"type":17,"tag":18,"props":3770,"children":3771},{},[3772],{"type":22,"value":3773},"So, let's divide our 3D space into sectors based on interaction radius length. Unlike QuadTree, which we used in the previous part, this will always be 1-level deep space partitioning.",{"type":17,"tag":233,"props":3775,"children":3777},{"className":2417,"code":3776,"language":2419,"meta":8,"style":8},"const axisDivisionCount = (Math.floor(2 / interactionRadius))\nconst axisDivisionLength = 2 / axisDivisionCount;\nconst sectorsNumber = Math.pow(axisDivisionCount, 3);\n",[3778],{"type":17,"tag":219,"props":3779,"children":3780},{"__ignoreMap":8},[3781,3825,3854],{"type":17,"tag":243,"props":3782,"children":3783},{"class":245,"line":246},[3784,3788,3793,3797,3802,3806,3810,3815,3820],{"type":17,"tag":243,"props":3785,"children":3786},{"style":250},[3787],{"type":22,"value":1691},{"type":17,"tag":243,"props":3789,"children":3790},{"style":378},[3791],{"type":22,"value":3792}," axisDivisionCount",{"type":17,"tag":243,"props":3794,"children":3795},{"style":250},[3796],{"type":22,"value":1474},{"type":17,"tag":243,"props":3798,"children":3799},{"style":262},[3800],{"type":22,"value":3801}," (Math.",{"type":17,"tag":243,"props":3803,"children":3804},{"style":256},[3805],{"type":22,"value":3059},{"type":17,"tag":243,"props":3807,"children":3808},{"style":262},[3809],{"type":22,"value":265},{"type":17,"tag":243,"props":3811,"children":3812},{"style":378},[3813],{"type":22,"value":3814},"2",{"type":17,"tag":243,"props":3816,"children":3817},{"style":250},[3818],{"type":22,"value":3819}," /",{"type":17,"tag":243,"props":3821,"children":3822},{"style":262},[3823],{"type":22,"value":3824}," interactionRadius))\n",{"type":17,"tag":243,"props":3826,"children":3827},{"class":245,"line":160},[3828,3832,3837,3841,3845,3849],{"type":17,"tag":243,"props":3829,"children":3830},{"style":250},[3831],{"type":22,"value":1691},{"type":17,"tag":243,"props":3833,"children":3834},{"style":378},[3835],{"type":22,"value":3836}," axisDivisionLength",{"type":17,"tag":243,"props":3838,"children":3839},{"style":250},[3840],{"type":22,"value":1474},{"type":17,"tag":243,"props":3842,"children":3843},{"style":378},[3844],{"type":22,"value":502},{"type":17,"tag":243,"props":3846,"children":3847},{"style":250},[3848],{"type":22,"value":3819},{"type":17,"tag":243,"props":3850,"children":3851},{"style":262},[3852],{"type":22,"value":3853}," axisDivisionCount;\n",{"type":17,"tag":243,"props":3855,"children":3856},{"class":245,"line":302},[3857,3861,3866,3870,3874,3879,3884,3889],{"type":17,"tag":243,"props":3858,"children":3859},{"style":250},[3860],{"type":22,"value":1691},{"type":17,"tag":243,"props":3862,"children":3863},{"style":378},[3864],{"type":22,"value":3865}," sectorsNumber",{"type":17,"tag":243,"props":3867,"children":3868},{"style":250},[3869],{"type":22,"value":1474},{"type":17,"tag":243,"props":3871,"children":3872},{"style":262},[3873],{"type":22,"value":2579},{"type":17,"tag":243,"props":3875,"children":3876},{"style":256},[3877],{"type":22,"value":3878},"pow",{"type":17,"tag":243,"props":3880,"children":3881},{"style":262},[3882],{"type":22,"value":3883},"(axisDivisionCount, ",{"type":17,"tag":243,"props":3885,"children":3886},{"style":378},[3887],{"type":22,"value":3888},"3",{"type":17,"tag":243,"props":3890,"children":3891},{"style":262},[3892],{"type":22,"value":1215},{"type":17,"tag":18,"props":3894,"children":3895},{},[3896],{"type":22,"value":3897},"As we see in the code above, to calculate the number of sectors, first we need to get the number of divisions of every axis. Based on that, we can calculate the side length of a sector. In clip space, coordinates always range from -1 to 1, so the total length is 2. To get the sectors count, we just raise the number of divisions per axis to the power of 3.",{"type":17,"tag":18,"props":3899,"children":3900},{},[3901],{"type":22,"value":3902},"We're going to loop over every particle, determine its sector, and push it to the correct sectors' array. Then, we'll rearrange the positionBufferData array so that particles from sector 1 are in the very beginning, followed by sector 2 particles, and so on. Additionally, we'll need an additional array with the first indexes in the buffer of every sector's particles, so we can access them in the shader module.",{"type":17,"tag":233,"props":3904,"children":3906},{"className":2417,"code":3905,"language":2419,"meta":8,"style":8},"//let's store particles for every sector separately\nlet sectors: number[] = [];\n//this array will store counters for sectors length\nlet sectorsLengths: number[] = [];\n\n//As discussed above, let's create axisDivisionCount^3 sectors, and set their initial length counters to 0.\nfor (let i = 0; i \u003C axisDivisionCount; i++) {\n  for (let j = 0; j \u003C axisDivisionCount; j++) {\n    for (let k = 0; k \u003C axisDivisionCount; k++) {\n      sectors.push([])\n      sectorsLengths.push(0)\n    }\n  }\n}\n\nfor (let i = 0; i \u003C positionBufferData.length; i += 4) {\n  determineParticlesSector([positionBufferData[i], positionBufferData[i + 1], positionBufferData[i + 2]])\n}\n\nfunction determineParticlesSector(particle: number[]) {\n  for (let i = 0; i \u003C axisDivisionCount; i++) {\n    for (let j = 0; j \u003C axisDivisionCount; j++) {\n      for (let k = 0; k \u003C axisDivisionCount; k++) {\n        //Determining particles sectors, as visualized on the image below. \n        //We're checking if the particle resides within gives area of 3D space\n        //Were moving alongside every axis, checking how many division lengths have we traversed\n        if ((particle[0] > (-1) + (axisDivisionLength * i) && particle[0] \u003C (-1) + (axisDivisionLength * (i + 1))) &&\n          (particle[1] > (-1) + (axisDivisionLength * j) && particle[1] \u003C (-1) + (axisDivisionLength * (j + 1))) &&\n          (particle[2] > (-1) + (axisDivisionLength * k) && particle[2] \u003C (-1) + (axisDivisionLength * (k + 1)))) {\n          \n          //Translate position in 3D array to 1D (flattened) array. We need to store data as 1D array for\n          //buffers. Let's consider sector 6 from the image below. It's axisDivisionCount is 2. Were on 0th division \n          //on x axis, 1st division on y axis and 1st division on z axis, which gives us: 0+2+4=6 (index in 1D array).\n          const sectorsIndex = i + (j * axisDivisionCount) + (k * Math.pow(axisDivisionCount, 2))\n          //get current length to determine its position in sectors array\n          const index = sectorsLengths[sectorsIndex]\n\n          //push the particle to its correct position\n          sectors[sectorsIndex][index] = particle[0]\n          sectors[sectorsIndex][index + 1] = particle[1]\n          sectors[sectorsIndex][index + 2] = particle[2]\n          sectors[sectorsIndex][index + 3] = 1\n          \n          //increment sector's length\n          sectorsLengths[sectorsIndex] += 4\n        }\n      }\n    }\n  }\n}\n",[3907],{"type":17,"tag":219,"props":3908,"children":3909},{"__ignoreMap":8},[3910,3918,3953,3961,3993,4000,4008,4056,4107,4158,4176,4200,4208,4215,4222,4229,4288,4327,4334,4341,4375,4422,4469,4517,4525,4533,4541,4672,4794,4912,4920,4928,4936,4944,5015,5023,5044,5051,5059,5084,5120,5155,5183,5190,5198,5215,5223,5231,5238,5245],{"type":17,"tag":243,"props":3911,"children":3912},{"class":245,"line":246},[3913],{"type":17,"tag":243,"props":3914,"children":3915},{"style":2429},[3916],{"type":22,"value":3917},"//let's store particles for every sector separately\n",{"type":17,"tag":243,"props":3919,"children":3920},{"class":245,"line":160},[3921,3925,3930,3934,3939,3944,3948],{"type":17,"tag":243,"props":3922,"children":3923},{"style":250},[3924],{"type":22,"value":1592},{"type":17,"tag":243,"props":3926,"children":3927},{"style":262},[3928],{"type":22,"value":3929}," sectors",{"type":17,"tag":243,"props":3931,"children":3932},{"style":250},[3933],{"type":22,"value":925},{"type":17,"tag":243,"props":3935,"children":3936},{"style":378},[3937],{"type":22,"value":3938}," number",{"type":17,"tag":243,"props":3940,"children":3941},{"style":262},[3942],{"type":22,"value":3943},"[] ",{"type":17,"tag":243,"props":3945,"children":3946},{"style":250},[3947],{"type":22,"value":1502},{"type":17,"tag":243,"props":3949,"children":3950},{"style":262},[3951],{"type":22,"value":3952}," [];\n",{"type":17,"tag":243,"props":3954,"children":3955},{"class":245,"line":302},[3956],{"type":17,"tag":243,"props":3957,"children":3958},{"style":2429},[3959],{"type":22,"value":3960},"//this array will store counters for sectors length\n",{"type":17,"tag":243,"props":3962,"children":3963},{"class":245,"line":311},[3964,3968,3973,3977,3981,3985,3989],{"type":17,"tag":243,"props":3965,"children":3966},{"style":250},[3967],{"type":22,"value":1592},{"type":17,"tag":243,"props":3969,"children":3970},{"style":262},[3971],{"type":22,"value":3972}," sectorsLengths",{"type":17,"tag":243,"props":3974,"children":3975},{"style":250},[3976],{"type":22,"value":925},{"type":17,"tag":243,"props":3978,"children":3979},{"style":378},[3980],{"type":22,"value":3938},{"type":17,"tag":243,"props":3982,"children":3983},{"style":262},[3984],{"type":22,"value":3943},{"type":17,"tag":243,"props":3986,"children":3987},{"style":250},[3988],{"type":22,"value":1502},{"type":17,"tag":243,"props":3990,"children":3991},{"style":262},[3992],{"type":22,"value":3952},{"type":17,"tag":243,"props":3994,"children":3995},{"class":245,"line":356},[3996],{"type":17,"tag":243,"props":3997,"children":3998},{"emptyLinePlaceholder":2340},[3999],{"type":22,"value":2932},{"type":17,"tag":243,"props":4001,"children":4002},{"class":245,"line":403},[4003],{"type":17,"tag":243,"props":4004,"children":4005},{"style":2429},[4006],{"type":22,"value":4007},"//As discussed above, let's create axisDivisionCount^3 sectors, and set their initial length counters to 0.\n",{"type":17,"tag":243,"props":4009,"children":4010},{"class":245,"line":411},[4011,4015,4019,4023,4027,4031,4035,4039,4043,4048,4052],{"type":17,"tag":243,"props":4012,"children":4013},{"style":250},[4014],{"type":22,"value":1583},{"type":17,"tag":243,"props":4016,"children":4017},{"style":262},[4018],{"type":22,"value":1523},{"type":17,"tag":243,"props":4020,"children":4021},{"style":250},[4022],{"type":22,"value":1592},{"type":17,"tag":243,"props":4024,"children":4025},{"style":262},[4026],{"type":22,"value":1497},{"type":17,"tag":243,"props":4028,"children":4029},{"style":250},[4030],{"type":22,"value":1502},{"type":17,"tag":243,"props":4032,"children":4033},{"style":378},[4034],{"type":22,"value":457},{"type":17,"tag":243,"props":4036,"children":4037},{"style":262},[4038],{"type":22,"value":1962},{"type":17,"tag":243,"props":4040,"children":4041},{"style":250},[4042],{"type":22,"value":481},{"type":17,"tag":243,"props":4044,"children":4045},{"style":262},[4046],{"type":22,"value":4047}," axisDivisionCount; i",{"type":17,"tag":243,"props":4049,"children":4050},{"style":250},[4051],{"type":22,"value":1550},{"type":17,"tag":243,"props":4053,"children":4054},{"style":262},[4055],{"type":22,"value":276},{"type":17,"tag":243,"props":4057,"children":4058},{"class":245,"line":437},[4059,4064,4068,4072,4077,4081,4085,4090,4094,4099,4103],{"type":17,"tag":243,"props":4060,"children":4061},{"style":250},[4062],{"type":22,"value":4063},"  for",{"type":17,"tag":243,"props":4065,"children":4066},{"style":262},[4067],{"type":22,"value":1523},{"type":17,"tag":243,"props":4069,"children":4070},{"style":250},[4071],{"type":22,"value":1592},{"type":17,"tag":243,"props":4073,"children":4074},{"style":262},[4075],{"type":22,"value":4076}," j ",{"type":17,"tag":243,"props":4078,"children":4079},{"style":250},[4080],{"type":22,"value":1502},{"type":17,"tag":243,"props":4082,"children":4083},{"style":378},[4084],{"type":22,"value":457},{"type":17,"tag":243,"props":4086,"children":4087},{"style":262},[4088],{"type":22,"value":4089},"; j ",{"type":17,"tag":243,"props":4091,"children":4092},{"style":250},[4093],{"type":22,"value":481},{"type":17,"tag":243,"props":4095,"children":4096},{"style":262},[4097],{"type":22,"value":4098}," axisDivisionCount; j",{"type":17,"tag":243,"props":4100,"children":4101},{"style":250},[4102],{"type":22,"value":1550},{"type":17,"tag":243,"props":4104,"children":4105},{"style":262},[4106],{"type":22,"value":276},{"type":17,"tag":243,"props":4108,"children":4109},{"class":245,"line":510},[4110,4115,4119,4123,4128,4132,4136,4141,4145,4150,4154],{"type":17,"tag":243,"props":4111,"children":4112},{"style":250},[4113],{"type":22,"value":4114},"    for",{"type":17,"tag":243,"props":4116,"children":4117},{"style":262},[4118],{"type":22,"value":1523},{"type":17,"tag":243,"props":4120,"children":4121},{"style":250},[4122],{"type":22,"value":1592},{"type":17,"tag":243,"props":4124,"children":4125},{"style":262},[4126],{"type":22,"value":4127}," k ",{"type":17,"tag":243,"props":4129,"children":4130},{"style":250},[4131],{"type":22,"value":1502},{"type":17,"tag":243,"props":4133,"children":4134},{"style":378},[4135],{"type":22,"value":457},{"type":17,"tag":243,"props":4137,"children":4138},{"style":262},[4139],{"type":22,"value":4140},"; k ",{"type":17,"tag":243,"props":4142,"children":4143},{"style":250},[4144],{"type":22,"value":481},{"type":17,"tag":243,"props":4146,"children":4147},{"style":262},[4148],{"type":22,"value":4149}," axisDivisionCount; k",{"type":17,"tag":243,"props":4151,"children":4152},{"style":250},[4153],{"type":22,"value":1550},{"type":17,"tag":243,"props":4155,"children":4156},{"style":262},[4157],{"type":22,"value":276},{"type":17,"tag":243,"props":4159,"children":4160},{"class":245,"line":518},[4161,4166,4171],{"type":17,"tag":243,"props":4162,"children":4163},{"style":262},[4164],{"type":22,"value":4165},"      sectors.",{"type":17,"tag":243,"props":4167,"children":4168},{"style":256},[4169],{"type":22,"value":4170},"push",{"type":17,"tag":243,"props":4172,"children":4173},{"style":262},[4174],{"type":22,"value":4175},"([])\n",{"type":17,"tag":243,"props":4177,"children":4178},{"class":245,"line":2757},[4179,4184,4188,4192,4196],{"type":17,"tag":243,"props":4180,"children":4181},{"style":262},[4182],{"type":22,"value":4183},"      sectorsLengths.",{"type":17,"tag":243,"props":4185,"children":4186},{"style":256},[4187],{"type":22,"value":4170},{"type":17,"tag":243,"props":4189,"children":4190},{"style":262},[4191],{"type":22,"value":265},{"type":17,"tag":243,"props":4193,"children":4194},{"style":378},[4195],{"type":22,"value":2070},{"type":17,"tag":243,"props":4197,"children":4198},{"style":262},[4199],{"type":22,"value":1341},{"type":17,"tag":243,"props":4201,"children":4202},{"class":245,"line":2765},[4203],{"type":17,"tag":243,"props":4204,"children":4205},{"style":262},[4206],{"type":22,"value":4207},"    }\n",{"type":17,"tag":243,"props":4209,"children":4210},{"class":245,"line":2774},[4211],{"type":17,"tag":243,"props":4212,"children":4213},{"style":262},[4214],{"type":22,"value":1413},{"type":17,"tag":243,"props":4216,"children":4217},{"class":245,"line":2783},[4218],{"type":17,"tag":243,"props":4219,"children":4220},{"style":262},[4221],{"type":22,"value":308},{"type":17,"tag":243,"props":4223,"children":4224},{"class":245,"line":2792},[4225],{"type":17,"tag":243,"props":4226,"children":4227},{"emptyLinePlaceholder":2340},[4228],{"type":22,"value":2932},{"type":17,"tag":243,"props":4230,"children":4231},{"class":245,"line":2801},[4232,4236,4240,4244,4248,4252,4256,4260,4264,4268,4272,4276,4280,4284],{"type":17,"tag":243,"props":4233,"children":4234},{"style":250},[4235],{"type":22,"value":1583},{"type":17,"tag":243,"props":4237,"children":4238},{"style":262},[4239],{"type":22,"value":1523},{"type":17,"tag":243,"props":4241,"children":4242},{"style":250},[4243],{"type":22,"value":1592},{"type":17,"tag":243,"props":4245,"children":4246},{"style":262},[4247],{"type":22,"value":1497},{"type":17,"tag":243,"props":4249,"children":4250},{"style":250},[4251],{"type":22,"value":1502},{"type":17,"tag":243,"props":4253,"children":4254},{"style":378},[4255],{"type":22,"value":457},{"type":17,"tag":243,"props":4257,"children":4258},{"style":262},[4259],{"type":22,"value":1962},{"type":17,"tag":243,"props":4261,"children":4262},{"style":250},[4263],{"type":22,"value":481},{"type":17,"tag":243,"props":4265,"children":4266},{"style":262},[4267],{"type":22,"value":2540},{"type":17,"tag":243,"props":4269,"children":4270},{"style":378},[4271],{"type":22,"value":2545},{"type":17,"tag":243,"props":4273,"children":4274},{"style":262},[4275],{"type":22,"value":1962},{"type":17,"tag":243,"props":4277,"children":4278},{"style":250},[4279],{"type":22,"value":2554},{"type":17,"tag":243,"props":4281,"children":4282},{"style":378},[4283],{"type":22,"value":381},{"type":17,"tag":243,"props":4285,"children":4286},{"style":262},[4287],{"type":22,"value":276},{"type":17,"tag":243,"props":4289,"children":4290},{"class":245,"line":2833},[4291,4296,4301,4305,4309,4314,4318,4322],{"type":17,"tag":243,"props":4292,"children":4293},{"style":256},[4294],{"type":22,"value":4295},"  determineParticlesSector",{"type":17,"tag":243,"props":4297,"children":4298},{"style":262},[4299],{"type":22,"value":4300},"([positionBufferData[i], positionBufferData[i ",{"type":17,"tag":243,"props":4302,"children":4303},{"style":250},[4304],{"type":22,"value":1891},{"type":17,"tag":243,"props":4306,"children":4307},{"style":378},[4308],{"type":22,"value":467},{"type":17,"tag":243,"props":4310,"children":4311},{"style":262},[4312],{"type":22,"value":4313},"], positionBufferData[i ",{"type":17,"tag":243,"props":4315,"children":4316},{"style":250},[4317],{"type":22,"value":1891},{"type":17,"tag":243,"props":4319,"children":4320},{"style":378},[4321],{"type":22,"value":502},{"type":17,"tag":243,"props":4323,"children":4324},{"style":262},[4325],{"type":22,"value":4326},"]])\n",{"type":17,"tag":243,"props":4328,"children":4329},{"class":245,"line":2842},[4330],{"type":17,"tag":243,"props":4331,"children":4332},{"style":262},[4333],{"type":22,"value":308},{"type":17,"tag":243,"props":4335,"children":4336},{"class":245,"line":2889},[4337],{"type":17,"tag":243,"props":4338,"children":4339},{"emptyLinePlaceholder":2340},[4340],{"type":22,"value":2932},{"type":17,"tag":243,"props":4342,"children":4343},{"class":245,"line":2898},[4344,4348,4353,4357,4362,4366,4370],{"type":17,"tag":243,"props":4345,"children":4346},{"style":250},[4347],{"type":22,"value":253},{"type":17,"tag":243,"props":4349,"children":4350},{"style":256},[4351],{"type":22,"value":4352}," determineParticlesSector",{"type":17,"tag":243,"props":4354,"children":4355},{"style":262},[4356],{"type":22,"value":265},{"type":17,"tag":243,"props":4358,"children":4359},{"style":268},[4360],{"type":22,"value":4361},"particle",{"type":17,"tag":243,"props":4363,"children":4364},{"style":250},[4365],{"type":22,"value":925},{"type":17,"tag":243,"props":4367,"children":4368},{"style":378},[4369],{"type":22,"value":3938},{"type":17,"tag":243,"props":4371,"children":4372},{"style":262},[4373],{"type":22,"value":4374},"[]) {\n",{"type":17,"tag":243,"props":4376,"children":4377},{"class":245,"line":2926},[4378,4382,4386,4390,4394,4398,4402,4406,4410,4414,4418],{"type":17,"tag":243,"props":4379,"children":4380},{"style":250},[4381],{"type":22,"value":4063},{"type":17,"tag":243,"props":4383,"children":4384},{"style":262},[4385],{"type":22,"value":1523},{"type":17,"tag":243,"props":4387,"children":4388},{"style":250},[4389],{"type":22,"value":1592},{"type":17,"tag":243,"props":4391,"children":4392},{"style":262},[4393],{"type":22,"value":1497},{"type":17,"tag":243,"props":4395,"children":4396},{"style":250},[4397],{"type":22,"value":1502},{"type":17,"tag":243,"props":4399,"children":4400},{"style":378},[4401],{"type":22,"value":457},{"type":17,"tag":243,"props":4403,"children":4404},{"style":262},[4405],{"type":22,"value":1962},{"type":17,"tag":243,"props":4407,"children":4408},{"style":250},[4409],{"type":22,"value":481},{"type":17,"tag":243,"props":4411,"children":4412},{"style":262},[4413],{"type":22,"value":4047},{"type":17,"tag":243,"props":4415,"children":4416},{"style":250},[4417],{"type":22,"value":1550},{"type":17,"tag":243,"props":4419,"children":4420},{"style":262},[4421],{"type":22,"value":276},{"type":17,"tag":243,"props":4423,"children":4424},{"class":245,"line":2935},[4425,4429,4433,4437,4441,4445,4449,4453,4457,4461,4465],{"type":17,"tag":243,"props":4426,"children":4427},{"style":250},[4428],{"type":22,"value":4114},{"type":17,"tag":243,"props":4430,"children":4431},{"style":262},[4432],{"type":22,"value":1523},{"type":17,"tag":243,"props":4434,"children":4435},{"style":250},[4436],{"type":22,"value":1592},{"type":17,"tag":243,"props":4438,"children":4439},{"style":262},[4440],{"type":22,"value":4076},{"type":17,"tag":243,"props":4442,"children":4443},{"style":250},[4444],{"type":22,"value":1502},{"type":17,"tag":243,"props":4446,"children":4447},{"style":378},[4448],{"type":22,"value":457},{"type":17,"tag":243,"props":4450,"children":4451},{"style":262},[4452],{"type":22,"value":4089},{"type":17,"tag":243,"props":4454,"children":4455},{"style":250},[4456],{"type":22,"value":481},{"type":17,"tag":243,"props":4458,"children":4459},{"style":262},[4460],{"type":22,"value":4098},{"type":17,"tag":243,"props":4462,"children":4463},{"style":250},[4464],{"type":22,"value":1550},{"type":17,"tag":243,"props":4466,"children":4467},{"style":262},[4468],{"type":22,"value":276},{"type":17,"tag":243,"props":4470,"children":4471},{"class":245,"line":2944},[4472,4477,4481,4485,4489,4493,4497,4501,4505,4509,4513],{"type":17,"tag":243,"props":4473,"children":4474},{"style":250},[4475],{"type":22,"value":4476},"      for",{"type":17,"tag":243,"props":4478,"children":4479},{"style":262},[4480],{"type":22,"value":1523},{"type":17,"tag":243,"props":4482,"children":4483},{"style":250},[4484],{"type":22,"value":1592},{"type":17,"tag":243,"props":4486,"children":4487},{"style":262},[4488],{"type":22,"value":4127},{"type":17,"tag":243,"props":4490,"children":4491},{"style":250},[4492],{"type":22,"value":1502},{"type":17,"tag":243,"props":4494,"children":4495},{"style":378},[4496],{"type":22,"value":457},{"type":17,"tag":243,"props":4498,"children":4499},{"style":262},[4500],{"type":22,"value":4140},{"type":17,"tag":243,"props":4502,"children":4503},{"style":250},[4504],{"type":22,"value":481},{"type":17,"tag":243,"props":4506,"children":4507},{"style":262},[4508],{"type":22,"value":4149},{"type":17,"tag":243,"props":4510,"children":4511},{"style":250},[4512],{"type":22,"value":1550},{"type":17,"tag":243,"props":4514,"children":4515},{"style":262},[4516],{"type":22,"value":276},{"type":17,"tag":243,"props":4518,"children":4519},{"class":245,"line":2953},[4520],{"type":17,"tag":243,"props":4521,"children":4522},{"style":2429},[4523],{"type":22,"value":4524},"        //Determining particles sectors, as visualized on the image below. \n",{"type":17,"tag":243,"props":4526,"children":4527},{"class":245,"line":2984},[4528],{"type":17,"tag":243,"props":4529,"children":4530},{"style":2429},[4531],{"type":22,"value":4532},"        //We're checking if the particle resides within gives area of 3D space\n",{"type":17,"tag":243,"props":4534,"children":4535},{"class":245,"line":3040},[4536],{"type":17,"tag":243,"props":4537,"children":4538},{"style":2429},[4539],{"type":22,"value":4540},"        //Were moving alongside every axis, checking how many division lengths have we traversed\n",{"type":17,"tag":243,"props":4542,"children":4543},{"class":245,"line":3084},[4544,4549,4554,4558,4562,4566,4570,4574,4578,4582,4586,4591,4595,4600,4605,4610,4614,4618,4622,4626,4630,4634,4638,4642,4646,4650,4654,4658,4662,4667],{"type":17,"tag":243,"props":4545,"children":4546},{"style":250},[4547],{"type":22,"value":4548},"        if",{"type":17,"tag":243,"props":4550,"children":4551},{"style":262},[4552],{"type":22,"value":4553}," ((particle[",{"type":17,"tag":243,"props":4555,"children":4556},{"style":378},[4557],{"type":22,"value":2070},{"type":17,"tag":243,"props":4559,"children":4560},{"style":262},[4561],{"type":22,"value":2631},{"type":17,"tag":243,"props":4563,"children":4564},{"style":250},[4565],{"type":22,"value":1627},{"type":17,"tag":243,"props":4567,"children":4568},{"style":262},[4569],{"type":22,"value":1523},{"type":17,"tag":243,"props":4571,"children":4572},{"style":250},[4573],{"type":22,"value":375},{"type":17,"tag":243,"props":4575,"children":4576},{"style":378},[4577],{"type":22,"value":551},{"type":17,"tag":243,"props":4579,"children":4580},{"style":262},[4581],{"type":22,"value":1637},{"type":17,"tag":243,"props":4583,"children":4584},{"style":250},[4585],{"type":22,"value":1891},{"type":17,"tag":243,"props":4587,"children":4588},{"style":262},[4589],{"type":22,"value":4590}," (axisDivisionLength ",{"type":17,"tag":243,"props":4592,"children":4593},{"style":250},[4594],{"type":22,"value":294},{"type":17,"tag":243,"props":4596,"children":4597},{"style":262},[4598],{"type":22,"value":4599}," i) ",{"type":17,"tag":243,"props":4601,"children":4602},{"style":250},[4603],{"type":22,"value":4604},"&&",{"type":17,"tag":243,"props":4606,"children":4607},{"style":262},[4608],{"type":22,"value":4609}," particle[",{"type":17,"tag":243,"props":4611,"children":4612},{"style":378},[4613],{"type":22,"value":2070},{"type":17,"tag":243,"props":4615,"children":4616},{"style":262},[4617],{"type":22,"value":2631},{"type":17,"tag":243,"props":4619,"children":4620},{"style":250},[4621],{"type":22,"value":481},{"type":17,"tag":243,"props":4623,"children":4624},{"style":262},[4625],{"type":22,"value":1523},{"type":17,"tag":243,"props":4627,"children":4628},{"style":250},[4629],{"type":22,"value":375},{"type":17,"tag":243,"props":4631,"children":4632},{"style":378},[4633],{"type":22,"value":551},{"type":17,"tag":243,"props":4635,"children":4636},{"style":262},[4637],{"type":22,"value":1637},{"type":17,"tag":243,"props":4639,"children":4640},{"style":250},[4641],{"type":22,"value":1891},{"type":17,"tag":243,"props":4643,"children":4644},{"style":262},[4645],{"type":22,"value":4590},{"type":17,"tag":243,"props":4647,"children":4648},{"style":250},[4649],{"type":22,"value":294},{"type":17,"tag":243,"props":4651,"children":4652},{"style":262},[4653],{"type":22,"value":1622},{"type":17,"tag":243,"props":4655,"children":4656},{"style":250},[4657],{"type":22,"value":1891},{"type":17,"tag":243,"props":4659,"children":4660},{"style":378},[4661],{"type":22,"value":467},{"type":17,"tag":243,"props":4663,"children":4664},{"style":262},[4665],{"type":22,"value":4666},"))) ",{"type":17,"tag":243,"props":4668,"children":4669},{"style":250},[4670],{"type":22,"value":4671},"&&\n",{"type":17,"tag":243,"props":4673,"children":4674},{"class":245,"line":3092},[4675,4680,4684,4688,4692,4696,4700,4704,4708,4712,4716,4720,4725,4729,4733,4737,4741,4745,4749,4753,4757,4761,4765,4769,4773,4778,4782,4786,4790],{"type":17,"tag":243,"props":4676,"children":4677},{"style":262},[4678],{"type":22,"value":4679},"          (particle[",{"type":17,"tag":243,"props":4681,"children":4682},{"style":378},[4683],{"type":22,"value":551},{"type":17,"tag":243,"props":4685,"children":4686},{"style":262},[4687],{"type":22,"value":2631},{"type":17,"tag":243,"props":4689,"children":4690},{"style":250},[4691],{"type":22,"value":1627},{"type":17,"tag":243,"props":4693,"children":4694},{"style":262},[4695],{"type":22,"value":1523},{"type":17,"tag":243,"props":4697,"children":4698},{"style":250},[4699],{"type":22,"value":375},{"type":17,"tag":243,"props":4701,"children":4702},{"style":378},[4703],{"type":22,"value":551},{"type":17,"tag":243,"props":4705,"children":4706},{"style":262},[4707],{"type":22,"value":1637},{"type":17,"tag":243,"props":4709,"children":4710},{"style":250},[4711],{"type":22,"value":1891},{"type":17,"tag":243,"props":4713,"children":4714},{"style":262},[4715],{"type":22,"value":4590},{"type":17,"tag":243,"props":4717,"children":4718},{"style":250},[4719],{"type":22,"value":294},{"type":17,"tag":243,"props":4721,"children":4722},{"style":262},[4723],{"type":22,"value":4724}," j) ",{"type":17,"tag":243,"props":4726,"children":4727},{"style":250},[4728],{"type":22,"value":4604},{"type":17,"tag":243,"props":4730,"children":4731},{"style":262},[4732],{"type":22,"value":4609},{"type":17,"tag":243,"props":4734,"children":4735},{"style":378},[4736],{"type":22,"value":551},{"type":17,"tag":243,"props":4738,"children":4739},{"style":262},[4740],{"type":22,"value":2631},{"type":17,"tag":243,"props":4742,"children":4743},{"style":250},[4744],{"type":22,"value":481},{"type":17,"tag":243,"props":4746,"children":4747},{"style":262},[4748],{"type":22,"value":1523},{"type":17,"tag":243,"props":4750,"children":4751},{"style":250},[4752],{"type":22,"value":375},{"type":17,"tag":243,"props":4754,"children":4755},{"style":378},[4756],{"type":22,"value":551},{"type":17,"tag":243,"props":4758,"children":4759},{"style":262},[4760],{"type":22,"value":1637},{"type":17,"tag":243,"props":4762,"children":4763},{"style":250},[4764],{"type":22,"value":1891},{"type":17,"tag":243,"props":4766,"children":4767},{"style":262},[4768],{"type":22,"value":4590},{"type":17,"tag":243,"props":4770,"children":4771},{"style":250},[4772],{"type":22,"value":294},{"type":17,"tag":243,"props":4774,"children":4775},{"style":262},[4776],{"type":22,"value":4777}," (j ",{"type":17,"tag":243,"props":4779,"children":4780},{"style":250},[4781],{"type":22,"value":1891},{"type":17,"tag":243,"props":4783,"children":4784},{"style":378},[4785],{"type":22,"value":467},{"type":17,"tag":243,"props":4787,"children":4788},{"style":262},[4789],{"type":22,"value":4666},{"type":17,"tag":243,"props":4791,"children":4792},{"style":250},[4793],{"type":22,"value":4671},{"type":17,"tag":243,"props":4795,"children":4796},{"class":245,"line":3121},[4797,4801,4805,4809,4813,4817,4821,4825,4829,4833,4837,4841,4846,4850,4854,4858,4862,4866,4870,4874,4878,4882,4886,4890,4894,4899,4903,4907],{"type":17,"tag":243,"props":4798,"children":4799},{"style":262},[4800],{"type":22,"value":4679},{"type":17,"tag":243,"props":4802,"children":4803},{"style":378},[4804],{"type":22,"value":3814},{"type":17,"tag":243,"props":4806,"children":4807},{"style":262},[4808],{"type":22,"value":2631},{"type":17,"tag":243,"props":4810,"children":4811},{"style":250},[4812],{"type":22,"value":1627},{"type":17,"tag":243,"props":4814,"children":4815},{"style":262},[4816],{"type":22,"value":1523},{"type":17,"tag":243,"props":4818,"children":4819},{"style":250},[4820],{"type":22,"value":375},{"type":17,"tag":243,"props":4822,"children":4823},{"style":378},[4824],{"type":22,"value":551},{"type":17,"tag":243,"props":4826,"children":4827},{"style":262},[4828],{"type":22,"value":1637},{"type":17,"tag":243,"props":4830,"children":4831},{"style":250},[4832],{"type":22,"value":1891},{"type":17,"tag":243,"props":4834,"children":4835},{"style":262},[4836],{"type":22,"value":4590},{"type":17,"tag":243,"props":4838,"children":4839},{"style":250},[4840],{"type":22,"value":294},{"type":17,"tag":243,"props":4842,"children":4843},{"style":262},[4844],{"type":22,"value":4845}," k) ",{"type":17,"tag":243,"props":4847,"children":4848},{"style":250},[4849],{"type":22,"value":4604},{"type":17,"tag":243,"props":4851,"children":4852},{"style":262},[4853],{"type":22,"value":4609},{"type":17,"tag":243,"props":4855,"children":4856},{"style":378},[4857],{"type":22,"value":3814},{"type":17,"tag":243,"props":4859,"children":4860},{"style":262},[4861],{"type":22,"value":2631},{"type":17,"tag":243,"props":4863,"children":4864},{"style":250},[4865],{"type":22,"value":481},{"type":17,"tag":243,"props":4867,"children":4868},{"style":262},[4869],{"type":22,"value":1523},{"type":17,"tag":243,"props":4871,"children":4872},{"style":250},[4873],{"type":22,"value":375},{"type":17,"tag":243,"props":4875,"children":4876},{"style":378},[4877],{"type":22,"value":551},{"type":17,"tag":243,"props":4879,"children":4880},{"style":262},[4881],{"type":22,"value":1637},{"type":17,"tag":243,"props":4883,"children":4884},{"style":250},[4885],{"type":22,"value":1891},{"type":17,"tag":243,"props":4887,"children":4888},{"style":262},[4889],{"type":22,"value":4590},{"type":17,"tag":243,"props":4891,"children":4892},{"style":250},[4893],{"type":22,"value":294},{"type":17,"tag":243,"props":4895,"children":4896},{"style":262},[4897],{"type":22,"value":4898}," (k ",{"type":17,"tag":243,"props":4900,"children":4901},{"style":250},[4902],{"type":22,"value":1891},{"type":17,"tag":243,"props":4904,"children":4905},{"style":378},[4906],{"type":22,"value":467},{"type":17,"tag":243,"props":4908,"children":4909},{"style":262},[4910],{"type":22,"value":4911},")))) {\n",{"type":17,"tag":243,"props":4913,"children":4914},{"class":245,"line":3130},[4915],{"type":17,"tag":243,"props":4916,"children":4917},{"style":262},[4918],{"type":22,"value":4919},"          \n",{"type":17,"tag":243,"props":4921,"children":4922},{"class":245,"line":3159},[4923],{"type":17,"tag":243,"props":4924,"children":4925},{"style":2429},[4926],{"type":22,"value":4927},"          //Translate position in 3D array to 1D (flattened) array. We need to store data as 1D array for\n",{"type":17,"tag":243,"props":4929,"children":4930},{"class":245,"line":3167},[4931],{"type":17,"tag":243,"props":4932,"children":4933},{"style":2429},[4934],{"type":22,"value":4935},"          //buffers. Let's consider sector 6 from the image below. It's axisDivisionCount is 2. Were on 0th division \n",{"type":17,"tag":243,"props":4937,"children":4938},{"class":245,"line":3193},[4939],{"type":17,"tag":243,"props":4940,"children":4941},{"style":2429},[4942],{"type":22,"value":4943},"          //on x axis, 1st division on y axis and 1st division on z axis, which gives us: 0+2+4=6 (index in 1D array).\n",{"type":17,"tag":243,"props":4945,"children":4946},{"class":245,"line":3201},[4947,4952,4957,4961,4965,4969,4973,4977,4982,4986,4990,4994,4998,5002,5006,5010],{"type":17,"tag":243,"props":4948,"children":4949},{"style":250},[4950],{"type":22,"value":4951},"          const",{"type":17,"tag":243,"props":4953,"children":4954},{"style":378},[4955],{"type":22,"value":4956}," sectorsIndex",{"type":17,"tag":243,"props":4958,"children":4959},{"style":250},[4960],{"type":22,"value":1474},{"type":17,"tag":243,"props":4962,"children":4963},{"style":262},[4964],{"type":22,"value":1497},{"type":17,"tag":243,"props":4966,"children":4967},{"style":250},[4968],{"type":22,"value":1891},{"type":17,"tag":243,"props":4970,"children":4971},{"style":262},[4972],{"type":22,"value":4777},{"type":17,"tag":243,"props":4974,"children":4975},{"style":250},[4976],{"type":22,"value":294},{"type":17,"tag":243,"props":4978,"children":4979},{"style":262},[4980],{"type":22,"value":4981}," axisDivisionCount) ",{"type":17,"tag":243,"props":4983,"children":4984},{"style":250},[4985],{"type":22,"value":1891},{"type":17,"tag":243,"props":4987,"children":4988},{"style":262},[4989],{"type":22,"value":4898},{"type":17,"tag":243,"props":4991,"children":4992},{"style":250},[4993],{"type":22,"value":294},{"type":17,"tag":243,"props":4995,"children":4996},{"style":262},[4997],{"type":22,"value":2579},{"type":17,"tag":243,"props":4999,"children":5000},{"style":256},[5001],{"type":22,"value":3878},{"type":17,"tag":243,"props":5003,"children":5004},{"style":262},[5005],{"type":22,"value":3883},{"type":17,"tag":243,"props":5007,"children":5008},{"style":378},[5009],{"type":22,"value":3814},{"type":17,"tag":243,"props":5011,"children":5012},{"style":262},[5013],{"type":22,"value":5014},"))\n",{"type":17,"tag":243,"props":5016,"children":5017},{"class":245,"line":3210},[5018],{"type":17,"tag":243,"props":5019,"children":5020},{"style":2429},[5021],{"type":22,"value":5022},"          //get current length to determine its position in sectors array\n",{"type":17,"tag":243,"props":5024,"children":5025},{"class":245,"line":3248},[5026,5030,5035,5039],{"type":17,"tag":243,"props":5027,"children":5028},{"style":250},[5029],{"type":22,"value":4951},{"type":17,"tag":243,"props":5031,"children":5032},{"style":378},[5033],{"type":22,"value":5034}," index",{"type":17,"tag":243,"props":5036,"children":5037},{"style":250},[5038],{"type":22,"value":1474},{"type":17,"tag":243,"props":5040,"children":5041},{"style":262},[5042],{"type":22,"value":5043}," sectorsLengths[sectorsIndex]\n",{"type":17,"tag":243,"props":5045,"children":5046},{"class":245,"line":3305},[5047],{"type":17,"tag":243,"props":5048,"children":5049},{"emptyLinePlaceholder":2340},[5050],{"type":22,"value":2932},{"type":17,"tag":243,"props":5052,"children":5053},{"class":245,"line":3333},[5054],{"type":17,"tag":243,"props":5055,"children":5056},{"style":2429},[5057],{"type":22,"value":5058},"          //push the particle to its correct position\n",{"type":17,"tag":243,"props":5060,"children":5061},{"class":245,"line":3341},[5062,5067,5071,5075,5079],{"type":17,"tag":243,"props":5063,"children":5064},{"style":262},[5065],{"type":22,"value":5066},"          sectors[sectorsIndex][index] ",{"type":17,"tag":243,"props":5068,"children":5069},{"style":250},[5070],{"type":22,"value":1502},{"type":17,"tag":243,"props":5072,"children":5073},{"style":262},[5074],{"type":22,"value":4609},{"type":17,"tag":243,"props":5076,"children":5077},{"style":378},[5078],{"type":22,"value":2070},{"type":17,"tag":243,"props":5080,"children":5081},{"style":262},[5082],{"type":22,"value":5083},"]\n",{"type":17,"tag":243,"props":5085,"children":5086},{"class":245,"line":3370},[5087,5092,5096,5100,5104,5108,5112,5116],{"type":17,"tag":243,"props":5088,"children":5089},{"style":262},[5090],{"type":22,"value":5091},"          sectors[sectorsIndex][index ",{"type":17,"tag":243,"props":5093,"children":5094},{"style":250},[5095],{"type":22,"value":1891},{"type":17,"tag":243,"props":5097,"children":5098},{"style":378},[5099],{"type":22,"value":467},{"type":17,"tag":243,"props":5101,"children":5102},{"style":262},[5103],{"type":22,"value":2631},{"type":17,"tag":243,"props":5105,"children":5106},{"style":250},[5107],{"type":22,"value":1502},{"type":17,"tag":243,"props":5109,"children":5110},{"style":262},[5111],{"type":22,"value":4609},{"type":17,"tag":243,"props":5113,"children":5114},{"style":378},[5115],{"type":22,"value":551},{"type":17,"tag":243,"props":5117,"children":5118},{"style":262},[5119],{"type":22,"value":5083},{"type":17,"tag":243,"props":5121,"children":5122},{"class":245,"line":3379},[5123,5127,5131,5135,5139,5143,5147,5151],{"type":17,"tag":243,"props":5124,"children":5125},{"style":262},[5126],{"type":22,"value":5091},{"type":17,"tag":243,"props":5128,"children":5129},{"style":250},[5130],{"type":22,"value":1891},{"type":17,"tag":243,"props":5132,"children":5133},{"style":378},[5134],{"type":22,"value":502},{"type":17,"tag":243,"props":5136,"children":5137},{"style":262},[5138],{"type":22,"value":2631},{"type":17,"tag":243,"props":5140,"children":5141},{"style":250},[5142],{"type":22,"value":1502},{"type":17,"tag":243,"props":5144,"children":5145},{"style":262},[5146],{"type":22,"value":4609},{"type":17,"tag":243,"props":5148,"children":5149},{"style":378},[5150],{"type":22,"value":3814},{"type":17,"tag":243,"props":5152,"children":5153},{"style":262},[5154],{"type":22,"value":5083},{"type":17,"tag":243,"props":5156,"children":5157},{"class":245,"line":3407},[5158,5162,5166,5170,5174,5178],{"type":17,"tag":243,"props":5159,"children":5160},{"style":262},[5161],{"type":22,"value":5091},{"type":17,"tag":243,"props":5163,"children":5164},{"style":250},[5165],{"type":22,"value":1891},{"type":17,"tag":243,"props":5167,"children":5168},{"style":378},[5169],{"type":22,"value":2738},{"type":17,"tag":243,"props":5171,"children":5172},{"style":262},[5173],{"type":22,"value":2631},{"type":17,"tag":243,"props":5175,"children":5176},{"style":250},[5177],{"type":22,"value":1502},{"type":17,"tag":243,"props":5179,"children":5180},{"style":378},[5181],{"type":22,"value":5182}," 1\n",{"type":17,"tag":243,"props":5184,"children":5185},{"class":245,"line":3415},[5186],{"type":17,"tag":243,"props":5187,"children":5188},{"style":262},[5189],{"type":22,"value":4919},{"type":17,"tag":243,"props":5191,"children":5192},{"class":245,"line":3441},[5193],{"type":17,"tag":243,"props":5194,"children":5195},{"style":2429},[5196],{"type":22,"value":5197},"          //increment sector's length\n",{"type":17,"tag":243,"props":5199,"children":5200},{"class":245,"line":3449},[5201,5206,5210],{"type":17,"tag":243,"props":5202,"children":5203},{"style":262},[5204],{"type":22,"value":5205},"          sectorsLengths[sectorsIndex] ",{"type":17,"tag":243,"props":5207,"children":5208},{"style":250},[5209],{"type":22,"value":2554},{"type":17,"tag":243,"props":5211,"children":5212},{"style":378},[5213],{"type":22,"value":5214}," 4\n",{"type":17,"tag":243,"props":5216,"children":5217},{"class":245,"line":3458},[5218],{"type":17,"tag":243,"props":5219,"children":5220},{"style":262},[5221],{"type":22,"value":5222},"        }\n",{"type":17,"tag":243,"props":5224,"children":5225},{"class":245,"line":3499},[5226],{"type":17,"tag":243,"props":5227,"children":5228},{"style":262},[5229],{"type":22,"value":5230},"      }\n",{"type":17,"tag":243,"props":5232,"children":5233},{"class":245,"line":3560},[5234],{"type":17,"tag":243,"props":5235,"children":5236},{"style":262},[5237],{"type":22,"value":4207},{"type":17,"tag":243,"props":5239,"children":5240},{"class":245,"line":3582},[5241],{"type":17,"tag":243,"props":5242,"children":5243},{"style":262},[5244],{"type":22,"value":1413},{"type":17,"tag":243,"props":5246,"children":5247},{"class":245,"line":3615},[5248],{"type":17,"tag":243,"props":5249,"children":5250},{"style":262},[5251],{"type":22,"value":308},{"type":17,"tag":18,"props":5253,"children":5254},{},[5255],{"type":22,"value":5256},"Determining the particle's sector was the most difficult part so far. This is when I had to step away from my laptop for a while, and just spend some time with pen and paper to wrap my head around this. Thinking about this as moving alongside the axes from -1 onwards and checking how many division lengths have we traversed, helped me come up with the formula above.",{"type":17,"tag":5258,"props":5259,"children":5261},"img",{"src":5260},"/articles/cube.png",[],{"type":17,"tag":18,"props":5263,"children":5264},{},[5265],{"type":22,"value":5266},"Now that we have our sectors in order, let's use the helper arrays to rearrange data in positionBufferData.",{"type":17,"tag":233,"props":5268,"children":5270},{"className":2417,"code":5269,"language":2419,"meta":8,"style":8},"let currentIndex = 0\nlet firstIndexes = new Uint32Array(sectorsNumber)\n\nfor (let i = 0; i \u003C sectors.length; i++) {\n  //to loop over the right particles in the shader module, we'll need starting index of every\n  //sectors data in 1D positions buffer\n  if (0 === i) {\n    firstIndexes[i] = 0;\n  } else {\n    firstIndexes[i] = (firstIndexes[i - 1] + sectors[i].length / 4);\n  }\n  for (let j = 0; j \u003C sectors[i].length; j++) {\n    positionBufferData[currentIndex] = (sectors[i][j]);\n    currentIndex++\n  }\n}\n",[5271],{"type":17,"tag":219,"props":5272,"children":5273},{"__ignoreMap":8},[5274,5295,5325,5332,5388,5396,5404,5429,5449,5466,5519,5526,5582,5599,5612,5619],{"type":17,"tag":243,"props":5275,"children":5276},{"class":245,"line":246},[5277,5281,5286,5290],{"type":17,"tag":243,"props":5278,"children":5279},{"style":250},[5280],{"type":22,"value":1592},{"type":17,"tag":243,"props":5282,"children":5283},{"style":262},[5284],{"type":22,"value":5285}," currentIndex ",{"type":17,"tag":243,"props":5287,"children":5288},{"style":250},[5289],{"type":22,"value":1502},{"type":17,"tag":243,"props":5291,"children":5292},{"style":378},[5293],{"type":22,"value":5294}," 0\n",{"type":17,"tag":243,"props":5296,"children":5297},{"class":245,"line":160},[5298,5302,5307,5311,5315,5320],{"type":17,"tag":243,"props":5299,"children":5300},{"style":250},[5301],{"type":22,"value":1592},{"type":17,"tag":243,"props":5303,"children":5304},{"style":262},[5305],{"type":22,"value":5306}," firstIndexes ",{"type":17,"tag":243,"props":5308,"children":5309},{"style":250},[5310],{"type":22,"value":1502},{"type":17,"tag":243,"props":5312,"children":5313},{"style":250},[5314],{"type":22,"value":2469},{"type":17,"tag":243,"props":5316,"children":5317},{"style":256},[5318],{"type":22,"value":5319}," Uint32Array",{"type":17,"tag":243,"props":5321,"children":5322},{"style":262},[5323],{"type":22,"value":5324},"(sectorsNumber)\n",{"type":17,"tag":243,"props":5326,"children":5327},{"class":245,"line":302},[5328],{"type":17,"tag":243,"props":5329,"children":5330},{"emptyLinePlaceholder":2340},[5331],{"type":22,"value":2932},{"type":17,"tag":243,"props":5333,"children":5334},{"class":245,"line":311},[5335,5339,5343,5347,5351,5355,5359,5363,5367,5372,5376,5380,5384],{"type":17,"tag":243,"props":5336,"children":5337},{"style":250},[5338],{"type":22,"value":1583},{"type":17,"tag":243,"props":5340,"children":5341},{"style":262},[5342],{"type":22,"value":1523},{"type":17,"tag":243,"props":5344,"children":5345},{"style":250},[5346],{"type":22,"value":1592},{"type":17,"tag":243,"props":5348,"children":5349},{"style":262},[5350],{"type":22,"value":1497},{"type":17,"tag":243,"props":5352,"children":5353},{"style":250},[5354],{"type":22,"value":1502},{"type":17,"tag":243,"props":5356,"children":5357},{"style":378},[5358],{"type":22,"value":457},{"type":17,"tag":243,"props":5360,"children":5361},{"style":262},[5362],{"type":22,"value":1962},{"type":17,"tag":243,"props":5364,"children":5365},{"style":250},[5366],{"type":22,"value":481},{"type":17,"tag":243,"props":5368,"children":5369},{"style":262},[5370],{"type":22,"value":5371}," sectors.",{"type":17,"tag":243,"props":5373,"children":5374},{"style":378},[5375],{"type":22,"value":2545},{"type":17,"tag":243,"props":5377,"children":5378},{"style":262},[5379],{"type":22,"value":1975},{"type":17,"tag":243,"props":5381,"children":5382},{"style":250},[5383],{"type":22,"value":1550},{"type":17,"tag":243,"props":5385,"children":5386},{"style":262},[5387],{"type":22,"value":276},{"type":17,"tag":243,"props":5389,"children":5390},{"class":245,"line":356},[5391],{"type":17,"tag":243,"props":5392,"children":5393},{"style":2429},[5394],{"type":22,"value":5395},"  //to loop over the right particles in the shader module, we'll need starting index of every\n",{"type":17,"tag":243,"props":5397,"children":5398},{"class":245,"line":403},[5399],{"type":17,"tag":243,"props":5400,"children":5401},{"style":2429},[5402],{"type":22,"value":5403},"  //sectors data in 1D positions buffer\n",{"type":17,"tag":243,"props":5405,"children":5406},{"class":245,"line":411},[5407,5411,5415,5419,5424],{"type":17,"tag":243,"props":5408,"children":5409},{"style":250},[5410],{"type":22,"value":1322},{"type":17,"tag":243,"props":5412,"children":5413},{"style":262},[5414],{"type":22,"value":1523},{"type":17,"tag":243,"props":5416,"children":5417},{"style":378},[5418],{"type":22,"value":2070},{"type":17,"tag":243,"props":5420,"children":5421},{"style":250},[5422],{"type":22,"value":5423}," ===",{"type":17,"tag":243,"props":5425,"children":5426},{"style":262},[5427],{"type":22,"value":5428}," i) {\n",{"type":17,"tag":243,"props":5430,"children":5431},{"class":245,"line":437},[5432,5437,5441,5445],{"type":17,"tag":243,"props":5433,"children":5434},{"style":262},[5435],{"type":22,"value":5436},"    firstIndexes[i] ",{"type":17,"tag":243,"props":5438,"children":5439},{"style":250},[5440],{"type":22,"value":1502},{"type":17,"tag":243,"props":5442,"children":5443},{"style":378},[5444],{"type":22,"value":457},{"type":17,"tag":243,"props":5446,"children":5447},{"style":262},[5448],{"type":22,"value":507},{"type":17,"tag":243,"props":5450,"children":5451},{"class":245,"line":510},[5452,5457,5462],{"type":17,"tag":243,"props":5453,"children":5454},{"style":262},[5455],{"type":22,"value":5456},"  } ",{"type":17,"tag":243,"props":5458,"children":5459},{"style":250},[5460],{"type":22,"value":5461},"else",{"type":17,"tag":243,"props":5463,"children":5464},{"style":262},[5465],{"type":22,"value":1370},{"type":17,"tag":243,"props":5467,"children":5468},{"class":245,"line":518},[5469,5473,5477,5482,5486,5490,5494,5498,5503,5507,5511,5515],{"type":17,"tag":243,"props":5470,"children":5471},{"style":262},[5472],{"type":22,"value":5436},{"type":17,"tag":243,"props":5474,"children":5475},{"style":250},[5476],{"type":22,"value":1502},{"type":17,"tag":243,"props":5478,"children":5479},{"style":262},[5480],{"type":22,"value":5481}," (firstIndexes[i ",{"type":17,"tag":243,"props":5483,"children":5484},{"style":250},[5485],{"type":22,"value":375},{"type":17,"tag":243,"props":5487,"children":5488},{"style":378},[5489],{"type":22,"value":467},{"type":17,"tag":243,"props":5491,"children":5492},{"style":262},[5493],{"type":22,"value":2631},{"type":17,"tag":243,"props":5495,"children":5496},{"style":250},[5497],{"type":22,"value":1891},{"type":17,"tag":243,"props":5499,"children":5500},{"style":262},[5501],{"type":22,"value":5502}," sectors[i].",{"type":17,"tag":243,"props":5504,"children":5505},{"style":378},[5506],{"type":22,"value":2545},{"type":17,"tag":243,"props":5508,"children":5509},{"style":250},[5510],{"type":22,"value":3819},{"type":17,"tag":243,"props":5512,"children":5513},{"style":378},[5514],{"type":22,"value":381},{"type":17,"tag":243,"props":5516,"children":5517},{"style":262},[5518],{"type":22,"value":1215},{"type":17,"tag":243,"props":5520,"children":5521},{"class":245,"line":2757},[5522],{"type":17,"tag":243,"props":5523,"children":5524},{"style":262},[5525],{"type":22,"value":1413},{"type":17,"tag":243,"props":5527,"children":5528},{"class":245,"line":2765},[5529,5533,5537,5541,5545,5549,5553,5557,5561,5565,5569,5574,5578],{"type":17,"tag":243,"props":5530,"children":5531},{"style":250},[5532],{"type":22,"value":4063},{"type":17,"tag":243,"props":5534,"children":5535},{"style":262},[5536],{"type":22,"value":1523},{"type":17,"tag":243,"props":5538,"children":5539},{"style":250},[5540],{"type":22,"value":1592},{"type":17,"tag":243,"props":5542,"children":5543},{"style":262},[5544],{"type":22,"value":4076},{"type":17,"tag":243,"props":5546,"children":5547},{"style":250},[5548],{"type":22,"value":1502},{"type":17,"tag":243,"props":5550,"children":5551},{"style":378},[5552],{"type":22,"value":457},{"type":17,"tag":243,"props":5554,"children":5555},{"style":262},[5556],{"type":22,"value":4089},{"type":17,"tag":243,"props":5558,"children":5559},{"style":250},[5560],{"type":22,"value":481},{"type":17,"tag":243,"props":5562,"children":5563},{"style":262},[5564],{"type":22,"value":5502},{"type":17,"tag":243,"props":5566,"children":5567},{"style":378},[5568],{"type":22,"value":2545},{"type":17,"tag":243,"props":5570,"children":5571},{"style":262},[5572],{"type":22,"value":5573},"; j",{"type":17,"tag":243,"props":5575,"children":5576},{"style":250},[5577],{"type":22,"value":1550},{"type":17,"tag":243,"props":5579,"children":5580},{"style":262},[5581],{"type":22,"value":276},{"type":17,"tag":243,"props":5583,"children":5584},{"class":245,"line":2774},[5585,5590,5594],{"type":17,"tag":243,"props":5586,"children":5587},{"style":262},[5588],{"type":22,"value":5589},"    positionBufferData[currentIndex] ",{"type":17,"tag":243,"props":5591,"children":5592},{"style":250},[5593],{"type":22,"value":1502},{"type":17,"tag":243,"props":5595,"children":5596},{"style":262},[5597],{"type":22,"value":5598}," (sectors[i][j]);\n",{"type":17,"tag":243,"props":5600,"children":5601},{"class":245,"line":2783},[5602,5607],{"type":17,"tag":243,"props":5603,"children":5604},{"style":262},[5605],{"type":22,"value":5606},"    currentIndex",{"type":17,"tag":243,"props":5608,"children":5609},{"style":250},[5610],{"type":22,"value":5611},"++\n",{"type":17,"tag":243,"props":5613,"children":5614},{"class":245,"line":2792},[5615],{"type":17,"tag":243,"props":5616,"children":5617},{"style":262},[5618],{"type":22,"value":1413},{"type":17,"tag":243,"props":5620,"children":5621},{"class":245,"line":2801},[5622],{"type":17,"tag":243,"props":5623,"children":5624},{"style":262},[5625],{"type":22,"value":308},{"type":17,"tag":18,"props":5627,"children":5628},{},[5629],{"type":22,"value":5630},"Here we have it. Now data in positionBufferData is grouped and particles born in the same sector will always occupy neighboring positions in the buffer. We have an additional array with the first indexes of every sector, which will allow us to only consider the relevant particles when calculating force. Now, we can proceed to writing our compute shader.",{"type":17,"tag":40,"props":5632,"children":5634},{"id":5633},"_3-the-compute-shader",[5635],{"type":22,"value":5636},"3. The compute shader",{"type":17,"tag":18,"props":5638,"children":5639},{},[5640,5642,5649],{"type":22,"value":5641},"WebGPU shaders are written in its own shader language, WGSL. To familiarize yourself with its basics, I can only recommend its ",{"type":17,"tag":340,"props":5643,"children":5646},{"href":5644,"rel":5645},"https://gpuweb.github.io/gpuweb/wgsl/",[686],[5647],{"type":22,"value":5648},"documentation",{"type":22,"value":5650},". It's clear, concise, and easy to navigate. Pretty much, it is the only resource I have used. We'll be executing the main shader function on every particle in parallel. My biggest pain when writing the shaders was how difficult it was to debug them. You cannot look up the value of variables, there's no print() or console.log(). You can only see the initial layout of buffers with the Chrome extension, and it's not very beneficial. Error messages are helpful, but it's not nearly enough. I had to be smart about debugging and conditionally do one thing or another, to see if my code was on the right track.",{"type":17,"tag":18,"props":5652,"children":5653},{},[5654],{"type":22,"value":5655},"It's important to notice that the algorithm below is not a 1:1 translation of the 2D version. When simplifying calculations for dev purposes, I noticed that if below the repulsive radius you apply symmetric, negative force, the shapes the particles take are much more beautiful. With little luck in generating the right initial forces, they start to resemble electron clouds you might remember from physics classes. Take your time to experiment and see for yourself!",{"type":17,"tag":233,"props":5657,"children":5659},{"className":2417,"code":5658,"language":2419,"meta":8,"style":8},"`\n@group(0) @binding(0) var\u003Cstorage, read_write> positions: array\u003Cvec4f>;\n@group(0) @binding(1) var\u003Cstorage, read_write> velocities: array\u003Cvec3f>; \n@group(0) @binding(2) var\u003Cstorage> colors: array\u003Ci32>; \n@group(0) @binding(3) var\u003Cstorage> attraction: array\u003Cf32>; \n@group(0) @binding(4) var\u003Cstorage> indexes: array\u003Cu32>; \n\n//Global space is divided into workgroups that share the same workgroup space\n//and workgroups are subdivided into threads executing entry point function in\n//parallel. Global_invocation_id equal to workgroup_id * workgroup_size + local_invocation_id.\n@compute @workgroup_size(${workGroupSize})\nfn cs(@builtin(global_invocation_id) global_id: vec3u) {\n    let index = global_id.x;\n    var position = positions[index].xyz;\n    var velocity = velocities[index].xyz;\n    var sectorsStartIndex: u32;\n    var sectorsEndIndex: u32;\n\n    //First, let's calculate first and last index, based on the \n    //firstIndexes array we calculated in previous paragraphs\n    for(var i: i32 = 0; i \u003C ${firstIndexes.length}; i+=1) {\n      if (i \u003C= ${firstIndexes.length - 2}) {\n        if (index > indexes[i] && index \u003C indexes[i+1]) {\n          sectorsStartIndex = indexes[i];\n          sectorsEndIndex = indexes[i+1];\n        }\n      } else {\n        if (index > indexes[i] && index \u003C ${particleCount}) {\n          sectorsStartIndex = indexes[i];\n          sectorsEndIndex = ${particleCount};\n        }\n      }\n    }\n\n    //initialize variables for total forces\n    var forcex = 0.0;\n    var forcey = 0.0;\n    var forcez = 0.0;\n\n    let interactionRadius = ${interactionRadius};\n    //force factor is an arbitrarily calculated value to balance out\n    //forces in the system\n    let forceFactor = ${interactionRadius}/${forceFactor};\n    \n    for (var i = sectorsStartIndex;i \u003C sectorsEndIndex; i++) {\n      let xdiff = positions[i].x - position.x;\n      let ydiff = positions[i].y - position.y;\n      let zdiff = positions[i].z - position.z;\n      \n      let dist = sqrt((xdiff*xdiff) + (ydiff*ydiff) + (zdiff*zdiff));\n\n      if (dist \u003C interactionRadius) {\n        //constants below are direct translations of code explained\n        //in the first part\n        let forceV = attraction[(${m}*colors[index])+colors[i]];\n        let ratio = dist/interactionRadius;\n        let repF = 0.2;\n        let force =  forceV * (1.0 - ratio) * forceFactor;\n\n        if (ratio > repF) {\n          forcex += xdiff*force;\n          forcey += ydiff*force;\n          forcez += zdiff*force;\n        //here lies the diffence compared to 2D version. On short distances, we \n        //apply symmetric, negative force\n        } else if (ratio \u003C= repF) {\n          forcex -= xdiff*force;\n          forcey -= ydiff*force;\n          forcez -= zdiff*force;\n        }\n      }\n    }\n\n    //code analogous to that explained in part 1\n    velocity.x+=forcex;\n    velocity.y+=forcey;\n    velocity.z+=forcez;\n\n    velocity*=0.3; // friction\n\n    positions[index] = vec4f(position + velocity, 1);\n    velocities[index] = vec3f(velocity);\n}\n\n`\n",[5660],{"type":17,"tag":219,"props":5661,"children":5662},{"__ignoreMap":8},[5663,5671,5679,5687,5695,5703,5711,5718,5726,5734,5742,5760,5768,5776,5784,5792,5800,5808,5815,5823,5831,5857,5890,5898,5906,5914,5921,5929,5946,5953,5970,5977,5984,5991,5998,6006,6014,6022,6030,6037,6054,6062,6070,6096,6104,6112,6120,6128,6136,6144,6152,6159,6167,6175,6183,6201,6209,6218,6227,6235,6244,6253,6262,6271,6280,6289,6298,6307,6316,6325,6333,6341,6349,6357,6366,6375,6384,6393,6401,6410,6418,6427,6436,6444,6452],{"type":17,"tag":243,"props":5664,"children":5665},{"class":245,"line":246},[5666],{"type":17,"tag":243,"props":5667,"children":5668},{"style":981},[5669],{"type":22,"value":5670},"`\n",{"type":17,"tag":243,"props":5672,"children":5673},{"class":245,"line":160},[5674],{"type":17,"tag":243,"props":5675,"children":5676},{"style":981},[5677],{"type":22,"value":5678},"@group(0) @binding(0) var\u003Cstorage, read_write> positions: array\u003Cvec4f>;\n",{"type":17,"tag":243,"props":5680,"children":5681},{"class":245,"line":302},[5682],{"type":17,"tag":243,"props":5683,"children":5684},{"style":981},[5685],{"type":22,"value":5686},"@group(0) @binding(1) var\u003Cstorage, read_write> velocities: array\u003Cvec3f>; \n",{"type":17,"tag":243,"props":5688,"children":5689},{"class":245,"line":311},[5690],{"type":17,"tag":243,"props":5691,"children":5692},{"style":981},[5693],{"type":22,"value":5694},"@group(0) @binding(2) var\u003Cstorage> colors: array\u003Ci32>; \n",{"type":17,"tag":243,"props":5696,"children":5697},{"class":245,"line":356},[5698],{"type":17,"tag":243,"props":5699,"children":5700},{"style":981},[5701],{"type":22,"value":5702},"@group(0) @binding(3) var\u003Cstorage> attraction: array\u003Cf32>; \n",{"type":17,"tag":243,"props":5704,"children":5705},{"class":245,"line":403},[5706],{"type":17,"tag":243,"props":5707,"children":5708},{"style":981},[5709],{"type":22,"value":5710},"@group(0) @binding(4) var\u003Cstorage> indexes: array\u003Cu32>; \n",{"type":17,"tag":243,"props":5712,"children":5713},{"class":245,"line":411},[5714],{"type":17,"tag":243,"props":5715,"children":5716},{"emptyLinePlaceholder":2340},[5717],{"type":22,"value":2932},{"type":17,"tag":243,"props":5719,"children":5720},{"class":245,"line":437},[5721],{"type":17,"tag":243,"props":5722,"children":5723},{"style":981},[5724],{"type":22,"value":5725},"//Global space is divided into workgroups that share the same workgroup space\n",{"type":17,"tag":243,"props":5727,"children":5728},{"class":245,"line":510},[5729],{"type":17,"tag":243,"props":5730,"children":5731},{"style":981},[5732],{"type":22,"value":5733},"//and workgroups are subdivided into threads executing entry point function in\n",{"type":17,"tag":243,"props":5735,"children":5736},{"class":245,"line":518},[5737],{"type":17,"tag":243,"props":5738,"children":5739},{"style":981},[5740],{"type":22,"value":5741},"//parallel. Global_invocation_id equal to workgroup_id * workgroup_size + local_invocation_id.\n",{"type":17,"tag":243,"props":5743,"children":5744},{"class":245,"line":2757},[5745,5750,5755],{"type":17,"tag":243,"props":5746,"children":5747},{"style":981},[5748],{"type":22,"value":5749},"@compute @workgroup_size(${",{"type":17,"tag":243,"props":5751,"children":5752},{"style":262},[5753],{"type":22,"value":5754},"workGroupSize",{"type":17,"tag":243,"props":5756,"children":5757},{"style":981},[5758],{"type":22,"value":5759},"})\n",{"type":17,"tag":243,"props":5761,"children":5762},{"class":245,"line":2765},[5763],{"type":17,"tag":243,"props":5764,"children":5765},{"style":981},[5766],{"type":22,"value":5767},"fn cs(@builtin(global_invocation_id) global_id: vec3u) {\n",{"type":17,"tag":243,"props":5769,"children":5770},{"class":245,"line":2774},[5771],{"type":17,"tag":243,"props":5772,"children":5773},{"style":981},[5774],{"type":22,"value":5775},"    let index = global_id.x;\n",{"type":17,"tag":243,"props":5777,"children":5778},{"class":245,"line":2783},[5779],{"type":17,"tag":243,"props":5780,"children":5781},{"style":981},[5782],{"type":22,"value":5783},"    var position = positions[index].xyz;\n",{"type":17,"tag":243,"props":5785,"children":5786},{"class":245,"line":2792},[5787],{"type":17,"tag":243,"props":5788,"children":5789},{"style":981},[5790],{"type":22,"value":5791},"    var velocity = velocities[index].xyz;\n",{"type":17,"tag":243,"props":5793,"children":5794},{"class":245,"line":2801},[5795],{"type":17,"tag":243,"props":5796,"children":5797},{"style":981},[5798],{"type":22,"value":5799},"    var sectorsStartIndex: u32;\n",{"type":17,"tag":243,"props":5801,"children":5802},{"class":245,"line":2833},[5803],{"type":17,"tag":243,"props":5804,"children":5805},{"style":981},[5806],{"type":22,"value":5807},"    var sectorsEndIndex: u32;\n",{"type":17,"tag":243,"props":5809,"children":5810},{"class":245,"line":2842},[5811],{"type":17,"tag":243,"props":5812,"children":5813},{"emptyLinePlaceholder":2340},[5814],{"type":22,"value":2932},{"type":17,"tag":243,"props":5816,"children":5817},{"class":245,"line":2889},[5818],{"type":17,"tag":243,"props":5819,"children":5820},{"style":981},[5821],{"type":22,"value":5822},"    //First, let's calculate first and last index, based on the \n",{"type":17,"tag":243,"props":5824,"children":5825},{"class":245,"line":2898},[5826],{"type":17,"tag":243,"props":5827,"children":5828},{"style":981},[5829],{"type":22,"value":5830},"    //firstIndexes array we calculated in previous paragraphs\n",{"type":17,"tag":243,"props":5832,"children":5833},{"class":245,"line":2926},[5834,5839,5844,5848,5852],{"type":17,"tag":243,"props":5835,"children":5836},{"style":981},[5837],{"type":22,"value":5838},"    for(var i: i32 = 0; i \u003C ${",{"type":17,"tag":243,"props":5840,"children":5841},{"style":262},[5842],{"type":22,"value":5843},"firstIndexes",{"type":17,"tag":243,"props":5845,"children":5846},{"style":981},[5847],{"type":22,"value":595},{"type":17,"tag":243,"props":5849,"children":5850},{"style":378},[5851],{"type":22,"value":2545},{"type":17,"tag":243,"props":5853,"children":5854},{"style":981},[5855],{"type":22,"value":5856},"}; i+=1) {\n",{"type":17,"tag":243,"props":5858,"children":5859},{"class":245,"line":2935},[5860,5865,5869,5873,5877,5881,5885],{"type":17,"tag":243,"props":5861,"children":5862},{"style":981},[5863],{"type":22,"value":5864},"      if (i \u003C= ${",{"type":17,"tag":243,"props":5866,"children":5867},{"style":262},[5868],{"type":22,"value":5843},{"type":17,"tag":243,"props":5870,"children":5871},{"style":981},[5872],{"type":22,"value":595},{"type":17,"tag":243,"props":5874,"children":5875},{"style":378},[5876],{"type":22,"value":2545},{"type":17,"tag":243,"props":5878,"children":5879},{"style":250},[5880],{"type":22,"value":2602},{"type":17,"tag":243,"props":5882,"children":5883},{"style":378},[5884],{"type":22,"value":502},{"type":17,"tag":243,"props":5886,"children":5887},{"style":981},[5888],{"type":22,"value":5889},"}) {\n",{"type":17,"tag":243,"props":5891,"children":5892},{"class":245,"line":2944},[5893],{"type":17,"tag":243,"props":5894,"children":5895},{"style":981},[5896],{"type":22,"value":5897},"        if (index > indexes[i] && index \u003C indexes[i+1]) {\n",{"type":17,"tag":243,"props":5899,"children":5900},{"class":245,"line":2953},[5901],{"type":17,"tag":243,"props":5902,"children":5903},{"style":981},[5904],{"type":22,"value":5905},"          sectorsStartIndex = indexes[i];\n",{"type":17,"tag":243,"props":5907,"children":5908},{"class":245,"line":2984},[5909],{"type":17,"tag":243,"props":5910,"children":5911},{"style":981},[5912],{"type":22,"value":5913},"          sectorsEndIndex = indexes[i+1];\n",{"type":17,"tag":243,"props":5915,"children":5916},{"class":245,"line":3040},[5917],{"type":17,"tag":243,"props":5918,"children":5919},{"style":981},[5920],{"type":22,"value":5222},{"type":17,"tag":243,"props":5922,"children":5923},{"class":245,"line":3084},[5924],{"type":17,"tag":243,"props":5925,"children":5926},{"style":981},[5927],{"type":22,"value":5928},"      } else {\n",{"type":17,"tag":243,"props":5930,"children":5931},{"class":245,"line":3092},[5932,5937,5942],{"type":17,"tag":243,"props":5933,"children":5934},{"style":981},[5935],{"type":22,"value":5936},"        if (index > indexes[i] && index \u003C ${",{"type":17,"tag":243,"props":5938,"children":5939},{"style":262},[5940],{"type":22,"value":5941},"particleCount",{"type":17,"tag":243,"props":5943,"children":5944},{"style":981},[5945],{"type":22,"value":5889},{"type":17,"tag":243,"props":5947,"children":5948},{"class":245,"line":3121},[5949],{"type":17,"tag":243,"props":5950,"children":5951},{"style":981},[5952],{"type":22,"value":5905},{"type":17,"tag":243,"props":5954,"children":5955},{"class":245,"line":3130},[5956,5961,5965],{"type":17,"tag":243,"props":5957,"children":5958},{"style":981},[5959],{"type":22,"value":5960},"          sectorsEndIndex = ${",{"type":17,"tag":243,"props":5962,"children":5963},{"style":262},[5964],{"type":22,"value":5941},{"type":17,"tag":243,"props":5966,"children":5967},{"style":981},[5968],{"type":22,"value":5969},"};\n",{"type":17,"tag":243,"props":5971,"children":5972},{"class":245,"line":3159},[5973],{"type":17,"tag":243,"props":5974,"children":5975},{"style":981},[5976],{"type":22,"value":5222},{"type":17,"tag":243,"props":5978,"children":5979},{"class":245,"line":3167},[5980],{"type":17,"tag":243,"props":5981,"children":5982},{"style":981},[5983],{"type":22,"value":5230},{"type":17,"tag":243,"props":5985,"children":5986},{"class":245,"line":3193},[5987],{"type":17,"tag":243,"props":5988,"children":5989},{"style":981},[5990],{"type":22,"value":4207},{"type":17,"tag":243,"props":5992,"children":5993},{"class":245,"line":3201},[5994],{"type":17,"tag":243,"props":5995,"children":5996},{"emptyLinePlaceholder":2340},[5997],{"type":22,"value":2932},{"type":17,"tag":243,"props":5999,"children":6000},{"class":245,"line":3210},[6001],{"type":17,"tag":243,"props":6002,"children":6003},{"style":981},[6004],{"type":22,"value":6005},"    //initialize variables for total forces\n",{"type":17,"tag":243,"props":6007,"children":6008},{"class":245,"line":3248},[6009],{"type":17,"tag":243,"props":6010,"children":6011},{"style":981},[6012],{"type":22,"value":6013},"    var forcex = 0.0;\n",{"type":17,"tag":243,"props":6015,"children":6016},{"class":245,"line":3305},[6017],{"type":17,"tag":243,"props":6018,"children":6019},{"style":981},[6020],{"type":22,"value":6021},"    var forcey = 0.0;\n",{"type":17,"tag":243,"props":6023,"children":6024},{"class":245,"line":3333},[6025],{"type":17,"tag":243,"props":6026,"children":6027},{"style":981},[6028],{"type":22,"value":6029},"    var forcez = 0.0;\n",{"type":17,"tag":243,"props":6031,"children":6032},{"class":245,"line":3341},[6033],{"type":17,"tag":243,"props":6034,"children":6035},{"emptyLinePlaceholder":2340},[6036],{"type":22,"value":2932},{"type":17,"tag":243,"props":6038,"children":6039},{"class":245,"line":3370},[6040,6045,6050],{"type":17,"tag":243,"props":6041,"children":6042},{"style":981},[6043],{"type":22,"value":6044},"    let interactionRadius = ${",{"type":17,"tag":243,"props":6046,"children":6047},{"style":262},[6048],{"type":22,"value":6049},"interactionRadius",{"type":17,"tag":243,"props":6051,"children":6052},{"style":981},[6053],{"type":22,"value":5969},{"type":17,"tag":243,"props":6055,"children":6056},{"class":245,"line":3379},[6057],{"type":17,"tag":243,"props":6058,"children":6059},{"style":981},[6060],{"type":22,"value":6061},"    //force factor is an arbitrarily calculated value to balance out\n",{"type":17,"tag":243,"props":6063,"children":6064},{"class":245,"line":3407},[6065],{"type":17,"tag":243,"props":6066,"children":6067},{"style":981},[6068],{"type":22,"value":6069},"    //forces in the system\n",{"type":17,"tag":243,"props":6071,"children":6072},{"class":245,"line":3415},[6073,6078,6082,6087,6092],{"type":17,"tag":243,"props":6074,"children":6075},{"style":981},[6076],{"type":22,"value":6077},"    let forceFactor = ${",{"type":17,"tag":243,"props":6079,"children":6080},{"style":262},[6081],{"type":22,"value":6049},{"type":17,"tag":243,"props":6083,"children":6084},{"style":981},[6085],{"type":22,"value":6086},"}/${",{"type":17,"tag":243,"props":6088,"children":6089},{"style":262},[6090],{"type":22,"value":6091},"forceFactor",{"type":17,"tag":243,"props":6093,"children":6094},{"style":981},[6095],{"type":22,"value":5969},{"type":17,"tag":243,"props":6097,"children":6098},{"class":245,"line":3441},[6099],{"type":17,"tag":243,"props":6100,"children":6101},{"style":981},[6102],{"type":22,"value":6103},"    \n",{"type":17,"tag":243,"props":6105,"children":6106},{"class":245,"line":3449},[6107],{"type":17,"tag":243,"props":6108,"children":6109},{"style":981},[6110],{"type":22,"value":6111},"    for (var i = sectorsStartIndex;i \u003C sectorsEndIndex; i++) {\n",{"type":17,"tag":243,"props":6113,"children":6114},{"class":245,"line":3458},[6115],{"type":17,"tag":243,"props":6116,"children":6117},{"style":981},[6118],{"type":22,"value":6119},"      let xdiff = positions[i].x - position.x;\n",{"type":17,"tag":243,"props":6121,"children":6122},{"class":245,"line":3499},[6123],{"type":17,"tag":243,"props":6124,"children":6125},{"style":981},[6126],{"type":22,"value":6127},"      let ydiff = positions[i].y - position.y;\n",{"type":17,"tag":243,"props":6129,"children":6130},{"class":245,"line":3560},[6131],{"type":17,"tag":243,"props":6132,"children":6133},{"style":981},[6134],{"type":22,"value":6135},"      let zdiff = positions[i].z - position.z;\n",{"type":17,"tag":243,"props":6137,"children":6138},{"class":245,"line":3582},[6139],{"type":17,"tag":243,"props":6140,"children":6141},{"style":981},[6142],{"type":22,"value":6143},"      \n",{"type":17,"tag":243,"props":6145,"children":6146},{"class":245,"line":3615},[6147],{"type":17,"tag":243,"props":6148,"children":6149},{"style":981},[6150],{"type":22,"value":6151},"      let dist = sqrt((xdiff*xdiff) + (ydiff*ydiff) + (zdiff*zdiff));\n",{"type":17,"tag":243,"props":6153,"children":6154},{"class":245,"line":3647},[6155],{"type":17,"tag":243,"props":6156,"children":6157},{"emptyLinePlaceholder":2340},[6158],{"type":22,"value":2932},{"type":17,"tag":243,"props":6160,"children":6161},{"class":245,"line":3655},[6162],{"type":17,"tag":243,"props":6163,"children":6164},{"style":981},[6165],{"type":22,"value":6166},"      if (dist \u003C interactionRadius) {\n",{"type":17,"tag":243,"props":6168,"children":6169},{"class":245,"line":3684},[6170],{"type":17,"tag":243,"props":6171,"children":6172},{"style":981},[6173],{"type":22,"value":6174},"        //constants below are direct translations of code explained\n",{"type":17,"tag":243,"props":6176,"children":6177},{"class":245,"line":3693},[6178],{"type":17,"tag":243,"props":6179,"children":6180},{"style":981},[6181],{"type":22,"value":6182},"        //in the first part\n",{"type":17,"tag":243,"props":6184,"children":6185},{"class":245,"line":3721},[6186,6191,6196],{"type":17,"tag":243,"props":6187,"children":6188},{"style":981},[6189],{"type":22,"value":6190},"        let forceV = attraction[(${",{"type":17,"tag":243,"props":6192,"children":6193},{"style":262},[6194],{"type":22,"value":6195},"m",{"type":17,"tag":243,"props":6197,"children":6198},{"style":981},[6199],{"type":22,"value":6200},"}*colors[index])+colors[i]];\n",{"type":17,"tag":243,"props":6202,"children":6203},{"class":245,"line":3729},[6204],{"type":17,"tag":243,"props":6205,"children":6206},{"style":981},[6207],{"type":22,"value":6208},"        let ratio = dist/interactionRadius;\n",{"type":17,"tag":243,"props":6210,"children":6212},{"class":245,"line":6211},57,[6213],{"type":17,"tag":243,"props":6214,"children":6215},{"style":981},[6216],{"type":22,"value":6217},"        let repF = 0.2;\n",{"type":17,"tag":243,"props":6219,"children":6221},{"class":245,"line":6220},58,[6222],{"type":17,"tag":243,"props":6223,"children":6224},{"style":981},[6225],{"type":22,"value":6226},"        let force =  forceV * (1.0 - ratio) * forceFactor;\n",{"type":17,"tag":243,"props":6228,"children":6230},{"class":245,"line":6229},59,[6231],{"type":17,"tag":243,"props":6232,"children":6233},{"emptyLinePlaceholder":2340},[6234],{"type":22,"value":2932},{"type":17,"tag":243,"props":6236,"children":6238},{"class":245,"line":6237},60,[6239],{"type":17,"tag":243,"props":6240,"children":6241},{"style":981},[6242],{"type":22,"value":6243},"        if (ratio > repF) {\n",{"type":17,"tag":243,"props":6245,"children":6247},{"class":245,"line":6246},61,[6248],{"type":17,"tag":243,"props":6249,"children":6250},{"style":981},[6251],{"type":22,"value":6252},"          forcex += xdiff*force;\n",{"type":17,"tag":243,"props":6254,"children":6256},{"class":245,"line":6255},62,[6257],{"type":17,"tag":243,"props":6258,"children":6259},{"style":981},[6260],{"type":22,"value":6261},"          forcey += ydiff*force;\n",{"type":17,"tag":243,"props":6263,"children":6265},{"class":245,"line":6264},63,[6266],{"type":17,"tag":243,"props":6267,"children":6268},{"style":981},[6269],{"type":22,"value":6270},"          forcez += zdiff*force;\n",{"type":17,"tag":243,"props":6272,"children":6274},{"class":245,"line":6273},64,[6275],{"type":17,"tag":243,"props":6276,"children":6277},{"style":981},[6278],{"type":22,"value":6279},"        //here lies the diffence compared to 2D version. On short distances, we \n",{"type":17,"tag":243,"props":6281,"children":6283},{"class":245,"line":6282},65,[6284],{"type":17,"tag":243,"props":6285,"children":6286},{"style":981},[6287],{"type":22,"value":6288},"        //apply symmetric, negative force\n",{"type":17,"tag":243,"props":6290,"children":6292},{"class":245,"line":6291},66,[6293],{"type":17,"tag":243,"props":6294,"children":6295},{"style":981},[6296],{"type":22,"value":6297},"        } else if (ratio \u003C= repF) {\n",{"type":17,"tag":243,"props":6299,"children":6301},{"class":245,"line":6300},67,[6302],{"type":17,"tag":243,"props":6303,"children":6304},{"style":981},[6305],{"type":22,"value":6306},"          forcex -= xdiff*force;\n",{"type":17,"tag":243,"props":6308,"children":6310},{"class":245,"line":6309},68,[6311],{"type":17,"tag":243,"props":6312,"children":6313},{"style":981},[6314],{"type":22,"value":6315},"          forcey -= ydiff*force;\n",{"type":17,"tag":243,"props":6317,"children":6319},{"class":245,"line":6318},69,[6320],{"type":17,"tag":243,"props":6321,"children":6322},{"style":981},[6323],{"type":22,"value":6324},"          forcez -= zdiff*force;\n",{"type":17,"tag":243,"props":6326,"children":6328},{"class":245,"line":6327},70,[6329],{"type":17,"tag":243,"props":6330,"children":6331},{"style":981},[6332],{"type":22,"value":5222},{"type":17,"tag":243,"props":6334,"children":6336},{"class":245,"line":6335},71,[6337],{"type":17,"tag":243,"props":6338,"children":6339},{"style":981},[6340],{"type":22,"value":5230},{"type":17,"tag":243,"props":6342,"children":6344},{"class":245,"line":6343},72,[6345],{"type":17,"tag":243,"props":6346,"children":6347},{"style":981},[6348],{"type":22,"value":4207},{"type":17,"tag":243,"props":6350,"children":6352},{"class":245,"line":6351},73,[6353],{"type":17,"tag":243,"props":6354,"children":6355},{"emptyLinePlaceholder":2340},[6356],{"type":22,"value":2932},{"type":17,"tag":243,"props":6358,"children":6360},{"class":245,"line":6359},74,[6361],{"type":17,"tag":243,"props":6362,"children":6363},{"style":981},[6364],{"type":22,"value":6365},"    //code analogous to that explained in part 1\n",{"type":17,"tag":243,"props":6367,"children":6369},{"class":245,"line":6368},75,[6370],{"type":17,"tag":243,"props":6371,"children":6372},{"style":981},[6373],{"type":22,"value":6374},"    velocity.x+=forcex;\n",{"type":17,"tag":243,"props":6376,"children":6378},{"class":245,"line":6377},76,[6379],{"type":17,"tag":243,"props":6380,"children":6381},{"style":981},[6382],{"type":22,"value":6383},"    velocity.y+=forcey;\n",{"type":17,"tag":243,"props":6385,"children":6387},{"class":245,"line":6386},77,[6388],{"type":17,"tag":243,"props":6389,"children":6390},{"style":981},[6391],{"type":22,"value":6392},"    velocity.z+=forcez;\n",{"type":17,"tag":243,"props":6394,"children":6396},{"class":245,"line":6395},78,[6397],{"type":17,"tag":243,"props":6398,"children":6399},{"emptyLinePlaceholder":2340},[6400],{"type":22,"value":2932},{"type":17,"tag":243,"props":6402,"children":6404},{"class":245,"line":6403},79,[6405],{"type":17,"tag":243,"props":6406,"children":6407},{"style":981},[6408],{"type":22,"value":6409},"    velocity*=0.3; // friction\n",{"type":17,"tag":243,"props":6411,"children":6413},{"class":245,"line":6412},80,[6414],{"type":17,"tag":243,"props":6415,"children":6416},{"emptyLinePlaceholder":2340},[6417],{"type":22,"value":2932},{"type":17,"tag":243,"props":6419,"children":6421},{"class":245,"line":6420},81,[6422],{"type":17,"tag":243,"props":6423,"children":6424},{"style":981},[6425],{"type":22,"value":6426},"    positions[index] = vec4f(position + velocity, 1);\n",{"type":17,"tag":243,"props":6428,"children":6430},{"class":245,"line":6429},82,[6431],{"type":17,"tag":243,"props":6432,"children":6433},{"style":981},[6434],{"type":22,"value":6435},"    velocities[index] = vec3f(velocity);\n",{"type":17,"tag":243,"props":6437,"children":6439},{"class":245,"line":6438},83,[6440],{"type":17,"tag":243,"props":6441,"children":6442},{"style":981},[6443],{"type":22,"value":308},{"type":17,"tag":243,"props":6445,"children":6447},{"class":245,"line":6446},84,[6448],{"type":17,"tag":243,"props":6449,"children":6450},{"emptyLinePlaceholder":2340},[6451],{"type":22,"value":2932},{"type":17,"tag":243,"props":6453,"children":6455},{"class":245,"line":6454},85,[6456],{"type":17,"tag":243,"props":6457,"children":6458},{"style":981},[6459],{"type":22,"value":5670},{"type":17,"tag":40,"props":6461,"children":6463},{"id":6462},"_4-rendering-shader",[6464],{"type":22,"value":6465},"4. Rendering shader",{"type":17,"tag":18,"props":6467,"children":6468},{},[6469],{"type":22,"value":6470},"Now, after creating the compute pipeline and bind group, it's time to prepare additional buffers for render pass  (which you can look up in the GitHub repo) and render the shader module itself. I won't be doing anything outside of the box there, except for one\nadjustment. When creating a colors buffer, I assigned every particle an initial opacity, loaded from system's parameters. Here, to improve the visual effect and give my animation more depth I will update the particle's opacity based on their z coordinate in the vertex shader. So, particles at -1 of the z-axis will have 0% of the initial opacity, and particles at 1 will have 100% of it.",{"type":17,"tag":233,"props":6472,"children":6474},{"className":2417,"code":6473,"language":2419,"meta":8,"style":8},"const renderShaderModule = device.createShaderModule({\ncode: `\n        struct VertexUniforms {\n            screenDimensions: vec2f,\n            particleSize: f32\n        };\n\n        struct VSOut {\n            @builtin(position) clipPosition: vec4f,\n            @location(0) color: vec4f\n        };\n\n        @group(0) @binding(0) var\u003Cuniform> vertexUniforms: VertexUniforms;\n\n        @vertex\n        fn vs(\n            @location(0) vertexPosition: vec2f,\n            @location(1) color: vec4f,\n            @location(2) position: vec3f\n        ) -> VSOut {\n            var vsOut: VSOut;\n            var adjustedP = position;\n            adjustedP.y *= ${screenRatio};\n            vsOut.clipPosition = vec4f(vertexPosition * vertexUniforms.particleSize / vertexUniforms.screenDimensions + adjustedP.xy, adjustedP.z, 1.0);\n            var normalizedColor = color;\n            normalizedColor.w *= ((position.z * 0.5 ) + 0.5);\n            vsOut.color = normalizedColor;\n            return vsOut;\n        }             \n\n        @fragment \n        fn fs(@location(0) color: vec4f) -> @location(0) vec4f {\n            return vec4f(color.rgb * color.a, color.a);\n        } \n    `\n});\n",[6475],{"type":17,"tag":219,"props":6476,"children":6477},{"__ignoreMap":8},[6478,6507,6519,6527,6535,6543,6551,6558,6566,6574,6582,6589,6596,6604,6611,6619,6627,6635,6643,6651,6659,6667,6675,6692,6700,6708,6716,6724,6732,6740,6747,6755,6763,6771,6779,6787],{"type":17,"tag":243,"props":6479,"children":6480},{"class":245,"line":246},[6481,6485,6490,6494,6498,6503],{"type":17,"tag":243,"props":6482,"children":6483},{"style":250},[6484],{"type":22,"value":1691},{"type":17,"tag":243,"props":6486,"children":6487},{"style":378},[6488],{"type":22,"value":6489}," renderShaderModule",{"type":17,"tag":243,"props":6491,"children":6492},{"style":250},[6493],{"type":22,"value":1474},{"type":17,"tag":243,"props":6495,"children":6496},{"style":262},[6497],{"type":22,"value":2820},{"type":17,"tag":243,"props":6499,"children":6500},{"style":256},[6501],{"type":22,"value":6502},"createShaderModule",{"type":17,"tag":243,"props":6504,"children":6505},{"style":262},[6506],{"type":22,"value":2830},{"type":17,"tag":243,"props":6508,"children":6509},{"class":245,"line":160},[6510,6515],{"type":17,"tag":243,"props":6511,"children":6512},{"style":262},[6513],{"type":22,"value":6514},"code: ",{"type":17,"tag":243,"props":6516,"children":6517},{"style":981},[6518],{"type":22,"value":5670},{"type":17,"tag":243,"props":6520,"children":6521},{"class":245,"line":302},[6522],{"type":17,"tag":243,"props":6523,"children":6524},{"style":981},[6525],{"type":22,"value":6526},"        struct VertexUniforms {\n",{"type":17,"tag":243,"props":6528,"children":6529},{"class":245,"line":311},[6530],{"type":17,"tag":243,"props":6531,"children":6532},{"style":981},[6533],{"type":22,"value":6534},"            screenDimensions: vec2f,\n",{"type":17,"tag":243,"props":6536,"children":6537},{"class":245,"line":356},[6538],{"type":17,"tag":243,"props":6539,"children":6540},{"style":981},[6541],{"type":22,"value":6542},"            particleSize: f32\n",{"type":17,"tag":243,"props":6544,"children":6545},{"class":245,"line":403},[6546],{"type":17,"tag":243,"props":6547,"children":6548},{"style":981},[6549],{"type":22,"value":6550},"        };\n",{"type":17,"tag":243,"props":6552,"children":6553},{"class":245,"line":411},[6554],{"type":17,"tag":243,"props":6555,"children":6556},{"emptyLinePlaceholder":2340},[6557],{"type":22,"value":2932},{"type":17,"tag":243,"props":6559,"children":6560},{"class":245,"line":437},[6561],{"type":17,"tag":243,"props":6562,"children":6563},{"style":981},[6564],{"type":22,"value":6565},"        struct VSOut {\n",{"type":17,"tag":243,"props":6567,"children":6568},{"class":245,"line":510},[6569],{"type":17,"tag":243,"props":6570,"children":6571},{"style":981},[6572],{"type":22,"value":6573},"            @builtin(position) clipPosition: vec4f,\n",{"type":17,"tag":243,"props":6575,"children":6576},{"class":245,"line":518},[6577],{"type":17,"tag":243,"props":6578,"children":6579},{"style":981},[6580],{"type":22,"value":6581},"            @location(0) color: vec4f\n",{"type":17,"tag":243,"props":6583,"children":6584},{"class":245,"line":2757},[6585],{"type":17,"tag":243,"props":6586,"children":6587},{"style":981},[6588],{"type":22,"value":6550},{"type":17,"tag":243,"props":6590,"children":6591},{"class":245,"line":2765},[6592],{"type":17,"tag":243,"props":6593,"children":6594},{"emptyLinePlaceholder":2340},[6595],{"type":22,"value":2932},{"type":17,"tag":243,"props":6597,"children":6598},{"class":245,"line":2774},[6599],{"type":17,"tag":243,"props":6600,"children":6601},{"style":981},[6602],{"type":22,"value":6603},"        @group(0) @binding(0) var\u003Cuniform> vertexUniforms: VertexUniforms;\n",{"type":17,"tag":243,"props":6605,"children":6606},{"class":245,"line":2783},[6607],{"type":17,"tag":243,"props":6608,"children":6609},{"emptyLinePlaceholder":2340},[6610],{"type":22,"value":2932},{"type":17,"tag":243,"props":6612,"children":6613},{"class":245,"line":2792},[6614],{"type":17,"tag":243,"props":6615,"children":6616},{"style":981},[6617],{"type":22,"value":6618},"        @vertex\n",{"type":17,"tag":243,"props":6620,"children":6621},{"class":245,"line":2801},[6622],{"type":17,"tag":243,"props":6623,"children":6624},{"style":981},[6625],{"type":22,"value":6626},"        fn vs(\n",{"type":17,"tag":243,"props":6628,"children":6629},{"class":245,"line":2833},[6630],{"type":17,"tag":243,"props":6631,"children":6632},{"style":981},[6633],{"type":22,"value":6634},"            @location(0) vertexPosition: vec2f,\n",{"type":17,"tag":243,"props":6636,"children":6637},{"class":245,"line":2842},[6638],{"type":17,"tag":243,"props":6639,"children":6640},{"style":981},[6641],{"type":22,"value":6642},"            @location(1) color: vec4f,\n",{"type":17,"tag":243,"props":6644,"children":6645},{"class":245,"line":2889},[6646],{"type":17,"tag":243,"props":6647,"children":6648},{"style":981},[6649],{"type":22,"value":6650},"            @location(2) position: vec3f\n",{"type":17,"tag":243,"props":6652,"children":6653},{"class":245,"line":2898},[6654],{"type":17,"tag":243,"props":6655,"children":6656},{"style":981},[6657],{"type":22,"value":6658},"        ) -> VSOut {\n",{"type":17,"tag":243,"props":6660,"children":6661},{"class":245,"line":2926},[6662],{"type":17,"tag":243,"props":6663,"children":6664},{"style":981},[6665],{"type":22,"value":6666},"            var vsOut: VSOut;\n",{"type":17,"tag":243,"props":6668,"children":6669},{"class":245,"line":2935},[6670],{"type":17,"tag":243,"props":6671,"children":6672},{"style":981},[6673],{"type":22,"value":6674},"            var adjustedP = position;\n",{"type":17,"tag":243,"props":6676,"children":6677},{"class":245,"line":2944},[6678,6683,6688],{"type":17,"tag":243,"props":6679,"children":6680},{"style":981},[6681],{"type":22,"value":6682},"            adjustedP.y *= ${",{"type":17,"tag":243,"props":6684,"children":6685},{"style":262},[6686],{"type":22,"value":6687},"screenRatio",{"type":17,"tag":243,"props":6689,"children":6690},{"style":981},[6691],{"type":22,"value":5969},{"type":17,"tag":243,"props":6693,"children":6694},{"class":245,"line":2953},[6695],{"type":17,"tag":243,"props":6696,"children":6697},{"style":981},[6698],{"type":22,"value":6699},"            vsOut.clipPosition = vec4f(vertexPosition * vertexUniforms.particleSize / vertexUniforms.screenDimensions + adjustedP.xy, adjustedP.z, 1.0);\n",{"type":17,"tag":243,"props":6701,"children":6702},{"class":245,"line":2984},[6703],{"type":17,"tag":243,"props":6704,"children":6705},{"style":981},[6706],{"type":22,"value":6707},"            var normalizedColor = color;\n",{"type":17,"tag":243,"props":6709,"children":6710},{"class":245,"line":3040},[6711],{"type":17,"tag":243,"props":6712,"children":6713},{"style":981},[6714],{"type":22,"value":6715},"            normalizedColor.w *= ((position.z * 0.5 ) + 0.5);\n",{"type":17,"tag":243,"props":6717,"children":6718},{"class":245,"line":3084},[6719],{"type":17,"tag":243,"props":6720,"children":6721},{"style":981},[6722],{"type":22,"value":6723},"            vsOut.color = normalizedColor;\n",{"type":17,"tag":243,"props":6725,"children":6726},{"class":245,"line":3092},[6727],{"type":17,"tag":243,"props":6728,"children":6729},{"style":981},[6730],{"type":22,"value":6731},"            return vsOut;\n",{"type":17,"tag":243,"props":6733,"children":6734},{"class":245,"line":3121},[6735],{"type":17,"tag":243,"props":6736,"children":6737},{"style":981},[6738],{"type":22,"value":6739},"        }             \n",{"type":17,"tag":243,"props":6741,"children":6742},{"class":245,"line":3130},[6743],{"type":17,"tag":243,"props":6744,"children":6745},{"emptyLinePlaceholder":2340},[6746],{"type":22,"value":2932},{"type":17,"tag":243,"props":6748,"children":6749},{"class":245,"line":3159},[6750],{"type":17,"tag":243,"props":6751,"children":6752},{"style":981},[6753],{"type":22,"value":6754},"        @fragment \n",{"type":17,"tag":243,"props":6756,"children":6757},{"class":245,"line":3167},[6758],{"type":17,"tag":243,"props":6759,"children":6760},{"style":981},[6761],{"type":22,"value":6762},"        fn fs(@location(0) color: vec4f) -> @location(0) vec4f {\n",{"type":17,"tag":243,"props":6764,"children":6765},{"class":245,"line":3193},[6766],{"type":17,"tag":243,"props":6767,"children":6768},{"style":981},[6769],{"type":22,"value":6770},"            return vec4f(color.rgb * color.a, color.a);\n",{"type":17,"tag":243,"props":6772,"children":6773},{"class":245,"line":3201},[6774],{"type":17,"tag":243,"props":6775,"children":6776},{"style":981},[6777],{"type":22,"value":6778},"        } \n",{"type":17,"tag":243,"props":6780,"children":6781},{"class":245,"line":3210},[6782],{"type":17,"tag":243,"props":6783,"children":6784},{"style":981},[6785],{"type":22,"value":6786},"    `\n",{"type":17,"tag":243,"props":6788,"children":6789},{"class":245,"line":3248},[6790],{"type":17,"tag":243,"props":6791,"children":6792},{"style":262},[6793],{"type":22,"value":2895},{"type":17,"tag":18,"props":6795,"children":6796},{},[6797,6799,6806,6808,6815,6817,6824],{"type":22,"value":6798},"I had to omit a lot of boilerplate code, otherwise, this would be a several-hour-long read.  To understand these parts, I can recommend ",{"type":17,"tag":340,"props":6800,"children":6803},{"href":6801,"rel":6802},"https://webgpufundamentals.org/",[686],[6804],{"type":22,"value":6805},"WebGPU fundamentals",{"type":22,"value":6807}," - I studied it myself. To see how all the pieces fit, please see ",{"type":17,"tag":340,"props":6809,"children":6812},{"href":6810,"rel":6811},"https://github.com/Caranea/gpulife/blob/main/src/components/Particles.vue",[686],[6813],{"type":22,"value":6814},"this component in the project",{"type":22,"value":6816},". The paragraphs above are crucial to understanding how my particles work, especially the space partitioning section. Additionally, please read through the current ",{"type":17,"tag":340,"props":6818,"children":6821},{"href":6819,"rel":6820},"https://github.com/gpuweb/gpuweb/wiki/Implementation-Status",[686],[6822],{"type":22,"value":6823},"webGPU implementation",{"type":22,"value":6825}," status.",{"type":17,"tag":40,"props":6827,"children":6829},{"id":6828},"final-thoughts",[6830],{"type":22,"value":6831},"Final thoughts",{"type":17,"tag":18,"props":6833,"children":6834},{},[6835],{"type":22,"value":6836},"This project made me really appreciate how far the web has come. I remember, just 15 years ago, when I was a little kid spending way too much time on my computer, sending a form over PHP would be a pinnacle of web development. Now, we have canvas-based-UIs thanks to GPU rendering, with applications like Figma or Photoshop working in the browser, we have file system APIs like IndexedDB, Cache API, or LocalStorage. Service workers allow our web apps to work offline. WebTransport can make low-latency, real-time updates possible for games and other applications. WebAssembly is natively supported in all major browsers. The things I just mentioned are probably just the tip of the iceberg. I still can't wrap my head around being able to render 4 million particles through my Chrome browser in just under 500 lines of code. How amazing is that?",{"type":17,"tag":2308,"props":6838,"children":6839},{},[6840],{"type":22,"value":2312},{"title":8,"searchDepth":160,"depth":160,"links":6842},[6843,6844,6845,6846,6847,6848],{"id":2347,"depth":160,"text":2350},{"id":2378,"depth":160,"text":2381},{"id":3755,"depth":160,"text":3758},{"id":5633,"depth":160,"text":5636},{"id":6462,"depth":160,"text":6465},{"id":6828,"depth":160,"text":6831},"content:articles:optimizing-the-article-life-millions-of-particles-with-webgpu.md","articles/optimizing-the-article-life-millions-of-particles-with-webgpu.md","articles/optimizing-the-article-life-millions-of-particles-with-webgpu",{"_path":6853,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":6854,"description":6855,"published":6856,"slug":6857,"body":6858,"_type":165,"_id":10858,"_source":167,"_file":10859,"_stem":10860,"_extension":170},"/articles/optimizing-the-particle-life-javascript-quadtree","Optimizing the Particle Life: Spatial Partitioning with QuadTree (Part 2)","Let's implement JavaScript Particle Life and optimize it using QuadTree.","2024/03/06","optimizing-the-particle-life-javascript-quadtree",{"type":14,"children":6859,"toc":10851},[6860,6866,6871,6889,6903,6916,10626,10632,10637,10649,10654,10658,10663,10667,10672,10677,10720,10725,10748,10768,10774,10779,10791,10797,10802,10807,10813,10834,10839,10847],{"type":17,"tag":40,"props":6861,"children":6863},{"id":6862},"typescript-particle-life",[6864],{"type":22,"value":6865},"TypeScript Particle Life",{"type":17,"tag":18,"props":6867,"children":6868},{},[6869],{"type":22,"value":6870},"Now that the decision is made, let’s get to work. I’ll start with writing a basic JavaScript (or, to be precise, TypeScript that will later compile to JS) implementation based on the Python code I created in the previous part. To improve the code, I’ll need to add the following:",{"type":17,"tag":580,"props":6872,"children":6873},{},[6874,6879,6884],{"type":17,"tag":584,"props":6875,"children":6876},{},[6877],{"type":22,"value":6878},"Space wrapping around the edges.",{"type":17,"tag":584,"props":6880,"children":6881},{},[6882],{"type":22,"value":6883},"Space partitioning for optimization purposes.",{"type":17,"tag":584,"props":6885,"children":6886},{},[6887],{"type":22,"value":6888},"Allowing the user to adjust the parameters.",{"type":17,"tag":18,"props":6890,"children":6891},{},[6892,6894,6901],{"type":22,"value":6893},"The code below is part of a Vue component. VueJS is great when you need a lightweight, simple, and robust tool for rapid development. While the whole application structure is out of the scope of this article, please have a look at ",{"type":17,"tag":340,"props":6895,"children":6898},{"href":6896,"rel":6897},"https://github.com/Caranea/gpulife",[686],[6899],{"type":22,"value":6900},"this GitHub repo",{"type":22,"value":6902}," to see how I organized my project.",{"type":17,"tag":18,"props":6904,"children":6905},{},[6906,6908,6914],{"type":22,"value":6907},"I will only explain in detail the parts not covered in the ",{"type":17,"tag":340,"props":6909,"children":6911},{"href":6910},"/articles/optimizing-the-article-life-from-a-thousand-to-a-milion-particles",[6912],{"type":22,"value":6913},"previous article",{"type":22,"value":6915},", so make sure you read it first. A very important disclaimer: comments regarding optimization (e.g. typed vs regular arrays) only refer to code running in Chrome browser. Performance will vary from environment to environment, and it would have to be taken into consideration in real-life products.",{"type":17,"tag":233,"props":6917,"children":6919},{"className":2417,"code":6918,"language":2419,"meta":8,"style":8},"  const canvas = document.getElementById(\"pl\") as HTMLCanvasElement; //Grab a reference to Canvas element and cast its type as HTMLCanvasElement to have access to all its properties and methods\n  const context = (canvas).getContext(\"2d\"); //Create 2D rendering context for our canvas\n  //Make our canvas full-screen\n  canvas!.width = document.documentElement.clientWidth\n  canvas!.height = document.documentElement.clientHeight\n  //Since our x,y coordinates have values between (0,1), we need screenRatio when drawing particles, so that we don't render stretched/distorted animation.\n  const screenRatio = canvas!.width / canvas!.height\n  //Let's store our systems parameters in localStorage, so that they persist between user's session. If no 'parameters' object is in localStorage, fallback to default config. \n  const parameters = window.localStorage.getItem('parameters') ? JSON.parse(window.localStorage.getItem('parameters')!) : defaultConfig\n  const m = parameters.colorsNumber;\n  const n = parameters.particlesCountJS;\n  const radius = parameters.interactionRadiusJS;\n  const fr = Math.pow(0.5, 20);\n\n  const matrix = createRandomMatrix(m);\n\n  //using typed arrays would give us no performance advantage\n  let colors: number[] = [];\n  let positionsX: number[] = [];\n  let positionsY: number[] = [];\n  let velocitiesX: any[] = [];\n  let velocitiesY: any[] = [];\n\n  for (let i = 0; i \u003C n; i++) {\n    colors[i] = Math.floor(Math.random() * m);\n    positionsX[i] = Math.random();\n    positionsY[i] = Math.random();\n    velocitiesX[i] = 0;\n    velocitiesY[i] = 0;\n  }\n\n  renderFrame();\n\n  function renderFrame() {\n    //Clear previous positions on every frame\n    context!.fillStyle = \"black\";\n    context!.fillRect(0, 0, canvas!.clientWidth, canvas!.clientHeight);\n\n    for (let i = 0; i \u003C n; i++) {\n      //beginPath() method is called before drawing every particle, so that they may be filled with different colors.\n      context!.beginPath();\n      let x = positionsX[i] * canvas!.clientWidth;\n      let y = positionsY[i] * canvas!.clientHeight\n      //Adjusting position for two cases:\n      //a) mobile screens -> x\u003Cy\n      //b) desktops -> x>y\n      x = screenRatio \u003C 1 ? x * (1 / screenRatio) : x;\n      y = screenRatio > 1 ? y * screenRatio : y;\n      if (!(x \u003C 1) && !(y \u003C 1) && !(x > canvas!.clientWidth - 1) && !(y > canvas!.clientHeight - 1)) { //avoid blinking at edges due to how space wrapping is done\n        //Drawing the actual particle\n        context!.arc(x, y, 1, 0, 2 * Math.PI); //js compilers are smart enough for me not to have to move math.pi to var\n        context!.fillStyle = `hsl(${360 * (colors[i] / m)},100%,50%)`;\n        context!.fill();\n      }\n    }\n\n    updateParticles();\n    // Native window method to request animation frame. Note: The frequency of calls aims to match the display refresh rate.\n    // This method passes DOMHighResTimeStamp as an argument to callback, so that we can calculate how much our animation should progress in one frame\n    // Otherwise there will be different speed for animation on screens with different refresh rates\n    requestAnimationFrame(renderFrame);\n  }\n\n  function updateParticles() {\n    for (let i = 0; i \u003C n; i++) {\n      let totalForceX = 0;\n      let totalForceY = 0;\n      for (let j = 0; j \u003C n; j++) {\n        if (i === j) continue;\n        let x = positionsX[j] - positionsX[i];\n        let y = positionsY[j] - positionsY[i];\n        let d = Math.sqrt(x * x + y * y); // No performance advantage in removing math.sqrt. 10x faster than math.hypot.\n        if (d \u003C radius) {\n          let f = force(\n            d / radius,\n            matrix[colors[i]][colors[j]])\n          totalForceX += (x / d) * f;\n          totalForceY += (y / d) * f;\n        }\n        velocitiesX[i] += totalForceX;\n        velocitiesY[i] += totalForceY;\n\n        velocitiesX[i] *= fr;\n        velocitiesY[i] *= fr;\n\n        positionsX[i] += velocitiesX[i];\n        positionsY[i] += velocitiesY[i];\n\n        x = positionsX[i];\n        y = positionsY[i];\n\n        // Prevent particles from running away from the viewport. \n        // If x or y is > 1, substract 1 from it, so that it moves to other part of the screen\n        // This only handles particle position - it's not interacting with \n        // particles from the other side of the screen. In other words, particle at position (0,0) with radius of 0.1\n        // will not interact with particle at position (1.0,1.0). This gives us interesting visual effect (see for GPU.js examples screenshots)\n        // but also causes some issues, like particles aggregating at the edges\n\n        x = x > 1 ? x - 1 : x;\n        y = y > 1 ? y - 1 : y;\n        x = x \u003C 0 ? x + 1 : x;\n        y = y \u003C 0 ? y + 1 : y;\n\n        positionsX[i] = x;\n        positionsY[i] = y;\n      }\n    }\n  }\n\n  //Instead of using one force function allow user to choose from several options. \n  //Graphs of every function (assuming the force value between two particles to be 1.0 and a repulsive radius of 1/4 of the max radius)\n  //available on live site of the project\n\n  function force(d: number, f: number): number {\n    let repRadius = parameters.repulsiveRadius;\n    switch (parameters.forceFunction) {\n      case '1':\n        return forceVariantI(d, f, repRadius);\n      case '2':\n        return forceVariantII(d, f, repRadius);\n      case '3':\n        return forceVariantIII(d, f, repRadius);\n      default:\n        return defaultForce(d, f, repRadius)\n    }\n  }\n\n  function forceVariantI(d: number, f: number, repRadius: number): number {\n    if (d \u003C= repRadius) {\n          return d / repRadius - 1\n        } else {\n          return f * (1 - Math.abs(2 * d - 1 - repRadius) / 1 - repRadius);\n        }\n  }\n\n  function forceVariantII(d: number, f: number, repRadius: number): number {\n    if (d \u003C= repRadius) {\n          return (d / repRadius - 1) + (f * (1 - d))\n        } else {\n          return f * (1 - d)\n        }\n  }\n\n  function forceVariantIII(d: number, f: number, repRadius: number): number {\n   return defaultForce(d,f,repRadius)\n  }\n\n  function defaultForce(d: number, f: number, repRadius: number): number {\n    if (d \u003C= repRadius) {\n      return d / repRadius - 1\n    } else {\n      return f * (1 - d)\n    }\n  }\n",[6920],{"type":17,"tag":219,"props":6921,"children":6922},{"__ignoreMap":8},[6923,6983,7028,7036,7063,7088,7096,7142,7150,7246,7267,7288,7309,7355,7362,7388,7395,7403,7435,7467,7499,7532,7564,7571,7619,7659,7683,7707,7727,7747,7754,7761,7773,7780,7797,7805,7835,7894,7901,7948,7956,7981,8019,8057,8065,8073,8081,8143,8192,8339,8347,8415,8492,8516,8523,8530,8537,8549,8557,8565,8573,8586,8593,8600,8616,8663,8687,8711,8759,8787,8817,8846,8905,8926,8953,8970,8978,9013,9046,9053,9070,9087,9094,9111,9126,9133,9151,9169,9177,9194,9211,9219,9228,9237,9246,9255,9264,9273,9281,9329,9377,9425,9473,9481,9497,9513,9521,9529,9537,9545,9554,9563,9572,9580,9642,9665,9679,9698,9717,9734,9751,9768,9785,9798,9816,9824,9832,9840,9917,9939,9968,9985,10072,10080,10088,10096,10172,10192,10254,10270,10303,10311,10319,10327,10403,10420,10428,10436,10512,10532,10561,10578,10610,10618],{"type":17,"tag":243,"props":6924,"children":6925},{"class":245,"line":246},[6926,6931,6936,6940,6945,6950,6954,6959,6963,6968,6973,6978],{"type":17,"tag":243,"props":6927,"children":6928},{"style":250},[6929],{"type":22,"value":6930},"  const",{"type":17,"tag":243,"props":6932,"children":6933},{"style":378},[6934],{"type":22,"value":6935}," canvas",{"type":17,"tag":243,"props":6937,"children":6938},{"style":250},[6939],{"type":22,"value":1474},{"type":17,"tag":243,"props":6941,"children":6942},{"style":262},[6943],{"type":22,"value":6944}," document.",{"type":17,"tag":243,"props":6946,"children":6947},{"style":256},[6948],{"type":22,"value":6949},"getElementById",{"type":17,"tag":243,"props":6951,"children":6952},{"style":262},[6953],{"type":22,"value":265},{"type":17,"tag":243,"props":6955,"children":6956},{"style":981},[6957],{"type":22,"value":6958},"\"pl\"",{"type":17,"tag":243,"props":6960,"children":6961},{"style":262},[6962],{"type":22,"value":1637},{"type":17,"tag":243,"props":6964,"children":6965},{"style":250},[6966],{"type":22,"value":6967},"as",{"type":17,"tag":243,"props":6969,"children":6970},{"style":256},[6971],{"type":22,"value":6972}," HTMLCanvasElement",{"type":17,"tag":243,"props":6974,"children":6975},{"style":262},[6976],{"type":22,"value":6977},"; ",{"type":17,"tag":243,"props":6979,"children":6980},{"style":2429},[6981],{"type":22,"value":6982},"//Grab a reference to Canvas element and cast its type as HTMLCanvasElement to have access to all its properties and methods\n",{"type":17,"tag":243,"props":6984,"children":6985},{"class":245,"line":160},[6986,6990,6995,6999,7004,7009,7013,7018,7023],{"type":17,"tag":243,"props":6987,"children":6988},{"style":250},[6989],{"type":22,"value":6930},{"type":17,"tag":243,"props":6991,"children":6992},{"style":378},[6993],{"type":22,"value":6994}," context",{"type":17,"tag":243,"props":6996,"children":6997},{"style":250},[6998],{"type":22,"value":1474},{"type":17,"tag":243,"props":7000,"children":7001},{"style":262},[7002],{"type":22,"value":7003}," (canvas).",{"type":17,"tag":243,"props":7005,"children":7006},{"style":256},[7007],{"type":22,"value":7008},"getContext",{"type":17,"tag":243,"props":7010,"children":7011},{"style":262},[7012],{"type":22,"value":265},{"type":17,"tag":243,"props":7014,"children":7015},{"style":981},[7016],{"type":22,"value":7017},"\"2d\"",{"type":17,"tag":243,"props":7019,"children":7020},{"style":262},[7021],{"type":22,"value":7022},"); ",{"type":17,"tag":243,"props":7024,"children":7025},{"style":2429},[7026],{"type":22,"value":7027},"//Create 2D rendering context for our canvas\n",{"type":17,"tag":243,"props":7029,"children":7030},{"class":245,"line":302},[7031],{"type":17,"tag":243,"props":7032,"children":7033},{"style":2429},[7034],{"type":22,"value":7035},"  //Make our canvas full-screen\n",{"type":17,"tag":243,"props":7037,"children":7038},{"class":245,"line":311},[7039,7044,7049,7054,7058],{"type":17,"tag":243,"props":7040,"children":7041},{"style":262},[7042],{"type":22,"value":7043},"  canvas",{"type":17,"tag":243,"props":7045,"children":7046},{"style":250},[7047],{"type":22,"value":7048},"!",{"type":17,"tag":243,"props":7050,"children":7051},{"style":262},[7052],{"type":22,"value":7053},".width ",{"type":17,"tag":243,"props":7055,"children":7056},{"style":250},[7057],{"type":22,"value":1502},{"type":17,"tag":243,"props":7059,"children":7060},{"style":262},[7061],{"type":22,"value":7062}," document.documentElement.clientWidth\n",{"type":17,"tag":243,"props":7064,"children":7065},{"class":245,"line":356},[7066,7070,7074,7079,7083],{"type":17,"tag":243,"props":7067,"children":7068},{"style":262},[7069],{"type":22,"value":7043},{"type":17,"tag":243,"props":7071,"children":7072},{"style":250},[7073],{"type":22,"value":7048},{"type":17,"tag":243,"props":7075,"children":7076},{"style":262},[7077],{"type":22,"value":7078},".height ",{"type":17,"tag":243,"props":7080,"children":7081},{"style":250},[7082],{"type":22,"value":1502},{"type":17,"tag":243,"props":7084,"children":7085},{"style":262},[7086],{"type":22,"value":7087}," document.documentElement.clientHeight\n",{"type":17,"tag":243,"props":7089,"children":7090},{"class":245,"line":403},[7091],{"type":17,"tag":243,"props":7092,"children":7093},{"style":2429},[7094],{"type":22,"value":7095},"  //Since our x,y coordinates have values between (0,1), we need screenRatio when drawing particles, so that we don't render stretched/distorted animation.\n",{"type":17,"tag":243,"props":7097,"children":7098},{"class":245,"line":411},[7099,7103,7108,7112,7116,7120,7124,7129,7133,7137],{"type":17,"tag":243,"props":7100,"children":7101},{"style":250},[7102],{"type":22,"value":6930},{"type":17,"tag":243,"props":7104,"children":7105},{"style":378},[7106],{"type":22,"value":7107}," screenRatio",{"type":17,"tag":243,"props":7109,"children":7110},{"style":250},[7111],{"type":22,"value":1474},{"type":17,"tag":243,"props":7113,"children":7114},{"style":262},[7115],{"type":22,"value":6935},{"type":17,"tag":243,"props":7117,"children":7118},{"style":250},[7119],{"type":22,"value":7048},{"type":17,"tag":243,"props":7121,"children":7122},{"style":262},[7123],{"type":22,"value":7053},{"type":17,"tag":243,"props":7125,"children":7126},{"style":250},[7127],{"type":22,"value":7128},"/",{"type":17,"tag":243,"props":7130,"children":7131},{"style":262},[7132],{"type":22,"value":6935},{"type":17,"tag":243,"props":7134,"children":7135},{"style":250},[7136],{"type":22,"value":7048},{"type":17,"tag":243,"props":7138,"children":7139},{"style":262},[7140],{"type":22,"value":7141},".height\n",{"type":17,"tag":243,"props":7143,"children":7144},{"class":245,"line":437},[7145],{"type":17,"tag":243,"props":7146,"children":7147},{"style":2429},[7148],{"type":22,"value":7149},"  //Let's store our systems parameters in localStorage, so that they persist between user's session. If no 'parameters' object is in localStorage, fallback to default config. \n",{"type":17,"tag":243,"props":7151,"children":7152},{"class":245,"line":510},[7153,7157,7162,7166,7171,7176,7180,7185,7189,7193,7198,7202,7207,7212,7216,7220,7224,7229,7233,7237,7241],{"type":17,"tag":243,"props":7154,"children":7155},{"style":250},[7156],{"type":22,"value":6930},{"type":17,"tag":243,"props":7158,"children":7159},{"style":378},[7160],{"type":22,"value":7161}," parameters",{"type":17,"tag":243,"props":7163,"children":7164},{"style":250},[7165],{"type":22,"value":1474},{"type":17,"tag":243,"props":7167,"children":7168},{"style":262},[7169],{"type":22,"value":7170}," window.localStorage.",{"type":17,"tag":243,"props":7172,"children":7173},{"style":256},[7174],{"type":22,"value":7175},"getItem",{"type":17,"tag":243,"props":7177,"children":7178},{"style":262},[7179],{"type":22,"value":265},{"type":17,"tag":243,"props":7181,"children":7182},{"style":981},[7183],{"type":22,"value":7184},"'parameters'",{"type":17,"tag":243,"props":7186,"children":7187},{"style":262},[7188],{"type":22,"value":1637},{"type":17,"tag":243,"props":7190,"children":7191},{"style":250},[7192],{"type":22,"value":915},{"type":17,"tag":243,"props":7194,"children":7195},{"style":378},[7196],{"type":22,"value":7197}," JSON",{"type":17,"tag":243,"props":7199,"children":7200},{"style":262},[7201],{"type":22,"value":595},{"type":17,"tag":243,"props":7203,"children":7204},{"style":256},[7205],{"type":22,"value":7206},"parse",{"type":17,"tag":243,"props":7208,"children":7209},{"style":262},[7210],{"type":22,"value":7211},"(window.localStorage.",{"type":17,"tag":243,"props":7213,"children":7214},{"style":256},[7215],{"type":22,"value":7175},{"type":17,"tag":243,"props":7217,"children":7218},{"style":262},[7219],{"type":22,"value":265},{"type":17,"tag":243,"props":7221,"children":7222},{"style":981},[7223],{"type":22,"value":7184},{"type":17,"tag":243,"props":7225,"children":7226},{"style":262},[7227],{"type":22,"value":7228},")",{"type":17,"tag":243,"props":7230,"children":7231},{"style":250},[7232],{"type":22,"value":7048},{"type":17,"tag":243,"props":7234,"children":7235},{"style":262},[7236],{"type":22,"value":1637},{"type":17,"tag":243,"props":7238,"children":7239},{"style":250},[7240],{"type":22,"value":925},{"type":17,"tag":243,"props":7242,"children":7243},{"style":262},[7244],{"type":22,"value":7245}," defaultConfig\n",{"type":17,"tag":243,"props":7247,"children":7248},{"class":245,"line":518},[7249,7253,7258,7262],{"type":17,"tag":243,"props":7250,"children":7251},{"style":250},[7252],{"type":22,"value":6930},{"type":17,"tag":243,"props":7254,"children":7255},{"style":378},[7256],{"type":22,"value":7257}," m",{"type":17,"tag":243,"props":7259,"children":7260},{"style":250},[7261],{"type":22,"value":1474},{"type":17,"tag":243,"props":7263,"children":7264},{"style":262},[7265],{"type":22,"value":7266}," parameters.colorsNumber;\n",{"type":17,"tag":243,"props":7268,"children":7269},{"class":245,"line":2757},[7270,7274,7279,7283],{"type":17,"tag":243,"props":7271,"children":7272},{"style":250},[7273],{"type":22,"value":6930},{"type":17,"tag":243,"props":7275,"children":7276},{"style":378},[7277],{"type":22,"value":7278}," n",{"type":17,"tag":243,"props":7280,"children":7281},{"style":250},[7282],{"type":22,"value":1474},{"type":17,"tag":243,"props":7284,"children":7285},{"style":262},[7286],{"type":22,"value":7287}," parameters.particlesCountJS;\n",{"type":17,"tag":243,"props":7289,"children":7290},{"class":245,"line":2765},[7291,7295,7300,7304],{"type":17,"tag":243,"props":7292,"children":7293},{"style":250},[7294],{"type":22,"value":6930},{"type":17,"tag":243,"props":7296,"children":7297},{"style":378},[7298],{"type":22,"value":7299}," radius",{"type":17,"tag":243,"props":7301,"children":7302},{"style":250},[7303],{"type":22,"value":1474},{"type":17,"tag":243,"props":7305,"children":7306},{"style":262},[7307],{"type":22,"value":7308}," parameters.interactionRadiusJS;\n",{"type":17,"tag":243,"props":7310,"children":7311},{"class":245,"line":2774},[7312,7316,7321,7325,7329,7333,7337,7342,7346,7351],{"type":17,"tag":243,"props":7313,"children":7314},{"style":250},[7315],{"type":22,"value":6930},{"type":17,"tag":243,"props":7317,"children":7318},{"style":378},[7319],{"type":22,"value":7320}," fr",{"type":17,"tag":243,"props":7322,"children":7323},{"style":250},[7324],{"type":22,"value":1474},{"type":17,"tag":243,"props":7326,"children":7327},{"style":262},[7328],{"type":22,"value":2579},{"type":17,"tag":243,"props":7330,"children":7331},{"style":256},[7332],{"type":22,"value":3878},{"type":17,"tag":243,"props":7334,"children":7335},{"style":262},[7336],{"type":22,"value":265},{"type":17,"tag":243,"props":7338,"children":7339},{"style":378},[7340],{"type":22,"value":7341},"0.5",{"type":17,"tag":243,"props":7343,"children":7344},{"style":262},[7345],{"type":22,"value":335},{"type":17,"tag":243,"props":7347,"children":7348},{"style":378},[7349],{"type":22,"value":7350},"20",{"type":17,"tag":243,"props":7352,"children":7353},{"style":262},[7354],{"type":22,"value":1215},{"type":17,"tag":243,"props":7356,"children":7357},{"class":245,"line":2783},[7358],{"type":17,"tag":243,"props":7359,"children":7360},{"emptyLinePlaceholder":2340},[7361],{"type":22,"value":2932},{"type":17,"tag":243,"props":7363,"children":7364},{"class":245,"line":2792},[7365,7369,7374,7378,7383],{"type":17,"tag":243,"props":7366,"children":7367},{"style":250},[7368],{"type":22,"value":6930},{"type":17,"tag":243,"props":7370,"children":7371},{"style":378},[7372],{"type":22,"value":7373}," matrix",{"type":17,"tag":243,"props":7375,"children":7376},{"style":250},[7377],{"type":22,"value":1474},{"type":17,"tag":243,"props":7379,"children":7380},{"style":256},[7381],{"type":22,"value":7382}," createRandomMatrix",{"type":17,"tag":243,"props":7384,"children":7385},{"style":262},[7386],{"type":22,"value":7387},"(m);\n",{"type":17,"tag":243,"props":7389,"children":7390},{"class":245,"line":2801},[7391],{"type":17,"tag":243,"props":7392,"children":7393},{"emptyLinePlaceholder":2340},[7394],{"type":22,"value":2932},{"type":17,"tag":243,"props":7396,"children":7397},{"class":245,"line":2833},[7398],{"type":17,"tag":243,"props":7399,"children":7400},{"style":2429},[7401],{"type":22,"value":7402},"  //using typed arrays would give us no performance advantage\n",{"type":17,"tag":243,"props":7404,"children":7405},{"class":245,"line":2842},[7406,7410,7415,7419,7423,7427,7431],{"type":17,"tag":243,"props":7407,"children":7408},{"style":250},[7409],{"type":22,"value":1492},{"type":17,"tag":243,"props":7411,"children":7412},{"style":262},[7413],{"type":22,"value":7414}," colors",{"type":17,"tag":243,"props":7416,"children":7417},{"style":250},[7418],{"type":22,"value":925},{"type":17,"tag":243,"props":7420,"children":7421},{"style":378},[7422],{"type":22,"value":3938},{"type":17,"tag":243,"props":7424,"children":7425},{"style":262},[7426],{"type":22,"value":3943},{"type":17,"tag":243,"props":7428,"children":7429},{"style":250},[7430],{"type":22,"value":1502},{"type":17,"tag":243,"props":7432,"children":7433},{"style":262},[7434],{"type":22,"value":3952},{"type":17,"tag":243,"props":7436,"children":7437},{"class":245,"line":2889},[7438,7442,7447,7451,7455,7459,7463],{"type":17,"tag":243,"props":7439,"children":7440},{"style":250},[7441],{"type":22,"value":1492},{"type":17,"tag":243,"props":7443,"children":7444},{"style":262},[7445],{"type":22,"value":7446}," positionsX",{"type":17,"tag":243,"props":7448,"children":7449},{"style":250},[7450],{"type":22,"value":925},{"type":17,"tag":243,"props":7452,"children":7453},{"style":378},[7454],{"type":22,"value":3938},{"type":17,"tag":243,"props":7456,"children":7457},{"style":262},[7458],{"type":22,"value":3943},{"type":17,"tag":243,"props":7460,"children":7461},{"style":250},[7462],{"type":22,"value":1502},{"type":17,"tag":243,"props":7464,"children":7465},{"style":262},[7466],{"type":22,"value":3952},{"type":17,"tag":243,"props":7468,"children":7469},{"class":245,"line":2898},[7470,7474,7479,7483,7487,7491,7495],{"type":17,"tag":243,"props":7471,"children":7472},{"style":250},[7473],{"type":22,"value":1492},{"type":17,"tag":243,"props":7475,"children":7476},{"style":262},[7477],{"type":22,"value":7478}," positionsY",{"type":17,"tag":243,"props":7480,"children":7481},{"style":250},[7482],{"type":22,"value":925},{"type":17,"tag":243,"props":7484,"children":7485},{"style":378},[7486],{"type":22,"value":3938},{"type":17,"tag":243,"props":7488,"children":7489},{"style":262},[7490],{"type":22,"value":3943},{"type":17,"tag":243,"props":7492,"children":7493},{"style":250},[7494],{"type":22,"value":1502},{"type":17,"tag":243,"props":7496,"children":7497},{"style":262},[7498],{"type":22,"value":3952},{"type":17,"tag":243,"props":7500,"children":7501},{"class":245,"line":2926},[7502,7506,7511,7515,7520,7524,7528],{"type":17,"tag":243,"props":7503,"children":7504},{"style":250},[7505],{"type":22,"value":1492},{"type":17,"tag":243,"props":7507,"children":7508},{"style":262},[7509],{"type":22,"value":7510}," velocitiesX",{"type":17,"tag":243,"props":7512,"children":7513},{"style":250},[7514],{"type":22,"value":925},{"type":17,"tag":243,"props":7516,"children":7517},{"style":378},[7518],{"type":22,"value":7519}," any",{"type":17,"tag":243,"props":7521,"children":7522},{"style":262},[7523],{"type":22,"value":3943},{"type":17,"tag":243,"props":7525,"children":7526},{"style":250},[7527],{"type":22,"value":1502},{"type":17,"tag":243,"props":7529,"children":7530},{"style":262},[7531],{"type":22,"value":3952},{"type":17,"tag":243,"props":7533,"children":7534},{"class":245,"line":2935},[7535,7539,7544,7548,7552,7556,7560],{"type":17,"tag":243,"props":7536,"children":7537},{"style":250},[7538],{"type":22,"value":1492},{"type":17,"tag":243,"props":7540,"children":7541},{"style":262},[7542],{"type":22,"value":7543}," velocitiesY",{"type":17,"tag":243,"props":7545,"children":7546},{"style":250},[7547],{"type":22,"value":925},{"type":17,"tag":243,"props":7549,"children":7550},{"style":378},[7551],{"type":22,"value":7519},{"type":17,"tag":243,"props":7553,"children":7554},{"style":262},[7555],{"type":22,"value":3943},{"type":17,"tag":243,"props":7557,"children":7558},{"style":250},[7559],{"type":22,"value":1502},{"type":17,"tag":243,"props":7561,"children":7562},{"style":262},[7563],{"type":22,"value":3952},{"type":17,"tag":243,"props":7565,"children":7566},{"class":245,"line":2944},[7567],{"type":17,"tag":243,"props":7568,"children":7569},{"emptyLinePlaceholder":2340},[7570],{"type":22,"value":2932},{"type":17,"tag":243,"props":7572,"children":7573},{"class":245,"line":2953},[7574,7578,7582,7586,7590,7594,7598,7602,7606,7611,7615],{"type":17,"tag":243,"props":7575,"children":7576},{"style":250},[7577],{"type":22,"value":4063},{"type":17,"tag":243,"props":7579,"children":7580},{"style":262},[7581],{"type":22,"value":1523},{"type":17,"tag":243,"props":7583,"children":7584},{"style":250},[7585],{"type":22,"value":1592},{"type":17,"tag":243,"props":7587,"children":7588},{"style":262},[7589],{"type":22,"value":1497},{"type":17,"tag":243,"props":7591,"children":7592},{"style":250},[7593],{"type":22,"value":1502},{"type":17,"tag":243,"props":7595,"children":7596},{"style":378},[7597],{"type":22,"value":457},{"type":17,"tag":243,"props":7599,"children":7600},{"style":262},[7601],{"type":22,"value":1962},{"type":17,"tag":243,"props":7603,"children":7604},{"style":250},[7605],{"type":22,"value":481},{"type":17,"tag":243,"props":7607,"children":7608},{"style":262},[7609],{"type":22,"value":7610}," n; i",{"type":17,"tag":243,"props":7612,"children":7613},{"style":250},[7614],{"type":22,"value":1550},{"type":17,"tag":243,"props":7616,"children":7617},{"style":262},[7618],{"type":22,"value":276},{"type":17,"tag":243,"props":7620,"children":7621},{"class":245,"line":2984},[7622,7627,7631,7635,7639,7643,7647,7651,7655],{"type":17,"tag":243,"props":7623,"children":7624},{"style":262},[7625],{"type":22,"value":7626},"    colors[i] ",{"type":17,"tag":243,"props":7628,"children":7629},{"style":250},[7630],{"type":22,"value":1502},{"type":17,"tag":243,"props":7632,"children":7633},{"style":262},[7634],{"type":22,"value":2579},{"type":17,"tag":243,"props":7636,"children":7637},{"style":256},[7638],{"type":22,"value":3059},{"type":17,"tag":243,"props":7640,"children":7641},{"style":262},[7642],{"type":22,"value":3064},{"type":17,"tag":243,"props":7644,"children":7645},{"style":256},[7646],{"type":22,"value":2584},{"type":17,"tag":243,"props":7648,"children":7649},{"style":262},[7650],{"type":22,"value":2589},{"type":17,"tag":243,"props":7652,"children":7653},{"style":250},[7654],{"type":22,"value":294},{"type":17,"tag":243,"props":7656,"children":7657},{"style":262},[7658],{"type":22,"value":3081},{"type":17,"tag":243,"props":7660,"children":7661},{"class":245,"line":3040},[7662,7667,7671,7675,7679],{"type":17,"tag":243,"props":7663,"children":7664},{"style":262},[7665],{"type":22,"value":7666},"    positionsX[i] ",{"type":17,"tag":243,"props":7668,"children":7669},{"style":250},[7670],{"type":22,"value":1502},{"type":17,"tag":243,"props":7672,"children":7673},{"style":262},[7674],{"type":22,"value":2579},{"type":17,"tag":243,"props":7676,"children":7677},{"style":256},[7678],{"type":22,"value":2584},{"type":17,"tag":243,"props":7680,"children":7681},{"style":262},[7682],{"type":22,"value":2191},{"type":17,"tag":243,"props":7684,"children":7685},{"class":245,"line":3084},[7686,7691,7695,7699,7703],{"type":17,"tag":243,"props":7687,"children":7688},{"style":262},[7689],{"type":22,"value":7690},"    positionsY[i] ",{"type":17,"tag":243,"props":7692,"children":7693},{"style":250},[7694],{"type":22,"value":1502},{"type":17,"tag":243,"props":7696,"children":7697},{"style":262},[7698],{"type":22,"value":2579},{"type":17,"tag":243,"props":7700,"children":7701},{"style":256},[7702],{"type":22,"value":2584},{"type":17,"tag":243,"props":7704,"children":7705},{"style":262},[7706],{"type":22,"value":2191},{"type":17,"tag":243,"props":7708,"children":7709},{"class":245,"line":3092},[7710,7715,7719,7723],{"type":17,"tag":243,"props":7711,"children":7712},{"style":262},[7713],{"type":22,"value":7714},"    velocitiesX[i] ",{"type":17,"tag":243,"props":7716,"children":7717},{"style":250},[7718],{"type":22,"value":1502},{"type":17,"tag":243,"props":7720,"children":7721},{"style":378},[7722],{"type":22,"value":457},{"type":17,"tag":243,"props":7724,"children":7725},{"style":262},[7726],{"type":22,"value":507},{"type":17,"tag":243,"props":7728,"children":7729},{"class":245,"line":3121},[7730,7735,7739,7743],{"type":17,"tag":243,"props":7731,"children":7732},{"style":262},[7733],{"type":22,"value":7734},"    velocitiesY[i] ",{"type":17,"tag":243,"props":7736,"children":7737},{"style":250},[7738],{"type":22,"value":1502},{"type":17,"tag":243,"props":7740,"children":7741},{"style":378},[7742],{"type":22,"value":457},{"type":17,"tag":243,"props":7744,"children":7745},{"style":262},[7746],{"type":22,"value":507},{"type":17,"tag":243,"props":7748,"children":7749},{"class":245,"line":3130},[7750],{"type":17,"tag":243,"props":7751,"children":7752},{"style":262},[7753],{"type":22,"value":1413},{"type":17,"tag":243,"props":7755,"children":7756},{"class":245,"line":3159},[7757],{"type":17,"tag":243,"props":7758,"children":7759},{"emptyLinePlaceholder":2340},[7760],{"type":22,"value":2932},{"type":17,"tag":243,"props":7762,"children":7763},{"class":245,"line":3167},[7764,7769],{"type":17,"tag":243,"props":7765,"children":7766},{"style":256},[7767],{"type":22,"value":7768},"  renderFrame",{"type":17,"tag":243,"props":7770,"children":7771},{"style":262},[7772],{"type":22,"value":2191},{"type":17,"tag":243,"props":7774,"children":7775},{"class":245,"line":3193},[7776],{"type":17,"tag":243,"props":7777,"children":7778},{"emptyLinePlaceholder":2340},[7779],{"type":22,"value":2932},{"type":17,"tag":243,"props":7781,"children":7782},{"class":245,"line":3201},[7783,7788,7793],{"type":17,"tag":243,"props":7784,"children":7785},{"style":250},[7786],{"type":22,"value":7787},"  function",{"type":17,"tag":243,"props":7789,"children":7790},{"style":256},[7791],{"type":22,"value":7792}," renderFrame",{"type":17,"tag":243,"props":7794,"children":7795},{"style":262},[7796],{"type":22,"value":2044},{"type":17,"tag":243,"props":7798,"children":7799},{"class":245,"line":3210},[7800],{"type":17,"tag":243,"props":7801,"children":7802},{"style":2429},[7803],{"type":22,"value":7804},"    //Clear previous positions on every frame\n",{"type":17,"tag":243,"props":7806,"children":7807},{"class":245,"line":3248},[7808,7813,7817,7822,7826,7831],{"type":17,"tag":243,"props":7809,"children":7810},{"style":262},[7811],{"type":22,"value":7812},"    context",{"type":17,"tag":243,"props":7814,"children":7815},{"style":250},[7816],{"type":22,"value":7048},{"type":17,"tag":243,"props":7818,"children":7819},{"style":262},[7820],{"type":22,"value":7821},".fillStyle ",{"type":17,"tag":243,"props":7823,"children":7824},{"style":250},[7825],{"type":22,"value":1502},{"type":17,"tag":243,"props":7827,"children":7828},{"style":981},[7829],{"type":22,"value":7830}," \"black\"",{"type":17,"tag":243,"props":7832,"children":7833},{"style":262},[7834],{"type":22,"value":507},{"type":17,"tag":243,"props":7836,"children":7837},{"class":245,"line":3305},[7838,7842,7846,7850,7855,7859,7863,7867,7871,7876,7880,7885,7889],{"type":17,"tag":243,"props":7839,"children":7840},{"style":262},[7841],{"type":22,"value":7812},{"type":17,"tag":243,"props":7843,"children":7844},{"style":250},[7845],{"type":22,"value":7048},{"type":17,"tag":243,"props":7847,"children":7848},{"style":262},[7849],{"type":22,"value":595},{"type":17,"tag":243,"props":7851,"children":7852},{"style":256},[7853],{"type":22,"value":7854},"fillRect",{"type":17,"tag":243,"props":7856,"children":7857},{"style":262},[7858],{"type":22,"value":265},{"type":17,"tag":243,"props":7860,"children":7861},{"style":378},[7862],{"type":22,"value":2070},{"type":17,"tag":243,"props":7864,"children":7865},{"style":262},[7866],{"type":22,"value":335},{"type":17,"tag":243,"props":7868,"children":7869},{"style":378},[7870],{"type":22,"value":2070},{"type":17,"tag":243,"props":7872,"children":7873},{"style":262},[7874],{"type":22,"value":7875},", canvas",{"type":17,"tag":243,"props":7877,"children":7878},{"style":250},[7879],{"type":22,"value":7048},{"type":17,"tag":243,"props":7881,"children":7882},{"style":262},[7883],{"type":22,"value":7884},".clientWidth, canvas",{"type":17,"tag":243,"props":7886,"children":7887},{"style":250},[7888],{"type":22,"value":7048},{"type":17,"tag":243,"props":7890,"children":7891},{"style":262},[7892],{"type":22,"value":7893},".clientHeight);\n",{"type":17,"tag":243,"props":7895,"children":7896},{"class":245,"line":3333},[7897],{"type":17,"tag":243,"props":7898,"children":7899},{"emptyLinePlaceholder":2340},[7900],{"type":22,"value":2932},{"type":17,"tag":243,"props":7902,"children":7903},{"class":245,"line":3341},[7904,7908,7912,7916,7920,7924,7928,7932,7936,7940,7944],{"type":17,"tag":243,"props":7905,"children":7906},{"style":250},[7907],{"type":22,"value":4114},{"type":17,"tag":243,"props":7909,"children":7910},{"style":262},[7911],{"type":22,"value":1523},{"type":17,"tag":243,"props":7913,"children":7914},{"style":250},[7915],{"type":22,"value":1592},{"type":17,"tag":243,"props":7917,"children":7918},{"style":262},[7919],{"type":22,"value":1497},{"type":17,"tag":243,"props":7921,"children":7922},{"style":250},[7923],{"type":22,"value":1502},{"type":17,"tag":243,"props":7925,"children":7926},{"style":378},[7927],{"type":22,"value":457},{"type":17,"tag":243,"props":7929,"children":7930},{"style":262},[7931],{"type":22,"value":1962},{"type":17,"tag":243,"props":7933,"children":7934},{"style":250},[7935],{"type":22,"value":481},{"type":17,"tag":243,"props":7937,"children":7938},{"style":262},[7939],{"type":22,"value":7610},{"type":17,"tag":243,"props":7941,"children":7942},{"style":250},[7943],{"type":22,"value":1550},{"type":17,"tag":243,"props":7945,"children":7946},{"style":262},[7947],{"type":22,"value":276},{"type":17,"tag":243,"props":7949,"children":7950},{"class":245,"line":3370},[7951],{"type":17,"tag":243,"props":7952,"children":7953},{"style":2429},[7954],{"type":22,"value":7955},"      //beginPath() method is called before drawing every particle, so that they may be filled with different colors.\n",{"type":17,"tag":243,"props":7957,"children":7958},{"class":245,"line":3379},[7959,7964,7968,7972,7977],{"type":17,"tag":243,"props":7960,"children":7961},{"style":262},[7962],{"type":22,"value":7963},"      context",{"type":17,"tag":243,"props":7965,"children":7966},{"style":250},[7967],{"type":22,"value":7048},{"type":17,"tag":243,"props":7969,"children":7970},{"style":262},[7971],{"type":22,"value":595},{"type":17,"tag":243,"props":7973,"children":7974},{"style":256},[7975],{"type":22,"value":7976},"beginPath",{"type":17,"tag":243,"props":7978,"children":7979},{"style":262},[7980],{"type":22,"value":2191},{"type":17,"tag":243,"props":7982,"children":7983},{"class":245,"line":3407},[7984,7989,7993,7997,8002,8006,8010,8014],{"type":17,"tag":243,"props":7985,"children":7986},{"style":250},[7987],{"type":22,"value":7988},"      let",{"type":17,"tag":243,"props":7990,"children":7991},{"style":262},[7992],{"type":22,"value":289},{"type":17,"tag":243,"props":7994,"children":7995},{"style":250},[7996],{"type":22,"value":1502},{"type":17,"tag":243,"props":7998,"children":7999},{"style":262},[8000],{"type":22,"value":8001}," positionsX[i] ",{"type":17,"tag":243,"props":8003,"children":8004},{"style":250},[8005],{"type":22,"value":294},{"type":17,"tag":243,"props":8007,"children":8008},{"style":262},[8009],{"type":22,"value":6935},{"type":17,"tag":243,"props":8011,"children":8012},{"style":250},[8013],{"type":22,"value":7048},{"type":17,"tag":243,"props":8015,"children":8016},{"style":262},[8017],{"type":22,"value":8018},".clientWidth;\n",{"type":17,"tag":243,"props":8020,"children":8021},{"class":245,"line":3415},[8022,8026,8031,8035,8040,8044,8048,8052],{"type":17,"tag":243,"props":8023,"children":8024},{"style":250},[8025],{"type":22,"value":7988},{"type":17,"tag":243,"props":8027,"children":8028},{"style":262},[8029],{"type":22,"value":8030}," y ",{"type":17,"tag":243,"props":8032,"children":8033},{"style":250},[8034],{"type":22,"value":1502},{"type":17,"tag":243,"props":8036,"children":8037},{"style":262},[8038],{"type":22,"value":8039}," positionsY[i] ",{"type":17,"tag":243,"props":8041,"children":8042},{"style":250},[8043],{"type":22,"value":294},{"type":17,"tag":243,"props":8045,"children":8046},{"style":262},[8047],{"type":22,"value":6935},{"type":17,"tag":243,"props":8049,"children":8050},{"style":250},[8051],{"type":22,"value":7048},{"type":17,"tag":243,"props":8053,"children":8054},{"style":262},[8055],{"type":22,"value":8056},".clientHeight\n",{"type":17,"tag":243,"props":8058,"children":8059},{"class":245,"line":3441},[8060],{"type":17,"tag":243,"props":8061,"children":8062},{"style":2429},[8063],{"type":22,"value":8064},"      //Adjusting position for two cases:\n",{"type":17,"tag":243,"props":8066,"children":8067},{"class":245,"line":3449},[8068],{"type":17,"tag":243,"props":8069,"children":8070},{"style":2429},[8071],{"type":22,"value":8072},"      //a) mobile screens -> x\u003Cy\n",{"type":17,"tag":243,"props":8074,"children":8075},{"class":245,"line":3458},[8076],{"type":17,"tag":243,"props":8077,"children":8078},{"style":2429},[8079],{"type":22,"value":8080},"      //b) desktops -> x>y\n",{"type":17,"tag":243,"props":8082,"children":8083},{"class":245,"line":3499},[8084,8089,8093,8098,8102,8106,8110,8114,8118,8122,8126,8130,8135,8139],{"type":17,"tag":243,"props":8085,"children":8086},{"style":262},[8087],{"type":22,"value":8088},"      x ",{"type":17,"tag":243,"props":8090,"children":8091},{"style":250},[8092],{"type":22,"value":1502},{"type":17,"tag":243,"props":8094,"children":8095},{"style":262},[8096],{"type":22,"value":8097}," screenRatio ",{"type":17,"tag":243,"props":8099,"children":8100},{"style":250},[8101],{"type":22,"value":481},{"type":17,"tag":243,"props":8103,"children":8104},{"style":378},[8105],{"type":22,"value":467},{"type":17,"tag":243,"props":8107,"children":8108},{"style":250},[8109],{"type":22,"value":462},{"type":17,"tag":243,"props":8111,"children":8112},{"style":262},[8113],{"type":22,"value":289},{"type":17,"tag":243,"props":8115,"children":8116},{"style":250},[8117],{"type":22,"value":294},{"type":17,"tag":243,"props":8119,"children":8120},{"style":262},[8121],{"type":22,"value":1523},{"type":17,"tag":243,"props":8123,"children":8124},{"style":378},[8125],{"type":22,"value":551},{"type":17,"tag":243,"props":8127,"children":8128},{"style":250},[8129],{"type":22,"value":3819},{"type":17,"tag":243,"props":8131,"children":8132},{"style":262},[8133],{"type":22,"value":8134}," screenRatio) ",{"type":17,"tag":243,"props":8136,"children":8137},{"style":250},[8138],{"type":22,"value":925},{"type":17,"tag":243,"props":8140,"children":8141},{"style":262},[8142],{"type":22,"value":299},{"type":17,"tag":243,"props":8144,"children":8145},{"class":245,"line":3560},[8146,8151,8155,8159,8163,8167,8171,8175,8179,8183,8187],{"type":17,"tag":243,"props":8147,"children":8148},{"style":262},[8149],{"type":22,"value":8150},"      y ",{"type":17,"tag":243,"props":8152,"children":8153},{"style":250},[8154],{"type":22,"value":1502},{"type":17,"tag":243,"props":8156,"children":8157},{"style":262},[8158],{"type":22,"value":8097},{"type":17,"tag":243,"props":8160,"children":8161},{"style":250},[8162],{"type":22,"value":1627},{"type":17,"tag":243,"props":8164,"children":8165},{"style":378},[8166],{"type":22,"value":467},{"type":17,"tag":243,"props":8168,"children":8169},{"style":250},[8170],{"type":22,"value":462},{"type":17,"tag":243,"props":8172,"children":8173},{"style":262},[8174],{"type":22,"value":8030},{"type":17,"tag":243,"props":8176,"children":8177},{"style":250},[8178],{"type":22,"value":294},{"type":17,"tag":243,"props":8180,"children":8181},{"style":262},[8182],{"type":22,"value":8097},{"type":17,"tag":243,"props":8184,"children":8185},{"style":250},[8186],{"type":22,"value":925},{"type":17,"tag":243,"props":8188,"children":8189},{"style":262},[8190],{"type":22,"value":8191}," y;\n",{"type":17,"tag":243,"props":8193,"children":8194},{"class":245,"line":3582},[8195,8200,8204,8208,8213,8217,8221,8225,8229,8234,8239,8243,8247,8251,8255,8259,8263,8267,8271,8275,8280,8284,8288,8292,8296,8300,8304,8308,8312,8316,8321,8325,8329,8334],{"type":17,"tag":243,"props":8196,"children":8197},{"style":250},[8198],{"type":22,"value":8199},"      if",{"type":17,"tag":243,"props":8201,"children":8202},{"style":262},[8203],{"type":22,"value":1523},{"type":17,"tag":243,"props":8205,"children":8206},{"style":250},[8207],{"type":22,"value":7048},{"type":17,"tag":243,"props":8209,"children":8210},{"style":262},[8211],{"type":22,"value":8212},"(x ",{"type":17,"tag":243,"props":8214,"children":8215},{"style":250},[8216],{"type":22,"value":481},{"type":17,"tag":243,"props":8218,"children":8219},{"style":378},[8220],{"type":22,"value":467},{"type":17,"tag":243,"props":8222,"children":8223},{"style":262},[8224],{"type":22,"value":1637},{"type":17,"tag":243,"props":8226,"children":8227},{"style":250},[8228],{"type":22,"value":4604},{"type":17,"tag":243,"props":8230,"children":8231},{"style":250},[8232],{"type":22,"value":8233}," !",{"type":17,"tag":243,"props":8235,"children":8236},{"style":262},[8237],{"type":22,"value":8238},"(y ",{"type":17,"tag":243,"props":8240,"children":8241},{"style":250},[8242],{"type":22,"value":481},{"type":17,"tag":243,"props":8244,"children":8245},{"style":378},[8246],{"type":22,"value":467},{"type":17,"tag":243,"props":8248,"children":8249},{"style":262},[8250],{"type":22,"value":1637},{"type":17,"tag":243,"props":8252,"children":8253},{"style":250},[8254],{"type":22,"value":4604},{"type":17,"tag":243,"props":8256,"children":8257},{"style":250},[8258],{"type":22,"value":8233},{"type":17,"tag":243,"props":8260,"children":8261},{"style":262},[8262],{"type":22,"value":8212},{"type":17,"tag":243,"props":8264,"children":8265},{"style":250},[8266],{"type":22,"value":1627},{"type":17,"tag":243,"props":8268,"children":8269},{"style":262},[8270],{"type":22,"value":6935},{"type":17,"tag":243,"props":8272,"children":8273},{"style":250},[8274],{"type":22,"value":7048},{"type":17,"tag":243,"props":8276,"children":8277},{"style":262},[8278],{"type":22,"value":8279},".clientWidth ",{"type":17,"tag":243,"props":8281,"children":8282},{"style":250},[8283],{"type":22,"value":375},{"type":17,"tag":243,"props":8285,"children":8286},{"style":378},[8287],{"type":22,"value":467},{"type":17,"tag":243,"props":8289,"children":8290},{"style":262},[8291],{"type":22,"value":1637},{"type":17,"tag":243,"props":8293,"children":8294},{"style":250},[8295],{"type":22,"value":4604},{"type":17,"tag":243,"props":8297,"children":8298},{"style":250},[8299],{"type":22,"value":8233},{"type":17,"tag":243,"props":8301,"children":8302},{"style":262},[8303],{"type":22,"value":8238},{"type":17,"tag":243,"props":8305,"children":8306},{"style":250},[8307],{"type":22,"value":1627},{"type":17,"tag":243,"props":8309,"children":8310},{"style":262},[8311],{"type":22,"value":6935},{"type":17,"tag":243,"props":8313,"children":8314},{"style":250},[8315],{"type":22,"value":7048},{"type":17,"tag":243,"props":8317,"children":8318},{"style":262},[8319],{"type":22,"value":8320},".clientHeight ",{"type":17,"tag":243,"props":8322,"children":8323},{"style":250},[8324],{"type":22,"value":375},{"type":17,"tag":243,"props":8326,"children":8327},{"style":378},[8328],{"type":22,"value":467},{"type":17,"tag":243,"props":8330,"children":8331},{"style":262},[8332],{"type":22,"value":8333},")) { ",{"type":17,"tag":243,"props":8335,"children":8336},{"style":2429},[8337],{"type":22,"value":8338},"//avoid blinking at edges due to how space wrapping is done\n",{"type":17,"tag":243,"props":8340,"children":8341},{"class":245,"line":3615},[8342],{"type":17,"tag":243,"props":8343,"children":8344},{"style":2429},[8345],{"type":22,"value":8346},"        //Drawing the actual particle\n",{"type":17,"tag":243,"props":8348,"children":8349},{"class":245,"line":3647},[8350,8355,8359,8363,8368,8373,8377,8381,8385,8389,8393,8397,8401,8406,8410],{"type":17,"tag":243,"props":8351,"children":8352},{"style":262},[8353],{"type":22,"value":8354},"        context",{"type":17,"tag":243,"props":8356,"children":8357},{"style":250},[8358],{"type":22,"value":7048},{"type":17,"tag":243,"props":8360,"children":8361},{"style":262},[8362],{"type":22,"value":595},{"type":17,"tag":243,"props":8364,"children":8365},{"style":256},[8366],{"type":22,"value":8367},"arc",{"type":17,"tag":243,"props":8369,"children":8370},{"style":262},[8371],{"type":22,"value":8372},"(x, y, ",{"type":17,"tag":243,"props":8374,"children":8375},{"style":378},[8376],{"type":22,"value":551},{"type":17,"tag":243,"props":8378,"children":8379},{"style":262},[8380],{"type":22,"value":335},{"type":17,"tag":243,"props":8382,"children":8383},{"style":378},[8384],{"type":22,"value":2070},{"type":17,"tag":243,"props":8386,"children":8387},{"style":262},[8388],{"type":22,"value":335},{"type":17,"tag":243,"props":8390,"children":8391},{"style":378},[8392],{"type":22,"value":3814},{"type":17,"tag":243,"props":8394,"children":8395},{"style":250},[8396],{"type":22,"value":386},{"type":17,"tag":243,"props":8398,"children":8399},{"style":262},[8400],{"type":22,"value":2579},{"type":17,"tag":243,"props":8402,"children":8403},{"style":378},[8404],{"type":22,"value":8405},"PI",{"type":17,"tag":243,"props":8407,"children":8408},{"style":262},[8409],{"type":22,"value":7022},{"type":17,"tag":243,"props":8411,"children":8412},{"style":2429},[8413],{"type":22,"value":8414},"//js compilers are smart enough for me not to have to move math.pi to var\n",{"type":17,"tag":243,"props":8416,"children":8417},{"class":245,"line":3655},[8418,8422,8426,8430,8434,8439,8444,8448,8452,8457,8462,8467,8471,8475,8479,8483,8488],{"type":17,"tag":243,"props":8419,"children":8420},{"style":262},[8421],{"type":22,"value":8354},{"type":17,"tag":243,"props":8423,"children":8424},{"style":250},[8425],{"type":22,"value":7048},{"type":17,"tag":243,"props":8427,"children":8428},{"style":262},[8429],{"type":22,"value":7821},{"type":17,"tag":243,"props":8431,"children":8432},{"style":250},[8433],{"type":22,"value":1502},{"type":17,"tag":243,"props":8435,"children":8436},{"style":981},[8437],{"type":22,"value":8438}," `hsl(${",{"type":17,"tag":243,"props":8440,"children":8441},{"style":378},[8442],{"type":22,"value":8443},"360",{"type":17,"tag":243,"props":8445,"children":8446},{"style":250},[8447],{"type":22,"value":386},{"type":17,"tag":243,"props":8449,"children":8450},{"style":981},[8451],{"type":22,"value":1523},{"type":17,"tag":243,"props":8453,"children":8454},{"style":262},[8455],{"type":22,"value":8456},"colors",{"type":17,"tag":243,"props":8458,"children":8459},{"style":981},[8460],{"type":22,"value":8461},"[",{"type":17,"tag":243,"props":8463,"children":8464},{"style":262},[8465],{"type":22,"value":8466},"i",{"type":17,"tag":243,"props":8468,"children":8469},{"style":981},[8470],{"type":22,"value":2631},{"type":17,"tag":243,"props":8472,"children":8473},{"style":250},[8474],{"type":22,"value":7128},{"type":17,"tag":243,"props":8476,"children":8477},{"style":262},[8478],{"type":22,"value":7257},{"type":17,"tag":243,"props":8480,"children":8481},{"style":981},[8482],{"type":22,"value":7228},{"type":17,"tag":243,"props":8484,"children":8485},{"style":981},[8486],{"type":22,"value":8487},"},100%,50%)`",{"type":17,"tag":243,"props":8489,"children":8490},{"style":262},[8491],{"type":22,"value":507},{"type":17,"tag":243,"props":8493,"children":8494},{"class":245,"line":3684},[8495,8499,8503,8507,8512],{"type":17,"tag":243,"props":8496,"children":8497},{"style":262},[8498],{"type":22,"value":8354},{"type":17,"tag":243,"props":8500,"children":8501},{"style":250},[8502],{"type":22,"value":7048},{"type":17,"tag":243,"props":8504,"children":8505},{"style":262},[8506],{"type":22,"value":595},{"type":17,"tag":243,"props":8508,"children":8509},{"style":256},[8510],{"type":22,"value":8511},"fill",{"type":17,"tag":243,"props":8513,"children":8514},{"style":262},[8515],{"type":22,"value":2191},{"type":17,"tag":243,"props":8517,"children":8518},{"class":245,"line":3693},[8519],{"type":17,"tag":243,"props":8520,"children":8521},{"style":262},[8522],{"type":22,"value":5230},{"type":17,"tag":243,"props":8524,"children":8525},{"class":245,"line":3721},[8526],{"type":17,"tag":243,"props":8527,"children":8528},{"style":262},[8529],{"type":22,"value":4207},{"type":17,"tag":243,"props":8531,"children":8532},{"class":245,"line":3729},[8533],{"type":17,"tag":243,"props":8534,"children":8535},{"emptyLinePlaceholder":2340},[8536],{"type":22,"value":2932},{"type":17,"tag":243,"props":8538,"children":8539},{"class":245,"line":6211},[8540,8545],{"type":17,"tag":243,"props":8541,"children":8542},{"style":256},[8543],{"type":22,"value":8544},"    updateParticles",{"type":17,"tag":243,"props":8546,"children":8547},{"style":262},[8548],{"type":22,"value":2191},{"type":17,"tag":243,"props":8550,"children":8551},{"class":245,"line":6220},[8552],{"type":17,"tag":243,"props":8553,"children":8554},{"style":2429},[8555],{"type":22,"value":8556},"    // Native window method to request animation frame. Note: The frequency of calls aims to match the display refresh rate.\n",{"type":17,"tag":243,"props":8558,"children":8559},{"class":245,"line":6229},[8560],{"type":17,"tag":243,"props":8561,"children":8562},{"style":2429},[8563],{"type":22,"value":8564},"    // This method passes DOMHighResTimeStamp as an argument to callback, so that we can calculate how much our animation should progress in one frame\n",{"type":17,"tag":243,"props":8566,"children":8567},{"class":245,"line":6237},[8568],{"type":17,"tag":243,"props":8569,"children":8570},{"style":2429},[8571],{"type":22,"value":8572},"    // Otherwise there will be different speed for animation on screens with different refresh rates\n",{"type":17,"tag":243,"props":8574,"children":8575},{"class":245,"line":6246},[8576,8581],{"type":17,"tag":243,"props":8577,"children":8578},{"style":256},[8579],{"type":22,"value":8580},"    requestAnimationFrame",{"type":17,"tag":243,"props":8582,"children":8583},{"style":262},[8584],{"type":22,"value":8585},"(renderFrame);\n",{"type":17,"tag":243,"props":8587,"children":8588},{"class":245,"line":6255},[8589],{"type":17,"tag":243,"props":8590,"children":8591},{"style":262},[8592],{"type":22,"value":1413},{"type":17,"tag":243,"props":8594,"children":8595},{"class":245,"line":6264},[8596],{"type":17,"tag":243,"props":8597,"children":8598},{"emptyLinePlaceholder":2340},[8599],{"type":22,"value":2932},{"type":17,"tag":243,"props":8601,"children":8602},{"class":245,"line":6273},[8603,8607,8612],{"type":17,"tag":243,"props":8604,"children":8605},{"style":250},[8606],{"type":22,"value":7787},{"type":17,"tag":243,"props":8608,"children":8609},{"style":256},[8610],{"type":22,"value":8611}," updateParticles",{"type":17,"tag":243,"props":8613,"children":8614},{"style":262},[8615],{"type":22,"value":2044},{"type":17,"tag":243,"props":8617,"children":8618},{"class":245,"line":6282},[8619,8623,8627,8631,8635,8639,8643,8647,8651,8655,8659],{"type":17,"tag":243,"props":8620,"children":8621},{"style":250},[8622],{"type":22,"value":4114},{"type":17,"tag":243,"props":8624,"children":8625},{"style":262},[8626],{"type":22,"value":1523},{"type":17,"tag":243,"props":8628,"children":8629},{"style":250},[8630],{"type":22,"value":1592},{"type":17,"tag":243,"props":8632,"children":8633},{"style":262},[8634],{"type":22,"value":1497},{"type":17,"tag":243,"props":8636,"children":8637},{"style":250},[8638],{"type":22,"value":1502},{"type":17,"tag":243,"props":8640,"children":8641},{"style":378},[8642],{"type":22,"value":457},{"type":17,"tag":243,"props":8644,"children":8645},{"style":262},[8646],{"type":22,"value":1962},{"type":17,"tag":243,"props":8648,"children":8649},{"style":250},[8650],{"type":22,"value":481},{"type":17,"tag":243,"props":8652,"children":8653},{"style":262},[8654],{"type":22,"value":7610},{"type":17,"tag":243,"props":8656,"children":8657},{"style":250},[8658],{"type":22,"value":1550},{"type":17,"tag":243,"props":8660,"children":8661},{"style":262},[8662],{"type":22,"value":276},{"type":17,"tag":243,"props":8664,"children":8665},{"class":245,"line":6291},[8666,8670,8675,8679,8683],{"type":17,"tag":243,"props":8667,"children":8668},{"style":250},[8669],{"type":22,"value":7988},{"type":17,"tag":243,"props":8671,"children":8672},{"style":262},[8673],{"type":22,"value":8674}," totalForceX ",{"type":17,"tag":243,"props":8676,"children":8677},{"style":250},[8678],{"type":22,"value":1502},{"type":17,"tag":243,"props":8680,"children":8681},{"style":378},[8682],{"type":22,"value":457},{"type":17,"tag":243,"props":8684,"children":8685},{"style":262},[8686],{"type":22,"value":507},{"type":17,"tag":243,"props":8688,"children":8689},{"class":245,"line":6300},[8690,8694,8699,8703,8707],{"type":17,"tag":243,"props":8691,"children":8692},{"style":250},[8693],{"type":22,"value":7988},{"type":17,"tag":243,"props":8695,"children":8696},{"style":262},[8697],{"type":22,"value":8698}," totalForceY ",{"type":17,"tag":243,"props":8700,"children":8701},{"style":250},[8702],{"type":22,"value":1502},{"type":17,"tag":243,"props":8704,"children":8705},{"style":378},[8706],{"type":22,"value":457},{"type":17,"tag":243,"props":8708,"children":8709},{"style":262},[8710],{"type":22,"value":507},{"type":17,"tag":243,"props":8712,"children":8713},{"class":245,"line":6309},[8714,8718,8722,8726,8730,8734,8738,8742,8746,8751,8755],{"type":17,"tag":243,"props":8715,"children":8716},{"style":250},[8717],{"type":22,"value":4476},{"type":17,"tag":243,"props":8719,"children":8720},{"style":262},[8721],{"type":22,"value":1523},{"type":17,"tag":243,"props":8723,"children":8724},{"style":250},[8725],{"type":22,"value":1592},{"type":17,"tag":243,"props":8727,"children":8728},{"style":262},[8729],{"type":22,"value":4076},{"type":17,"tag":243,"props":8731,"children":8732},{"style":250},[8733],{"type":22,"value":1502},{"type":17,"tag":243,"props":8735,"children":8736},{"style":378},[8737],{"type":22,"value":457},{"type":17,"tag":243,"props":8739,"children":8740},{"style":262},[8741],{"type":22,"value":4089},{"type":17,"tag":243,"props":8743,"children":8744},{"style":250},[8745],{"type":22,"value":481},{"type":17,"tag":243,"props":8747,"children":8748},{"style":262},[8749],{"type":22,"value":8750}," n; j",{"type":17,"tag":243,"props":8752,"children":8753},{"style":250},[8754],{"type":22,"value":1550},{"type":17,"tag":243,"props":8756,"children":8757},{"style":262},[8758],{"type":22,"value":276},{"type":17,"tag":243,"props":8760,"children":8761},{"class":245,"line":6318},[8762,8766,8770,8774,8778,8783],{"type":17,"tag":243,"props":8763,"children":8764},{"style":250},[8765],{"type":22,"value":4548},{"type":17,"tag":243,"props":8767,"children":8768},{"style":262},[8769],{"type":22,"value":1622},{"type":17,"tag":243,"props":8771,"children":8772},{"style":250},[8773],{"type":22,"value":452},{"type":17,"tag":243,"props":8775,"children":8776},{"style":262},[8777],{"type":22,"value":4724},{"type":17,"tag":243,"props":8779,"children":8780},{"style":250},[8781],{"type":22,"value":8782},"continue",{"type":17,"tag":243,"props":8784,"children":8785},{"style":262},[8786],{"type":22,"value":507},{"type":17,"tag":243,"props":8788,"children":8789},{"class":245,"line":6327},[8790,8795,8799,8803,8808,8812],{"type":17,"tag":243,"props":8791,"children":8792},{"style":250},[8793],{"type":22,"value":8794},"        let",{"type":17,"tag":243,"props":8796,"children":8797},{"style":262},[8798],{"type":22,"value":289},{"type":17,"tag":243,"props":8800,"children":8801},{"style":250},[8802],{"type":22,"value":1502},{"type":17,"tag":243,"props":8804,"children":8805},{"style":262},[8806],{"type":22,"value":8807}," positionsX[j] ",{"type":17,"tag":243,"props":8809,"children":8810},{"style":250},[8811],{"type":22,"value":375},{"type":17,"tag":243,"props":8813,"children":8814},{"style":262},[8815],{"type":22,"value":8816}," positionsX[i];\n",{"type":17,"tag":243,"props":8818,"children":8819},{"class":245,"line":6335},[8820,8824,8828,8832,8837,8841],{"type":17,"tag":243,"props":8821,"children":8822},{"style":250},[8823],{"type":22,"value":8794},{"type":17,"tag":243,"props":8825,"children":8826},{"style":262},[8827],{"type":22,"value":8030},{"type":17,"tag":243,"props":8829,"children":8830},{"style":250},[8831],{"type":22,"value":1502},{"type":17,"tag":243,"props":8833,"children":8834},{"style":262},[8835],{"type":22,"value":8836}," positionsY[j] ",{"type":17,"tag":243,"props":8838,"children":8839},{"style":250},[8840],{"type":22,"value":375},{"type":17,"tag":243,"props":8842,"children":8843},{"style":262},[8844],{"type":22,"value":8845}," positionsY[i];\n",{"type":17,"tag":243,"props":8847,"children":8848},{"class":245,"line":6343},[8849,8853,8858,8862,8866,8871,8875,8879,8883,8887,8891,8895,8900],{"type":17,"tag":243,"props":8850,"children":8851},{"style":250},[8852],{"type":22,"value":8794},{"type":17,"tag":243,"props":8854,"children":8855},{"style":262},[8856],{"type":22,"value":8857}," d ",{"type":17,"tag":243,"props":8859,"children":8860},{"style":250},[8861],{"type":22,"value":1502},{"type":17,"tag":243,"props":8863,"children":8864},{"style":262},[8865],{"type":22,"value":2579},{"type":17,"tag":243,"props":8867,"children":8868},{"style":256},[8869],{"type":22,"value":8870},"sqrt",{"type":17,"tag":243,"props":8872,"children":8873},{"style":262},[8874],{"type":22,"value":8212},{"type":17,"tag":243,"props":8876,"children":8877},{"style":250},[8878],{"type":22,"value":294},{"type":17,"tag":243,"props":8880,"children":8881},{"style":262},[8882],{"type":22,"value":289},{"type":17,"tag":243,"props":8884,"children":8885},{"style":250},[8886],{"type":22,"value":1891},{"type":17,"tag":243,"props":8888,"children":8889},{"style":262},[8890],{"type":22,"value":8030},{"type":17,"tag":243,"props":8892,"children":8893},{"style":250},[8894],{"type":22,"value":294},{"type":17,"tag":243,"props":8896,"children":8897},{"style":262},[8898],{"type":22,"value":8899}," y); ",{"type":17,"tag":243,"props":8901,"children":8902},{"style":2429},[8903],{"type":22,"value":8904},"// No performance advantage in removing math.sqrt. 10x faster than math.hypot.\n",{"type":17,"tag":243,"props":8906,"children":8907},{"class":245,"line":6351},[8908,8912,8917,8921],{"type":17,"tag":243,"props":8909,"children":8910},{"style":250},[8911],{"type":22,"value":4548},{"type":17,"tag":243,"props":8913,"children":8914},{"style":262},[8915],{"type":22,"value":8916}," (d ",{"type":17,"tag":243,"props":8918,"children":8919},{"style":250},[8920],{"type":22,"value":481},{"type":17,"tag":243,"props":8922,"children":8923},{"style":262},[8924],{"type":22,"value":8925}," radius) {\n",{"type":17,"tag":243,"props":8927,"children":8928},{"class":245,"line":6359},[8929,8934,8939,8943,8948],{"type":17,"tag":243,"props":8930,"children":8931},{"style":250},[8932],{"type":22,"value":8933},"          let",{"type":17,"tag":243,"props":8935,"children":8936},{"style":262},[8937],{"type":22,"value":8938}," f ",{"type":17,"tag":243,"props":8940,"children":8941},{"style":250},[8942],{"type":22,"value":1502},{"type":17,"tag":243,"props":8944,"children":8945},{"style":256},[8946],{"type":22,"value":8947}," force",{"type":17,"tag":243,"props":8949,"children":8950},{"style":262},[8951],{"type":22,"value":8952},"(\n",{"type":17,"tag":243,"props":8954,"children":8955},{"class":245,"line":6368},[8956,8961,8965],{"type":17,"tag":243,"props":8957,"children":8958},{"style":262},[8959],{"type":22,"value":8960},"            d ",{"type":17,"tag":243,"props":8962,"children":8963},{"style":250},[8964],{"type":22,"value":7128},{"type":17,"tag":243,"props":8966,"children":8967},{"style":262},[8968],{"type":22,"value":8969}," radius,\n",{"type":17,"tag":243,"props":8971,"children":8972},{"class":245,"line":6377},[8973],{"type":17,"tag":243,"props":8974,"children":8975},{"style":262},[8976],{"type":22,"value":8977},"            matrix[colors[i]][colors[j]])\n",{"type":17,"tag":243,"props":8979,"children":8980},{"class":245,"line":6386},[8981,8986,8990,8995,8999,9004,9008],{"type":17,"tag":243,"props":8982,"children":8983},{"style":262},[8984],{"type":22,"value":8985},"          totalForceX ",{"type":17,"tag":243,"props":8987,"children":8988},{"style":250},[8989],{"type":22,"value":2554},{"type":17,"tag":243,"props":8991,"children":8992},{"style":262},[8993],{"type":22,"value":8994}," (x ",{"type":17,"tag":243,"props":8996,"children":8997},{"style":250},[8998],{"type":22,"value":7128},{"type":17,"tag":243,"props":9000,"children":9001},{"style":262},[9002],{"type":22,"value":9003}," d) ",{"type":17,"tag":243,"props":9005,"children":9006},{"style":250},[9007],{"type":22,"value":294},{"type":17,"tag":243,"props":9009,"children":9010},{"style":262},[9011],{"type":22,"value":9012}," f;\n",{"type":17,"tag":243,"props":9014,"children":9015},{"class":245,"line":6395},[9016,9021,9025,9030,9034,9038,9042],{"type":17,"tag":243,"props":9017,"children":9018},{"style":262},[9019],{"type":22,"value":9020},"          totalForceY ",{"type":17,"tag":243,"props":9022,"children":9023},{"style":250},[9024],{"type":22,"value":2554},{"type":17,"tag":243,"props":9026,"children":9027},{"style":262},[9028],{"type":22,"value":9029}," (y ",{"type":17,"tag":243,"props":9031,"children":9032},{"style":250},[9033],{"type":22,"value":7128},{"type":17,"tag":243,"props":9035,"children":9036},{"style":262},[9037],{"type":22,"value":9003},{"type":17,"tag":243,"props":9039,"children":9040},{"style":250},[9041],{"type":22,"value":294},{"type":17,"tag":243,"props":9043,"children":9044},{"style":262},[9045],{"type":22,"value":9012},{"type":17,"tag":243,"props":9047,"children":9048},{"class":245,"line":6403},[9049],{"type":17,"tag":243,"props":9050,"children":9051},{"style":262},[9052],{"type":22,"value":5222},{"type":17,"tag":243,"props":9054,"children":9055},{"class":245,"line":6412},[9056,9061,9065],{"type":17,"tag":243,"props":9057,"children":9058},{"style":262},[9059],{"type":22,"value":9060},"        velocitiesX[i] ",{"type":17,"tag":243,"props":9062,"children":9063},{"style":250},[9064],{"type":22,"value":2554},{"type":17,"tag":243,"props":9066,"children":9067},{"style":262},[9068],{"type":22,"value":9069}," totalForceX;\n",{"type":17,"tag":243,"props":9071,"children":9072},{"class":245,"line":6420},[9073,9078,9082],{"type":17,"tag":243,"props":9074,"children":9075},{"style":262},[9076],{"type":22,"value":9077},"        velocitiesY[i] ",{"type":17,"tag":243,"props":9079,"children":9080},{"style":250},[9081],{"type":22,"value":2554},{"type":17,"tag":243,"props":9083,"children":9084},{"style":262},[9085],{"type":22,"value":9086}," totalForceY;\n",{"type":17,"tag":243,"props":9088,"children":9089},{"class":245,"line":6429},[9090],{"type":17,"tag":243,"props":9091,"children":9092},{"emptyLinePlaceholder":2340},[9093],{"type":22,"value":2932},{"type":17,"tag":243,"props":9095,"children":9096},{"class":245,"line":6438},[9097,9101,9106],{"type":17,"tag":243,"props":9098,"children":9099},{"style":262},[9100],{"type":22,"value":9060},{"type":17,"tag":243,"props":9102,"children":9103},{"style":250},[9104],{"type":22,"value":9105},"*=",{"type":17,"tag":243,"props":9107,"children":9108},{"style":262},[9109],{"type":22,"value":9110}," fr;\n",{"type":17,"tag":243,"props":9112,"children":9113},{"class":245,"line":6446},[9114,9118,9122],{"type":17,"tag":243,"props":9115,"children":9116},{"style":262},[9117],{"type":22,"value":9077},{"type":17,"tag":243,"props":9119,"children":9120},{"style":250},[9121],{"type":22,"value":9105},{"type":17,"tag":243,"props":9123,"children":9124},{"style":262},[9125],{"type":22,"value":9110},{"type":17,"tag":243,"props":9127,"children":9128},{"class":245,"line":6454},[9129],{"type":17,"tag":243,"props":9130,"children":9131},{"emptyLinePlaceholder":2340},[9132],{"type":22,"value":2932},{"type":17,"tag":243,"props":9134,"children":9136},{"class":245,"line":9135},86,[9137,9142,9146],{"type":17,"tag":243,"props":9138,"children":9139},{"style":262},[9140],{"type":22,"value":9141},"        positionsX[i] ",{"type":17,"tag":243,"props":9143,"children":9144},{"style":250},[9145],{"type":22,"value":2554},{"type":17,"tag":243,"props":9147,"children":9148},{"style":262},[9149],{"type":22,"value":9150}," velocitiesX[i];\n",{"type":17,"tag":243,"props":9152,"children":9154},{"class":245,"line":9153},87,[9155,9160,9164],{"type":17,"tag":243,"props":9156,"children":9157},{"style":262},[9158],{"type":22,"value":9159},"        positionsY[i] ",{"type":17,"tag":243,"props":9161,"children":9162},{"style":250},[9163],{"type":22,"value":2554},{"type":17,"tag":243,"props":9165,"children":9166},{"style":262},[9167],{"type":22,"value":9168}," velocitiesY[i];\n",{"type":17,"tag":243,"props":9170,"children":9172},{"class":245,"line":9171},88,[9173],{"type":17,"tag":243,"props":9174,"children":9175},{"emptyLinePlaceholder":2340},[9176],{"type":22,"value":2932},{"type":17,"tag":243,"props":9178,"children":9180},{"class":245,"line":9179},89,[9181,9186,9190],{"type":17,"tag":243,"props":9182,"children":9183},{"style":262},[9184],{"type":22,"value":9185},"        x ",{"type":17,"tag":243,"props":9187,"children":9188},{"style":250},[9189],{"type":22,"value":1502},{"type":17,"tag":243,"props":9191,"children":9192},{"style":262},[9193],{"type":22,"value":8816},{"type":17,"tag":243,"props":9195,"children":9197},{"class":245,"line":9196},90,[9198,9203,9207],{"type":17,"tag":243,"props":9199,"children":9200},{"style":262},[9201],{"type":22,"value":9202},"        y ",{"type":17,"tag":243,"props":9204,"children":9205},{"style":250},[9206],{"type":22,"value":1502},{"type":17,"tag":243,"props":9208,"children":9209},{"style":262},[9210],{"type":22,"value":8845},{"type":17,"tag":243,"props":9212,"children":9214},{"class":245,"line":9213},91,[9215],{"type":17,"tag":243,"props":9216,"children":9217},{"emptyLinePlaceholder":2340},[9218],{"type":22,"value":2932},{"type":17,"tag":243,"props":9220,"children":9222},{"class":245,"line":9221},92,[9223],{"type":17,"tag":243,"props":9224,"children":9225},{"style":2429},[9226],{"type":22,"value":9227},"        // Prevent particles from running away from the viewport. \n",{"type":17,"tag":243,"props":9229,"children":9231},{"class":245,"line":9230},93,[9232],{"type":17,"tag":243,"props":9233,"children":9234},{"style":2429},[9235],{"type":22,"value":9236},"        // If x or y is > 1, substract 1 from it, so that it moves to other part of the screen\n",{"type":17,"tag":243,"props":9238,"children":9240},{"class":245,"line":9239},94,[9241],{"type":17,"tag":243,"props":9242,"children":9243},{"style":2429},[9244],{"type":22,"value":9245},"        // This only handles particle position - it's not interacting with \n",{"type":17,"tag":243,"props":9247,"children":9249},{"class":245,"line":9248},95,[9250],{"type":17,"tag":243,"props":9251,"children":9252},{"style":2429},[9253],{"type":22,"value":9254},"        // particles from the other side of the screen. In other words, particle at position (0,0) with radius of 0.1\n",{"type":17,"tag":243,"props":9256,"children":9258},{"class":245,"line":9257},96,[9259],{"type":17,"tag":243,"props":9260,"children":9261},{"style":2429},[9262],{"type":22,"value":9263},"        // will not interact with particle at position (1.0,1.0). This gives us interesting visual effect (see for GPU.js examples screenshots)\n",{"type":17,"tag":243,"props":9265,"children":9267},{"class":245,"line":9266},97,[9268],{"type":17,"tag":243,"props":9269,"children":9270},{"style":2429},[9271],{"type":22,"value":9272},"        // but also causes some issues, like particles aggregating at the edges\n",{"type":17,"tag":243,"props":9274,"children":9276},{"class":245,"line":9275},98,[9277],{"type":17,"tag":243,"props":9278,"children":9279},{"emptyLinePlaceholder":2340},[9280],{"type":22,"value":2932},{"type":17,"tag":243,"props":9282,"children":9284},{"class":245,"line":9283},99,[9285,9289,9293,9297,9301,9305,9309,9313,9317,9321,9325],{"type":17,"tag":243,"props":9286,"children":9287},{"style":262},[9288],{"type":22,"value":9185},{"type":17,"tag":243,"props":9290,"children":9291},{"style":250},[9292],{"type":22,"value":1502},{"type":17,"tag":243,"props":9294,"children":9295},{"style":262},[9296],{"type":22,"value":289},{"type":17,"tag":243,"props":9298,"children":9299},{"style":250},[9300],{"type":22,"value":1627},{"type":17,"tag":243,"props":9302,"children":9303},{"style":378},[9304],{"type":22,"value":467},{"type":17,"tag":243,"props":9306,"children":9307},{"style":250},[9308],{"type":22,"value":462},{"type":17,"tag":243,"props":9310,"children":9311},{"style":262},[9312],{"type":22,"value":289},{"type":17,"tag":243,"props":9314,"children":9315},{"style":250},[9316],{"type":22,"value":375},{"type":17,"tag":243,"props":9318,"children":9319},{"style":378},[9320],{"type":22,"value":467},{"type":17,"tag":243,"props":9322,"children":9323},{"style":250},[9324],{"type":22,"value":472},{"type":17,"tag":243,"props":9326,"children":9327},{"style":262},[9328],{"type":22,"value":299},{"type":17,"tag":243,"props":9330,"children":9332},{"class":245,"line":9331},100,[9333,9337,9341,9345,9349,9353,9357,9361,9365,9369,9373],{"type":17,"tag":243,"props":9334,"children":9335},{"style":262},[9336],{"type":22,"value":9202},{"type":17,"tag":243,"props":9338,"children":9339},{"style":250},[9340],{"type":22,"value":1502},{"type":17,"tag":243,"props":9342,"children":9343},{"style":262},[9344],{"type":22,"value":8030},{"type":17,"tag":243,"props":9346,"children":9347},{"style":250},[9348],{"type":22,"value":1627},{"type":17,"tag":243,"props":9350,"children":9351},{"style":378},[9352],{"type":22,"value":467},{"type":17,"tag":243,"props":9354,"children":9355},{"style":250},[9356],{"type":22,"value":462},{"type":17,"tag":243,"props":9358,"children":9359},{"style":262},[9360],{"type":22,"value":8030},{"type":17,"tag":243,"props":9362,"children":9363},{"style":250},[9364],{"type":22,"value":375},{"type":17,"tag":243,"props":9366,"children":9367},{"style":378},[9368],{"type":22,"value":467},{"type":17,"tag":243,"props":9370,"children":9371},{"style":250},[9372],{"type":22,"value":472},{"type":17,"tag":243,"props":9374,"children":9375},{"style":262},[9376],{"type":22,"value":8191},{"type":17,"tag":243,"props":9378,"children":9380},{"class":245,"line":9379},101,[9381,9385,9389,9393,9397,9401,9405,9409,9413,9417,9421],{"type":17,"tag":243,"props":9382,"children":9383},{"style":262},[9384],{"type":22,"value":9185},{"type":17,"tag":243,"props":9386,"children":9387},{"style":250},[9388],{"type":22,"value":1502},{"type":17,"tag":243,"props":9390,"children":9391},{"style":262},[9392],{"type":22,"value":289},{"type":17,"tag":243,"props":9394,"children":9395},{"style":250},[9396],{"type":22,"value":481},{"type":17,"tag":243,"props":9398,"children":9399},{"style":378},[9400],{"type":22,"value":457},{"type":17,"tag":243,"props":9402,"children":9403},{"style":250},[9404],{"type":22,"value":462},{"type":17,"tag":243,"props":9406,"children":9407},{"style":262},[9408],{"type":22,"value":289},{"type":17,"tag":243,"props":9410,"children":9411},{"style":250},[9412],{"type":22,"value":1891},{"type":17,"tag":243,"props":9414,"children":9415},{"style":378},[9416],{"type":22,"value":467},{"type":17,"tag":243,"props":9418,"children":9419},{"style":250},[9420],{"type":22,"value":472},{"type":17,"tag":243,"props":9422,"children":9423},{"style":262},[9424],{"type":22,"value":299},{"type":17,"tag":243,"props":9426,"children":9428},{"class":245,"line":9427},102,[9429,9433,9437,9441,9445,9449,9453,9457,9461,9465,9469],{"type":17,"tag":243,"props":9430,"children":9431},{"style":262},[9432],{"type":22,"value":9202},{"type":17,"tag":243,"props":9434,"children":9435},{"style":250},[9436],{"type":22,"value":1502},{"type":17,"tag":243,"props":9438,"children":9439},{"style":262},[9440],{"type":22,"value":8030},{"type":17,"tag":243,"props":9442,"children":9443},{"style":250},[9444],{"type":22,"value":481},{"type":17,"tag":243,"props":9446,"children":9447},{"style":378},[9448],{"type":22,"value":457},{"type":17,"tag":243,"props":9450,"children":9451},{"style":250},[9452],{"type":22,"value":462},{"type":17,"tag":243,"props":9454,"children":9455},{"style":262},[9456],{"type":22,"value":8030},{"type":17,"tag":243,"props":9458,"children":9459},{"style":250},[9460],{"type":22,"value":1891},{"type":17,"tag":243,"props":9462,"children":9463},{"style":378},[9464],{"type":22,"value":467},{"type":17,"tag":243,"props":9466,"children":9467},{"style":250},[9468],{"type":22,"value":472},{"type":17,"tag":243,"props":9470,"children":9471},{"style":262},[9472],{"type":22,"value":8191},{"type":17,"tag":243,"props":9474,"children":9476},{"class":245,"line":9475},103,[9477],{"type":17,"tag":243,"props":9478,"children":9479},{"emptyLinePlaceholder":2340},[9480],{"type":22,"value":2932},{"type":17,"tag":243,"props":9482,"children":9484},{"class":245,"line":9483},104,[9485,9489,9493],{"type":17,"tag":243,"props":9486,"children":9487},{"style":262},[9488],{"type":22,"value":9141},{"type":17,"tag":243,"props":9490,"children":9491},{"style":250},[9492],{"type":22,"value":1502},{"type":17,"tag":243,"props":9494,"children":9495},{"style":262},[9496],{"type":22,"value":299},{"type":17,"tag":243,"props":9498,"children":9500},{"class":245,"line":9499},105,[9501,9505,9509],{"type":17,"tag":243,"props":9502,"children":9503},{"style":262},[9504],{"type":22,"value":9159},{"type":17,"tag":243,"props":9506,"children":9507},{"style":250},[9508],{"type":22,"value":1502},{"type":17,"tag":243,"props":9510,"children":9511},{"style":262},[9512],{"type":22,"value":8191},{"type":17,"tag":243,"props":9514,"children":9516},{"class":245,"line":9515},106,[9517],{"type":17,"tag":243,"props":9518,"children":9519},{"style":262},[9520],{"type":22,"value":5230},{"type":17,"tag":243,"props":9522,"children":9524},{"class":245,"line":9523},107,[9525],{"type":17,"tag":243,"props":9526,"children":9527},{"style":262},[9528],{"type":22,"value":4207},{"type":17,"tag":243,"props":9530,"children":9532},{"class":245,"line":9531},108,[9533],{"type":17,"tag":243,"props":9534,"children":9535},{"style":262},[9536],{"type":22,"value":1413},{"type":17,"tag":243,"props":9538,"children":9540},{"class":245,"line":9539},109,[9541],{"type":17,"tag":243,"props":9542,"children":9543},{"emptyLinePlaceholder":2340},[9544],{"type":22,"value":2932},{"type":17,"tag":243,"props":9546,"children":9548},{"class":245,"line":9547},110,[9549],{"type":17,"tag":243,"props":9550,"children":9551},{"style":2429},[9552],{"type":22,"value":9553},"  //Instead of using one force function allow user to choose from several options. \n",{"type":17,"tag":243,"props":9555,"children":9557},{"class":245,"line":9556},111,[9558],{"type":17,"tag":243,"props":9559,"children":9560},{"style":2429},[9561],{"type":22,"value":9562},"  //Graphs of every function (assuming the force value between two particles to be 1.0 and a repulsive radius of 1/4 of the max radius)\n",{"type":17,"tag":243,"props":9564,"children":9566},{"class":245,"line":9565},112,[9567],{"type":17,"tag":243,"props":9568,"children":9569},{"style":2429},[9570],{"type":22,"value":9571},"  //available on live site of the project\n",{"type":17,"tag":243,"props":9573,"children":9575},{"class":245,"line":9574},113,[9576],{"type":17,"tag":243,"props":9577,"children":9578},{"emptyLinePlaceholder":2340},[9579],{"type":22,"value":2932},{"type":17,"tag":243,"props":9581,"children":9583},{"class":245,"line":9582},114,[9584,9588,9592,9596,9601,9605,9609,9613,9618,9622,9626,9630,9634,9638],{"type":17,"tag":243,"props":9585,"children":9586},{"style":250},[9587],{"type":22,"value":7787},{"type":17,"tag":243,"props":9589,"children":9590},{"style":256},[9591],{"type":22,"value":8947},{"type":17,"tag":243,"props":9593,"children":9594},{"style":262},[9595],{"type":22,"value":265},{"type":17,"tag":243,"props":9597,"children":9598},{"style":268},[9599],{"type":22,"value":9600},"d",{"type":17,"tag":243,"props":9602,"children":9603},{"style":250},[9604],{"type":22,"value":925},{"type":17,"tag":243,"props":9606,"children":9607},{"style":378},[9608],{"type":22,"value":3938},{"type":17,"tag":243,"props":9610,"children":9611},{"style":262},[9612],{"type":22,"value":335},{"type":17,"tag":243,"props":9614,"children":9615},{"style":268},[9616],{"type":22,"value":9617},"f",{"type":17,"tag":243,"props":9619,"children":9620},{"style":250},[9621],{"type":22,"value":925},{"type":17,"tag":243,"props":9623,"children":9624},{"style":378},[9625],{"type":22,"value":3938},{"type":17,"tag":243,"props":9627,"children":9628},{"style":262},[9629],{"type":22,"value":7228},{"type":17,"tag":243,"props":9631,"children":9632},{"style":250},[9633],{"type":22,"value":925},{"type":17,"tag":243,"props":9635,"children":9636},{"style":378},[9637],{"type":22,"value":3938},{"type":17,"tag":243,"props":9639,"children":9640},{"style":262},[9641],{"type":22,"value":1370},{"type":17,"tag":243,"props":9643,"children":9645},{"class":245,"line":9644},115,[9646,9651,9656,9660],{"type":17,"tag":243,"props":9647,"children":9648},{"style":250},[9649],{"type":22,"value":9650},"    let",{"type":17,"tag":243,"props":9652,"children":9653},{"style":262},[9654],{"type":22,"value":9655}," repRadius ",{"type":17,"tag":243,"props":9657,"children":9658},{"style":250},[9659],{"type":22,"value":1502},{"type":17,"tag":243,"props":9661,"children":9662},{"style":262},[9663],{"type":22,"value":9664}," parameters.repulsiveRadius;\n",{"type":17,"tag":243,"props":9666,"children":9668},{"class":245,"line":9667},116,[9669,9674],{"type":17,"tag":243,"props":9670,"children":9671},{"style":250},[9672],{"type":22,"value":9673},"    switch",{"type":17,"tag":243,"props":9675,"children":9676},{"style":262},[9677],{"type":22,"value":9678}," (parameters.forceFunction) {\n",{"type":17,"tag":243,"props":9680,"children":9682},{"class":245,"line":9681},117,[9683,9688,9693],{"type":17,"tag":243,"props":9684,"children":9685},{"style":250},[9686],{"type":22,"value":9687},"      case",{"type":17,"tag":243,"props":9689,"children":9690},{"style":981},[9691],{"type":22,"value":9692}," '1'",{"type":17,"tag":243,"props":9694,"children":9695},{"style":262},[9696],{"type":22,"value":9697},":\n",{"type":17,"tag":243,"props":9699,"children":9701},{"class":245,"line":9700},118,[9702,9707,9712],{"type":17,"tag":243,"props":9703,"children":9704},{"style":250},[9705],{"type":22,"value":9706},"        return",{"type":17,"tag":243,"props":9708,"children":9709},{"style":256},[9710],{"type":22,"value":9711}," forceVariantI",{"type":17,"tag":243,"props":9713,"children":9714},{"style":262},[9715],{"type":22,"value":9716},"(d, f, repRadius);\n",{"type":17,"tag":243,"props":9718,"children":9720},{"class":245,"line":9719},119,[9721,9725,9730],{"type":17,"tag":243,"props":9722,"children":9723},{"style":250},[9724],{"type":22,"value":9687},{"type":17,"tag":243,"props":9726,"children":9727},{"style":981},[9728],{"type":22,"value":9729}," '2'",{"type":17,"tag":243,"props":9731,"children":9732},{"style":262},[9733],{"type":22,"value":9697},{"type":17,"tag":243,"props":9735,"children":9737},{"class":245,"line":9736},120,[9738,9742,9747],{"type":17,"tag":243,"props":9739,"children":9740},{"style":250},[9741],{"type":22,"value":9706},{"type":17,"tag":243,"props":9743,"children":9744},{"style":256},[9745],{"type":22,"value":9746}," forceVariantII",{"type":17,"tag":243,"props":9748,"children":9749},{"style":262},[9750],{"type":22,"value":9716},{"type":17,"tag":243,"props":9752,"children":9754},{"class":245,"line":9753},121,[9755,9759,9764],{"type":17,"tag":243,"props":9756,"children":9757},{"style":250},[9758],{"type":22,"value":9687},{"type":17,"tag":243,"props":9760,"children":9761},{"style":981},[9762],{"type":22,"value":9763}," '3'",{"type":17,"tag":243,"props":9765,"children":9766},{"style":262},[9767],{"type":22,"value":9697},{"type":17,"tag":243,"props":9769,"children":9771},{"class":245,"line":9770},122,[9772,9776,9781],{"type":17,"tag":243,"props":9773,"children":9774},{"style":250},[9775],{"type":22,"value":9706},{"type":17,"tag":243,"props":9777,"children":9778},{"style":256},[9779],{"type":22,"value":9780}," forceVariantIII",{"type":17,"tag":243,"props":9782,"children":9783},{"style":262},[9784],{"type":22,"value":9716},{"type":17,"tag":243,"props":9786,"children":9788},{"class":245,"line":9787},123,[9789,9794],{"type":17,"tag":243,"props":9790,"children":9791},{"style":250},[9792],{"type":22,"value":9793},"      default",{"type":17,"tag":243,"props":9795,"children":9796},{"style":262},[9797],{"type":22,"value":9697},{"type":17,"tag":243,"props":9799,"children":9801},{"class":245,"line":9800},124,[9802,9806,9811],{"type":17,"tag":243,"props":9803,"children":9804},{"style":250},[9805],{"type":22,"value":9706},{"type":17,"tag":243,"props":9807,"children":9808},{"style":256},[9809],{"type":22,"value":9810}," defaultForce",{"type":17,"tag":243,"props":9812,"children":9813},{"style":262},[9814],{"type":22,"value":9815},"(d, f, repRadius)\n",{"type":17,"tag":243,"props":9817,"children":9819},{"class":245,"line":9818},125,[9820],{"type":17,"tag":243,"props":9821,"children":9822},{"style":262},[9823],{"type":22,"value":4207},{"type":17,"tag":243,"props":9825,"children":9827},{"class":245,"line":9826},126,[9828],{"type":17,"tag":243,"props":9829,"children":9830},{"style":262},[9831],{"type":22,"value":1413},{"type":17,"tag":243,"props":9833,"children":9835},{"class":245,"line":9834},127,[9836],{"type":17,"tag":243,"props":9837,"children":9838},{"emptyLinePlaceholder":2340},[9839],{"type":22,"value":2932},{"type":17,"tag":243,"props":9841,"children":9843},{"class":245,"line":9842},128,[9844,9848,9852,9856,9860,9864,9868,9872,9876,9880,9884,9888,9893,9897,9901,9905,9909,9913],{"type":17,"tag":243,"props":9845,"children":9846},{"style":250},[9847],{"type":22,"value":7787},{"type":17,"tag":243,"props":9849,"children":9850},{"style":256},[9851],{"type":22,"value":9711},{"type":17,"tag":243,"props":9853,"children":9854},{"style":262},[9855],{"type":22,"value":265},{"type":17,"tag":243,"props":9857,"children":9858},{"style":268},[9859],{"type":22,"value":9600},{"type":17,"tag":243,"props":9861,"children":9862},{"style":250},[9863],{"type":22,"value":925},{"type":17,"tag":243,"props":9865,"children":9866},{"style":378},[9867],{"type":22,"value":3938},{"type":17,"tag":243,"props":9869,"children":9870},{"style":262},[9871],{"type":22,"value":335},{"type":17,"tag":243,"props":9873,"children":9874},{"style":268},[9875],{"type":22,"value":9617},{"type":17,"tag":243,"props":9877,"children":9878},{"style":250},[9879],{"type":22,"value":925},{"type":17,"tag":243,"props":9881,"children":9882},{"style":378},[9883],{"type":22,"value":3938},{"type":17,"tag":243,"props":9885,"children":9886},{"style":262},[9887],{"type":22,"value":335},{"type":17,"tag":243,"props":9889,"children":9890},{"style":268},[9891],{"type":22,"value":9892},"repRadius",{"type":17,"tag":243,"props":9894,"children":9895},{"style":250},[9896],{"type":22,"value":925},{"type":17,"tag":243,"props":9898,"children":9899},{"style":378},[9900],{"type":22,"value":3938},{"type":17,"tag":243,"props":9902,"children":9903},{"style":262},[9904],{"type":22,"value":7228},{"type":17,"tag":243,"props":9906,"children":9907},{"style":250},[9908],{"type":22,"value":925},{"type":17,"tag":243,"props":9910,"children":9911},{"style":378},[9912],{"type":22,"value":3938},{"type":17,"tag":243,"props":9914,"children":9915},{"style":262},[9916],{"type":22,"value":1370},{"type":17,"tag":243,"props":9918,"children":9920},{"class":245,"line":9919},129,[9921,9926,9930,9934],{"type":17,"tag":243,"props":9922,"children":9923},{"style":250},[9924],{"type":22,"value":9925},"    if",{"type":17,"tag":243,"props":9927,"children":9928},{"style":262},[9929],{"type":22,"value":8916},{"type":17,"tag":243,"props":9931,"children":9932},{"style":250},[9933],{"type":22,"value":1831},{"type":17,"tag":243,"props":9935,"children":9936},{"style":262},[9937],{"type":22,"value":9938}," repRadius) {\n",{"type":17,"tag":243,"props":9940,"children":9942},{"class":245,"line":9941},130,[9943,9948,9952,9956,9960,9964],{"type":17,"tag":243,"props":9944,"children":9945},{"style":250},[9946],{"type":22,"value":9947},"          return",{"type":17,"tag":243,"props":9949,"children":9950},{"style":262},[9951],{"type":22,"value":8857},{"type":17,"tag":243,"props":9953,"children":9954},{"style":250},[9955],{"type":22,"value":7128},{"type":17,"tag":243,"props":9957,"children":9958},{"style":262},[9959],{"type":22,"value":9655},{"type":17,"tag":243,"props":9961,"children":9962},{"style":250},[9963],{"type":22,"value":375},{"type":17,"tag":243,"props":9965,"children":9966},{"style":378},[9967],{"type":22,"value":5182},{"type":17,"tag":243,"props":9969,"children":9971},{"class":245,"line":9970},131,[9972,9977,9981],{"type":17,"tag":243,"props":9973,"children":9974},{"style":262},[9975],{"type":22,"value":9976},"        } ",{"type":17,"tag":243,"props":9978,"children":9979},{"style":250},[9980],{"type":22,"value":5461},{"type":17,"tag":243,"props":9982,"children":9983},{"style":262},[9984],{"type":22,"value":1370},{"type":17,"tag":243,"props":9986,"children":9988},{"class":245,"line":9987},132,[9989,9993,9997,10001,10005,10009,10013,10017,10022,10026,10030,10034,10038,10042,10046,10050,10055,10059,10063,10067],{"type":17,"tag":243,"props":9990,"children":9991},{"style":250},[9992],{"type":22,"value":9947},{"type":17,"tag":243,"props":9994,"children":9995},{"style":262},[9996],{"type":22,"value":8938},{"type":17,"tag":243,"props":9998,"children":9999},{"style":250},[10000],{"type":22,"value":294},{"type":17,"tag":243,"props":10002,"children":10003},{"style":262},[10004],{"type":22,"value":1523},{"type":17,"tag":243,"props":10006,"children":10007},{"style":378},[10008],{"type":22,"value":551},{"type":17,"tag":243,"props":10010,"children":10011},{"style":250},[10012],{"type":22,"value":2602},{"type":17,"tag":243,"props":10014,"children":10015},{"style":262},[10016],{"type":22,"value":2579},{"type":17,"tag":243,"props":10018,"children":10019},{"style":256},[10020],{"type":22,"value":10021},"abs",{"type":17,"tag":243,"props":10023,"children":10024},{"style":262},[10025],{"type":22,"value":265},{"type":17,"tag":243,"props":10027,"children":10028},{"style":378},[10029],{"type":22,"value":3814},{"type":17,"tag":243,"props":10031,"children":10032},{"style":250},[10033],{"type":22,"value":386},{"type":17,"tag":243,"props":10035,"children":10036},{"style":262},[10037],{"type":22,"value":8857},{"type":17,"tag":243,"props":10039,"children":10040},{"style":250},[10041],{"type":22,"value":375},{"type":17,"tag":243,"props":10043,"children":10044},{"style":378},[10045],{"type":22,"value":467},{"type":17,"tag":243,"props":10047,"children":10048},{"style":250},[10049],{"type":22,"value":2602},{"type":17,"tag":243,"props":10051,"children":10052},{"style":262},[10053],{"type":22,"value":10054}," repRadius) ",{"type":17,"tag":243,"props":10056,"children":10057},{"style":250},[10058],{"type":22,"value":7128},{"type":17,"tag":243,"props":10060,"children":10061},{"style":378},[10062],{"type":22,"value":467},{"type":17,"tag":243,"props":10064,"children":10065},{"style":250},[10066],{"type":22,"value":2602},{"type":17,"tag":243,"props":10068,"children":10069},{"style":262},[10070],{"type":22,"value":10071}," repRadius);\n",{"type":17,"tag":243,"props":10073,"children":10075},{"class":245,"line":10074},133,[10076],{"type":17,"tag":243,"props":10077,"children":10078},{"style":262},[10079],{"type":22,"value":5222},{"type":17,"tag":243,"props":10081,"children":10083},{"class":245,"line":10082},134,[10084],{"type":17,"tag":243,"props":10085,"children":10086},{"style":262},[10087],{"type":22,"value":1413},{"type":17,"tag":243,"props":10089,"children":10091},{"class":245,"line":10090},135,[10092],{"type":17,"tag":243,"props":10093,"children":10094},{"emptyLinePlaceholder":2340},[10095],{"type":22,"value":2932},{"type":17,"tag":243,"props":10097,"children":10099},{"class":245,"line":10098},136,[10100,10104,10108,10112,10116,10120,10124,10128,10132,10136,10140,10144,10148,10152,10156,10160,10164,10168],{"type":17,"tag":243,"props":10101,"children":10102},{"style":250},[10103],{"type":22,"value":7787},{"type":17,"tag":243,"props":10105,"children":10106},{"style":256},[10107],{"type":22,"value":9746},{"type":17,"tag":243,"props":10109,"children":10110},{"style":262},[10111],{"type":22,"value":265},{"type":17,"tag":243,"props":10113,"children":10114},{"style":268},[10115],{"type":22,"value":9600},{"type":17,"tag":243,"props":10117,"children":10118},{"style":250},[10119],{"type":22,"value":925},{"type":17,"tag":243,"props":10121,"children":10122},{"style":378},[10123],{"type":22,"value":3938},{"type":17,"tag":243,"props":10125,"children":10126},{"style":262},[10127],{"type":22,"value":335},{"type":17,"tag":243,"props":10129,"children":10130},{"style":268},[10131],{"type":22,"value":9617},{"type":17,"tag":243,"props":10133,"children":10134},{"style":250},[10135],{"type":22,"value":925},{"type":17,"tag":243,"props":10137,"children":10138},{"style":378},[10139],{"type":22,"value":3938},{"type":17,"tag":243,"props":10141,"children":10142},{"style":262},[10143],{"type":22,"value":335},{"type":17,"tag":243,"props":10145,"children":10146},{"style":268},[10147],{"type":22,"value":9892},{"type":17,"tag":243,"props":10149,"children":10150},{"style":250},[10151],{"type":22,"value":925},{"type":17,"tag":243,"props":10153,"children":10154},{"style":378},[10155],{"type":22,"value":3938},{"type":17,"tag":243,"props":10157,"children":10158},{"style":262},[10159],{"type":22,"value":7228},{"type":17,"tag":243,"props":10161,"children":10162},{"style":250},[10163],{"type":22,"value":925},{"type":17,"tag":243,"props":10165,"children":10166},{"style":378},[10167],{"type":22,"value":3938},{"type":17,"tag":243,"props":10169,"children":10170},{"style":262},[10171],{"type":22,"value":1370},{"type":17,"tag":243,"props":10173,"children":10175},{"class":245,"line":10174},137,[10176,10180,10184,10188],{"type":17,"tag":243,"props":10177,"children":10178},{"style":250},[10179],{"type":22,"value":9925},{"type":17,"tag":243,"props":10181,"children":10182},{"style":262},[10183],{"type":22,"value":8916},{"type":17,"tag":243,"props":10185,"children":10186},{"style":250},[10187],{"type":22,"value":1831},{"type":17,"tag":243,"props":10189,"children":10190},{"style":262},[10191],{"type":22,"value":9938},{"type":17,"tag":243,"props":10193,"children":10195},{"class":245,"line":10194},138,[10196,10200,10204,10208,10212,10216,10220,10224,10228,10233,10237,10241,10245,10249],{"type":17,"tag":243,"props":10197,"children":10198},{"style":250},[10199],{"type":22,"value":9947},{"type":17,"tag":243,"props":10201,"children":10202},{"style":262},[10203],{"type":22,"value":8916},{"type":17,"tag":243,"props":10205,"children":10206},{"style":250},[10207],{"type":22,"value":7128},{"type":17,"tag":243,"props":10209,"children":10210},{"style":262},[10211],{"type":22,"value":9655},{"type":17,"tag":243,"props":10213,"children":10214},{"style":250},[10215],{"type":22,"value":375},{"type":17,"tag":243,"props":10217,"children":10218},{"style":378},[10219],{"type":22,"value":467},{"type":17,"tag":243,"props":10221,"children":10222},{"style":262},[10223],{"type":22,"value":1637},{"type":17,"tag":243,"props":10225,"children":10226},{"style":250},[10227],{"type":22,"value":1891},{"type":17,"tag":243,"props":10229,"children":10230},{"style":262},[10231],{"type":22,"value":10232}," (f ",{"type":17,"tag":243,"props":10234,"children":10235},{"style":250},[10236],{"type":22,"value":294},{"type":17,"tag":243,"props":10238,"children":10239},{"style":262},[10240],{"type":22,"value":1523},{"type":17,"tag":243,"props":10242,"children":10243},{"style":378},[10244],{"type":22,"value":551},{"type":17,"tag":243,"props":10246,"children":10247},{"style":250},[10248],{"type":22,"value":2602},{"type":17,"tag":243,"props":10250,"children":10251},{"style":262},[10252],{"type":22,"value":10253}," d))\n",{"type":17,"tag":243,"props":10255,"children":10257},{"class":245,"line":10256},139,[10258,10262,10266],{"type":17,"tag":243,"props":10259,"children":10260},{"style":262},[10261],{"type":22,"value":9976},{"type":17,"tag":243,"props":10263,"children":10264},{"style":250},[10265],{"type":22,"value":5461},{"type":17,"tag":243,"props":10267,"children":10268},{"style":262},[10269],{"type":22,"value":1370},{"type":17,"tag":243,"props":10271,"children":10273},{"class":245,"line":10272},140,[10274,10278,10282,10286,10290,10294,10298],{"type":17,"tag":243,"props":10275,"children":10276},{"style":250},[10277],{"type":22,"value":9947},{"type":17,"tag":243,"props":10279,"children":10280},{"style":262},[10281],{"type":22,"value":8938},{"type":17,"tag":243,"props":10283,"children":10284},{"style":250},[10285],{"type":22,"value":294},{"type":17,"tag":243,"props":10287,"children":10288},{"style":262},[10289],{"type":22,"value":1523},{"type":17,"tag":243,"props":10291,"children":10292},{"style":378},[10293],{"type":22,"value":551},{"type":17,"tag":243,"props":10295,"children":10296},{"style":250},[10297],{"type":22,"value":2602},{"type":17,"tag":243,"props":10299,"children":10300},{"style":262},[10301],{"type":22,"value":10302}," d)\n",{"type":17,"tag":243,"props":10304,"children":10306},{"class":245,"line":10305},141,[10307],{"type":17,"tag":243,"props":10308,"children":10309},{"style":262},[10310],{"type":22,"value":5222},{"type":17,"tag":243,"props":10312,"children":10314},{"class":245,"line":10313},142,[10315],{"type":17,"tag":243,"props":10316,"children":10317},{"style":262},[10318],{"type":22,"value":1413},{"type":17,"tag":243,"props":10320,"children":10322},{"class":245,"line":10321},143,[10323],{"type":17,"tag":243,"props":10324,"children":10325},{"emptyLinePlaceholder":2340},[10326],{"type":22,"value":2932},{"type":17,"tag":243,"props":10328,"children":10330},{"class":245,"line":10329},144,[10331,10335,10339,10343,10347,10351,10355,10359,10363,10367,10371,10375,10379,10383,10387,10391,10395,10399],{"type":17,"tag":243,"props":10332,"children":10333},{"style":250},[10334],{"type":22,"value":7787},{"type":17,"tag":243,"props":10336,"children":10337},{"style":256},[10338],{"type":22,"value":9780},{"type":17,"tag":243,"props":10340,"children":10341},{"style":262},[10342],{"type":22,"value":265},{"type":17,"tag":243,"props":10344,"children":10345},{"style":268},[10346],{"type":22,"value":9600},{"type":17,"tag":243,"props":10348,"children":10349},{"style":250},[10350],{"type":22,"value":925},{"type":17,"tag":243,"props":10352,"children":10353},{"style":378},[10354],{"type":22,"value":3938},{"type":17,"tag":243,"props":10356,"children":10357},{"style":262},[10358],{"type":22,"value":335},{"type":17,"tag":243,"props":10360,"children":10361},{"style":268},[10362],{"type":22,"value":9617},{"type":17,"tag":243,"props":10364,"children":10365},{"style":250},[10366],{"type":22,"value":925},{"type":17,"tag":243,"props":10368,"children":10369},{"style":378},[10370],{"type":22,"value":3938},{"type":17,"tag":243,"props":10372,"children":10373},{"style":262},[10374],{"type":22,"value":335},{"type":17,"tag":243,"props":10376,"children":10377},{"style":268},[10378],{"type":22,"value":9892},{"type":17,"tag":243,"props":10380,"children":10381},{"style":250},[10382],{"type":22,"value":925},{"type":17,"tag":243,"props":10384,"children":10385},{"style":378},[10386],{"type":22,"value":3938},{"type":17,"tag":243,"props":10388,"children":10389},{"style":262},[10390],{"type":22,"value":7228},{"type":17,"tag":243,"props":10392,"children":10393},{"style":250},[10394],{"type":22,"value":925},{"type":17,"tag":243,"props":10396,"children":10397},{"style":378},[10398],{"type":22,"value":3938},{"type":17,"tag":243,"props":10400,"children":10401},{"style":262},[10402],{"type":22,"value":1370},{"type":17,"tag":243,"props":10404,"children":10406},{"class":245,"line":10405},145,[10407,10411,10415],{"type":17,"tag":243,"props":10408,"children":10409},{"style":250},[10410],{"type":22,"value":1847},{"type":17,"tag":243,"props":10412,"children":10413},{"style":256},[10414],{"type":22,"value":9810},{"type":17,"tag":243,"props":10416,"children":10417},{"style":262},[10418],{"type":22,"value":10419},"(d,f,repRadius)\n",{"type":17,"tag":243,"props":10421,"children":10423},{"class":245,"line":10422},146,[10424],{"type":17,"tag":243,"props":10425,"children":10426},{"style":262},[10427],{"type":22,"value":1413},{"type":17,"tag":243,"props":10429,"children":10431},{"class":245,"line":10430},147,[10432],{"type":17,"tag":243,"props":10433,"children":10434},{"emptyLinePlaceholder":2340},[10435],{"type":22,"value":2932},{"type":17,"tag":243,"props":10437,"children":10439},{"class":245,"line":10438},148,[10440,10444,10448,10452,10456,10460,10464,10468,10472,10476,10480,10484,10488,10492,10496,10500,10504,10508],{"type":17,"tag":243,"props":10441,"children":10442},{"style":250},[10443],{"type":22,"value":7787},{"type":17,"tag":243,"props":10445,"children":10446},{"style":256},[10447],{"type":22,"value":9810},{"type":17,"tag":243,"props":10449,"children":10450},{"style":262},[10451],{"type":22,"value":265},{"type":17,"tag":243,"props":10453,"children":10454},{"style":268},[10455],{"type":22,"value":9600},{"type":17,"tag":243,"props":10457,"children":10458},{"style":250},[10459],{"type":22,"value":925},{"type":17,"tag":243,"props":10461,"children":10462},{"style":378},[10463],{"type":22,"value":3938},{"type":17,"tag":243,"props":10465,"children":10466},{"style":262},[10467],{"type":22,"value":335},{"type":17,"tag":243,"props":10469,"children":10470},{"style":268},[10471],{"type":22,"value":9617},{"type":17,"tag":243,"props":10473,"children":10474},{"style":250},[10475],{"type":22,"value":925},{"type":17,"tag":243,"props":10477,"children":10478},{"style":378},[10479],{"type":22,"value":3938},{"type":17,"tag":243,"props":10481,"children":10482},{"style":262},[10483],{"type":22,"value":335},{"type":17,"tag":243,"props":10485,"children":10486},{"style":268},[10487],{"type":22,"value":9892},{"type":17,"tag":243,"props":10489,"children":10490},{"style":250},[10491],{"type":22,"value":925},{"type":17,"tag":243,"props":10493,"children":10494},{"style":378},[10495],{"type":22,"value":3938},{"type":17,"tag":243,"props":10497,"children":10498},{"style":262},[10499],{"type":22,"value":7228},{"type":17,"tag":243,"props":10501,"children":10502},{"style":250},[10503],{"type":22,"value":925},{"type":17,"tag":243,"props":10505,"children":10506},{"style":378},[10507],{"type":22,"value":3938},{"type":17,"tag":243,"props":10509,"children":10510},{"style":262},[10511],{"type":22,"value":1370},{"type":17,"tag":243,"props":10513,"children":10515},{"class":245,"line":10514},149,[10516,10520,10524,10528],{"type":17,"tag":243,"props":10517,"children":10518},{"style":250},[10519],{"type":22,"value":9925},{"type":17,"tag":243,"props":10521,"children":10522},{"style":262},[10523],{"type":22,"value":8916},{"type":17,"tag":243,"props":10525,"children":10526},{"style":250},[10527],{"type":22,"value":1831},{"type":17,"tag":243,"props":10529,"children":10530},{"style":262},[10531],{"type":22,"value":9938},{"type":17,"tag":243,"props":10533,"children":10535},{"class":245,"line":10534},150,[10536,10541,10545,10549,10553,10557],{"type":17,"tag":243,"props":10537,"children":10538},{"style":250},[10539],{"type":22,"value":10540},"      return",{"type":17,"tag":243,"props":10542,"children":10543},{"style":262},[10544],{"type":22,"value":8857},{"type":17,"tag":243,"props":10546,"children":10547},{"style":250},[10548],{"type":22,"value":7128},{"type":17,"tag":243,"props":10550,"children":10551},{"style":262},[10552],{"type":22,"value":9655},{"type":17,"tag":243,"props":10554,"children":10555},{"style":250},[10556],{"type":22,"value":375},{"type":17,"tag":243,"props":10558,"children":10559},{"style":378},[10560],{"type":22,"value":5182},{"type":17,"tag":243,"props":10562,"children":10564},{"class":245,"line":10563},151,[10565,10570,10574],{"type":17,"tag":243,"props":10566,"children":10567},{"style":262},[10568],{"type":22,"value":10569},"    } ",{"type":17,"tag":243,"props":10571,"children":10572},{"style":250},[10573],{"type":22,"value":5461},{"type":17,"tag":243,"props":10575,"children":10576},{"style":262},[10577],{"type":22,"value":1370},{"type":17,"tag":243,"props":10579,"children":10581},{"class":245,"line":10580},152,[10582,10586,10590,10594,10598,10602,10606],{"type":17,"tag":243,"props":10583,"children":10584},{"style":250},[10585],{"type":22,"value":10540},{"type":17,"tag":243,"props":10587,"children":10588},{"style":262},[10589],{"type":22,"value":8938},{"type":17,"tag":243,"props":10591,"children":10592},{"style":250},[10593],{"type":22,"value":294},{"type":17,"tag":243,"props":10595,"children":10596},{"style":262},[10597],{"type":22,"value":1523},{"type":17,"tag":243,"props":10599,"children":10600},{"style":378},[10601],{"type":22,"value":551},{"type":17,"tag":243,"props":10603,"children":10604},{"style":250},[10605],{"type":22,"value":2602},{"type":17,"tag":243,"props":10607,"children":10608},{"style":262},[10609],{"type":22,"value":10302},{"type":17,"tag":243,"props":10611,"children":10613},{"class":245,"line":10612},153,[10614],{"type":17,"tag":243,"props":10615,"children":10616},{"style":262},[10617],{"type":22,"value":4207},{"type":17,"tag":243,"props":10619,"children":10621},{"class":245,"line":10620},154,[10622],{"type":17,"tag":243,"props":10623,"children":10624},{"style":262},[10625],{"type":22,"value":1413},{"type":17,"tag":40,"props":10627,"children":10629},{"id":10628},"quadtree",[10630],{"type":22,"value":10631},"QuadTree",{"type":17,"tag":18,"props":10633,"children":10634},{},[10635],{"type":22,"value":10636},"Now that my code is running in the browser, it's time for optimization. We have a set of points in 2D space that can only interact with one another within a given radius. To see which particles fall within this range, we must examine every particle in the system. This is the root cause of the inefficiency of our program.",{"type":17,"tag":18,"props":10638,"children":10639},{},[10640,10642,10647],{"type":22,"value":10641},"So, how do we retrieve particles that only reside in the surroundings of the particle we’re calculating the velocity of? We would need a data structure that stores ",{"type":17,"tag":91,"props":10643,"children":10644},{},[10645],{"type":22,"value":10646},"regions",{"type":22,"value":10648}," of space and their corresponding particles. This way, we could just query regions within a given area and thus get all particles living there. Here comes the QuadTree!",{"type":17,"tag":18,"props":10650,"children":10651},{},[10652],{"type":22,"value":10653},"Consider the root node, which will translate to our entire 2D plane:",{"type":17,"tag":5258,"props":10655,"children":10657},{"src":10656},"/articles/drawisland.png",[],{"type":17,"tag":18,"props":10659,"children":10660},{},[10661],{"type":22,"value":10662},"First, let’s examine if our node has more particles than its carrying capacity. Let’s assume the carrying capacity for every sector is 4.\nBelow, we have 5 particles. The number of particles exceeds the carrying capacity of our sector, so we need to subdivide it. We’ll divide one sector into 4 smaller ones:",{"type":17,"tag":5258,"props":10664,"children":10666},{"src":10665},"/articles/drawisland (2).png",[],{"type":17,"tag":18,"props":10668,"children":10669},{},[10670],{"type":22,"value":10671},"Now, let’s repeat the first step for every one of our new nodes. In this case, none of the child nodes exceed the carrying capacity, so we stop here, and this is our final quadtree. Had it not been the case, we’d repeat the division recursively, creating smaller and smaller sections for every node that exceeds its capacity. This makes it a very good data structure for our simulation, where attraction between particles will usually lead to an uneven distribution of particles. Only crowded sectors get subdivided.",{"type":17,"tag":18,"props":10673,"children":10674},{},[10675],{"type":22,"value":10676},"Now, every sector needs the following properties:",{"type":17,"tag":580,"props":10678,"children":10679},{},[10680,10690,10700,10710],{"type":17,"tag":584,"props":10681,"children":10682},{},[10683,10688],{"type":17,"tag":91,"props":10684,"children":10685},{},[10686],{"type":22,"value":10687},"boundary",{"type":22,"value":10689}," - a region of space it covers. We can represent it as a rectangle with a center point (x,y) and its height and width;",{"type":17,"tag":584,"props":10691,"children":10692},{},[10693,10698],{"type":17,"tag":91,"props":10694,"children":10695},{},[10696],{"type":22,"value":10697},"capacity",{"type":22,"value":10699}," - carrying capacity;",{"type":17,"tag":584,"props":10701,"children":10702},{},[10703,10708],{"type":17,"tag":91,"props":10704,"children":10705},{},[10706],{"type":22,"value":10707},"points",{"type":22,"value":10709}," - an array of points, given the sector is not subdivided;",{"type":17,"tag":584,"props":10711,"children":10712},{},[10713,10718],{"type":17,"tag":91,"props":10714,"children":10715},{},[10716],{"type":22,"value":10717},"divided",{"type":22,"value":10719}," - indicates if the sector is subdivided;",{"type":17,"tag":18,"props":10721,"children":10722},{},[10723],{"type":22,"value":10724},"Of course, we also need at least methods to insert, delete, and query particles. These methods will work recursively. For example, to implement query() method, we need to:",{"type":17,"tag":580,"props":10726,"children":10727},{},[10728,10733,10738,10743],{"type":17,"tag":584,"props":10729,"children":10730},{},[10731],{"type":22,"value":10732},"Check if the queried area intersects with the root node",{"type":17,"tag":584,"props":10734,"children":10735},{},[10736],{"type":22,"value":10737},"If it doesn’t return an empty array",{"type":17,"tag":584,"props":10739,"children":10740},{},[10741],{"type":22,"value":10742},"If it does and the root node is not subdivided, return all points belonging to this node",{"type":17,"tag":584,"props":10744,"children":10745},{},[10746],{"type":22,"value":10747},"If it does and the node is subdivided, repeat the same for every child node",{"type":17,"tag":18,"props":10749,"children":10750},{},[10751,10753,10760,10762],{"type":22,"value":10752},"This way, we can efficiently traverse our tree and return only relevant points. I decided to use ready implementation, as I don’t like reinventing the tree - thanks to ",{"type":17,"tag":340,"props":10754,"children":10757},{"href":10755,"rel":10756},"https://github.com/CodingTrain",[686],[10758],{"type":22,"value":10759},"The coding train",{"type":22,"value":10761}," for sharing his ",{"type":17,"tag":340,"props":10763,"children":10765},{"href":10764},"github.com/CodingTrain/QuadTree/blob/main/quadtree.js",[10766],{"type":22,"value":10767},"implementation",{"type":17,"tag":40,"props":10769,"children":10771},{"id":10770},"drawbacks",[10772],{"type":22,"value":10773},"Drawbacks",{"type":17,"tag":18,"props":10775,"children":10776},{},[10777],{"type":22,"value":10778},"Spatial partitioning can already take our Particle Life to another level, but it is far from an ideal solution. In the end, what limits us is the number of particles in the range that we need to test. If we want to keep things efficient, the radius needs to be small enough to contain a limited number of particles. This way, we create a zoomed-out, uniform version of the particle life. It’s an interesting optimization exercise, but nothing more. The more particles we want, the smaller the radius we need to set, and the less we see.",{"type":17,"tag":18,"props":10780,"children":10781},{},[10782,10784,10789],{"type":22,"value":10783},"What if we wanted to see how, let’s say, 100000 particles in range interact with one another? To achieve this, we need to think in a different way. Instead of sequentially calculating forces for every particle (which would require ",{"type":17,"tag":91,"props":10785,"children":10786},{},[10787],{"type":22,"value":10788},"10 billion checks",{"type":22,"value":10790}," for every frame), let’s use the GPU to calculate force for every particle in parallel. So it happens that I was reading about the new webGPU API a few days ago, and I think it would be a nice programming experiment to implement our particle life this way.",{"type":17,"tag":40,"props":10792,"children":10794},{"id":10793},"further-considerations",[10795],{"type":22,"value":10796},"Further considerations",{"type":17,"tag":18,"props":10798,"children":10799},{},[10800],{"type":22,"value":10801},"If we were to continue developing our javascript implementation, there are more things we could do to optimize the code. Our system is very dynamic, and everything is moving with every frame, forcing us to reconstruct the tree. It happens to be quite an expensive operation.",{"type":17,"tag":18,"props":10803,"children":10804},{},[10805],{"type":22,"value":10806},"To further improve this, we could draw from data structure used in computer simulations, verlet list. Instead of querying particles within a maximum interaction radius, we add a padding of X%. Then, we consider how many repeated position updates we can calculate before particles move outside of our adjusted radius. This way, we can rebuild our quadtree not on every frame, but once in every few frames. The tricky part is finding a balance between an increased radius (and hence more particles to loop over) and the frequency of rebuilding the quadtree. This will vary depending on our system parameters.",{"type":17,"tag":40,"props":10808,"children":10810},{"id":10809},"particle-life-online",[10811],{"type":22,"value":10812},"Particle Life online",{"type":17,"tag":18,"props":10814,"children":10815},{},[10816,10818,10825,10827,10833],{"type":22,"value":10817},"I deployed my code to ",{"type":17,"tag":340,"props":10819,"children":10822},{"href":10820,"rel":10821},"https://webgpulife.netlify.app/",[686],[10823],{"type":22,"value":10824},"Netlify",{"type":22,"value":10826},", where you can play with an unoptimized JS version, quadtree enhanced code, and webGPU 3D particles. Remember to increase the parameters carefully if you’re not on a good machine, otherwise your browser will freeze. The code is available ",{"type":17,"tag":340,"props":10828,"children":10830},{"href":6896,"rel":10829},[686],[10831],{"type":22,"value":10832},"here",{"type":22,"value":595},{"type":17,"tag":18,"props":10835,"children":10836},{},[10837],{"type":22,"value":10838},"See you in the next part, where I’ll take things to the next level by implementing and optimizing the webGPU version!",{"type":17,"tag":18,"props":10840,"children":10841},{},[10842],{"type":17,"tag":340,"props":10843,"children":10844},{"href":2324},[10845],{"type":22,"value":10846},"See the next part",{"type":17,"tag":2308,"props":10848,"children":10849},{},[10850],{"type":22,"value":2312},{"title":8,"searchDepth":160,"depth":160,"links":10852},[10853,10854,10855,10856,10857],{"id":6862,"depth":160,"text":6865},{"id":10628,"depth":160,"text":10631},{"id":10770,"depth":160,"text":10773},{"id":10793,"depth":160,"text":10796},{"id":10809,"depth":160,"text":10812},"content:articles:optimizing-the-particle-life-javascript-quadtree.md","articles/optimizing-the-particle-life-javascript-quadtree.md","articles/optimizing-the-particle-life-javascript-quadtree",{"_path":6910,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":10862,"description":10863,"published":10864,"slug":10865,"body":10866,"_type":165,"_id":13469,"_source":167,"_file":13470,"_stem":13471,"_extension":170},"Optimizing the Particle Life: From 400 to 4 million particles (Part 1)","Detailed description of an algorithm and a comparison between different languages.","2024/02/27","optimizing-the-article-life-from-400-to-4-milion-particles",{"type":14,"children":10867,"toc":13464},[10868,10874,10880,10885,10890,10895,10900,10905,10941,10946,10951,10956,10962,10967,10972,11043,11048,11053,11058,11062,11067,11071,11075,11079,11084,11089,11996,12002,12014,12019,12024,12029,12034,12039,12044,12049,12266,12271,12671,12676,12814,12819,12823,12828,12848,12853,12858,12863,13358,13363,13383,13388,13393,13398,13403,13408,13413,13418,13422,13428,13433,13438,13443,13448,13453,13460],{"type":17,"tag":5258,"props":10869,"children":10873},{"className":10870,"src":10872},[10871],"w-full","/articles/1.webp",[],{"type":17,"tag":40,"props":10875,"children":10877},{"id":10876},"why-particle-life",[10878],{"type":22,"value":10879},"Why Particle Life?",{"type":17,"tag":18,"props":10881,"children":10882},{},[10883],{"type":22,"value":10884},"For one of my programming classes this semester, my task was writing a program in Python. It was only an introductory course, so it didn’t have to be anything fancy. Whenever I get assignments like this one, my choice is simple: I enjoy tinkering around with cellular automata and particle simulations.",{"type":17,"tag":18,"props":10886,"children":10887},{},[10888],{"type":22,"value":10889},"I have had an eye on Particle Life for quite a while now. The idea belongs to Jeffrey Ventrella, who called it \"Clusters.\" As the name suggests, its simple rules result in the emergence of lifelike, cell-like structures interacting with one another. During my experiments, I was also amazed by the fact that applying the same rules on much larger scales gives us a resemblance to many different phenomena in nature, somewhat like electron clouds or cosmic structures. I, personally, found it mesmerizing, and I got completely absorbed by writing this program for the better part of a week, completely neglecting other things I needed to take care of.",{"type":17,"tag":18,"props":10891,"children":10892},{},[10893],{"type":22,"value":10894},"But what do I even mean by emergence in the paragraph above?",{"type":17,"tag":18,"props":10896,"children":10897},{},[10898],{"type":22,"value":10899},"Have you ever wondered how a flock of birds operates? How is it able to travel, forage, and respond to predators? An individual bird does not have a blueprint of the flock's final behavior and its part in it.",{"type":17,"tag":18,"props":10901,"children":10902},{},[10903],{"type":22,"value":10904},"Instead, a singular bird operates based on simple rules guiding its behavior. For example, in boids, an algorithm simulating the flocking behavior of birds, an individual agent's interaction must adhere to (a simplified) set of rules:",{"type":17,"tag":580,"props":10906,"children":10907},{},[10908,10920,10930],{"type":17,"tag":584,"props":10909,"children":10910},{},[10911,10913,10918],{"type":22,"value":10912},"Stay ",{"type":17,"tag":91,"props":10914,"children":10915},{},[10916],{"type":22,"value":10917},"separated",{"type":22,"value":10919}," to avoid crowding local flockmates.",{"type":17,"tag":584,"props":10921,"children":10922},{},[10923,10928],{"type":17,"tag":91,"props":10924,"children":10925},{},[10926],{"type":22,"value":10927},"Align",{"type":22,"value":10929}," with the average direction of your local flockmates.",{"type":17,"tag":584,"props":10931,"children":10932},{},[10933,10935,10940],{"type":22,"value":10934},"Navigate towards the average position of your local flockmates to retain ",{"type":17,"tag":91,"props":10936,"children":10937},{},[10938],{"type":22,"value":10939},"cohesion",{"type":22,"value":595},{"type":17,"tag":18,"props":10942,"children":10943},{},[10944],{"type":22,"value":10945},"The complexity of the flock emerges from every agent in the system following these rules. Flock has distinct properties that arose from the behavior of its components, but there's no way for us to deduce these properties from the rules we applied to individual agents. This is why we can call a flock a complex system.",{"type":17,"tag":18,"props":10947,"children":10948},{},[10949],{"type":22,"value":10950},"Human societies, the universe, climate, cities—all these are examples of complex systems. And the simulation we'll write is an example of it as well. You'll see for yourself how the structures we'll see on the screen are described nowhere in the code but emerge as a result of uncomplicated rules generated for every particle randomly each time we start the program.",{"type":17,"tag":18,"props":10952,"children":10953},{},[10954],{"type":22,"value":10955},"There are multiple implementations of the algorithm available online. To contribute something new, I decided to focus on the optimization of the program. This is a deep-dive, several-piece series, but at the end, we'll render a million particles in real-time, which makes it completely worth the time spent on the project!",{"type":17,"tag":40,"props":10957,"children":10959},{"id":10958},"the-rules",[10960],{"type":22,"value":10961},"The rules",{"type":17,"tag":18,"props":10963,"children":10964},{},[10965],{"type":22,"value":10966},"The first thing we need to specify is the number of classes of particles. We will denote these classes by their colors, and how particles interact with each other will depend on their respective colors. This force can be attractive or repulsive, depending on our color-attraction matrix. It doesn’t have to be symmetric: red particles can be attracted to green particles, but green particles can be repulsed by red ones.",{"type":17,"tag":18,"props":10968,"children":10969},{},[10970],{"type":22,"value":10971},"To visualize this dependence, let’s see an example matrix with two classes of particles and forces ranging from -1.0 to 1.0:",{"type":17,"tag":10973,"props":10974,"children":10975},"table",{},[10976,10998],{"type":17,"tag":10977,"props":10978,"children":10979},"thead",{},[10980],{"type":17,"tag":10981,"props":10982,"children":10983},"tr",{},[10984,10988,10993],{"type":17,"tag":10985,"props":10986,"children":10987},"th",{},[],{"type":17,"tag":10985,"props":10989,"children":10990},{},[10991],{"type":22,"value":10992},"Red",{"type":17,"tag":10985,"props":10994,"children":10995},{},[10996],{"type":22,"value":10997},"Blue",{"type":17,"tag":10999,"props":11000,"children":11001},"tbody",{},[11002,11023],{"type":17,"tag":10981,"props":11003,"children":11004},{},[11005,11013,11018],{"type":17,"tag":11006,"props":11007,"children":11008},"td",{},[11009],{"type":17,"tag":91,"props":11010,"children":11011},{},[11012],{"type":22,"value":10992},{"type":17,"tag":11006,"props":11014,"children":11015},{},[11016],{"type":22,"value":11017},".86",{"type":17,"tag":11006,"props":11019,"children":11020},{},[11021],{"type":22,"value":11022},"-.15",{"type":17,"tag":10981,"props":11024,"children":11025},{},[11026,11033,11038],{"type":17,"tag":11006,"props":11027,"children":11028},{},[11029],{"type":17,"tag":91,"props":11030,"children":11031},{},[11032],{"type":22,"value":10997},{"type":17,"tag":11006,"props":11034,"children":11035},{},[11036],{"type":22,"value":11037},".33",{"type":17,"tag":11006,"props":11039,"children":11040},{},[11041],{"type":22,"value":11042},".24",{"type":17,"tag":18,"props":11044,"children":11045},{},[11046],{"type":22,"value":11047},"In this case, red particles are strongly attracted to one another. They’re slightly repulsed by blue ones. Blue particles also attract each other, although in a weaker manner, and they’re also attracted to red particles.",{"type":17,"tag":18,"props":11049,"children":11050},{},[11051],{"type":22,"value":11052},"This force works within a radius that we’ll specify. But within a fraction of this radius, we have another force, the universal repulsive force. Otherwise, particles that are attracted to each other would end up collapsing into one.",{"type":17,"tag":18,"props":11054,"children":11055},{},[11056],{"type":22,"value":11057},"This is how we can visualize our force function, assuming the force value between two particles to be 1.0 and a repulsive radius of 1/4 of the max radius:",{"type":17,"tag":5258,"props":11059,"children":11061},{"src":11060},"/articles/graph (1).png",[],{"type":17,"tag":18,"props":11063,"children":11064},{},[11065],{"type":22,"value":11066},"Of course, these rules are not set in stone. In the following parts, you will see how slight changes in force function affect our system:",{"type":17,"tag":5258,"props":11068,"children":11070},{"src":11069},"/articles/graph.png",[],{"type":17,"tag":5258,"props":11072,"children":11074},{"src":11073},"/articles/graph (2).png",[],{"type":17,"tag":5258,"props":11076,"children":11078},{"src":11077},"/articles/graph (3).png",[],{"type":17,"tag":18,"props":11080,"children":11081},{},[11082],{"type":22,"value":11083},"So far, so good. You must admit that these rules are really beautifully simple. It's time to write a Python script to test if I can get it up and running.",{"type":17,"tag":18,"props":11085,"children":11086},{},[11087],{"type":22,"value":11088},"After some time, and some frustrating errors originating from Qt, my particles came to life. Below, you can find the whole script. I tried to add explicit comments to every line so that there aren’t any confusing bits. A little note about system parameters: those are arbitrarily chosen values. You have to experiment for a bit to see what works and what doesn’t.",{"type":17,"tag":233,"props":11090,"children":11094},{"className":11091,"code":11092,"language":11093,"meta":8,"style":8},"language-python shiki shiki-themes github-dark","import numpy as np\nimport colorsys as cs\nimport random as rd\nimport sys\nimport math\nfrom PySide6.QtCore import *\nfrom PySide6.QtWidgets import *\nfrom PySide6.QtGui import *\n\nwidth = 800\nheight = 800\n\n#function definitions\ndef buildAttractionMatrix(m):\n    return (m*2)-1 # Multiple random between [0.0,1.0] by 2 and substract one to get random between [-1.0,1.0]\n\n#With HSL, unlike RGB, to change color we have to update only one value [[H]SL -> Hue]. Hence, it will work perfectly\n#for generating predefined no of colors, sufficiently distinct from one another. Since our GUI library accepts only RGB colors,\n#we have to convert it RGB.\ndef createColors(m):\n    colors = list()\n    for i in range(m):\n        hueValue = (i *( 360/(m - 1)))\n        #hsvtorgb() returns values between [0.0,1.0] hence i*255\n        color = tuple(round(i * 255) for i in cs.hsv_to_rgb(hueValue/100,1,1))\n        colors.append(QColor(color[0],color[1],color[2]))\n    return colors\n\ndef force(d, f): #d - ratio of particles distance and max distance , f - force according to attraction matrix\n    repRadius = 0.25 #universal repulsive force that prevents our particles from collapsing into each other\n    #25% is an arbitrary value I tested to behave the best - feel free to experiment, like with other system parameters.\n    if (d\u003CrepRadius):\n        #if d is within the range of universal repulsive we return negative value. As the distance approaches 0 returned value approaches -1 which is max value\n        #for our repulsive force\n        return (d/repRadius - 1)\n    elif (repRadius \u003C d and d\u003C1): #our distance is within max radius for standard force defined by attraction matrix\n        #the closer we get the particles together, the stronger their interaction is.\n        #As the particle move apart from each other, the force dissipates to reach 0 as we\n        #reach max radius\n        return f * (1-d)\n    else:\n        return 0 #particles are indiffirent to each other\n\ndef updatePositions():\n    #we initiate a loop to update all particles in our system\n    for i in range(n):\n        #every particle will accumulate total force value we'll get by evaluating it's attraction to every other particle in the system. Hence, our algorithm\n        #has a time complexity of O(n^2) if we don't add any optimizations.\n        totalForceX = 0\n        totalForceY = 0\n        for j in range(n):\n            if (i!=j):#we're not calculating the particle's influence on itself\n                #calculating distance between tested particle (i) to all other particles (j)\n                x = positionsX[j]-positionsX[i]\n                y = positionsY[j]-positionsY[i]\n                d = math.sqrt(x * x + y* y)\n\n                if (d\u003Cradius): #we're only proceeding with calculating distance if the distance between particle is less than max radius we specified for our system\n                    #1st param: We have to apply force proportionally to the distance between particles instead of simply using the value from out matrix\n                    #2nd param: To get the right value from the attraction matrix we need to get colors of particles we test\n                    f = force(d/radius, attractionMatrix[colors.index(particlesColors[i])][colors.index(particlesColors[j])])\n                    #lets add our force for this particle (j) to our total forces for particle (i)\n                    totalForceX+=(x / d)*f\n                    totalForceY+=(y / d)*f\n        #total force we just calculated will increase the particle's velocity\n        velocitiesX[i]+=totalForceX\n        velocitiesY[i]+=totalForceY\n        #we have to apply friction so that our particles don't accumulate velocity forever\n        velocitiesX[i]*=fr\n        velocitiesY[i]*=fr\n        #now that we have the particles velocity we can know how to change its position\n        positionsX[i]+=velocitiesX[i]\n        positionsY[i]+=velocitiesY[i]\n\n#system properties\nn = 400 #number of particles\nm = 5 #number of colors\nradius = 0.20\nfr = math.pow(.5, 10) #friction\n\n#init arrays to hold our values\nattractionMatrix = buildAttractionMatrix(np.random.random((m,m))) #create 2-d matrix based on number of colors\ncolors = createColors(m)\nparticlesColors = [rd.choice(colors) for _ in range(n)] #every particle is assigned random color from colors we created\n#every particle is assigned random position\npositionsX = [rd.random() for _ in range(n)]\npositionsY = [rd.random() for _ in range(n)]\n#every particle is assigned velocity = 0\nvelocitiesX = np.empty(n, dtype=float)\nvelocitiesY = np.empty(n, dtype=float)\n\nclass Window(QWidget):\n    def __init__(self):\n        super().__init__()\n\n    def paintEvent(self, event):\n        painter = QPainter(self)\n\n        updatePositions()\n        for i in range(n):\n            x = positionsX[i] * width\n            y = positionsY[i] * height\n            painter.setPen(particlesColors[i])\n            painter.drawEllipse(x, y, 1, 1)\n            self.update()\n\n\napp = QApplication(sys.argv)\nwindow = Window()\nwindow.height = height\nwindow.width = width\nwindow.show()\n\nsys.exit(app.exec())\n","python",[11095],{"type":17,"tag":219,"props":11096,"children":11097},{"__ignoreMap":8},[11098,11106,11114,11122,11130,11138,11146,11154,11162,11169,11177,11185,11192,11200,11208,11216,11223,11231,11239,11247,11255,11263,11271,11279,11287,11295,11303,11311,11318,11326,11334,11342,11350,11358,11366,11374,11382,11390,11398,11406,11414,11422,11430,11437,11445,11453,11461,11469,11477,11485,11493,11501,11509,11517,11525,11533,11541,11548,11556,11564,11572,11580,11588,11596,11604,11612,11620,11628,11636,11644,11652,11660,11668,11676,11683,11691,11699,11707,11715,11723,11730,11738,11746,11754,11762,11770,11778,11786,11794,11802,11810,11817,11825,11833,11841,11848,11856,11864,11871,11879,11887,11895,11903,11911,11919,11927,11934,11941,11949,11957,11965,11973,11981,11988],{"type":17,"tag":243,"props":11099,"children":11100},{"class":245,"line":246},[11101],{"type":17,"tag":243,"props":11102,"children":11103},{},[11104],{"type":22,"value":11105},"import numpy as np\n",{"type":17,"tag":243,"props":11107,"children":11108},{"class":245,"line":160},[11109],{"type":17,"tag":243,"props":11110,"children":11111},{},[11112],{"type":22,"value":11113},"import colorsys as cs\n",{"type":17,"tag":243,"props":11115,"children":11116},{"class":245,"line":302},[11117],{"type":17,"tag":243,"props":11118,"children":11119},{},[11120],{"type":22,"value":11121},"import random as rd\n",{"type":17,"tag":243,"props":11123,"children":11124},{"class":245,"line":311},[11125],{"type":17,"tag":243,"props":11126,"children":11127},{},[11128],{"type":22,"value":11129},"import sys\n",{"type":17,"tag":243,"props":11131,"children":11132},{"class":245,"line":356},[11133],{"type":17,"tag":243,"props":11134,"children":11135},{},[11136],{"type":22,"value":11137},"import math\n",{"type":17,"tag":243,"props":11139,"children":11140},{"class":245,"line":403},[11141],{"type":17,"tag":243,"props":11142,"children":11143},{},[11144],{"type":22,"value":11145},"from PySide6.QtCore import *\n",{"type":17,"tag":243,"props":11147,"children":11148},{"class":245,"line":411},[11149],{"type":17,"tag":243,"props":11150,"children":11151},{},[11152],{"type":22,"value":11153},"from PySide6.QtWidgets import *\n",{"type":17,"tag":243,"props":11155,"children":11156},{"class":245,"line":437},[11157],{"type":17,"tag":243,"props":11158,"children":11159},{},[11160],{"type":22,"value":11161},"from PySide6.QtGui import *\n",{"type":17,"tag":243,"props":11163,"children":11164},{"class":245,"line":510},[11165],{"type":17,"tag":243,"props":11166,"children":11167},{"emptyLinePlaceholder":2340},[11168],{"type":22,"value":2932},{"type":17,"tag":243,"props":11170,"children":11171},{"class":245,"line":518},[11172],{"type":17,"tag":243,"props":11173,"children":11174},{},[11175],{"type":22,"value":11176},"width = 800\n",{"type":17,"tag":243,"props":11178,"children":11179},{"class":245,"line":2757},[11180],{"type":17,"tag":243,"props":11181,"children":11182},{},[11183],{"type":22,"value":11184},"height = 800\n",{"type":17,"tag":243,"props":11186,"children":11187},{"class":245,"line":2765},[11188],{"type":17,"tag":243,"props":11189,"children":11190},{"emptyLinePlaceholder":2340},[11191],{"type":22,"value":2932},{"type":17,"tag":243,"props":11193,"children":11194},{"class":245,"line":2774},[11195],{"type":17,"tag":243,"props":11196,"children":11197},{},[11198],{"type":22,"value":11199},"#function definitions\n",{"type":17,"tag":243,"props":11201,"children":11202},{"class":245,"line":2783},[11203],{"type":17,"tag":243,"props":11204,"children":11205},{},[11206],{"type":22,"value":11207},"def buildAttractionMatrix(m):\n",{"type":17,"tag":243,"props":11209,"children":11210},{"class":245,"line":2792},[11211],{"type":17,"tag":243,"props":11212,"children":11213},{},[11214],{"type":22,"value":11215},"    return (m*2)-1 # Multiple random between [0.0,1.0] by 2 and substract one to get random between [-1.0,1.0]\n",{"type":17,"tag":243,"props":11217,"children":11218},{"class":245,"line":2801},[11219],{"type":17,"tag":243,"props":11220,"children":11221},{"emptyLinePlaceholder":2340},[11222],{"type":22,"value":2932},{"type":17,"tag":243,"props":11224,"children":11225},{"class":245,"line":2833},[11226],{"type":17,"tag":243,"props":11227,"children":11228},{},[11229],{"type":22,"value":11230},"#With HSL, unlike RGB, to change color we have to update only one value [[H]SL -> Hue]. Hence, it will work perfectly\n",{"type":17,"tag":243,"props":11232,"children":11233},{"class":245,"line":2842},[11234],{"type":17,"tag":243,"props":11235,"children":11236},{},[11237],{"type":22,"value":11238},"#for generating predefined no of colors, sufficiently distinct from one another. Since our GUI library accepts only RGB colors,\n",{"type":17,"tag":243,"props":11240,"children":11241},{"class":245,"line":2889},[11242],{"type":17,"tag":243,"props":11243,"children":11244},{},[11245],{"type":22,"value":11246},"#we have to convert it RGB.\n",{"type":17,"tag":243,"props":11248,"children":11249},{"class":245,"line":2898},[11250],{"type":17,"tag":243,"props":11251,"children":11252},{},[11253],{"type":22,"value":11254},"def createColors(m):\n",{"type":17,"tag":243,"props":11256,"children":11257},{"class":245,"line":2926},[11258],{"type":17,"tag":243,"props":11259,"children":11260},{},[11261],{"type":22,"value":11262},"    colors = list()\n",{"type":17,"tag":243,"props":11264,"children":11265},{"class":245,"line":2935},[11266],{"type":17,"tag":243,"props":11267,"children":11268},{},[11269],{"type":22,"value":11270},"    for i in range(m):\n",{"type":17,"tag":243,"props":11272,"children":11273},{"class":245,"line":2944},[11274],{"type":17,"tag":243,"props":11275,"children":11276},{},[11277],{"type":22,"value":11278},"        hueValue = (i *( 360/(m - 1)))\n",{"type":17,"tag":243,"props":11280,"children":11281},{"class":245,"line":2953},[11282],{"type":17,"tag":243,"props":11283,"children":11284},{},[11285],{"type":22,"value":11286},"        #hsvtorgb() returns values between [0.0,1.0] hence i*255\n",{"type":17,"tag":243,"props":11288,"children":11289},{"class":245,"line":2984},[11290],{"type":17,"tag":243,"props":11291,"children":11292},{},[11293],{"type":22,"value":11294},"        color = tuple(round(i * 255) for i in cs.hsv_to_rgb(hueValue/100,1,1))\n",{"type":17,"tag":243,"props":11296,"children":11297},{"class":245,"line":3040},[11298],{"type":17,"tag":243,"props":11299,"children":11300},{},[11301],{"type":22,"value":11302},"        colors.append(QColor(color[0],color[1],color[2]))\n",{"type":17,"tag":243,"props":11304,"children":11305},{"class":245,"line":3084},[11306],{"type":17,"tag":243,"props":11307,"children":11308},{},[11309],{"type":22,"value":11310},"    return colors\n",{"type":17,"tag":243,"props":11312,"children":11313},{"class":245,"line":3092},[11314],{"type":17,"tag":243,"props":11315,"children":11316},{"emptyLinePlaceholder":2340},[11317],{"type":22,"value":2932},{"type":17,"tag":243,"props":11319,"children":11320},{"class":245,"line":3121},[11321],{"type":17,"tag":243,"props":11322,"children":11323},{},[11324],{"type":22,"value":11325},"def force(d, f): #d - ratio of particles distance and max distance , f - force according to attraction matrix\n",{"type":17,"tag":243,"props":11327,"children":11328},{"class":245,"line":3130},[11329],{"type":17,"tag":243,"props":11330,"children":11331},{},[11332],{"type":22,"value":11333},"    repRadius = 0.25 #universal repulsive force that prevents our particles from collapsing into each other\n",{"type":17,"tag":243,"props":11335,"children":11336},{"class":245,"line":3159},[11337],{"type":17,"tag":243,"props":11338,"children":11339},{},[11340],{"type":22,"value":11341},"    #25% is an arbitrary value I tested to behave the best - feel free to experiment, like with other system parameters.\n",{"type":17,"tag":243,"props":11343,"children":11344},{"class":245,"line":3167},[11345],{"type":17,"tag":243,"props":11346,"children":11347},{},[11348],{"type":22,"value":11349},"    if (d\u003CrepRadius):\n",{"type":17,"tag":243,"props":11351,"children":11352},{"class":245,"line":3193},[11353],{"type":17,"tag":243,"props":11354,"children":11355},{},[11356],{"type":22,"value":11357},"        #if d is within the range of universal repulsive we return negative value. As the distance approaches 0 returned value approaches -1 which is max value\n",{"type":17,"tag":243,"props":11359,"children":11360},{"class":245,"line":3201},[11361],{"type":17,"tag":243,"props":11362,"children":11363},{},[11364],{"type":22,"value":11365},"        #for our repulsive force\n",{"type":17,"tag":243,"props":11367,"children":11368},{"class":245,"line":3210},[11369],{"type":17,"tag":243,"props":11370,"children":11371},{},[11372],{"type":22,"value":11373},"        return (d/repRadius - 1)\n",{"type":17,"tag":243,"props":11375,"children":11376},{"class":245,"line":3248},[11377],{"type":17,"tag":243,"props":11378,"children":11379},{},[11380],{"type":22,"value":11381},"    elif (repRadius \u003C d and d\u003C1): #our distance is within max radius for standard force defined by attraction matrix\n",{"type":17,"tag":243,"props":11383,"children":11384},{"class":245,"line":3305},[11385],{"type":17,"tag":243,"props":11386,"children":11387},{},[11388],{"type":22,"value":11389},"        #the closer we get the particles together, the stronger their interaction is.\n",{"type":17,"tag":243,"props":11391,"children":11392},{"class":245,"line":3333},[11393],{"type":17,"tag":243,"props":11394,"children":11395},{},[11396],{"type":22,"value":11397},"        #As the particle move apart from each other, the force dissipates to reach 0 as we\n",{"type":17,"tag":243,"props":11399,"children":11400},{"class":245,"line":3341},[11401],{"type":17,"tag":243,"props":11402,"children":11403},{},[11404],{"type":22,"value":11405},"        #reach max radius\n",{"type":17,"tag":243,"props":11407,"children":11408},{"class":245,"line":3370},[11409],{"type":17,"tag":243,"props":11410,"children":11411},{},[11412],{"type":22,"value":11413},"        return f * (1-d)\n",{"type":17,"tag":243,"props":11415,"children":11416},{"class":245,"line":3379},[11417],{"type":17,"tag":243,"props":11418,"children":11419},{},[11420],{"type":22,"value":11421},"    else:\n",{"type":17,"tag":243,"props":11423,"children":11424},{"class":245,"line":3407},[11425],{"type":17,"tag":243,"props":11426,"children":11427},{},[11428],{"type":22,"value":11429},"        return 0 #particles are indiffirent to each other\n",{"type":17,"tag":243,"props":11431,"children":11432},{"class":245,"line":3415},[11433],{"type":17,"tag":243,"props":11434,"children":11435},{"emptyLinePlaceholder":2340},[11436],{"type":22,"value":2932},{"type":17,"tag":243,"props":11438,"children":11439},{"class":245,"line":3441},[11440],{"type":17,"tag":243,"props":11441,"children":11442},{},[11443],{"type":22,"value":11444},"def updatePositions():\n",{"type":17,"tag":243,"props":11446,"children":11447},{"class":245,"line":3449},[11448],{"type":17,"tag":243,"props":11449,"children":11450},{},[11451],{"type":22,"value":11452},"    #we initiate a loop to update all particles in our system\n",{"type":17,"tag":243,"props":11454,"children":11455},{"class":245,"line":3458},[11456],{"type":17,"tag":243,"props":11457,"children":11458},{},[11459],{"type":22,"value":11460},"    for i in range(n):\n",{"type":17,"tag":243,"props":11462,"children":11463},{"class":245,"line":3499},[11464],{"type":17,"tag":243,"props":11465,"children":11466},{},[11467],{"type":22,"value":11468},"        #every particle will accumulate total force value we'll get by evaluating it's attraction to every other particle in the system. Hence, our algorithm\n",{"type":17,"tag":243,"props":11470,"children":11471},{"class":245,"line":3560},[11472],{"type":17,"tag":243,"props":11473,"children":11474},{},[11475],{"type":22,"value":11476},"        #has a time complexity of O(n^2) if we don't add any optimizations.\n",{"type":17,"tag":243,"props":11478,"children":11479},{"class":245,"line":3582},[11480],{"type":17,"tag":243,"props":11481,"children":11482},{},[11483],{"type":22,"value":11484},"        totalForceX = 0\n",{"type":17,"tag":243,"props":11486,"children":11487},{"class":245,"line":3615},[11488],{"type":17,"tag":243,"props":11489,"children":11490},{},[11491],{"type":22,"value":11492},"        totalForceY = 0\n",{"type":17,"tag":243,"props":11494,"children":11495},{"class":245,"line":3647},[11496],{"type":17,"tag":243,"props":11497,"children":11498},{},[11499],{"type":22,"value":11500},"        for j in range(n):\n",{"type":17,"tag":243,"props":11502,"children":11503},{"class":245,"line":3655},[11504],{"type":17,"tag":243,"props":11505,"children":11506},{},[11507],{"type":22,"value":11508},"            if (i!=j):#we're not calculating the particle's influence on itself\n",{"type":17,"tag":243,"props":11510,"children":11511},{"class":245,"line":3684},[11512],{"type":17,"tag":243,"props":11513,"children":11514},{},[11515],{"type":22,"value":11516},"                #calculating distance between tested particle (i) to all other particles (j)\n",{"type":17,"tag":243,"props":11518,"children":11519},{"class":245,"line":3693},[11520],{"type":17,"tag":243,"props":11521,"children":11522},{},[11523],{"type":22,"value":11524},"                x = positionsX[j]-positionsX[i]\n",{"type":17,"tag":243,"props":11526,"children":11527},{"class":245,"line":3721},[11528],{"type":17,"tag":243,"props":11529,"children":11530},{},[11531],{"type":22,"value":11532},"                y = positionsY[j]-positionsY[i]\n",{"type":17,"tag":243,"props":11534,"children":11535},{"class":245,"line":3729},[11536],{"type":17,"tag":243,"props":11537,"children":11538},{},[11539],{"type":22,"value":11540},"                d = math.sqrt(x * x + y* y)\n",{"type":17,"tag":243,"props":11542,"children":11543},{"class":245,"line":6211},[11544],{"type":17,"tag":243,"props":11545,"children":11546},{"emptyLinePlaceholder":2340},[11547],{"type":22,"value":2932},{"type":17,"tag":243,"props":11549,"children":11550},{"class":245,"line":6220},[11551],{"type":17,"tag":243,"props":11552,"children":11553},{},[11554],{"type":22,"value":11555},"                if (d\u003Cradius): #we're only proceeding with calculating distance if the distance between particle is less than max radius we specified for our system\n",{"type":17,"tag":243,"props":11557,"children":11558},{"class":245,"line":6229},[11559],{"type":17,"tag":243,"props":11560,"children":11561},{},[11562],{"type":22,"value":11563},"                    #1st param: We have to apply force proportionally to the distance between particles instead of simply using the value from out matrix\n",{"type":17,"tag":243,"props":11565,"children":11566},{"class":245,"line":6237},[11567],{"type":17,"tag":243,"props":11568,"children":11569},{},[11570],{"type":22,"value":11571},"                    #2nd param: To get the right value from the attraction matrix we need to get colors of particles we test\n",{"type":17,"tag":243,"props":11573,"children":11574},{"class":245,"line":6246},[11575],{"type":17,"tag":243,"props":11576,"children":11577},{},[11578],{"type":22,"value":11579},"                    f = force(d/radius, attractionMatrix[colors.index(particlesColors[i])][colors.index(particlesColors[j])])\n",{"type":17,"tag":243,"props":11581,"children":11582},{"class":245,"line":6255},[11583],{"type":17,"tag":243,"props":11584,"children":11585},{},[11586],{"type":22,"value":11587},"                    #lets add our force for this particle (j) to our total forces for particle (i)\n",{"type":17,"tag":243,"props":11589,"children":11590},{"class":245,"line":6264},[11591],{"type":17,"tag":243,"props":11592,"children":11593},{},[11594],{"type":22,"value":11595},"                    totalForceX+=(x / d)*f\n",{"type":17,"tag":243,"props":11597,"children":11598},{"class":245,"line":6273},[11599],{"type":17,"tag":243,"props":11600,"children":11601},{},[11602],{"type":22,"value":11603},"                    totalForceY+=(y / d)*f\n",{"type":17,"tag":243,"props":11605,"children":11606},{"class":245,"line":6282},[11607],{"type":17,"tag":243,"props":11608,"children":11609},{},[11610],{"type":22,"value":11611},"        #total force we just calculated will increase the particle's velocity\n",{"type":17,"tag":243,"props":11613,"children":11614},{"class":245,"line":6291},[11615],{"type":17,"tag":243,"props":11616,"children":11617},{},[11618],{"type":22,"value":11619},"        velocitiesX[i]+=totalForceX\n",{"type":17,"tag":243,"props":11621,"children":11622},{"class":245,"line":6300},[11623],{"type":17,"tag":243,"props":11624,"children":11625},{},[11626],{"type":22,"value":11627},"        velocitiesY[i]+=totalForceY\n",{"type":17,"tag":243,"props":11629,"children":11630},{"class":245,"line":6309},[11631],{"type":17,"tag":243,"props":11632,"children":11633},{},[11634],{"type":22,"value":11635},"        #we have to apply friction so that our particles don't accumulate velocity forever\n",{"type":17,"tag":243,"props":11637,"children":11638},{"class":245,"line":6318},[11639],{"type":17,"tag":243,"props":11640,"children":11641},{},[11642],{"type":22,"value":11643},"        velocitiesX[i]*=fr\n",{"type":17,"tag":243,"props":11645,"children":11646},{"class":245,"line":6327},[11647],{"type":17,"tag":243,"props":11648,"children":11649},{},[11650],{"type":22,"value":11651},"        velocitiesY[i]*=fr\n",{"type":17,"tag":243,"props":11653,"children":11654},{"class":245,"line":6335},[11655],{"type":17,"tag":243,"props":11656,"children":11657},{},[11658],{"type":22,"value":11659},"        #now that we have the particles velocity we can know how to change its position\n",{"type":17,"tag":243,"props":11661,"children":11662},{"class":245,"line":6343},[11663],{"type":17,"tag":243,"props":11664,"children":11665},{},[11666],{"type":22,"value":11667},"        positionsX[i]+=velocitiesX[i]\n",{"type":17,"tag":243,"props":11669,"children":11670},{"class":245,"line":6351},[11671],{"type":17,"tag":243,"props":11672,"children":11673},{},[11674],{"type":22,"value":11675},"        positionsY[i]+=velocitiesY[i]\n",{"type":17,"tag":243,"props":11677,"children":11678},{"class":245,"line":6359},[11679],{"type":17,"tag":243,"props":11680,"children":11681},{"emptyLinePlaceholder":2340},[11682],{"type":22,"value":2932},{"type":17,"tag":243,"props":11684,"children":11685},{"class":245,"line":6368},[11686],{"type":17,"tag":243,"props":11687,"children":11688},{},[11689],{"type":22,"value":11690},"#system properties\n",{"type":17,"tag":243,"props":11692,"children":11693},{"class":245,"line":6377},[11694],{"type":17,"tag":243,"props":11695,"children":11696},{},[11697],{"type":22,"value":11698},"n = 400 #number of particles\n",{"type":17,"tag":243,"props":11700,"children":11701},{"class":245,"line":6386},[11702],{"type":17,"tag":243,"props":11703,"children":11704},{},[11705],{"type":22,"value":11706},"m = 5 #number of colors\n",{"type":17,"tag":243,"props":11708,"children":11709},{"class":245,"line":6395},[11710],{"type":17,"tag":243,"props":11711,"children":11712},{},[11713],{"type":22,"value":11714},"radius = 0.20\n",{"type":17,"tag":243,"props":11716,"children":11717},{"class":245,"line":6403},[11718],{"type":17,"tag":243,"props":11719,"children":11720},{},[11721],{"type":22,"value":11722},"fr = math.pow(.5, 10) #friction\n",{"type":17,"tag":243,"props":11724,"children":11725},{"class":245,"line":6412},[11726],{"type":17,"tag":243,"props":11727,"children":11728},{"emptyLinePlaceholder":2340},[11729],{"type":22,"value":2932},{"type":17,"tag":243,"props":11731,"children":11732},{"class":245,"line":6420},[11733],{"type":17,"tag":243,"props":11734,"children":11735},{},[11736],{"type":22,"value":11737},"#init arrays to hold our values\n",{"type":17,"tag":243,"props":11739,"children":11740},{"class":245,"line":6429},[11741],{"type":17,"tag":243,"props":11742,"children":11743},{},[11744],{"type":22,"value":11745},"attractionMatrix = buildAttractionMatrix(np.random.random((m,m))) #create 2-d matrix based on number of colors\n",{"type":17,"tag":243,"props":11747,"children":11748},{"class":245,"line":6438},[11749],{"type":17,"tag":243,"props":11750,"children":11751},{},[11752],{"type":22,"value":11753},"colors = createColors(m)\n",{"type":17,"tag":243,"props":11755,"children":11756},{"class":245,"line":6446},[11757],{"type":17,"tag":243,"props":11758,"children":11759},{},[11760],{"type":22,"value":11761},"particlesColors = [rd.choice(colors) for _ in range(n)] #every particle is assigned random color from colors we created\n",{"type":17,"tag":243,"props":11763,"children":11764},{"class":245,"line":6454},[11765],{"type":17,"tag":243,"props":11766,"children":11767},{},[11768],{"type":22,"value":11769},"#every particle is assigned random position\n",{"type":17,"tag":243,"props":11771,"children":11772},{"class":245,"line":9135},[11773],{"type":17,"tag":243,"props":11774,"children":11775},{},[11776],{"type":22,"value":11777},"positionsX = [rd.random() for _ in range(n)]\n",{"type":17,"tag":243,"props":11779,"children":11780},{"class":245,"line":9153},[11781],{"type":17,"tag":243,"props":11782,"children":11783},{},[11784],{"type":22,"value":11785},"positionsY = [rd.random() for _ in range(n)]\n",{"type":17,"tag":243,"props":11787,"children":11788},{"class":245,"line":9171},[11789],{"type":17,"tag":243,"props":11790,"children":11791},{},[11792],{"type":22,"value":11793},"#every particle is assigned velocity = 0\n",{"type":17,"tag":243,"props":11795,"children":11796},{"class":245,"line":9179},[11797],{"type":17,"tag":243,"props":11798,"children":11799},{},[11800],{"type":22,"value":11801},"velocitiesX = np.empty(n, dtype=float)\n",{"type":17,"tag":243,"props":11803,"children":11804},{"class":245,"line":9196},[11805],{"type":17,"tag":243,"props":11806,"children":11807},{},[11808],{"type":22,"value":11809},"velocitiesY = np.empty(n, dtype=float)\n",{"type":17,"tag":243,"props":11811,"children":11812},{"class":245,"line":9213},[11813],{"type":17,"tag":243,"props":11814,"children":11815},{"emptyLinePlaceholder":2340},[11816],{"type":22,"value":2932},{"type":17,"tag":243,"props":11818,"children":11819},{"class":245,"line":9221},[11820],{"type":17,"tag":243,"props":11821,"children":11822},{},[11823],{"type":22,"value":11824},"class Window(QWidget):\n",{"type":17,"tag":243,"props":11826,"children":11827},{"class":245,"line":9230},[11828],{"type":17,"tag":243,"props":11829,"children":11830},{},[11831],{"type":22,"value":11832},"    def __init__(self):\n",{"type":17,"tag":243,"props":11834,"children":11835},{"class":245,"line":9239},[11836],{"type":17,"tag":243,"props":11837,"children":11838},{},[11839],{"type":22,"value":11840},"        super().__init__()\n",{"type":17,"tag":243,"props":11842,"children":11843},{"class":245,"line":9248},[11844],{"type":17,"tag":243,"props":11845,"children":11846},{"emptyLinePlaceholder":2340},[11847],{"type":22,"value":2932},{"type":17,"tag":243,"props":11849,"children":11850},{"class":245,"line":9257},[11851],{"type":17,"tag":243,"props":11852,"children":11853},{},[11854],{"type":22,"value":11855},"    def paintEvent(self, event):\n",{"type":17,"tag":243,"props":11857,"children":11858},{"class":245,"line":9266},[11859],{"type":17,"tag":243,"props":11860,"children":11861},{},[11862],{"type":22,"value":11863},"        painter = QPainter(self)\n",{"type":17,"tag":243,"props":11865,"children":11866},{"class":245,"line":9275},[11867],{"type":17,"tag":243,"props":11868,"children":11869},{"emptyLinePlaceholder":2340},[11870],{"type":22,"value":2932},{"type":17,"tag":243,"props":11872,"children":11873},{"class":245,"line":9283},[11874],{"type":17,"tag":243,"props":11875,"children":11876},{},[11877],{"type":22,"value":11878},"        updatePositions()\n",{"type":17,"tag":243,"props":11880,"children":11881},{"class":245,"line":9331},[11882],{"type":17,"tag":243,"props":11883,"children":11884},{},[11885],{"type":22,"value":11886},"        for i in range(n):\n",{"type":17,"tag":243,"props":11888,"children":11889},{"class":245,"line":9379},[11890],{"type":17,"tag":243,"props":11891,"children":11892},{},[11893],{"type":22,"value":11894},"            x = positionsX[i] * width\n",{"type":17,"tag":243,"props":11896,"children":11897},{"class":245,"line":9427},[11898],{"type":17,"tag":243,"props":11899,"children":11900},{},[11901],{"type":22,"value":11902},"            y = positionsY[i] * height\n",{"type":17,"tag":243,"props":11904,"children":11905},{"class":245,"line":9475},[11906],{"type":17,"tag":243,"props":11907,"children":11908},{},[11909],{"type":22,"value":11910},"            painter.setPen(particlesColors[i])\n",{"type":17,"tag":243,"props":11912,"children":11913},{"class":245,"line":9483},[11914],{"type":17,"tag":243,"props":11915,"children":11916},{},[11917],{"type":22,"value":11918},"            painter.drawEllipse(x, y, 1, 1)\n",{"type":17,"tag":243,"props":11920,"children":11921},{"class":245,"line":9499},[11922],{"type":17,"tag":243,"props":11923,"children":11924},{},[11925],{"type":22,"value":11926},"            self.update()\n",{"type":17,"tag":243,"props":11928,"children":11929},{"class":245,"line":9515},[11930],{"type":17,"tag":243,"props":11931,"children":11932},{"emptyLinePlaceholder":2340},[11933],{"type":22,"value":2932},{"type":17,"tag":243,"props":11935,"children":11936},{"class":245,"line":9523},[11937],{"type":17,"tag":243,"props":11938,"children":11939},{"emptyLinePlaceholder":2340},[11940],{"type":22,"value":2932},{"type":17,"tag":243,"props":11942,"children":11943},{"class":245,"line":9531},[11944],{"type":17,"tag":243,"props":11945,"children":11946},{},[11947],{"type":22,"value":11948},"app = QApplication(sys.argv)\n",{"type":17,"tag":243,"props":11950,"children":11951},{"class":245,"line":9539},[11952],{"type":17,"tag":243,"props":11953,"children":11954},{},[11955],{"type":22,"value":11956},"window = Window()\n",{"type":17,"tag":243,"props":11958,"children":11959},{"class":245,"line":9547},[11960],{"type":17,"tag":243,"props":11961,"children":11962},{},[11963],{"type":22,"value":11964},"window.height = height\n",{"type":17,"tag":243,"props":11966,"children":11967},{"class":245,"line":9556},[11968],{"type":17,"tag":243,"props":11969,"children":11970},{},[11971],{"type":22,"value":11972},"window.width = width\n",{"type":17,"tag":243,"props":11974,"children":11975},{"class":245,"line":9565},[11976],{"type":17,"tag":243,"props":11977,"children":11978},{},[11979],{"type":22,"value":11980},"window.show()\n",{"type":17,"tag":243,"props":11982,"children":11983},{"class":245,"line":9574},[11984],{"type":17,"tag":243,"props":11985,"children":11986},{"emptyLinePlaceholder":2340},[11987],{"type":22,"value":2932},{"type":17,"tag":243,"props":11989,"children":11990},{"class":245,"line":9582},[11991],{"type":17,"tag":243,"props":11992,"children":11993},{},[11994],{"type":22,"value":11995},"sys.exit(app.exec())\n",{"type":17,"tag":40,"props":11997,"children":11999},{"id":11998},"choosing-the-right-language-for-the-job",[12000],{"type":22,"value":12001},"Choosing the right language for the job",{"type":17,"tag":18,"props":12003,"children":12004},{},[12005,12007,12012],{"type":22,"value":12006},"There’s just one problem. My code is embarrassingly inefficient. I haven’t implemented any optimizations yet, but I didn’t expect it to be so bad! I work on a decent machine with an M2 processor, but I was barely able to run 500 particles before the animation stopped being smooth. It was my first time writing any Python code, so I suspected stepping on mine of using an inappropriate data structure or an unfortunate library function call (for example, later on, when I was implementing the same thing in javascript, calculating distance using Math.hypot() instead of Math.sqrt(x",{"type":17,"tag":2300,"props":12008,"children":12009},{},[12010],{"type":22,"value":12011},"x+y",{"type":22,"value":12013},"y) turned out to be nearly 10x slower).",{"type":17,"tag":18,"props":12015,"children":12016},{},[12017],{"type":22,"value":12018},"Unfortunately, after using line profiler I realized that it is basic arithmetic operations that take up most of the time. I know Python is not exactly the most efficient language out there, but I expected better.",{"type":17,"tag":18,"props":12020,"children":12021},{},[12022],{"type":22,"value":12023},"At this stage, I decided that my Python script would be only a point of origin, and I would write my proper implementation in something else. I’d love to simply embed my work to a webpage, where everyone can play with it, but first I wanted to see how JS will perform with a large amount of arithmetics compared to low-level languages. I know that nowadays v8 is pretty performant, so I had a good feeling about this. I know, I know - you can use C modules for Python, but since I don’t plan to dive deep into Python anytime soon, this option didn’t interest me. Another thing I was curious about was how WebAssebly would perform compared to JS.",{"type":17,"tag":18,"props":12025,"children":12026},{},[12027],{"type":22,"value":12028},"Before we start any benchmarking, we have to consider what we need to measure. What are the most costly operations of our algorithm?",{"type":17,"tag":18,"props":12030,"children":12031},{},[12032],{"type":22,"value":12033},"First of all, let's stress the fact that to calculate the positions of every particle we have to iterate over every other particle in the system, which gives us O(N^2) complexity. So, it is the code inside the inner loop in the updatePositions() function that takes most of the time. What is this code responsible for? Simply speaking, it performs basic arithmetic operations on array elements.",{"type":17,"tag":18,"props":12035,"children":12036},{},[12037],{"type":22,"value":12038},"It is important to realize you should never treat these types of benchmarks as an oracle guiding your development decisions. Here, it was useful. But there are many factors that influence code execution time besides language itself, and the first call should be always to optimize what you can with the language of your choice, unless it really is unreasonable, like using Python in this case.",{"type":17,"tag":18,"props":12040,"children":12041},{},[12042],{"type":22,"value":12043},"Having this little disclaimer out of the way, let's see what we can expect from Python, C, JS, and WebAssembly for the tasks described above.",{"type":17,"tag":18,"props":12045,"children":12046},{},[12047],{"type":22,"value":12048},"C:",{"type":17,"tag":233,"props":12050,"children":12054},{"className":12051,"code":12052,"language":12053,"meta":8,"style":8},"language-C shiki shiki-themes github-dark","int main(int argc, char * argv[]) {\n  srand((unsigned int) time(NULL));\n\n  int diff;\n  int i;\n  int j;\n  int l = 10000;\n  float t[l];\n\n  clock_t start = clock();\n\n  for (int i = 0; i \u003C l; i++) {\n    t[i] = 0.0;\n    for (j = 0; j \u003C l; j++) {\n      t[i] += 0.02 * (float)j;\n      t[i] *= 0.03 * (float)j;\n      t[i] -= 0.04 * (float)j;\n      t[i] /= 0.05 * (float)j+1.00;\n    }\n  }\n\n  clock_t end = clock();\n  int elapsed = (int)(end - start) / (CLOCKS_PER_SEC / 1000);\n  printf(\"%d %s\", elapsed, \"ms elapsed\");\n\n  return 0;\n}\n","C",[12055],{"type":17,"tag":219,"props":12056,"children":12057},{"__ignoreMap":8},[12058,12066,12074,12081,12089,12097,12105,12113,12121,12128,12136,12143,12151,12159,12167,12175,12183,12191,12199,12206,12213,12220,12228,12236,12244,12251,12259],{"type":17,"tag":243,"props":12059,"children":12060},{"class":245,"line":246},[12061],{"type":17,"tag":243,"props":12062,"children":12063},{},[12064],{"type":22,"value":12065},"int main(int argc, char * argv[]) {\n",{"type":17,"tag":243,"props":12067,"children":12068},{"class":245,"line":160},[12069],{"type":17,"tag":243,"props":12070,"children":12071},{},[12072],{"type":22,"value":12073},"  srand((unsigned int) time(NULL));\n",{"type":17,"tag":243,"props":12075,"children":12076},{"class":245,"line":302},[12077],{"type":17,"tag":243,"props":12078,"children":12079},{"emptyLinePlaceholder":2340},[12080],{"type":22,"value":2932},{"type":17,"tag":243,"props":12082,"children":12083},{"class":245,"line":311},[12084],{"type":17,"tag":243,"props":12085,"children":12086},{},[12087],{"type":22,"value":12088},"  int diff;\n",{"type":17,"tag":243,"props":12090,"children":12091},{"class":245,"line":356},[12092],{"type":17,"tag":243,"props":12093,"children":12094},{},[12095],{"type":22,"value":12096},"  int i;\n",{"type":17,"tag":243,"props":12098,"children":12099},{"class":245,"line":403},[12100],{"type":17,"tag":243,"props":12101,"children":12102},{},[12103],{"type":22,"value":12104},"  int j;\n",{"type":17,"tag":243,"props":12106,"children":12107},{"class":245,"line":411},[12108],{"type":17,"tag":243,"props":12109,"children":12110},{},[12111],{"type":22,"value":12112},"  int l = 10000;\n",{"type":17,"tag":243,"props":12114,"children":12115},{"class":245,"line":437},[12116],{"type":17,"tag":243,"props":12117,"children":12118},{},[12119],{"type":22,"value":12120},"  float t[l];\n",{"type":17,"tag":243,"props":12122,"children":12123},{"class":245,"line":510},[12124],{"type":17,"tag":243,"props":12125,"children":12126},{"emptyLinePlaceholder":2340},[12127],{"type":22,"value":2932},{"type":17,"tag":243,"props":12129,"children":12130},{"class":245,"line":518},[12131],{"type":17,"tag":243,"props":12132,"children":12133},{},[12134],{"type":22,"value":12135},"  clock_t start = clock();\n",{"type":17,"tag":243,"props":12137,"children":12138},{"class":245,"line":2757},[12139],{"type":17,"tag":243,"props":12140,"children":12141},{"emptyLinePlaceholder":2340},[12142],{"type":22,"value":2932},{"type":17,"tag":243,"props":12144,"children":12145},{"class":245,"line":2765},[12146],{"type":17,"tag":243,"props":12147,"children":12148},{},[12149],{"type":22,"value":12150},"  for (int i = 0; i \u003C l; i++) {\n",{"type":17,"tag":243,"props":12152,"children":12153},{"class":245,"line":2774},[12154],{"type":17,"tag":243,"props":12155,"children":12156},{},[12157],{"type":22,"value":12158},"    t[i] = 0.0;\n",{"type":17,"tag":243,"props":12160,"children":12161},{"class":245,"line":2783},[12162],{"type":17,"tag":243,"props":12163,"children":12164},{},[12165],{"type":22,"value":12166},"    for (j = 0; j \u003C l; j++) {\n",{"type":17,"tag":243,"props":12168,"children":12169},{"class":245,"line":2792},[12170],{"type":17,"tag":243,"props":12171,"children":12172},{},[12173],{"type":22,"value":12174},"      t[i] += 0.02 * (float)j;\n",{"type":17,"tag":243,"props":12176,"children":12177},{"class":245,"line":2801},[12178],{"type":17,"tag":243,"props":12179,"children":12180},{},[12181],{"type":22,"value":12182},"      t[i] *= 0.03 * (float)j;\n",{"type":17,"tag":243,"props":12184,"children":12185},{"class":245,"line":2833},[12186],{"type":17,"tag":243,"props":12187,"children":12188},{},[12189],{"type":22,"value":12190},"      t[i] -= 0.04 * (float)j;\n",{"type":17,"tag":243,"props":12192,"children":12193},{"class":245,"line":2842},[12194],{"type":17,"tag":243,"props":12195,"children":12196},{},[12197],{"type":22,"value":12198},"      t[i] /= 0.05 * (float)j+1.00;\n",{"type":17,"tag":243,"props":12200,"children":12201},{"class":245,"line":2889},[12202],{"type":17,"tag":243,"props":12203,"children":12204},{},[12205],{"type":22,"value":4207},{"type":17,"tag":243,"props":12207,"children":12208},{"class":245,"line":2898},[12209],{"type":17,"tag":243,"props":12210,"children":12211},{},[12212],{"type":22,"value":1413},{"type":17,"tag":243,"props":12214,"children":12215},{"class":245,"line":2926},[12216],{"type":17,"tag":243,"props":12217,"children":12218},{"emptyLinePlaceholder":2340},[12219],{"type":22,"value":2932},{"type":17,"tag":243,"props":12221,"children":12222},{"class":245,"line":2935},[12223],{"type":17,"tag":243,"props":12224,"children":12225},{},[12226],{"type":22,"value":12227},"  clock_t end = clock();\n",{"type":17,"tag":243,"props":12229,"children":12230},{"class":245,"line":2944},[12231],{"type":17,"tag":243,"props":12232,"children":12233},{},[12234],{"type":22,"value":12235},"  int elapsed = (int)(end - start) / (CLOCKS_PER_SEC / 1000);\n",{"type":17,"tag":243,"props":12237,"children":12238},{"class":245,"line":2953},[12239],{"type":17,"tag":243,"props":12240,"children":12241},{},[12242],{"type":22,"value":12243},"  printf(\"%d %s\", elapsed, \"ms elapsed\");\n",{"type":17,"tag":243,"props":12245,"children":12246},{"class":245,"line":2984},[12247],{"type":17,"tag":243,"props":12248,"children":12249},{"emptyLinePlaceholder":2340},[12250],{"type":22,"value":2932},{"type":17,"tag":243,"props":12252,"children":12253},{"class":245,"line":3040},[12254],{"type":17,"tag":243,"props":12255,"children":12256},{},[12257],{"type":22,"value":12258},"  return 0;\n",{"type":17,"tag":243,"props":12260,"children":12261},{"class":245,"line":3084},[12262],{"type":17,"tag":243,"props":12263,"children":12264},{},[12265],{"type":22,"value":308},{"type":17,"tag":18,"props":12267,"children":12268},{},[12269],{"type":22,"value":12270},"JS:",{"type":17,"tag":233,"props":12272,"children":12274},{"className":235,"code":12273,"language":237,"meta":8,"style":8},"const l = 10000;\nconst t = [];\n\nconst s = Date.now();\n\nfor (let i = 0; i \u003C l; i++) {\n  t[i] = 0;\n\n  for (j = 0; j \u003C l; j++) {\n    t[i] += 0.02 * j;\n    t[i] *= 0.03 * j;\n    t[i] -= 0.04 * j;\n    t[i] /= 0.05 * (j + 1);\n  }\n}\n\nconsole.log(\n  Date.now() - s,\n  \"ms elapsed\"\n);\n",[12275],{"type":17,"tag":219,"props":12276,"children":12277},{"__ignoreMap":8},[12278,12303,12323,12330,12360,12367,12415,12435,12442,12482,12508,12532,12557,12594,12601,12608,12615,12631,12656,12664],{"type":17,"tag":243,"props":12279,"children":12280},{"class":245,"line":246},[12281,12285,12290,12294,12299],{"type":17,"tag":243,"props":12282,"children":12283},{"style":250},[12284],{"type":22,"value":1691},{"type":17,"tag":243,"props":12286,"children":12287},{"style":378},[12288],{"type":22,"value":12289}," l",{"type":17,"tag":243,"props":12291,"children":12292},{"style":250},[12293],{"type":22,"value":1474},{"type":17,"tag":243,"props":12295,"children":12296},{"style":378},[12297],{"type":22,"value":12298}," 10000",{"type":17,"tag":243,"props":12300,"children":12301},{"style":262},[12302],{"type":22,"value":507},{"type":17,"tag":243,"props":12304,"children":12305},{"class":245,"line":160},[12306,12310,12315,12319],{"type":17,"tag":243,"props":12307,"children":12308},{"style":250},[12309],{"type":22,"value":1691},{"type":17,"tag":243,"props":12311,"children":12312},{"style":378},[12313],{"type":22,"value":12314}," t",{"type":17,"tag":243,"props":12316,"children":12317},{"style":250},[12318],{"type":22,"value":1474},{"type":17,"tag":243,"props":12320,"children":12321},{"style":262},[12322],{"type":22,"value":3952},{"type":17,"tag":243,"props":12324,"children":12325},{"class":245,"line":302},[12326],{"type":17,"tag":243,"props":12327,"children":12328},{"emptyLinePlaceholder":2340},[12329],{"type":22,"value":2932},{"type":17,"tag":243,"props":12331,"children":12332},{"class":245,"line":311},[12333,12337,12342,12346,12351,12356],{"type":17,"tag":243,"props":12334,"children":12335},{"style":250},[12336],{"type":22,"value":1691},{"type":17,"tag":243,"props":12338,"children":12339},{"style":378},[12340],{"type":22,"value":12341}," s",{"type":17,"tag":243,"props":12343,"children":12344},{"style":250},[12345],{"type":22,"value":1474},{"type":17,"tag":243,"props":12347,"children":12348},{"style":262},[12349],{"type":22,"value":12350}," Date.",{"type":17,"tag":243,"props":12352,"children":12353},{"style":256},[12354],{"type":22,"value":12355},"now",{"type":17,"tag":243,"props":12357,"children":12358},{"style":262},[12359],{"type":22,"value":2191},{"type":17,"tag":243,"props":12361,"children":12362},{"class":245,"line":356},[12363],{"type":17,"tag":243,"props":12364,"children":12365},{"emptyLinePlaceholder":2340},[12366],{"type":22,"value":2932},{"type":17,"tag":243,"props":12368,"children":12369},{"class":245,"line":403},[12370,12374,12378,12382,12386,12390,12394,12398,12402,12407,12411],{"type":17,"tag":243,"props":12371,"children":12372},{"style":250},[12373],{"type":22,"value":1583},{"type":17,"tag":243,"props":12375,"children":12376},{"style":262},[12377],{"type":22,"value":1523},{"type":17,"tag":243,"props":12379,"children":12380},{"style":250},[12381],{"type":22,"value":1592},{"type":17,"tag":243,"props":12383,"children":12384},{"style":262},[12385],{"type":22,"value":1497},{"type":17,"tag":243,"props":12387,"children":12388},{"style":250},[12389],{"type":22,"value":1502},{"type":17,"tag":243,"props":12391,"children":12392},{"style":378},[12393],{"type":22,"value":457},{"type":17,"tag":243,"props":12395,"children":12396},{"style":262},[12397],{"type":22,"value":1962},{"type":17,"tag":243,"props":12399,"children":12400},{"style":250},[12401],{"type":22,"value":481},{"type":17,"tag":243,"props":12403,"children":12404},{"style":262},[12405],{"type":22,"value":12406}," l; i",{"type":17,"tag":243,"props":12408,"children":12409},{"style":250},[12410],{"type":22,"value":1550},{"type":17,"tag":243,"props":12412,"children":12413},{"style":262},[12414],{"type":22,"value":276},{"type":17,"tag":243,"props":12416,"children":12417},{"class":245,"line":411},[12418,12423,12427,12431],{"type":17,"tag":243,"props":12419,"children":12420},{"style":262},[12421],{"type":22,"value":12422},"  t[i] ",{"type":17,"tag":243,"props":12424,"children":12425},{"style":250},[12426],{"type":22,"value":1502},{"type":17,"tag":243,"props":12428,"children":12429},{"style":378},[12430],{"type":22,"value":457},{"type":17,"tag":243,"props":12432,"children":12433},{"style":262},[12434],{"type":22,"value":507},{"type":17,"tag":243,"props":12436,"children":12437},{"class":245,"line":437},[12438],{"type":17,"tag":243,"props":12439,"children":12440},{"emptyLinePlaceholder":2340},[12441],{"type":22,"value":2932},{"type":17,"tag":243,"props":12443,"children":12444},{"class":245,"line":510},[12445,12449,12453,12457,12461,12465,12469,12474,12478],{"type":17,"tag":243,"props":12446,"children":12447},{"style":250},[12448],{"type":22,"value":4063},{"type":17,"tag":243,"props":12450,"children":12451},{"style":262},[12452],{"type":22,"value":4777},{"type":17,"tag":243,"props":12454,"children":12455},{"style":250},[12456],{"type":22,"value":1502},{"type":17,"tag":243,"props":12458,"children":12459},{"style":378},[12460],{"type":22,"value":457},{"type":17,"tag":243,"props":12462,"children":12463},{"style":262},[12464],{"type":22,"value":4089},{"type":17,"tag":243,"props":12466,"children":12467},{"style":250},[12468],{"type":22,"value":481},{"type":17,"tag":243,"props":12470,"children":12471},{"style":262},[12472],{"type":22,"value":12473}," l; j",{"type":17,"tag":243,"props":12475,"children":12476},{"style":250},[12477],{"type":22,"value":1550},{"type":17,"tag":243,"props":12479,"children":12480},{"style":262},[12481],{"type":22,"value":276},{"type":17,"tag":243,"props":12483,"children":12484},{"class":245,"line":518},[12485,12490,12494,12499,12503],{"type":17,"tag":243,"props":12486,"children":12487},{"style":262},[12488],{"type":22,"value":12489},"    t[i] ",{"type":17,"tag":243,"props":12491,"children":12492},{"style":250},[12493],{"type":22,"value":2554},{"type":17,"tag":243,"props":12495,"children":12496},{"style":378},[12497],{"type":22,"value":12498}," 0.02",{"type":17,"tag":243,"props":12500,"children":12501},{"style":250},[12502],{"type":22,"value":386},{"type":17,"tag":243,"props":12504,"children":12505},{"style":262},[12506],{"type":22,"value":12507}," j;\n",{"type":17,"tag":243,"props":12509,"children":12510},{"class":245,"line":2757},[12511,12515,12519,12524,12528],{"type":17,"tag":243,"props":12512,"children":12513},{"style":262},[12514],{"type":22,"value":12489},{"type":17,"tag":243,"props":12516,"children":12517},{"style":250},[12518],{"type":22,"value":9105},{"type":17,"tag":243,"props":12520,"children":12521},{"style":378},[12522],{"type":22,"value":12523}," 0.03",{"type":17,"tag":243,"props":12525,"children":12526},{"style":250},[12527],{"type":22,"value":386},{"type":17,"tag":243,"props":12529,"children":12530},{"style":262},[12531],{"type":22,"value":12507},{"type":17,"tag":243,"props":12533,"children":12534},{"class":245,"line":2765},[12535,12539,12544,12549,12553],{"type":17,"tag":243,"props":12536,"children":12537},{"style":262},[12538],{"type":22,"value":12489},{"type":17,"tag":243,"props":12540,"children":12541},{"style":250},[12542],{"type":22,"value":12543},"-=",{"type":17,"tag":243,"props":12545,"children":12546},{"style":378},[12547],{"type":22,"value":12548}," 0.04",{"type":17,"tag":243,"props":12550,"children":12551},{"style":250},[12552],{"type":22,"value":386},{"type":17,"tag":243,"props":12554,"children":12555},{"style":262},[12556],{"type":22,"value":12507},{"type":17,"tag":243,"props":12558,"children":12559},{"class":245,"line":2774},[12560,12564,12569,12574,12578,12582,12586,12590],{"type":17,"tag":243,"props":12561,"children":12562},{"style":262},[12563],{"type":22,"value":12489},{"type":17,"tag":243,"props":12565,"children":12566},{"style":250},[12567],{"type":22,"value":12568},"/=",{"type":17,"tag":243,"props":12570,"children":12571},{"style":378},[12572],{"type":22,"value":12573}," 0.05",{"type":17,"tag":243,"props":12575,"children":12576},{"style":250},[12577],{"type":22,"value":386},{"type":17,"tag":243,"props":12579,"children":12580},{"style":262},[12581],{"type":22,"value":4777},{"type":17,"tag":243,"props":12583,"children":12584},{"style":250},[12585],{"type":22,"value":1891},{"type":17,"tag":243,"props":12587,"children":12588},{"style":378},[12589],{"type":22,"value":467},{"type":17,"tag":243,"props":12591,"children":12592},{"style":262},[12593],{"type":22,"value":1215},{"type":17,"tag":243,"props":12595,"children":12596},{"class":245,"line":2783},[12597],{"type":17,"tag":243,"props":12598,"children":12599},{"style":262},[12600],{"type":22,"value":1413},{"type":17,"tag":243,"props":12602,"children":12603},{"class":245,"line":2792},[12604],{"type":17,"tag":243,"props":12605,"children":12606},{"style":262},[12607],{"type":22,"value":308},{"type":17,"tag":243,"props":12609,"children":12610},{"class":245,"line":2801},[12611],{"type":17,"tag":243,"props":12612,"children":12613},{"emptyLinePlaceholder":2340},[12614],{"type":22,"value":2932},{"type":17,"tag":243,"props":12616,"children":12617},{"class":245,"line":2833},[12618,12623,12627],{"type":17,"tag":243,"props":12619,"children":12620},{"style":262},[12621],{"type":22,"value":12622},"console.",{"type":17,"tag":243,"props":12624,"children":12625},{"style":256},[12626],{"type":22,"value":1659},{"type":17,"tag":243,"props":12628,"children":12629},{"style":262},[12630],{"type":22,"value":8952},{"type":17,"tag":243,"props":12632,"children":12633},{"class":245,"line":2842},[12634,12639,12643,12647,12651],{"type":17,"tag":243,"props":12635,"children":12636},{"style":262},[12637],{"type":22,"value":12638},"  Date.",{"type":17,"tag":243,"props":12640,"children":12641},{"style":256},[12642],{"type":22,"value":12355},{"type":17,"tag":243,"props":12644,"children":12645},{"style":262},[12646],{"type":22,"value":2589},{"type":17,"tag":243,"props":12648,"children":12649},{"style":250},[12650],{"type":22,"value":375},{"type":17,"tag":243,"props":12652,"children":12653},{"style":262},[12654],{"type":22,"value":12655}," s,\n",{"type":17,"tag":243,"props":12657,"children":12658},{"class":245,"line":2889},[12659],{"type":17,"tag":243,"props":12660,"children":12661},{"style":981},[12662],{"type":22,"value":12663},"  \"ms elapsed\"\n",{"type":17,"tag":243,"props":12665,"children":12666},{"class":245,"line":2898},[12667],{"type":17,"tag":243,"props":12668,"children":12669},{"style":262},[12670],{"type":22,"value":1215},{"type":17,"tag":18,"props":12672,"children":12673},{},[12674],{"type":22,"value":12675},"Python:",{"type":17,"tag":233,"props":12677,"children":12679},{"className":11091,"code":12678,"language":11093,"meta":8,"style":8},"import time\nimport random as rd\nimport numpy as np\n\nl = 10000\nt = np.empty(l, dtype=float)\n\ns= time.time()\nfor i in range(l):\n    t[i] = 0.0\n    for j in range(l):\n        t[i] += 0.02 * j\n        t[i] *= 0.03 * j\n        t[i] -= 0.04 * j\n        t[i] /= 0.05 * (j+1)\n\nprint( (time.time()-s) * 1000, 'ms elapsed')\n\n\n",[12680],{"type":17,"tag":219,"props":12681,"children":12682},{"__ignoreMap":8},[12683,12691,12698,12705,12712,12720,12728,12735,12743,12751,12759,12767,12775,12783,12791,12799,12806],{"type":17,"tag":243,"props":12684,"children":12685},{"class":245,"line":246},[12686],{"type":17,"tag":243,"props":12687,"children":12688},{},[12689],{"type":22,"value":12690},"import time\n",{"type":17,"tag":243,"props":12692,"children":12693},{"class":245,"line":160},[12694],{"type":17,"tag":243,"props":12695,"children":12696},{},[12697],{"type":22,"value":11121},{"type":17,"tag":243,"props":12699,"children":12700},{"class":245,"line":302},[12701],{"type":17,"tag":243,"props":12702,"children":12703},{},[12704],{"type":22,"value":11105},{"type":17,"tag":243,"props":12706,"children":12707},{"class":245,"line":311},[12708],{"type":17,"tag":243,"props":12709,"children":12710},{"emptyLinePlaceholder":2340},[12711],{"type":22,"value":2932},{"type":17,"tag":243,"props":12713,"children":12714},{"class":245,"line":356},[12715],{"type":17,"tag":243,"props":12716,"children":12717},{},[12718],{"type":22,"value":12719},"l = 10000\n",{"type":17,"tag":243,"props":12721,"children":12722},{"class":245,"line":403},[12723],{"type":17,"tag":243,"props":12724,"children":12725},{},[12726],{"type":22,"value":12727},"t = np.empty(l, dtype=float)\n",{"type":17,"tag":243,"props":12729,"children":12730},{"class":245,"line":411},[12731],{"type":17,"tag":243,"props":12732,"children":12733},{"emptyLinePlaceholder":2340},[12734],{"type":22,"value":2932},{"type":17,"tag":243,"props":12736,"children":12737},{"class":245,"line":437},[12738],{"type":17,"tag":243,"props":12739,"children":12740},{},[12741],{"type":22,"value":12742},"s= time.time()\n",{"type":17,"tag":243,"props":12744,"children":12745},{"class":245,"line":510},[12746],{"type":17,"tag":243,"props":12747,"children":12748},{},[12749],{"type":22,"value":12750},"for i in range(l):\n",{"type":17,"tag":243,"props":12752,"children":12753},{"class":245,"line":518},[12754],{"type":17,"tag":243,"props":12755,"children":12756},{},[12757],{"type":22,"value":12758},"    t[i] = 0.0\n",{"type":17,"tag":243,"props":12760,"children":12761},{"class":245,"line":2757},[12762],{"type":17,"tag":243,"props":12763,"children":12764},{},[12765],{"type":22,"value":12766},"    for j in range(l):\n",{"type":17,"tag":243,"props":12768,"children":12769},{"class":245,"line":2765},[12770],{"type":17,"tag":243,"props":12771,"children":12772},{},[12773],{"type":22,"value":12774},"        t[i] += 0.02 * j\n",{"type":17,"tag":243,"props":12776,"children":12777},{"class":245,"line":2774},[12778],{"type":17,"tag":243,"props":12779,"children":12780},{},[12781],{"type":22,"value":12782},"        t[i] *= 0.03 * j\n",{"type":17,"tag":243,"props":12784,"children":12785},{"class":245,"line":2783},[12786],{"type":17,"tag":243,"props":12787,"children":12788},{},[12789],{"type":22,"value":12790},"        t[i] -= 0.04 * j\n",{"type":17,"tag":243,"props":12792,"children":12793},{"class":245,"line":2792},[12794],{"type":17,"tag":243,"props":12795,"children":12796},{},[12797],{"type":22,"value":12798},"        t[i] /= 0.05 * (j+1)\n",{"type":17,"tag":243,"props":12800,"children":12801},{"class":245,"line":2801},[12802],{"type":17,"tag":243,"props":12803,"children":12804},{"emptyLinePlaceholder":2340},[12805],{"type":22,"value":2932},{"type":17,"tag":243,"props":12807,"children":12808},{"class":245,"line":2833},[12809],{"type":17,"tag":243,"props":12810,"children":12811},{},[12812],{"type":22,"value":12813},"print( (time.time()-s) * 1000, 'ms elapsed')\n",{"type":17,"tag":18,"props":12815,"children":12816},{},[12817],{"type":22,"value":12818},"The results were interesting to say the least:",{"type":17,"tag":5258,"props":12820,"children":12822},{"src":12821},"/articles/Zrzut ekranu 2024-02-26 o 18.50.11.png",[],{"type":17,"tag":18,"props":12824,"children":12825},{},[12826],{"type":22,"value":12827},"Few things require noting here:",{"type":17,"tag":580,"props":12829,"children":12830},{},[12831,12843],{"type":17,"tag":584,"props":12832,"children":12833},{},[12834,12836,12841],{"type":22,"value":12835},"I didn't use any optimization flags when compiling my C code. My focus is on checking if JS is ",{"type":17,"tag":91,"props":12837,"children":12838},{},[12839],{"type":22,"value":12840},"good enough",{"type":22,"value":12842}," for the job, not if JS is faster than C! This is a very important point to keep in mind.",{"type":17,"tag":584,"props":12844,"children":12845},{},[12846],{"type":22,"value":12847},"Node is using a V8 engine. When I ran the same file using Apple's JavascriptCore, the result was nearly twice as long. I can turn a blind eye to that when developing a hobby project, but for the real product, it would be quite an issue.",{"type":17,"tag":18,"props":12849,"children":12850},{},[12851],{"type":22,"value":12852},"We need to remember that these benchmarks measure nothing but the efficiency of my little script. It would be unwise to draw any premature conclusions from it. Still, we should appreciate how optimized modern JS is. In the next part, you'll see that many of the go-to points developers usually go through when optimizing their code, give no advantage, because the V8 compiler is just smart enough to know to take care of it for us... If there's one lesson to be learned from the examples above, it would be that for things requiring performance, developers should never trust, and always verify. I was very surprised!",{"type":17,"tag":18,"props":12854,"children":12855},{},[12856],{"type":22,"value":12857},"If JS performed so well compared to low-level C, you can probably already guess what my next point will be: using WebAssembly gives us no advantage in this case.",{"type":17,"tag":18,"props":12859,"children":12860},{},[12861],{"type":22,"value":12862},"For the curious of you, WASM module compiled from this AssemblyScript:",{"type":17,"tag":233,"props":12864,"children":12866},{"className":235,"code":12865,"language":237,"meta":8,"style":8},"export function updateParticles(): void {\n  const l = 10000;\n  const t: f32[] = [];\n\n  const s = Date.now();\n\n  for (let i = 0; i \u003C l; i++) {\n    t[i] = 0;\n\n    for (let j = 0; j \u003C l; j++) {\n      t[i] += 0.02 * (j as f32);\n      t[i] *= 0.03 * (j as f32);\n      t[i] -= 0.04 * (j as f32);\n      t[i] /= 0.05 * ((j + 1) as f32);\n    }\n  }\n\n  console.log((Date.now() - s).toString() + \" ms elapsed\");\n}\n",[12867],{"type":17,"tag":219,"props":12868,"children":12869},{"__ignoreMap":8},[12870,12905,12928,12960,12967,12994,13001,13048,13067,13074,13121,13157,13192,13227,13275,13282,13289,13296,13351],{"type":17,"tag":243,"props":12871,"children":12872},{"class":245,"line":246},[12873,12878,12883,12887,12892,12896,12901],{"type":17,"tag":243,"props":12874,"children":12875},{"style":250},[12876],{"type":22,"value":12877},"export",{"type":17,"tag":243,"props":12879,"children":12880},{"style":250},[12881],{"type":22,"value":12882}," function",{"type":17,"tag":243,"props":12884,"children":12885},{"style":256},[12886],{"type":22,"value":8611},{"type":17,"tag":243,"props":12888,"children":12889},{"style":262},[12890],{"type":22,"value":12891},"()",{"type":17,"tag":243,"props":12893,"children":12894},{"style":250},[12895],{"type":22,"value":925},{"type":17,"tag":243,"props":12897,"children":12898},{"style":378},[12899],{"type":22,"value":12900}," void",{"type":17,"tag":243,"props":12902,"children":12903},{"style":262},[12904],{"type":22,"value":1370},{"type":17,"tag":243,"props":12906,"children":12907},{"class":245,"line":160},[12908,12912,12916,12920,12924],{"type":17,"tag":243,"props":12909,"children":12910},{"style":250},[12911],{"type":22,"value":6930},{"type":17,"tag":243,"props":12913,"children":12914},{"style":378},[12915],{"type":22,"value":12289},{"type":17,"tag":243,"props":12917,"children":12918},{"style":250},[12919],{"type":22,"value":1474},{"type":17,"tag":243,"props":12921,"children":12922},{"style":378},[12923],{"type":22,"value":12298},{"type":17,"tag":243,"props":12925,"children":12926},{"style":262},[12927],{"type":22,"value":507},{"type":17,"tag":243,"props":12929,"children":12930},{"class":245,"line":302},[12931,12935,12939,12943,12948,12952,12956],{"type":17,"tag":243,"props":12932,"children":12933},{"style":250},[12934],{"type":22,"value":6930},{"type":17,"tag":243,"props":12936,"children":12937},{"style":378},[12938],{"type":22,"value":12314},{"type":17,"tag":243,"props":12940,"children":12941},{"style":250},[12942],{"type":22,"value":925},{"type":17,"tag":243,"props":12944,"children":12945},{"style":256},[12946],{"type":22,"value":12947}," f32",{"type":17,"tag":243,"props":12949,"children":12950},{"style":262},[12951],{"type":22,"value":3943},{"type":17,"tag":243,"props":12953,"children":12954},{"style":250},[12955],{"type":22,"value":1502},{"type":17,"tag":243,"props":12957,"children":12958},{"style":262},[12959],{"type":22,"value":3952},{"type":17,"tag":243,"props":12961,"children":12962},{"class":245,"line":311},[12963],{"type":17,"tag":243,"props":12964,"children":12965},{"emptyLinePlaceholder":2340},[12966],{"type":22,"value":2932},{"type":17,"tag":243,"props":12968,"children":12969},{"class":245,"line":356},[12970,12974,12978,12982,12986,12990],{"type":17,"tag":243,"props":12971,"children":12972},{"style":250},[12973],{"type":22,"value":6930},{"type":17,"tag":243,"props":12975,"children":12976},{"style":378},[12977],{"type":22,"value":12341},{"type":17,"tag":243,"props":12979,"children":12980},{"style":250},[12981],{"type":22,"value":1474},{"type":17,"tag":243,"props":12983,"children":12984},{"style":262},[12985],{"type":22,"value":12350},{"type":17,"tag":243,"props":12987,"children":12988},{"style":256},[12989],{"type":22,"value":12355},{"type":17,"tag":243,"props":12991,"children":12992},{"style":262},[12993],{"type":22,"value":2191},{"type":17,"tag":243,"props":12995,"children":12996},{"class":245,"line":403},[12997],{"type":17,"tag":243,"props":12998,"children":12999},{"emptyLinePlaceholder":2340},[13000],{"type":22,"value":2932},{"type":17,"tag":243,"props":13002,"children":13003},{"class":245,"line":411},[13004,13008,13012,13016,13020,13024,13028,13032,13036,13040,13044],{"type":17,"tag":243,"props":13005,"children":13006},{"style":250},[13007],{"type":22,"value":4063},{"type":17,"tag":243,"props":13009,"children":13010},{"style":262},[13011],{"type":22,"value":1523},{"type":17,"tag":243,"props":13013,"children":13014},{"style":250},[13015],{"type":22,"value":1592},{"type":17,"tag":243,"props":13017,"children":13018},{"style":262},[13019],{"type":22,"value":1497},{"type":17,"tag":243,"props":13021,"children":13022},{"style":250},[13023],{"type":22,"value":1502},{"type":17,"tag":243,"props":13025,"children":13026},{"style":378},[13027],{"type":22,"value":457},{"type":17,"tag":243,"props":13029,"children":13030},{"style":262},[13031],{"type":22,"value":1962},{"type":17,"tag":243,"props":13033,"children":13034},{"style":250},[13035],{"type":22,"value":481},{"type":17,"tag":243,"props":13037,"children":13038},{"style":262},[13039],{"type":22,"value":12406},{"type":17,"tag":243,"props":13041,"children":13042},{"style":250},[13043],{"type":22,"value":1550},{"type":17,"tag":243,"props":13045,"children":13046},{"style":262},[13047],{"type":22,"value":276},{"type":17,"tag":243,"props":13049,"children":13050},{"class":245,"line":437},[13051,13055,13059,13063],{"type":17,"tag":243,"props":13052,"children":13053},{"style":262},[13054],{"type":22,"value":12489},{"type":17,"tag":243,"props":13056,"children":13057},{"style":250},[13058],{"type":22,"value":1502},{"type":17,"tag":243,"props":13060,"children":13061},{"style":378},[13062],{"type":22,"value":457},{"type":17,"tag":243,"props":13064,"children":13065},{"style":262},[13066],{"type":22,"value":507},{"type":17,"tag":243,"props":13068,"children":13069},{"class":245,"line":510},[13070],{"type":17,"tag":243,"props":13071,"children":13072},{"emptyLinePlaceholder":2340},[13073],{"type":22,"value":2932},{"type":17,"tag":243,"props":13075,"children":13076},{"class":245,"line":518},[13077,13081,13085,13089,13093,13097,13101,13105,13109,13113,13117],{"type":17,"tag":243,"props":13078,"children":13079},{"style":250},[13080],{"type":22,"value":4114},{"type":17,"tag":243,"props":13082,"children":13083},{"style":262},[13084],{"type":22,"value":1523},{"type":17,"tag":243,"props":13086,"children":13087},{"style":250},[13088],{"type":22,"value":1592},{"type":17,"tag":243,"props":13090,"children":13091},{"style":262},[13092],{"type":22,"value":4076},{"type":17,"tag":243,"props":13094,"children":13095},{"style":250},[13096],{"type":22,"value":1502},{"type":17,"tag":243,"props":13098,"children":13099},{"style":378},[13100],{"type":22,"value":457},{"type":17,"tag":243,"props":13102,"children":13103},{"style":262},[13104],{"type":22,"value":4089},{"type":17,"tag":243,"props":13106,"children":13107},{"style":250},[13108],{"type":22,"value":481},{"type":17,"tag":243,"props":13110,"children":13111},{"style":262},[13112],{"type":22,"value":12473},{"type":17,"tag":243,"props":13114,"children":13115},{"style":250},[13116],{"type":22,"value":1550},{"type":17,"tag":243,"props":13118,"children":13119},{"style":262},[13120],{"type":22,"value":276},{"type":17,"tag":243,"props":13122,"children":13123},{"class":245,"line":2757},[13124,13129,13133,13137,13141,13145,13149,13153],{"type":17,"tag":243,"props":13125,"children":13126},{"style":262},[13127],{"type":22,"value":13128},"      t[i] ",{"type":17,"tag":243,"props":13130,"children":13131},{"style":250},[13132],{"type":22,"value":2554},{"type":17,"tag":243,"props":13134,"children":13135},{"style":378},[13136],{"type":22,"value":12498},{"type":17,"tag":243,"props":13138,"children":13139},{"style":250},[13140],{"type":22,"value":386},{"type":17,"tag":243,"props":13142,"children":13143},{"style":262},[13144],{"type":22,"value":4777},{"type":17,"tag":243,"props":13146,"children":13147},{"style":250},[13148],{"type":22,"value":6967},{"type":17,"tag":243,"props":13150,"children":13151},{"style":256},[13152],{"type":22,"value":12947},{"type":17,"tag":243,"props":13154,"children":13155},{"style":262},[13156],{"type":22,"value":1215},{"type":17,"tag":243,"props":13158,"children":13159},{"class":245,"line":2765},[13160,13164,13168,13172,13176,13180,13184,13188],{"type":17,"tag":243,"props":13161,"children":13162},{"style":262},[13163],{"type":22,"value":13128},{"type":17,"tag":243,"props":13165,"children":13166},{"style":250},[13167],{"type":22,"value":9105},{"type":17,"tag":243,"props":13169,"children":13170},{"style":378},[13171],{"type":22,"value":12523},{"type":17,"tag":243,"props":13173,"children":13174},{"style":250},[13175],{"type":22,"value":386},{"type":17,"tag":243,"props":13177,"children":13178},{"style":262},[13179],{"type":22,"value":4777},{"type":17,"tag":243,"props":13181,"children":13182},{"style":250},[13183],{"type":22,"value":6967},{"type":17,"tag":243,"props":13185,"children":13186},{"style":256},[13187],{"type":22,"value":12947},{"type":17,"tag":243,"props":13189,"children":13190},{"style":262},[13191],{"type":22,"value":1215},{"type":17,"tag":243,"props":13193,"children":13194},{"class":245,"line":2774},[13195,13199,13203,13207,13211,13215,13219,13223],{"type":17,"tag":243,"props":13196,"children":13197},{"style":262},[13198],{"type":22,"value":13128},{"type":17,"tag":243,"props":13200,"children":13201},{"style":250},[13202],{"type":22,"value":12543},{"type":17,"tag":243,"props":13204,"children":13205},{"style":378},[13206],{"type":22,"value":12548},{"type":17,"tag":243,"props":13208,"children":13209},{"style":250},[13210],{"type":22,"value":386},{"type":17,"tag":243,"props":13212,"children":13213},{"style":262},[13214],{"type":22,"value":4777},{"type":17,"tag":243,"props":13216,"children":13217},{"style":250},[13218],{"type":22,"value":6967},{"type":17,"tag":243,"props":13220,"children":13221},{"style":256},[13222],{"type":22,"value":12947},{"type":17,"tag":243,"props":13224,"children":13225},{"style":262},[13226],{"type":22,"value":1215},{"type":17,"tag":243,"props":13228,"children":13229},{"class":245,"line":2783},[13230,13234,13238,13242,13246,13251,13255,13259,13263,13267,13271],{"type":17,"tag":243,"props":13231,"children":13232},{"style":262},[13233],{"type":22,"value":13128},{"type":17,"tag":243,"props":13235,"children":13236},{"style":250},[13237],{"type":22,"value":12568},{"type":17,"tag":243,"props":13239,"children":13240},{"style":378},[13241],{"type":22,"value":12573},{"type":17,"tag":243,"props":13243,"children":13244},{"style":250},[13245],{"type":22,"value":386},{"type":17,"tag":243,"props":13247,"children":13248},{"style":262},[13249],{"type":22,"value":13250}," ((j ",{"type":17,"tag":243,"props":13252,"children":13253},{"style":250},[13254],{"type":22,"value":1891},{"type":17,"tag":243,"props":13256,"children":13257},{"style":378},[13258],{"type":22,"value":467},{"type":17,"tag":243,"props":13260,"children":13261},{"style":262},[13262],{"type":22,"value":1637},{"type":17,"tag":243,"props":13264,"children":13265},{"style":250},[13266],{"type":22,"value":6967},{"type":17,"tag":243,"props":13268,"children":13269},{"style":256},[13270],{"type":22,"value":12947},{"type":17,"tag":243,"props":13272,"children":13273},{"style":262},[13274],{"type":22,"value":1215},{"type":17,"tag":243,"props":13276,"children":13277},{"class":245,"line":2792},[13278],{"type":17,"tag":243,"props":13279,"children":13280},{"style":262},[13281],{"type":22,"value":4207},{"type":17,"tag":243,"props":13283,"children":13284},{"class":245,"line":2801},[13285],{"type":17,"tag":243,"props":13286,"children":13287},{"style":262},[13288],{"type":22,"value":1413},{"type":17,"tag":243,"props":13290,"children":13291},{"class":245,"line":2833},[13292],{"type":17,"tag":243,"props":13293,"children":13294},{"emptyLinePlaceholder":2340},[13295],{"type":22,"value":2932},{"type":17,"tag":243,"props":13297,"children":13298},{"class":245,"line":2842},[13299,13303,13307,13312,13316,13320,13324,13329,13334,13338,13342,13347],{"type":17,"tag":243,"props":13300,"children":13301},{"style":262},[13302],{"type":22,"value":1654},{"type":17,"tag":243,"props":13304,"children":13305},{"style":256},[13306],{"type":22,"value":1659},{"type":17,"tag":243,"props":13308,"children":13309},{"style":262},[13310],{"type":22,"value":13311},"((Date.",{"type":17,"tag":243,"props":13313,"children":13314},{"style":256},[13315],{"type":22,"value":12355},{"type":17,"tag":243,"props":13317,"children":13318},{"style":262},[13319],{"type":22,"value":2589},{"type":17,"tag":243,"props":13321,"children":13322},{"style":250},[13323],{"type":22,"value":375},{"type":17,"tag":243,"props":13325,"children":13326},{"style":262},[13327],{"type":22,"value":13328}," s).",{"type":17,"tag":243,"props":13330,"children":13331},{"style":256},[13332],{"type":22,"value":13333},"toString",{"type":17,"tag":243,"props":13335,"children":13336},{"style":262},[13337],{"type":22,"value":2589},{"type":17,"tag":243,"props":13339,"children":13340},{"style":250},[13341],{"type":22,"value":1891},{"type":17,"tag":243,"props":13343,"children":13344},{"style":981},[13345],{"type":22,"value":13346}," \" ms elapsed\"",{"type":17,"tag":243,"props":13348,"children":13349},{"style":262},[13350],{"type":22,"value":1215},{"type":17,"tag":243,"props":13352,"children":13353},{"class":245,"line":2889},[13354],{"type":17,"tag":243,"props":13355,"children":13356},{"style":262},[13357],{"type":22,"value":308},{"type":17,"tag":18,"props":13359,"children":13360},{},[13361],{"type":22,"value":13362},"Yielded the following result. My research here was nearly non-existing, so I don't feel confident enough to make any further comments:",{"type":17,"tag":233,"props":13364,"children":13366},{"className":235,"code":13365,"language":237,"meta":8,"style":8},"12878 ms elapsed\n",[13367],{"type":17,"tag":219,"props":13368,"children":13369},{"__ignoreMap":8},[13370],{"type":17,"tag":243,"props":13371,"children":13372},{"class":245,"line":246},[13373,13378],{"type":17,"tag":243,"props":13374,"children":13375},{"style":378},[13376],{"type":22,"value":13377},"12878",{"type":17,"tag":243,"props":13379,"children":13380},{"style":262},[13381],{"type":22,"value":13382}," ms elapsed\n",{"type":17,"tag":18,"props":13384,"children":13385},{},[13386],{"type":22,"value":13387},"This is the end of the first part. In the next part, we’ll implement the same code in JS and use spatial partitioning methods to get rid of the scary O(N^2) complexity. In part 3, we’ll implement 3D life on GPU with the new WebGPU API and optimize our WGSL code. Spoiler alert: the goal is to reach one million particles!",{"type":17,"tag":18,"props":13389,"children":13390},{},[13391],{"type":22,"value":13392},"To keep you interested, a few screenshots:",{"type":17,"tag":5258,"props":13394,"children":13397},{"src":13395,"alt":13396},"/articles/Zrzut ekranu 2024-02-26 o 22.02.57.png","1000 2D particles - JS",[],{"type":17,"tag":13399,"props":13400,"children":13401},"sup",{},[13402],{"type":22,"value":13396},{"type":17,"tag":5258,"props":13404,"children":13407},{"src":13405,"alt":13406},"/articles/Zrzut ekranu 2024-02-26 o 22.06.52.png","1 million 2D particles - GPU.js",[],{"type":17,"tag":13399,"props":13409,"children":13410},{},[13411],{"type":22,"value":13412},"1 million 2D particles - GPU.js. First frames.",{"type":17,"tag":5258,"props":13414,"children":13417},{"src":13415,"alt":13416},"/articles/Zrzut ekranu 2024-02-26 o 22.09.40.png","50000 2D particles - vanilla JS optimized with quadtree.",[],{"type":17,"tag":13399,"props":13419,"children":13420},{},[13421],{"type":22,"value":13416},{"type":17,"tag":2332,"props":13423,"children":13424},{"style":2334},[13425],{"type":17,"tag":2337,"props":13426,"children":13427},{"allow":2339,"allowFullScreen":2340,"height":2341,"src":2342,"width":2341,"style":2343},[],{"type":17,"tag":13399,"props":13429,"children":13430},{},[13431],{"type":22,"value":13432},"Playing around with webGPU implementation.",{"type":17,"tag":5258,"props":13434,"children":13437},{"src":13435,"alt":13436},"/articles/3dparticle.png","256000 particles within interaction radius.",[],{"type":17,"tag":13399,"props":13439,"children":13440},{},[13441],{"type":22,"value":13442},"256000 particles within interaction radius",{"type":17,"tag":5258,"props":13444,"children":13447},{"src":13445,"alt":13446},"/articles/image.png","4 million particles.",[],{"type":17,"tag":13399,"props":13449,"children":13450},{},[13451],{"type":22,"value":13452},"4 million particles. WebGPU.",{"type":17,"tag":18,"props":13454,"children":13455},{},[13456],{"type":17,"tag":340,"props":13457,"children":13458},{"href":6853},[13459],{"type":22,"value":10846},{"type":17,"tag":2308,"props":13461,"children":13462},{},[13463],{"type":22,"value":2312},{"title":8,"searchDepth":160,"depth":160,"links":13465},[13466,13467,13468],{"id":10876,"depth":160,"text":10879},{"id":10958,"depth":160,"text":10961},{"id":11998,"depth":160,"text":12001},"content:articles:optimizing-the-article-life-from-a-thousand-to-a-milion-particles.md","articles/optimizing-the-article-life-from-a-thousand-to-a-milion-particles.md","articles/optimizing-the-article-life-from-a-thousand-to-a-milion-particles",1792947342892]