DEV Community

Cover image for Bouncing DOM Elements at Warp Speed with Coi to WASM
artydev
artydev

Posted on

Bouncing DOM Elements at Warp Speed with Coi to WASM

This is a balls collisions demo of 100 DOM elements in WASM :

WASMDomCollision

here is the code (Coi language)

component DomBouncer {
    // --- Parameters ---
    int ballCount = 100;
    float width = 800.0;
    float height = 500.0;
    float diameter = 30.0;

    // --- State: Parallel Arrays ---
    mut float[] px = [];
    mut float[] py = [];
    mut float[] vx = [];
    mut float[] vy = [];
    mut string[] ballColors = [];

    // --- State: DOM Handles ---
    mut DOMElement[] ballHandles = [];
    mut DOMElement container;

    init {
        string[] palette = ["#ff4757", "#2ed573", "#1e90ff", "#ffa502", "#a29bfe"];

        for i in 0:100 {
            px.push(100.0 + (System.random() * 600.0));
            py.push(100.0 + (System.random() * 300.0));
            vx.push((System.random() * 400.0) - 200.0);
            vy.push((System.random() * 400.0) - 200.0);
            ballColors.push(palette[i % 5]);
        }
    }

    mount {
        container = Dom.getElementById("ball-container");

        for i in 0:100 {
            DOMElement el = Dom.createElement("div");

            // FIX: Initialize the string in ONE line so it doesn't need reassignment
            string ballCss = "position:absolute;width:30px;height:30px;border-radius:50%;top:0;left:0;background:" + ballColors[i];

            Dom.setAttribute(el, "style", ballCss);
            Dom.appendChild(container, el);

            ballHandles.push(el);
        }
    }

    tick(float dt) {
        float subDt = dt / 2.0;

        for s in 0:2 {
            for i in 0:100 {
                px[i] = px[i] + (vx[i] * subDt);
                py[i] = py[i] + (vy[i] * subDt);

                if (px[i] < 0.0) { px[i] = 0.0; vx[i] = vx[i] * -1.0; }
                if (px[i] > (width - 30.0)) { px[i] = width - 30.0; vx[i] = vx[i] * -1.0; }
                if (py[i] < 0.0) { py[i] = 0.0; vy[i] = vy[i] * -1.0; }
                if (py[i] > (height - 30.0)) { py[i] = height - 30.0; vy[i] = vy[i] * -1.0; }
            }

            for i in 0:100 {
                for j in 0:100 {
                    if (j > i) {
                        float dx = px[j] - px[i];
                        float dy = py[j] - py[i];
                        float d2 = (dx * dx) + (dy * dy);
                        if (d2 < 900.0) {
                            float tx = vx[i]; float ty = vy[i];
                            vx[i] = vx[j]; vy[i] = vy[j];
                            vx[j] = tx; vy[j] = ty;
                            px[i] = px[i] - (dx * 0.1);
                            py[i] = py[i] - (dy * 0.1);
                        }
                    }
                }
            }
        }

        // Render Step
        for i in 0:100 {
            DOMElement h = ballHandles[i];

            // FIX: Single-line assignments for strings
            string transformStr = "translate3d(" + px[i] + "px," + py[i] + "px,0)";
            string finalStyle = "position:absolute;width:30px;height:30px;border-radius:50%;background:" + ballColors[i] + ";transform:" + transformStr;

            Dom.setAttribute(h, "style", finalStyle);
        }
    }

    style {
        #ball-container {
            position: relative;
            width: 800px;
            height: 500px;
            background: #050505;
            overflow: hidden;
            border: 2px solid #333;
            border-radius: 12px;
            margin: 20px auto;
        }
    }

    view {
        <div id="ball-container">
        </div>
    }
}

app { root = DomBouncer; }

Enter fullscreen mode Exit fullscreen mode

Top comments (0)