UNPKG

@aladas-org/cryptoshape

Version:

Generates a representation of a Bip39 seed phrase as a 3D scene

755 lines (601 loc) 26.3 kB
// ===================================================================================================== // ======================================== renderer.js ======================================== // ===================================================================================================== // Notes: PointCloud to Mesh // https://github.com/KineticTactic/marching-cubes-js/blob/master/sketch.js "use strict"; // https://www.npmjs.com/package/@babylonjs/core const MNEMONICS_INDEXES = [ 1104, 169, 526, 1304, 1799, 884, 915, 1720, 1637, 1950, 153, 1633, 615, 272, 339, 1773, 1978, 704, 483, 190, 1382, 25, 254, 216 ]; const CUBE_DOT = "Cube"; const SPHERE_DOT = "Sphere"; const canvas = document.getElementById("renderCanvas"); const MODE_NAME_TO_CLASS = { [ARC_VIZMODE]: ArcVizMode, [CORONAVIRUS_VIZMODE]: CoronaVirusVizMode, [HELICAL_VIRUS_VIZMODE]: HelicalVirusVizMode, [QBIT_VIZMODE]: QBitVizMode, [PIN_VIZMODE]: PinVizMode, [BLOCKCHAIN_VIZMODE]: BlockchainVizMode, [SIMPLE_VIZMODE]: SimpleVizMode, [CENTROID_VIZMODE]: CentroidVizMode }; // MODE_NAME_TO_CLASS let PreventRecursiveEventCall = false; let SelectedGUIMnemonicNode = undefined; let SelectedMnemonic = ""; const SHOW_MNEMONICS = "Show Mnemonics"; const INPUT_MNEMONICS = "Input Mnemonics"; let MnemonicsMode = SHOW_MNEMONICS; // https://forum.babylonjs.com/t/how-to-build-animation-for-arcrotatecamera-so-it-can-rotate-smoothly/25698/4 // https://playground.babylonjs.com/#U5SSCN#169 BABYLON.ArcRotateCamera.prototype.spinTo = function (whichprop, targetval, speed) { let ease = new BABYLON.CubicEase(); ease.setEasingMode( BABYLON.EasingFunction.EASINGMODE_EASEINOUT ); setTimeout( async () => { let animation = BABYLON.Animation.CreateAndStartAnimation ('at4', this, whichprop, speed, 120, this[whichprop], targetval, 0, ease); console.log("before this.alpha: " + this.alpha); let save_alpha = this.alpha; await animation.waitAsync(); console.log("after this.alpha: " + this.alpha); this.alpha = save_alpha; }); } // BABYLON.ArcRotateCamera.prototype.spinTo() // ============================== Renderer class ============================== class Renderer { static #Key = Symbol('Renderer'); static #Singleton = new Renderer( Renderer.#Key ); static #InstanceCount = 0; static #Scene = undefined; static #SceneObjects = []; static get This() { if( Renderer.#Singleton == undefined ) { this.#Singleton = new Renderer(); if (this.#InstanceCount > 0) { throw new TypeError("'Renderer' constructor called more than once"); } this.#InstanceCount++; } return Renderer.#Singleton; } // Renderer 'This' getter get main_word_indexes() { // console.log("> GET 'main_word_indexes': '" + this._main_word_indexes + "'"); return this._main_word_indexes; } // 'main_word_indexes' getter set main_word_indexes( value ) { // console.log("> SET 'main_word_indexes': '" + value + "'"); this._main_word_indexes = value; } // 'main_word_indexes' setter constructor( instance_key ) { // console.log(">> ---- Renderer.new instance_key: " + String(instance_key)); if ( instance_key != Renderer.#Key ) { throw new Error("**Error** in Renderer: private constructor use Renderer.This"); } // console.log(">> ---- new Renderer"); this.seedphrase = new SeedPhrase( this ); this.cgi_mode = false; this._main_word_indexes = []; this.scene = undefined; this.scene_objects = []; this.parameters = {}; this.parameters[THEME_PARAM] = SCREEN_THEME; this.viz_mode = ARC_VIZMODE; this.parameters[MODE_PARAM] = this.viz_mode; this.parameters[WORD_COUNT_PARAM] = 12; this.parameters[RENDERING_PARAM] = DEFAULT_RENDERING; this.parameters[RENDERING_FRAME_PARAM] = 1; //this.parameters[ARC_MODE_PARAM] = false; //this.parameters[STAIR_STEP_PARAM] = true; this.parameters[FILLED_TRIANGLES_PARAM] = false; this.parameters[METADATA_PARAM] = true; this.parameters[FILE_FORMAT_PARAM] = GLB_FILE_FORMAT; this.parameters[SHOW_BALLS_PARAM] = true; this.parameters[SHOW_CENTROID_PARAM] = false; this.parameters[SHOW_BOUNDING_BOX_PARAM] = true; this.parameters[SHOW_GRID_PARAM] = false; this.parameters[DEBUG_PARAM] = false; this.registerCallbacks(); } // constructor() getScene() { return this.scene; } // getScene() getCamera() { return this.camera; } // getCamera() animateCamera() { // console.log(" renderer.getCamera().alpha): " + this.camera.alpha ); let speed = 50; // 50 this.camera.spinTo("alpha", 6.75*Math.PI/4, speed); // console.log(" renderer.getCamera().alpha): " + this.camera.alpha ); } // animateCamera() getUrlParams() { console.log("> getUrlParams"); // https://www.sitepoint.com/get-url-parameters-with-javascript/ const query_string = window.location.search; // console.log("> query_string: " + query_string); if ( query_string == "" ) { // console.log("> getUrlParams: NO Query String"); return; } const url_params = new URLSearchParams(query_string); const mnemonics_str = url_params.get('mnemonics'); if (mnemonics_str == null || mnemonics_str == undefined) { return; } // console.log("> mnemonics_str: " + mnemonics_str); let mnemonic_items = mnemonics_str.split(' '); console.log('> mnemonics(' + mnemonic_items.length + '): ' + mnemonic_items.join(' ')); let mnemonic_count = mnemonic_items.length; if ( mnemonic_count >= 12 && ( mnemonic_count == 12 || mnemonic_count == 15 || mnemonic_count == 18 || mnemonic_count == 21 || mnemonic_count == 24) ) { this.updateCGIMode( true ); this.main_word_indexes = MnemonicUtils.MnemonicsToWordIndexes( mnemonics_str ); console.log('> this.main_word_indexes (CGI): ' + this.main_word_indexes); Renderer.This.displayMnemonics( this.main_word_indexes ); } } // getUrlParams() updateCGIMode( value ) { console.log("> updateCGIMode"); this.cgi_mode = value; if ( this.cgi_mode ) { HtmlUtils.HideNode('toolbar'); HtmlUtils.ShowNode('toolbar_cgi_id'); } } // updateCGIMode() displayMnemonics( word_indexes ) { console.log("> displayMnemonics"); if ( word_indexes != undefined && word_indexes.length >= 12 ) { let mnemonics_elt = document.getElementById( 'mnemonics_id' ); // console.log("> mnemonics_elt: " + mnemonics_elt); if ( mnemonics_elt == undefined ) return; let mnemonics = MnemonicUtils.WordIndexesToMemonics( word_indexes ); let mnemonics_str = ""; for ( let i=0; i< mnemonics.length; i++ ) { let mnemonic = mnemonics[i]; let text_color = "#d0d0d0"; if ( mnemonic == SelectedMnemonic ) { text_color = "cyan"; } mnemonics_str += '<span style="color: ' + text_color + '">' + mnemonic + "&nbsp;&nbsp;"+ "</span>"; } mnemonics_elt.innerHTML = "&nbsp;&nbsp;&nbsp;&nbsp;"+ mnemonics_str; let mnemonics_cgi_elt = document.getElementById( 'mnemonics_cgi_id' ); // console.log("> mnemonics_cgi_elt: " + mnemonics_cgi_elt); if ( mnemonics_cgi_elt == undefined ) return; mnemonics_cgi_elt.innerHTML = "&nbsp;&nbsp;&nbsp;&nbsp;"+ mnemonics_str; } } // displayMnemonics() // ==================== Create Scene ==================== createScene() { console.log(">> ---- createScene ----"); // This creates a basic Babylon Scene object (non-mesh) this.scene = new BABYLON.Scene( engine ); // ********** ARC ROTATE CAMERA EXAMPLE ********** // Creates, angles, distances and targets the camera this.camera = new BABYLON.ArcRotateCamera ("Camera", 0, 0, 10, new BABYLON.Vector3(0, 0, 0), this.scene); this.camera.setTarget(BABYLON.Vector3.Zero()); // https://doc.babylonjs.com/typedoc/classes/BABYLON.PickingInfo#hit const onPointerDown = (evt) => { let pickInfo = scene.pick( this.scene.pointerX, this.scene.pointerY, function (mesh) { return true; }, false, this.camera); if ( pickInfo.hit ) { if ( pickInfo.pickedMesh != undefined && pickInfo.pickedMesh.metadata != undefined ) { let word_index = pickInfo.pickedMesh.metadata['word_index']; console.log(" *Hit* word_index: " + word_index ); displaySelectedNode( pickInfo.pickedMesh ); } } else { console.log("No Hit"); } }; // onPointerDown() // https://forum.babylonjs.com/t/arcrotatecamera-pan-and-zoom-sensitivity/33046 this.camera.wheelDeltaPercentage = 0.01; // This rotates the camera let camera_alpha = 2; // 2; // 0; let camera_beta = 2; // 2; let camera_radius = -3; // -10; // https://doc.babylonjs.com/features/featuresDeepDive/cameras/camera_introduction // Positions the camera overwriting alpha, beta, radius this.camera.setPosition( new BABYLON.Vector3(camera_alpha, camera_beta, camera_radius) ); // This attaches the camera to the canvas this.camera.attachControl( canvas, true ); // https://stackoverflow.com/questions/45901063/how-to-find-the-coordinates-of-a-click-in-the-babylon-js-scene this.scene.cameraToUseForPointers = this.camera; canvas.addEventListener("pointerdown", onPointerDown, false); this.scene.onDispose = () => { canvas.removeEventListener("pointerdown", onPointerDown); }; // scene.onDispose() /**************************************************************/ // This creates a light, aiming 0,1,0 - to the sky (non-mesh) this.light = new BABYLON.HemisphericLight ("light", new BABYLON.Vector3(0, 1, 0), this.scene); Materials.CreateMaterials( this.scene ); // console.log(">> this.main_word_indexes: '" + this.main_word_indexes + "'"); if ( this.main_word_indexes == [] || this.main_word_indexes == '' || this.main_word_indexes == undefined ) { this.main_word_indexes = getRandomWordIndexes( this.parameters[WORD_COUNT_PARAM] ); } // ---------- GUI ---------- let advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI"); let gui_selected_mnemonic = new BABYLON.GUI.TextBlock(); gui_selected_mnemonic.text = ""; gui_selected_mnemonic.color = "cyan"; gui_selected_mnemonic.fontSize = 24; //text1.left = "-50%"; gui_selected_mnemonic.top = "-47%";//"-46%"; advancedTexture.addControl( gui_selected_mnemonic ); SelectedGUIMnemonicNode = gui_selected_mnemonic; // ---------- GUI // ---------- Draw 'Mnemonics Shape' ---------- this.drawScene(); // ---------- Create 'Mnemonics Shape' // https://doc.babylonjs.com/toolsAndResources/assetLibraries/materialsLibrary/gridMat //let ground = BABYLON.MeshBuilder.CreateGround // ("ground1", { width: 10, height: 10, subdivisions: 2 }, scene); return this.scene; }; // createScene() // ==================== Create Scene // https://forum.babylonjs.com/t/how-do-you-properly-remove-an-object-from-the-scene/1790/4 clearScene() { ShapeUtils.Reset(); BaseShape.ResetObjectCount(); for ( let i=0; i < this.scene_objects.length; i++) { if ( this.scene_objects[i] != null && this.scene_objects[i] != undefined ) { this.scene_objects[i].dispose(); this.scene_objects[i] = null; } } this.scene_objects = []; this.clearObjects(); } // clearScene() drawScene( args ) { console.log(">> ---- Renderer.drawScene ----"); if ( args == undefined ) args = {}; let background_color = THEMES[this.parameters[THEME_PARAM]][BACKGROUND_COLOR][0]; this.scene.clearColor = Color.AsVec3( background_color ); let viz_mode = this.parameters[MODE_PARAM]; console.log(" viz_mode: " + viz_mode); if ( MODE_NAME_TO_CLASS[viz_mode] != undefined ) { this.viz_mode = new MODE_NAME_TO_CLASS[viz_mode]( this, this.main_word_indexes ); this.viz_mode.draw(); return; } // =================================================================== if ( this.parameters[SHOW_BOUNDING_BOX_PARAM] ) { ShapeUtils.DrawCubeBox(); } if ( this.parameters[SHOW_GRID_PARAM] ) { ShapeUtils.CreateDotGrid( MATERIALS[GREY], scene, this.scene_objects ); } // ---------- Closed Triangles mode ---------- let closed_mode = ClosedTrianglesMode; if ( args != undefined && args['closed_triangles'] != undefined ) { closed_mode = args['closed_triangles']; } // ---------- Closed Triangles mode // ---------- Filled Triangles mode ---------- let filled_mode = this.parameters[FILLED_TRIANGLES_PARAM]; if ( args != undefined && args['filled_triangles'] != undefined ) { filled_mode = args['filled_triangles']; this.parameters[FILLED_TRIANGLES_PARAM] = filled_mode; } // ---------- Filled Triangles mode this.seedphrase.draw( this.main_word_indexes, { "closed_triangles": closed_mode, "filled_triangles": filled_mode } ); } // drawScene() setEventHandler( elt_id, event_name, handler_function ) { let elt = document.getElementById( elt_id ); if ( elt != undefined ) { elt.addEventListener(event_name, handler_function ); } } // setEventHandler() onParameterChange( elt_id ) { let event_name = elt_id.replace('_id',''); console.log(">> Renderer.onParameterChange id:" + elt_id + " evt:" + event_name); let elt = document.getElementById( name + "_id" ); // console.log(" elt.nodeName: " + elt.nodeName); if ( elt.nodeName == "INPUT" && elt.type === 'checkbox') { this.parameters[ event_name ] = elt.checked; } else if ( elt.nodeName == "SELECT" ) { this.parameters[ event_name ] = elt.value; console.log(" renderer.parameters[" + event_name + "]: " + this.parameters[ event_name ] ); } if ( event_name == WORD_COUNT_PARAM ) { this.main_word_indexes = getRandomWordIndexes( this.parameters[ WORD_COUNT_PARAM ] ); } else if ( event_name == MODE_PARAM ) { this.parameters[ MODE_PARAM ] = elt.value; } this.clearScene(); this.drawScene(); } // onParameterChange() registerCallbacks() { // ---------- THEME_ID ---------- this.setEventHandler( THEME_ID, 'change', (evt) => { console.log( "Renderer.evtHandler> " + THEME_ID ); let elt = document.getElementById(THEME_ID); this.parameters[THEME_PARAM] = elt.value; console.log( " this.parameters[THEME_PARAM]: " + elt.value ); this.clearScene(); this.drawScene(); } ); // ---------- THEME_ID // ---------- MODE_ID ---------- this.setEventHandler( MODE_ID, 'change', (evt) => { console.log( "Renderer.evtHandler> " + MODE_ID ); let elt = document.getElementById(MODE_ID); this.parameters[MODE_PARAM] = elt.value; // console.log( " this.parameters[MODE_PARAM]: " + elt.value ); this.clearScene(); this.drawScene(); // NB: to prevent ficus on 'mode_id' which prevents 'A' key to trigger 'animateCamera' document.getElementById(ANIMATION_BTN_ID).focus(); } ); // ---------- MODE_ID // ---------- MODE_CGI_ID ---------- this.setEventHandler( MODE_CGI_ID, 'change', (evt) => { console.log( "Renderer.evtHandler> " + MODE_CGI_ID ); let elt = document.getElementById(MODE_CGI_ID); this.parameters[MODE_PARAM] = elt.value; console.log( " this.parameters[MODE_PARAM]: " + elt.value ); this.clearScene(); this.drawScene(); // NB: to prevent ficus on 'mode_id' which prevents 'A' key to trigger 'animateCamera' document.getElementById(ANIMATION_BTN_ID).focus(); } ); // ---------- MODE_CGI_ID // ---------- Camera Animation on 'body' ---------- document.body.addEventListener( 'keypress', (evt) => { console.log("keypress: '"+ evt.key + "'"); // NB: Better use 'evt.key' than 'evt.keyCode' (which is deprecated) // https://stackoverflow.com/questions/35394937/keyboardevent-keycode-deprecated-what-does-this-mean-in-practice // NB: Disable 'A'/'a' keys on 'mode_id' SELECT entity to 'arc': onkeydown="disableKey(event)" if ( ['A', 'a'].includes(evt.key) ) { this.animateCamera(); } }); // ---------- Camera Animation on 'body' } // registerCallbacks() getParameter( name ) { return (this.parameters[name] != undefined) ? this.parameters[name] : undefined; } // getParameter() setParameter( name, value ) { this.parameters[name] = value; } // setParameter() getThemeName() { return this.parameters[THEME_PARAM]; } // getThemeName() setThemeName( theme_name ) { this.parameters[THEME_PARAM] = theme_name; ThemeManager.UpdateTheme( theme_name ); } // setThemeName() addObject( object ) { this.scene_objects.push( object ); } // addObject() clearObjects() { ShapeUtils.Reset(); for ( let i=0; i < this.scene_objects.length; i++) { if ( this.scene_objects[i] != null && this.scene_objects[i] != undefined ) { this.scene_objects[i].dispose(); this.scene_objects[i] = null; } } this.scene_objects = []; } // clearObjects() getScene() { return this.scene; } // constructor() } // Renderer class // ============================== Renderer class // NB: to be continued... ToDo: Mesh with Arc Shape (Polyline), add positions as a discretization of Arc shape const createArcMesh = ( mesh_material, scene, positions ) => { // https://playground.babylonjs.com/#G37IGN#4 let arc_mesh = new BABYLON.Mesh("arc_" + ObjectCount, scene); arc_mesh.material = mesh_material; let indices = [0, 1, 2]; // Empty array to contain calculated values or normals added let normals = []; // Calculations of normals added BABYLON.VertexData.ComputeNormals( positions, indices, normals ); let vertexData = new BABYLON.VertexData(); vertexData.positions = positions; vertexData.indices = indices; vertexData.normals = normals; // Assignment of normal to vertexData added vertexData.applyToMesh( arc_mesh ); ObjectCount++; return arc_mesh; }; // createArcMesh() const createTriangleMesh = ( mesh_material, scene, positions ) => { let triangle_mesh = new BABYLON.Mesh("triangle_" + ObjectCount, scene); triangle_mesh.material = mesh_material; let indices = [0, 1, 2]; // Empty array to contain calculated values or normals added let normals = []; // Calculations of normals added BABYLON.VertexData.ComputeNormals( positions, indices, normals ); let vertexData = new BABYLON.VertexData(); vertexData.positions = positions; vertexData.indices = indices; vertexData.normals = normals; // Assignment of normal to vertexData added vertexData.applyToMesh( triangle_mesh ); ObjectCount++; return triangle_mesh; }; // createTriangleMesh() const displaySelectedNode = ( mesh ) => { if ( mesh.metadata != undefined ) { // dot_mesh.metadata = { "gltf": { "mnemonic": mnemonic, "word_index": word_index } }; // cube.metadata = {"gltf":{"extras": {"someKey": "someValue"}}}; if ( mesh.metadata == undefined ) return; let gltf_properties = mesh.metadata['gltf']; let extras_property = gltf_properties['extras']; let word_index = extras_property['word_index']; let mnemonic = MnemonicUtils.WordIndexToMnemonic( word_index ); console.log(">> *** displaySelectedNode word["+ word_index + "] : " + mnemonic ); SelectedMnemonic = mnemonic; SelectedGUIMnemonicNode.text = mnemonic; Renderer.This.displayMnemonics( this.main_word_indexes ); } }; // displaySelectedNode () const getRandomWordIndexes = ( index_count ) => { console.log("> **** getRandomWordIndexes " + index_count ); if ( index_count == undefined ) { index_count = 24; } const get_randomInt = ( max ) => { return Math.floor(Math.random() * max); }; // get_randomInt() let random_indexes = []; for ( let i=0; i< index_count; i++ ) { let rnd_index = get_randomInt( 2048 ); random_indexes.push(rnd_index); } SelectedMnemonic = MnemonicUtils.WordIndexToMnemonic( random_indexes[0] ); this.main_word_indexes = random_indexes; Renderer.This.displayMnemonics( this.main_word_indexes ); return random_indexes; }; // getRandomWordIndexes() let startRenderLoop = ( engine, canvas ) => { engine.runRenderLoop( () => { if ( window.scene && window.scene.activeCamera ) { window.scene.render(); } }); }; // startRenderLoop() let createDefaultEngine = () => { return new BABYLON.Engine (canvas, true, { preserveDrawingBuffer: true, stencil: true, disableWebGL2Support: false}); }; // createDefaultEngine() // ======================================= EVENTS ======================================= const disableKey = ( evt ) => { let event = evt ? evt : window.event; if ( event ) { if ( event.preventDefault ) event.preventDefault(); else event.returnValue = false; } }; // disableKey() const onGenerate = ( evt ) => { console.log(">> *** onGenerate "); // console.log(">> *** onGenerate main_word_indexes: '" + Renderer.This.main_word_indexes + "'"); Renderer.This.main_word_indexes = getRandomWordIndexes( Renderer.This.getParameter(WORD_COUNT_PARAM) ); Renderer.This.clearScene(); Renderer.This.drawScene(); }; // onGenerate() // https://doc.babylonjs.com/features/featuresDeepDive/Exporters/glTFExporter function onSave( evt ) { console.log(">> *** onSave "); let renderer = Renderer.This; let file_format = renderer.getParameter( FILE_FORMAT_PARAM ); console.log("onSave file_format: " + file_format); switch ( file_format ) { case GLB_FILE_FORMAT: BABYLON.GLTF2Export.GLBAsync( scene, "cryptoshape" ).then((glb) => { glb.downloadFiles(); }); break; case PNG_FILE_FORMAT: // https://doc.babylonjs.com/features/featuresDeepDive/scene/renderToPNG/#createscreenshot BABYLON.Tools.CreateScreenshot( renderer.scene.getEngine(), renderer.getCamera(), {precision: 1.0} ); break; } //switch ( file_format ) } // onSave() function onAnimate() { console.log(">> *** onAnimate "); Renderer.This.animateCamera(); } // onAnimate() const onMnemonicsEditMode = () => { console.log(">> *** onMnemonicsEditMode "); if ( MnemonicsMode == SHOW_MNEMONICS ) { $("#mnemonics_id").hide(); $("#editMnemonicsIcon").hide(); $("#mnemonics_input_container_id").show(); MnemonicsMode = INPUT_MNEMONICS; } }; // onMnemonicsEditMode() const onApplyMnemonicsChange = () => { console.log(">> *** onApplyMnemonicsChange "); if ( MnemonicsMode == INPUT_MNEMONICS ) { $("#mnemonics_id").show(); $("#editMnemonicsIcon").show(); $("#mnemonics_input_container_id").hide(); MnemonicsMode = SHOW_MNEMONICS; let mnemonics = document.getElementById( "mnemonics_input_id" ).value .trim().replaceAll(" "," "); console.log(" mnemonics: '" + mnemonics + "'"); let mnemonics_count = mnemonics.split(' ').length; console.log(" mnemonics length: '" + mnemonics_count + "'"); document.getElementById(WORD_COUNT_ID).value = mnemonics_count; Renderer.This.setParameter(WORD_COUNT_PARAM, mnemonics_count); let word_indexes = MnemonicUtils.MnemonicsToWordIndexes( mnemonics); Renderer.This.main_word_indexes = word_indexes; Renderer.This.displayMnemonics( Renderer.This.main_word_indexes ); Renderer.This.clearScene(); Renderer.This.drawScene(); } }; // onApplyMnemonicsChange() const onCancelMnemonicsChange = () => { $("#mnemonics_id").show(); $("#editMnemonicsIcon").show(); $("#mnemonics_input_container_id").hide(); MnemonicsMode = SHOW_MNEMONICS; }; // onCancelMnemonicsChange() const onParameterChange = ( name ) => { console.log(">> *** onParameterChange " + name); let elt = document.getElementById( name + "_id" ); // console.log(" elt.nodeName: " + elt.nodeName); if ( elt.nodeName == "INPUT" && elt.type === 'checkbox') { Renderer.This.setParameter( name, elt.checked); } else if ( elt.nodeName == "SELECT" ) { Renderer.This.setParameter( name, elt.value); console.log(" Renderer.This.parameters[" + name + "]: " + Renderer.This.getParameter(name) ); } if ( name == WORD_COUNT_PARAM ) { Renderer.This.main_word_indexes = getRandomWordIndexes( Renderer.This.getParameter(WORD_COUNT_PARAM) ); } else if ( name == MODE_PARAM ) { Renderer.This.setParameter(MODE_PARAM, elt.value); } Renderer.This.clearScene(); Renderer.This.drawScene(); }; // onParameterChange() const onClosedChange = ( data ) => { let elt = document.getElementById("closed_id"); ClosedTrianglesMode = elt.checked; console.log(">> *** onClosedChange " + ClosedTrianglesMode); Renderer.This.clearScene(); Renderer.This.drawScene(); }; // onClosedChange() window.initFunction = async () => { console.log(">> --- window.initFunction"); let asyncEngineCreation = async () => { try { return createDefaultEngine(); } catch(e) { console.log("the available createEngine function failed. Creating the default engine instead"); return createDefaultEngine(); } }; // asyncEngineCreation() window.engine = await asyncEngineCreation(); if ( ! engine ) throw 'engine should not be null.'; startRenderLoop( engine, canvas ); Renderer.This.getUrlParams(); window.scene = Renderer.This.createScene(); }; // window.initFunction() initFunction().then( () => { // sceneToRender = scene; } ); // call of window.initFunction() // Resize window.addEventListener( "resize", () => { engine.resize(); } ); // ======================================= EVENTS