UI


Usually, the canvas is full screen, keeping this on every resize in JS.
  eq.js
150
151
152
153
154
155
 
158
159
 
252
let resize = function ()
{
    if (!canvas || !gl) return;
    
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    
    gl.viewport(0, 0, canvas.width, canvas.height);
};

window.addEventListener("resize", function() { resize(); draw(); });
The canvas is
position: absolute
placed, and so is the menu over it. Pressing M key shows or hides the menu. This is a problem for inputs on the menu accepting the M character. Ctrl+M is the mute shortcut for browsers, so I didn't use it. Instead, in the keypress handler function, I checked if any textareas has the focus, the handler exits without doing anything.

TextAreas are usually for code, and pressing the Tab key in browsers just transfers focus. To prevent this, there is no magic switch, I had to hardcode Tab key handling.
627
628
629
630
631
632
633
634
635
636
637
638
639
640
let handletab = function (ta_dom)
{
    ta_dom.addEventListener('keydown', (e) => {
        if (e.key === 'Tab')
        {
            e.preventDefault();
            let str = ta_dom.value;
            let start = ta_dom.selectionStart;
            let end   = ta_dom.selectionEnd;
            ta_dom.value = str.substring(0, start) + "    " + str.substring(end);
            ta_dom.selectionEnd = end-(end-start)+4;
        }
    });
};
Inputs either have immediate effect when the onchange fires, but sometimes, usually on bigger computation need, several inputs have a "SET" button. It is a bit confusing, I plan to indicate this somehow.

Input variables, and their DOM variables are usually in the global scope. There is an exception, in the Grid program. There were so many variables, I created a class for them, in grid-ui.js.
Scripting


There are two types of scripts I use, GLSL and Javascript. Shaders are compiled in the programs, so GLSL scripting is really just a string manipulation before the compilation. It is used in eq, it works well. It is also used in the Parametric surfaces, and the trouble is there that the created geometry is made by the vertex shader, it is only on GPU, and it is a bit problematic to transfer to the CPU. (Haven't yet tried the transform feedback, which could do the job)

The other one is JS. I use the Function API.
Small example:
1
2
3
let script = "return (a+b)*c;";
let F   = Function('a', 'b', 'c', script);
let res = F(1, 2, 3);
Note that both line 2 and 3 can throw exception.
Files


Every sketch is client only.

For saving files, I use a simplified version of Eli Grey's FileSaver, like here: my version

Loading files from the server
163
164
165
166
167
168
180
181
182
183
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function()
{
    if (xhr.readyState === 4 && xhr.status === 200)
    {
        let model_resp = obj.create(xhr.responseText, 0.5, true, lcol);
    }
}
xhr.open('GET', objfile, true);
xhr.send(null);


Binary files:
Read:
const view = new DataView(arrayBuffer);
let f = view.getFloat32(4*i, true);
Write:
  mc.js
597
598
599
600
601
602
let buffer = new ArrayBuffer(3*4 + Nx*Ny*Nz*4);
let view   = new DataView(buffer);

view.setUint32(0, Nx);
view.setUint32(4, Ny);
view.setUint32(8, Nz);