Ignore:
Timestamp:
08/25/24 01:56:48 (4 months ago)
Author:
Maciej Komosinski
Message:

Updated standard.expdef animated demo: uses the most recent Framsticks SDK, supports 6 genetic encodings, adjustable mutation and crossover probabilities, shows colored genotypes, allows user to manually increase/decrease fitness of the current individual, displays its neural network

Location:
js/standard_expdef_demo
Files:
14 added
2 deleted
12 edited

Legend:

Unmodified
Added
Removed
  • js/standard_expdef_demo/index.html

    r880 r1326  
    55    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    66    <link rel="stylesheet" type="text/css" href="static/styles.css">
    7                 <title>Standard.expdef Animation</title>
     7                <title>Standard.expdef demo animation</title>
     8        <script type="importmap">
     9                {
     10                        "imports": {
     11                                "three": "./node_modules/three/build/three.module.js",
     12                                "three/addons/OrbitControls.js": "./node_modules/three/examples/jsm/controls/OrbitControls.js",
     13                                "three/addons/CSS3DRenderer.js": "./node_modules/three/examples/jsm/renderers/CSS3DRenderer.js",
     14                                "three/addons/Sky.js": "./node_modules/three/examples/jsm/objects/Sky.js",
     15                                "tween": "./node_modules/three/examples/jsm/libs/tween.module.js"
     16                        }
     17                }
     18        </script>
     19        <script type="module">
     20                import * as TWEEN from 'tween';
     21                import * as THREE from 'three';
     22                import {OrbitControls} from "three/addons/OrbitControls.js";
     23                import {CSS3DObject, CSS3DSprite, CSS3DRenderer} from "three/addons/CSS3DRenderer.js";
     24                import {Sky} from "three/addons/Sky.js";
     25
     26                // this trick is done to avoid refactoring the entire app
     27                window.THREE = THREE;
     28                window.Sky = Sky;
     29                window.OrbitControls = OrbitControls;
     30                window.CSS3DRenderer = CSS3DRenderer;
     31                window.CSS3DObject = CSS3DObject;
     32                window.CSS3DSprite = CSS3DSprite;
     33                window.TWEEN = TWEEN;
     34        </script>
     35
     36
     37   
     38               
    839        </head>
    940        <body style="margin: 0; overflow: hidden;">
    10     <!--External dependencies-->
    11                 <script src="js/external/threejs/three.min.js"></script>
    12     <script src="js/external/threejs/CSS3DRenderer.js"></script>
    13     <script src="js/external/threejs/OrbitControls.js"></script>
    14     <script src="js/external/threejs/Sky.js"></script>
    15     <script src="js/external/tweenjs/tween.min.js"></script>
    16     <script src="../sdk/frams-sdk.js"></script>
    17     <script src="js/external/framsjs/visualization/jointmeshfactory.js"></script>
    18     <script src="js/external/framsjs/visualization/partmeshfactory.js"></script>
    19     <script src="js/external/framsjs/visualization/transformations.js"></script>
    20     <!--Project sources-->
    21     <script src="js/config.js"></script>
    22     <script src="js/world/core.js"></script>
    23     <script src="js/world/object/framstick.js"></script>
    24     <script src="js/world/object/table.js"></script>
    25     <script src="js/world/object/text.js"></script>
    26     <script src="js/world/object/arrow.js"></script>
    27     <script src="js/simulation/core.js"></script>
    28                 <script src="js/app.js"></script>
     41                <div class="column controls">
     42                        <div class="row control-container" id="fitness-rater">
     43                                <span>Rate creature:</span>
     44                        </div>
     45                        <div class="row control-container">
     46                                <span>Genotype: </span>
     47                                <select id="genotype-selector">
     48                                </select>
     49                        </div>
     50                       
     51                </div>
     52                <!--External dependencies-->
     53               
     54                <!-- <script src="js/external/threejs/three.min.js"></script>
     55                <script src="js/external/threejs/CSS3DRenderer.js"></script>
     56                <script src="js/external/threejs/OrbitControls.js"></script>
     57                <script src="js/external/threejs/Sky.js"></script> -->
     58                <!-- <script src="js/external/tweenjs/tween.min.js"></script> -->
     59                <script src="sdk/frams-sdk.js"></script>
     60                <script src="js/external/framsjs/visualization/jointmeshfactory.js" defer></script>
     61                <script src="js/external/framsjs/visualization/partmeshfactory.js" defer></script>
     62                <script src="js/external/framsjs/visualization/transformations.js" defer></script>
     63                <!--Project sources-->
     64                <script src="js/config.js" defer></script>
     65                <script src="js/utils.js" defer></script>
     66                <script src="js/world/core.js" defer></script>
     67                <script src="js/world/object/framstick.js" defer></script>
     68                <script src="js/world/object/table.js"></script>
     69                <script src="js/world/object/text.js" defer></script>
     70                <script src="js/world/object/arrow.js" defer></script>
     71                <script src="js/neuroviewer/view.js" defer></script>
     72                <script src="js/neuroviewer/neurofactory.js" defer></script>
     73                <script src="js/neuroviewer/neurons/basedrawableneuron.js" defer></script>
     74                <script src="js/neuroviewer/neurons/genericdrawableneuron.js" defer></script>
     75                <script src="js/neuroviewer/neurons/receptordrawableneuron.js" defer></script>
     76                <script src="js/components/slider.js" defer></script>
     77                <script src="js/components/option.js" defer></script>
     78                <script src="js/components/button.js" defer></script>
     79                <script src="js/simulation/core.js" defer></script>
     80                <script src="js/app.js" defer></script>
    2981        </body>
    3082</html>
  • js/standard_expdef_demo/js/app.js

    r880 r1326  
    1212  constructor() {
    1313    this.scene = this.Scene();
    14     this.camera = this.Camera();
    15     this.controls = this.Controls();
     14        this.camera = this.Camera();
    1615    this.webGLRenderer = this.WebGLRenderer();
     16        this.cameraControls = this.CameraControls();
    1717    this.css3DRenderer = this.CSS3DRenderer();
    1818
    19     this.simulation = new Simulation(new World(this.camera, this.scene));
     19        this.args = this.parseArguments();
     20        Config.Simulation.GENOTYPE = this.args["genotype_format"]?this.args["genotype_format"]:Config.Simulation.GENOTYPE;
     21    this.simulation = new Simulation(new World(this.camera, this.scene),this.args);
    2022
    2123    document.body.appendChild(this.webGLRenderer.domElement);
    2224    document.body.appendChild(this.css3DRenderer.domElement);
    2325    window.addEventListener("resize", this.onWindowResize.bind(this), false);
    24     return this;
     26
     27        this.Controls();
     28        this.Options();
     29        this.NeuroView();
     30        this.FitnessRater();
     31  }
     32
     33  NeuroView(){
     34        var thisApp = this;
     35        window.addEventListener('DOMContentLoaded',()=>{
     36                var neuroViewer = NeuroViewerView( Config.NeuroViewer );
     37                thisApp.simulation.neuroViewer = neuroViewer;
     38                neuroViewer.make3D();
     39        })
     40  }
     41
     42  Controls(){
     43        var thisApp = this;
     44        window.addEventListener('DOMContentLoaded', () => {
     45                const controls = document.getElementsByClassName('controls')[0];
     46                thisApp.mutation_slider = new Slider(
     47                        controls,
     48                        "Mutation",
     49                        function(prob){
     50                                thisApp.simulation.setMutationProb(parseFloat(prob));
     51                        });
     52                thisApp.crossover_slider = new Slider(
     53                        controls,
     54                        "Crossover",
     55                        function(prob){
     56                                thisApp.simulation.setCrossoverProb(parseFloat(prob));
     57                        });
     58                thisApp.simulation.mutationListeners.push(thisApp.mutation_slider);
     59                thisApp.simulation.crossoverListeners.push(thisApp.crossover_slider);
     60                thisApp.simulation.reupdateListeners();
     61                return this;
     62        });
     63  }
     64
     65  Options(){
     66        const encodings = this.findEncodings();
     67
     68        var thisApp = this;
     69        window.addEventListener('DOMContentLoaded', () => {
     70                const selector = document.getElementById("genotype-selector");
     71                for(let i=0;i<encodings.length;i++){
     72                        new Option(selector,encodings[i]);
     73                }
     74                selector.onchange = function(){
     75                        thisApp.simulation.setProposedGenotype(`/*${this.value}*/`);
     76                        // let url = new URL(window.location.href);
     77                        // let params = new URLSearchParams(url.search);
     78                        // let paramName = "genotype_format";
     79                        // let paramValue = `/*${this.value}*/`;
     80
     81                        // if(params.has(paramName)){
     82                        //      params.set(paramName,paramValue);
     83                        // }else{
     84                        //      params.append(paramName,paramValue);
     85                        // }
     86                        // window.location.href = window.location.origin+'/?'+params.toString();
     87                }
     88        });
     89  }
     90
     91  FitnessRater(){
     92        var sim = this.simulation;
     93        window.addEventListener('DOMContentLoaded', ()=>{
     94                const rater = document.getElementById("fitness-rater");
     95                const thumbUp = new Button(rater,"👍",()=>{
     96                        sim.updateFitness(5);
     97                });
     98                const thumbDown = new Button(rater,"👎",()=>{
     99                        sim.updateFitness(-5);
     100                })
     101
     102                sim.buttons.push(thumbUp);
     103                sim.buttons.push(thumbDown);
     104        });
     105  }
     106
     107  findEncodings(){
     108        const functionName = "GenoConv_f";
     109        return Object
     110        .keys(Module) //framsticks module
     111        .filter((k)=>{return k.startsWith(functionName);})
     112        .map((k)=>{return k.replace(functionName,"")[0]});
    25113  }
    26114
     
    44132  }
    45133
    46   Controls() {
     134  CameraControls() {
    47135    /**
    48136     * Creates a new Control object alowing to steer the camera.
    49137     */
    50     let controls = new THREE.OrbitControls(this.camera);
     138    let controls = new OrbitControls(this.camera,this.webGLRenderer.domElement );
    51139    controls.autoRotate = Config.Controls.AUTO_ROTATE;
    52140    controls.autoRotateSpeed = Config.Controls.AUTO_ROTATE_SPEED;
     
    54142    controls.maxDistance = Config.Controls.MAX_DISTANCE;
    55143    controls.maxPolarAngle = Config.Controls.MAX_POLAR_ANGLE;
     144        controls.enableKeys = false;
    56145    controls.update();
    57146    return controls
     
    77166     * Creates a CSS3D Renderer object used to visualize HTML+CSS components in 3D scene.
    78167     */
    79     let renderer = new THREE.CSS3DRenderer();
     168    let renderer = new CSS3DRenderer();
    80169    renderer.setSize(Config.CSS3DRenderer.WIDTH, Config.CSS3DRenderer.HEIGHT);
    81170    renderer.domElement.style.position = Config.CSS3DRenderer.POSITION;
    82171    renderer.domElement.style.top = Config.CSS3DRenderer.TOP;
     172        renderer.domElement.style.setProperty('pointer-events','none','');
    83173    return renderer
    84174  }
     
    98188    requestAnimationFrame(this.render.bind(this));
    99189    TWEEN.update();
    100     this.controls.update();
     190    this.cameraControls.update();
    101191    this.webGLRenderer.render(this.scene, this.camera);
    102192    this.css3DRenderer.render(this.scene, this.camera);
     
    112202    this.css3DRenderer.setSize(window.innerWidth, window.innerHeight);
    113203  }
     204
     205  parseArguments() {
     206        /**
     207         * Parses URL arguemnts
     208         */
     209
     210        const queryString = window.location.search;
     211        const urlParams = new URLSearchParams(queryString);
     212        return {
     213                "mutation_prob" : parseFloat(urlParams.get("mutation_prob")),
     214                "crossover_prob" : parseFloat(urlParams.get("crossover_prob")),
     215                "genotype_format": urlParams.get("genotype_format")
     216        };
     217  }
    114218}
    115219
  • js/standard_expdef_demo/js/config.js

    r880 r1326  
    1111    CROSSOVER_PROBABILITY: 0.3,
    1212    EVOLUTION_MAX_REPETITIONS: 100,
    13     GENOTYPES: [
    14       "/*4*/ #5,<<X><<X>X>X>>LLX",
    15       "/*4*/ <X>l<X>l<<X>X>LLLX",
    16       "/*4*/ <,<,,<,X,,>X>X>X",
    17       "/*4*/ <X><X><<X>X><X>X",
    18       "/*4*/ <<X>RR<<X>X>X>X",
    19       "/*4*/ <<X><<X>X>X>X",
    20     ],
     13        NUMBER_OF_GENOTYPES: 6,
     14        INITIAL_MUTATIONS: 10,
     15        GENOTYPE: "/*4*/",
    2116
    2217    Timing: {
     
    3833        FITNESS_TEXT: {x: 400, y: 300, z: 485},
    3934        EVOLVED_GENOTYPE_PLANK: {x: 400, y: 240, z: 0},
     35                NEURAL_NETWORK: {x: 400, y: 100, z: 300},
    4036        EVOLVED_FITNESS_PLANK: {x: 400, y: 240, z: 380},
    4137        MUTATION_GENOTYPE_PLANK: {x: 400, y: 400, z: 0},
     
    8379  Light: {
    8480    Ambient: {
    85       COLOR: 0x8a8a8a
     81      COLOR: 0xffffff
    8682    },
    8783
    8884    Directional: {
    89       COLOR: 0xdfebff,
    90       INTENSITY: 1,
     85      COLOR: 0xffffff,
     86      INTENSITY: 2,
    9187      X_POS: 50,
    9288      Y_POS: 200,
     
    167163  },
    168164
     165  NeuroViewer: {
     166        layoutType: 2,
     167        emptyLabel: "No neural network",
     168        canvas: {
     169          id: "neuro-viewer-canvas",
     170          drawMarginInPx: 20,
     171          font: "14px Lucida Grande, sans-serif",
     172          strokeStyle: '#DEDEDE'
     173        },
     174  },
     175
    169176  Framstick: {
    170177    COLOR: 0xcacaca,
     
    174181    CAST_SHADOW: true,
    175182
     183       
     184
    176185    Tween: {
    177186      Scale: {
     
    196205      PART: {
    197206        defaultShape: {
    198           radius: 0.213,
     207          radius: Module.Part.prototype.BALL_AND_STICK_RADIUS,
    199208          segments: 16
    200209        },
     
    206215      JOINT: {
    207216        cylinderShape: {
    208           radius: 0.1,
     217                  thickness: 0.8,
     218          radius: undefined, // if undefined -> depends on Part radius
    209219          radiusSegments: 10,
    210220          isTransparent: false,
     
    239249      HEIGHT: 65,
    240250      THICKNESS: 10,
    241       TEXTURE: "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/hardwood2_diffuse.jpg",
     251      TEXTURE: "js/hardwood2_diffuse_brighter.jpg",
    242252      REPEAT: 3,
    243253      ANISOTROPY: 8,
     
    264274      HEIGHT: 65,
    265275      THICKNESS: 10,
    266       TEXTURE: "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/hardwood2_diffuse.jpg",
     276      TEXTURE: "js/hardwood2_diffuse_brighter.jpg",
    267277      REPEAT: 1,
    268278      ANISOTROPY: 8,
     
    288298    LENGTH: 100,
    289299    FACES: 32,
    290     TEXTURE:"https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/hardwood2_diffuse.jpg",
     300    TEXTURE: "js/hardwood2_diffuse_brighter.jpg",
    291301    REPEAT: 1,
    292302    ANISOTROPY: 8,
     
    323333  }
    324334};
     335
     336
     337if (!Config.Framstick.Geometry.JOINT.cylinderShape.radius) {
     338        Config.Framstick.Geometry.JOINT.cylinderShape.radius = Config.Framstick.Geometry.PART.defaultShape.radius * Config.Framstick.Geometry.JOINT.cylinderShape.thickness;
     339}
  • js/standard_expdef_demo/js/external/framsjs/visualization/jointmeshfactory.js

    r880 r1326  
    102102        let shape = joint.get_shape();
    103103
    104         if (this.jointShapes['SHAPE_FIXED'].value == shape) {
    105             result = this.getNewJointMesh(joint, this.config.linkShape);
     104        if (this.jointShapes['SHAPE_STICK'].value == shape) {
     105            result = this.getNewJointMesh(joint, this.config.cylinderShape);
    106106        } else {
    107             result = this.getNewJointMesh(joint, this.config.cylinderShape);
     107                        result = this.getNewJointMesh(joint, this.config.linkShape);
    108108        }
    109109
  • js/standard_expdef_demo/js/external/framsjs/visualization/transformations.js

    r880 r1326  
    1717    getPartShapes() {
    1818        let shapes = [];
    19         shapes["SHAPE_BALL_AND_STICK"] = { name: "Ball & Stick", value: Module.Part["SHAPE_BALL_AND_STICK"] };
     19        shapes["SHAPE_BALL"] = { name: "Ball", value: Module.Part["SHAPE_BALL"] };
    2020        shapes["SHAPE_ELLIPSOID"] = { name: "Elipsoid", value: Module.Part["SHAPE_ELLIPSOID"] };
    2121        shapes["SHAPE_CUBOID"] = { name: "Cuboid", value: Module.Part["SHAPE_CUBOID"] };
     
    3030    getJointShapes() {
    3131        let shapes = [];
    32         shapes["SHAPE_BALL_AND_STICK"] = { name: "Ball & Stick", value: Module.Joint["SHAPE_BALL_AND_STICK"] };
     32        shapes["SHAPE_STICK"] = { name: "Stick", value: Module.Joint["SHAPE_STICK"] };
    3333        shapes["SHAPE_FIXED"] = { name: "Fixed", value: Module.Joint["SHAPE_FIXED"] };
     34                shapes["SHAPE_HINGE_X"] = { name: "Fixed", value: Module.Joint["SHAPE_HINGE_X"] };
     35                shapes["SHAPE_HINGE_XY"] = { name: "Fixed", value: Module.Joint["SHAPE_HINGE_XY"] };
    3436        return shapes;
    3537    }
     
    100102     */
    101103    calcColorComponent(value) {
    102         return THREE.Math.clamp(value, 0, 1);
     104        return THREE.MathUtils.clamp(value, 0, 1);
    103105    }
    104106
     
    151153
    152154        let m = new THREE.Matrix4();
    153         m.makeRotationZ(THREE.Math.degToRad(90));
     155        m.makeRotationZ(THREE.MathUtils.degToRad(90));
    154156
    155157        let m2 = new THREE.Matrix4();
     
    242244                part.get_scale().get_x(),
    243245                part.get_scale().get_z());
    244         } else if (this.partShapes['SHAPE_BALL_AND_STICK'].value != shape) {
     246        } else if (this.partShapes['SHAPE_BALL'].value != shape) {
    245247            bodyElement.mesh.scale.set(
    246248                part.get_scale().get_x(),
  • js/standard_expdef_demo/js/simulation/core.js

    r880 r1326  
    1010   */
    1111
    12   constructor(world) {
     12  constructor(world, args) {
    1313    this.world = world;
     14        this.buttons = [];
    1415
    1516    this.genPoolText = this.getText("Genotype Pool", EVOLUTION_METHOD_TEXT_POSITION);
     
    2223    this.fitnessText = this.getText("Fitness", Config.Simulation.Element.Position.FITNESS_TEXT);
    2324
     25        this.genotypeEncoding = Config.Simulation.GENOTYPE;
     26        this.proposedGenotypeEncoding = undefined;
     27
    2428    this.world.scene.add(this.genPoolText);
    2529    this.world.scene.add(this.mutationText);
     
    3135    this.world.scene.add(this.fitnessText);
    3236
     37        this.world.createTable(this.createGenotypes(Config.Simulation.NUMBER_OF_GENOTYPES,Config.Simulation.INITIAL_MUTATIONS),this.genotypeEncoding);
     38
    3339    this.state = State.INITIAL;
    3440    this.timing = Config.Simulation.Timing.INITIAL;
     41
     42        this.mutationProb = 0;
     43        this.mutationListeners = [];
     44        this.setMutationProb(args.mutation_prob?args.mutation_prob:Config.Simulation.MUTATION_PROBABILITY);
     45       
     46        this.crossoverProb = 0;
     47        this.crossoverListeners = [];
     48        this.setCrossoverProb(args.crossover_prob?args.crossover_prob:Config.Simulation.CROSSOVER_PROBABILITY);
     49
     50        this.neuroLayoutModel = undefined;
     51        this.neuroLayoutFunctionHelper = new Module.NNLayoutFunctionHelper();
     52        this.neuroViewer = undefined;
     53
     54        this.evolvedFitness = 0;
     55
     56        this.lastTimeout = undefined;
     57  }
     58
     59  activateButtons(){
     60        for(let i=0;i<this.buttons.length;i++){
     61                this.buttons[i].activate();
     62        }
     63  }
     64
     65  deactivateButtons(){
     66        for(let i=0;i<this.buttons.length;i++){
     67                this.buttons[i].deactivate();
     68        }
     69  }
     70
     71  updateListeners(list,value){
     72        for(let i=0;i<list.length;i++){
     73                list[i].update(value);
     74        }
     75  }
     76
     77  reupdateListeners(){
     78        this.updateListeners(this.mutationListeners,this.mutationProb);
     79        this.updateListeners(this.crossoverListeners,this.crossoverProb);
     80  }
     81
     82  getMutationProb(){
     83        return this.mutationProb;
     84  }
     85  setMutationProb(prob){
     86        this.mutationProb = Math.min(Math.max(prob,0),1);
     87        if(this.crossoverProb + this.mutationProb > 1){
     88                this.setCrossoverProb(1 - this.mutationProb);
     89        }
     90        this.updateListeners(this.mutationListeners,this.mutationProb);
     91  }
     92
     93  getCrossoverProb(){
     94        return this.crossoverProb;
     95  }
     96  setCrossoverProb(prob){
     97        this.crossoverProb = Math.min(Math.max(prob,0),1);
     98        if(this.crossoverProb + this.mutationProb > 1){
     99                this.setMutationProb(1 - this.crossoverProb);
     100        }
     101        this.updateListeners(this.crossoverListeners,this.crossoverProb);
     102  }
     103
     104  updateNeuroLayoutModel(model) {
     105    if( this.neuroLayoutModel ) {
     106      Module.destroy( this.neuroLayoutModel );
     107    }
     108    this.neuroLayoutModel = new Module.NNLayoutState_Model_Fred( model );
     109    this.neuroLayoutFunctionHelper.doLayout( Config.NeuroViewer.layoutType , this.neuroLayoutModel );
     110  }
     111
     112  getBrainData (model) {
     113        var thisSim = this;
     114    return {
     115      getElements: function () {
     116        return thisSim.neuroLayoutModel.GetElements();
     117      },
     118      getValueXYWH: function ( i ) {
     119        return thisSim.neuroLayoutModel.GetValueXYWH( i );
     120      },
     121      getNeuro: function ( i ) {
     122        return model.getNeuro( i );
     123      }
     124    };
     125  }
     126
     127  updateFitness(value){
     128        // if (this.state !== State.SHOW_FRAMSTICK && this.state !== State.DESTROY_FRAMSTICK){
     129        //      return;
     130        // }
     131        this.evolvedFitness += value;
     132        this.evolvedFitness = Math.max(this.evolvedFitness,0);
     133        if(this.evolvedFitnessPlank){
     134                this.evolvedFitnessPlank.updateFitness(this.evolvedFitness);
     135        }
     136  }
     137
     138  isGenotypeChanging(){
     139        return this.proposedGenotypeEncoding && this.proposedGenotypeEncoding !== this.genotypeEncoding;
    35140  }
    36141
     
    43148        this.state = State.EVOLUTION_METHOD_SELECTION;
    44149        this.timing = Config.Simulation.Timing.INITIAL;
     150
     151                if(this.isGenotypeChanging()){
     152                        this.state = State.CHANGE_GENOTYPE;
     153                }
     154
    45155        break;
    46156
     
    50160        this.timing = Config.Simulation.Timing.EVOLUTION_METHOD_SELECTION;
    51161        let randomVal = Math.random()
    52         if (randomVal < Config.Simulation.MUTATION_PROBABILITY) {
     162        if (randomVal < this.mutationProb) {
    53163          this.state = State.MUTATION_GENOTYPE_SELECTION;
    54         } else if (randomVal < Config.Simulation.MUTATION_PROBABILITY +
    55                                Config.Simulation.CROSSOVER_PROBABILITY){
     164        } else if (randomVal < this.mutationProb +
     165                               this.crossoverProb){
    56166          this.state = State.CROSSOVER_GENOTYPE_SELECTION;
    57167        } else {
     
    65175        this.hideText(this.genPoolText);
    66176
    67         this.mutationIdx = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
     177        this.mutationIdx = this.chooseIdx();
    68178        this.mutationArrow = this.getArrow(this.mutationIdx).mesh;
    69179        this.world.scene.add(this.mutationArrow);
     
    100210        this.hideText(this.genPoolText);
    101211
    102         this.cloningIdx = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
     212        this.cloningIdx = this.chooseIdx();
    103213        this.cloningArrow = this.getArrow(this.cloningIdx).mesh;
    104214        this.world.scene.add(this.cloningArrow);
     
    135245        this.hideText(this.genPoolText);
    136246
    137         this.crossoverIdx1 = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
     247        this.crossoverIdx1 = this.chooseIdx();
    138248        do {
    139           this.crossoverIdx2 = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
     249          this.crossoverIdx2 = this.chooseIdx();
    140250        } while (this.crossoverIdx1 == this.crossoverIdx2);
    141251
     
    175285
    176286      case State.SHOW_FRAMSTICK:
     287                this.activateButtons();
    177288        this.moveCamera(Config.Simulation.Camera.Position.FRAMSTICK);
    178 
     289               
    179290        this.evolvedFramstick = new Framstick(this.evolvedGenotype);
     291                const model = this.evolvedFramstick.getModelFromGenotype(this.evolvedGenotype);
    180292        this.world.scene.add(this.evolvedFramstick.mesh);
    181 
     293               
     294                this.updateNeuroLayoutModel(model);
     295                this.neuroViewer.updateBrain(this.getBrainData(model));
     296                Module.destroy(model);
    182297        this.timing = Config.Simulation.Timing.SHOW_FRAMSTICK;
    183298        this.state = State.DESTROY_FRAMSTICK;
     
    187302        this.evolvedFramstick.scaleUpSize = 0.01;
    188303        this.evolvedFramstick.scaleDownSize = 0.01;
     304                this.neuroViewer.clear();
     305                this.world.scene.remove(this.neuroViewer.get3DContainer());
    189306
    190307        this.showText(this.fitnessText);
     
    195312        this.evolvedFitnessPlank.move(Config.Simulation.Element.Position.EVOLVED_FITNESS_PLANK);
    196313        this.evolvedFitnessPlank.rotate(Config.Simulation.Element.Angle.SIDE_VIEW);
    197         this.world.scene.add(this.evolvedFitnessPlank.mesh)
    198         this.world.scene.add(this.evolvedFitnessPlank.textMesh)
     314        this.world.scene.add(this.evolvedFitnessPlank.mesh);
     315        this.world.scene.add(this.evolvedFitnessPlank.textMesh);
     316
    199317
    200318        this.timing = Config.Simulation.Timing.DESTROY_FRAMSTICK;
     
    207325        }
    208326        break;
     327        case State.CHANGE_GENOTYPE:
     328                this.genotypeEncoding = this.proposedGenotypeEncoding;
     329                this.world.setGenotypes(this.createGenotypes(Config.Simulation.NUMBER_OF_GENOTYPES,Config.Simulation.INITIAL_MUTATIONS),this.genotypeEncoding);
     330                this.proposedGenotypeEncoding = undefined;
     331
     332                this.state = State.INITIAL;
     333                break;
    209334    }
    210 
    211     setTimeout(this.run.bind(this), this.timing);
    212   }
    213 
    214   getMutatedGenotype(genotype) {
    215     let genoF4 = new Module.Geno_f4();
    216     let genoOperatorsHelper = new Module.GenoOperatorsHelper(genoF4);
     335        if(this.isGenotypeChanging()){
     336                this.timing = 0;
     337        }
     338    this.lastTimeout = setTimeout(this.run.bind(this), this.timing);
     339  }
     340
     341  setProposedGenotype(proposed){
     342        this.proposedGenotypeEncoding = proposed;
     343        if (this.lastTimeout){
     344                clearTimeout(this.lastTimeout);
     345                this.run();
     346        }
     347  }
     348
     349  chooseIdx(){
     350        return this.weightedChoice();
     351  }
     352
     353  randomChoice(){
     354        return parseInt(Math.random() * Config.Simulation.NUMBER_OF_GENOTYPES);
     355  }
     356
     357  weightedChoice(){
     358        const fitness = this.world.table.fitnessPlanks
     359                                        .map((k)=>{
     360                                                return parseFloat(k.fitness)+0.0001;
     361                                        });
     362        const fitness_sum = fitness.reduce((partialSum, a) => partialSum + a, 0);
     363        const probs = fitness
     364                                        .map((k)=>{
     365                                                return k/fitness_sum;
     366                                        });
     367
     368        var prob = Math.random();
     369        for(let i=0;i<probs.length;i++){
     370                if(prob < probs[i]){
     371                        return i;
     372                }
     373                prob -= probs[i];
     374        }
     375        return -1;
     376  }
     377
     378  createGenotypes(n,mutation_count){
     379        var func = this.getOperator(this.genotypeEncoding);
     380    let genoOper = new func();
     381    let genoOperatorsHelper = new Module.GenoOperatorsHelper(genoOper);
     382        var genotypes = [];
     383
     384        for(let i=0;i<n;i++){
     385                var genotype = genoOperatorsHelper.getSimplest();
     386                genotypes.push(this.mutate(genotype,genoOperatorsHelper,mutation_count));
     387        }
     388
     389        return genotypes;
     390  }
     391
     392  getOperator(genoName){
     393        const genoType = genoName.replace("/*","").replace("*/","");
     394        var func = Module[`Geno_f${genoType}`];
     395        func = func?func:Module[`GenoOper_f${genoType}`];
     396        return func;
     397  }
     398
     399  getMutatedGenotype(genotype){
     400        var func = this.getOperator(this.genotypeEncoding);
     401    let genoOper = new func();
     402    let genoOperatorsHelper = new Module.GenoOperatorsHelper(genoOper);
     403        genotype = this.mutate(genotype,genoOperatorsHelper,1);
     404        Module.destroy(genoOper);
     405    Module.destroy(genoOperatorsHelper);
     406    return genotype;
     407  }
     408
     409  mutate(genotype,genoOperatorsHelper,times) {
     410        for(let i = 0;i<times;i++){
     411                genotype = this.tryMutation(genotype,genoOperatorsHelper);
     412        }
     413        return genotype;
     414  }
     415
     416  tryMutation(genotype,genoOperatorsHelper){
     417        let genetics = new Module.PreconfiguredGenetics();
     418    let iteration = 0;
     419        do {
     420                if (genoOperatorsHelper.mutate(genotype.replace(this.genotypeEncoding, "")) == 0) {
     421                  let mutated = genoOperatorsHelper.getLastMutateGeno().c_str();
     422          let newGenotype = `${this.genotypeEncoding}` + mutated;
     423 
     424                  let stringObj = new Module.SString();
     425                  stringObj.set(newGenotype);
     426                  let genoObj = new Module.Geno(stringObj);
     427 
     428                  if (genoObj.isValid()) {
     429                        genotype = newGenotype;
     430                        iteration = Config.Simulation.EVOLUTION_MAX_REPETITIONS;
     431                  }
     432 
     433                  Module.destroy(stringObj);
     434                  Module.destroy(genoObj);
     435                } else {
     436                  iteration = Config.Simulation.EVOLUTION_MAX_REPETITIONS;
     437                }
     438                iteration += 1;
     439          } while(iteration < Config.Simulation.EVOLUTION_MAX_REPETITIONS);
     440
     441          return genotype;
     442  }
     443
     444  getCrossoveredGenotype(genotype1, genotype2) {
     445        var func = this.getOperator(this.genotypeEncoding);
     446    let genoOper = new func();
     447    let genoOperatorsHelper = new Module.GenoOperatorsHelper(genoOper);
    217448    let genetics = new Module.PreconfiguredGenetics();
    218449    let iteration = 0;
    219450
    220451    do {
    221       if (genoOperatorsHelper.mutate(genotype.replace("/*4*/", "")) == 0) {
    222         let mutated = genoOperatorsHelper.getLastMutateGeno();
    223         let newGenotype = "/*4*/ " + mutated;
     452      if (genoOperatorsHelper.crossOver(genotype1.replace(this.genotypeEncoding, ""),
     453                                        genotype2.replace(this.genotypeEncoding, "")) == 0) {
     454        let crossovered = genoOperatorsHelper.getLastCrossGeno1().c_str();
     455        let newGenotype = `${this.genotypeEncoding}` + crossovered;
     456
    224457
    225458        let stringObj = new Module.SString();
     
    228461
    229462        if (genoObj.isValid()) {
    230           genotype = newGenotype;
     463          genotype1 = newGenotype;
    231464          iteration = Config.Simulation.EVOLUTION_MAX_REPETITIONS;
    232465        }
     
    240473    } while(iteration < Config.Simulation.EVOLUTION_MAX_REPETITIONS);
    241474
    242     Module.destroy(genoF4);
    243     Module.destroy(genoOperatorsHelper);
    244     return genotype;
    245   }
    246 
    247   getCrossoveredGenotype(genotype1, genotype2) {
    248     let genoF4 = new Module.Geno_f4();
    249     let genoOperatorsHelper = new Module.GenoOperatorsHelper(genoF4);
    250     let genetics = new Module.PreconfiguredGenetics();
    251     let iteration = 0;
    252 
    253     do {
    254       if (genoOperatorsHelper.crossOver(genotype1.replace("/*4*/", ""),
    255                                         genotype2.replace("/*4*/", "")) == 0) {
    256         let crossovered = genoOperatorsHelper.getLastCrossGeno1();
    257         let newGenotype = "/*4*/ " + crossovered;
    258 
    259         let stringObj = new Module.SString();
    260         stringObj.set(newGenotype);
    261         let genoObj = new Module.Geno(stringObj);
    262 
    263         if (genoObj.isValid()) {
    264           genotype1 = newGenotype;
    265           iteration = Config.Simulation.EVOLUTION_MAX_REPETITIONS;
    266         }
    267 
    268         Module.destroy(stringObj);
    269         Module.destroy(genoObj);
    270       } else {
    271         iteration = Config.Simulation.EVOLUTION_MAX_REPETITIONS;
    272       }
    273       iteration += 1;
    274     } while(iteration < Config.Simulation.EVOLUTION_MAX_REPETITIONS);
    275 
    276     Module.destroy(genoF4);
     475    Module.destroy(genoOper);
    277476    Module.destroy(genoOperatorsHelper);
    278477    return genotype1;
     
    280479
    281480  showEvolutionResult() {
    282     this.evolvedGenotypePlank = new GenotypePlank(this.evolvedGenotype, 10);
     481    this.evolvedGenotypePlank = new GenotypePlank(this.evolvedGenotype, this.genotypeEncoding, 10);
    283482    this.evolvedGenotypePlank.move(Config.Simulation.Element.Position.EVOLVED_GENOTYPE_PLANK);
    284483    this.evolvedGenotypePlank.rotate(Config.Simulation.Element.Angle.SIDE_VIEW);
     484
     485        this.neuroViewer.move(Config.Simulation.Element.Position.NEURAL_NETWORK);
     486    this.neuroViewer.rotate(Config.Simulation.Element.Angle.SIDE_VIEW);
    285487    this.world.scene.add(this.evolvedGenotypePlank.mesh);
    286488    this.world.scene.add(this.evolvedGenotypePlank.textMesh);
     489        this.world.scene.add(this.neuroViewer.get3DContainer());
    287490
    288491    if (this.evolutionMethod == State.MUTATION_GENOTYPE_SELECTION) {
     
    302505
    303506  evolutionReturn() {
    304     let replaceIdx = parseInt(Math.random() * Config.Simulation.GENOTYPES.length);
     507    let replaceIdx = parseInt(Math.random() * Config.Simulation.NUMBER_OF_GENOTYPES);
    305508    let genotypePlank = this.world.table.genotypePlanks[replaceIdx];
    306509    let fitnessPlank = this.world.table.fitnessPlanks[replaceIdx];
     
    322525    this.world.table.genotypePlanks[replaceIdx] = this.evolvedGenotypePlank;
    323526    this.world.table.fitnessPlanks[replaceIdx] = this.evolvedFitnessPlank;
     527        this.evolvedFitnessPlank = undefined;
    324528    this.hideText(this.fitnessText);
     529        this.deactivateButtons();
    325530  }
    326531
     
    378583  "CROSSOVER_SIDE_VIEW": 9, "CROSSOVER_RESULT": 10, "CROSSOVER_RETURN": 11,
    379584  "DESTROY_FRAMSTICK": 12, "CLONING_GENOTYPE_SELECTION": 13,
    380   "CLONING_SIDE_VIEW": 14, "CLONING_RESULT": 15, "CLONING_RETURN": 16
     585  "CLONING_SIDE_VIEW": 14, "CLONING_RESULT": 15, "CLONING_RETURN": 16,
     586  "CHANGE_GENOTYPE": 17
    381587};
    382588
    383589var EVOLUTION_METHOD_TEXT_POSITION = {
    384590  x: -210,
    385   y: 80 + (Config.Table.FitnessPlank.HEIGHT + Config.Table.Board.SPACING) * (Config.Simulation.GENOTYPES.length + 1),
     591  y: 80 + (Config.Table.FitnessPlank.HEIGHT + Config.Table.Board.SPACING) * (Config.Simulation.NUMBER_OF_GENOTYPES + 1),
    386592  z: -500
    387593};
  • js/standard_expdef_demo/js/world/core.js

    r880 r1326  
    1717    this.sky = this.Sky();
    1818    this.sun = this.Sun();
    19     this.table = this.Table();
    2019  }
    2120
     
    2524    texture.repeat.set(Config.Ground.REPEAT, Config.Ground.REPEAT);
    2625    texture.anisotropy = Config.Ground.ANISOTROPY;
     26        texture.colorSpace = THREE.SRGBColorSpace;
    2727
    28     let geometry = new THREE.PlaneBufferGeometry(Config.Ground.WIDTH, Config.Ground.WIDTH);
     28    let geometry = new THREE.PlaneGeometry(Config.Ground.WIDTH, Config.Ground.WIDTH);
    2929    let material = new THREE.MeshLambertMaterial({map: texture});
    3030    let ground = new THREE.Mesh(geometry, material);
     
    3636  }
    3737
    38   Table() {
    39     let table = new Table(Config.Simulation.GENOTYPES);
     38  createTable(genotypes,genotypeEncoding){
     39        this.table = this.Table(genotypes,genotypeEncoding);
     40  }
     41
     42  setGenotypes(genotypes, genotypeEncoding){
     43        this.table.genotypes = genotypes;
     44        for (let i = 0; i < this.table.genotypes.length; i++) {
     45                this.scene.remove(this.table.genotypePlanks[i].textMesh);
     46                // this.table.genotypePlanks[i] = new GenotypePlank(genotypes[i],genotypeEncoding,i);
     47                this.table.genotypePlanks[i].updateGenotype(genotypes[i],genotypeEncoding);
     48                this.scene.add(this.table.genotypePlanks[i].textMesh);
     49                this.table.fitnessPlanks[i].updateFitness((Math.random() * 100).toFixed(2));
     50        }
     51  }
     52
     53  Table(genotypes,genotypeEncoding) {
     54    let table = new Table(genotypes,genotypeEncoding);
    4055    this.scene.add(table.board);
    4156    this.scene.add(table.genotypeHeader.mesh);
     
    7691
    7792  Sky() {
    78     let sky = new THREE.Sky()
     93    let sky = new Sky()
    7994    sky.scale.setScalar(Config.Sky.SCALE);
    8095    sky.material.uniforms.turbidity.value = Config.Sky.TURBIDITY;
    8196    sky.material.uniforms.rayleigh.value = Config.Sky.RAYLEIGH;
    82     sky.material.uniforms.luminance.value = Config.Sky.LUMINANCE;
     97        // sky.material.uniforms.luminance.value = Config.Sky.LUMINANCE;
    8398    sky.material.uniforms.mieCoefficient.value = Config.Sky.MIE_COEFFICIENT;
    8499    sky.material.uniforms.mieDirectionalG.value = Config.Sky.MIE_DIRECTIONAL_G;
     
    89104  Sun() {
    90105    let sun = new THREE.Mesh(
    91       new THREE.SphereBufferGeometry(Config.Sun.RADIUS, Config.Sun.WIDTH_SEGMENTS, Config.Sun.HEIGHT_SEGMENTS),
     106      new THREE.SphereGeometry(Config.Sun.RADIUS, Config.Sun.WIDTH_SEGMENTS, Config.Sun.HEIGHT_SEGMENTS),
    92107      new THREE.MeshBasicMaterial({color: Config.Sun.COLOR})
    93108    );
  • js/standard_expdef_demo/js/world/object/arrow.js

    r880 r1326  
    2222    let material = new THREE.MeshLambertMaterial({map: texture});
    2323    material.opacity = 0;
    24     material.blending = THREE.NoBlending;
     24    // material.blending = THREE.NoBlending;
    2525
    2626    this.mesh = new THREE.Mesh(geometry, material);
  • js/standard_expdef_demo/js/world/object/framstick.js

    r880 r1326  
    112112    }
    113113
    114     let model = new Module.Model(genoObj, true);
     114    let model = new Module.Model(genoObj, Module.Model["SHAPETYPE_UNKNOWN"], true);
     115        model.open();
     116        model.close();
    115117    Module.destroy(stringObj);
    116118    Module.destroy(genoObj);
  • js/standard_expdef_demo/js/world/object/table.js

    r880 r1326  
    1010   */
    1111
    12   constructor(genotypes) {
    13     this.genotypes = genotypes
     12  constructor(genotypes,genotypeType) {
     13    this.genotypes = genotypes;
     14        this.genotypeType = genotypeType;
    1415
    1516    this.board = this.Board();
     
    2526    texture.repeat.set(Config.Table.Board.REPEAT, Config.Table.Board.REPEAT);
    2627    texture.anisotropy = Config.Table.Board.ANISOTROPY;
     28        texture.colorSpace = THREE.SRGBColorSpace;
    2729
    2830    let geometry = new THREE.BoxGeometry(Config.Table.Board.WIDTH,
     
    3234    let material = new THREE.MeshLambertMaterial({map: texture});
    3335    material.opacity = 0;
    34     material.blending = THREE.NoBlending;
     36    // material.blending = THREE.NoBlending;
    3537
    3638    let board = new THREE.Mesh(geometry, material);
     
    4648    let planks = []
    4749    for (let i = 0; i < this.genotypes.length; i++) {
    48       planks.push(new GenotypePlank(this.genotypes[i], i));
     50      planks.push(new GenotypePlank(this.genotypes[i],this.genotypeType, i));
    4951    }
    5052    return planks
     
    6062
    6163  GenotypeHeader() {
    62     return new GenotypePlank("Genotype", this.genotypes.length, true)
     64    return new GenotypePlank("Genotype",this.genotypeType, this.genotypes.length, true)
    6365  }
    6466
     
    7173class GenotypePlank {
    7274
    73   constructor(genotype, position, bold) {
     75  constructor(genotype, genotypeEncoding, position, bold) {
    7476    this.genotype = genotype;
    7577    this.position = {
     
    8385    texture.repeat.set(Config.Table.GenotypePlank.REPEAT, Config.Table.GenotypePlank.REPEAT);
    8486    texture.anisotropy = Config.Table.GenotypePlank.ANISOTROPY;
     87        texture.colorSpace = THREE.SRGBColorSpace;
    8588
    8689    let geometry = new THREE.BoxGeometry(Config.Table.GenotypePlank.WIDTH,
     
    9497    this.mesh.receiveShadow = Config.Table.GenotypePlank.RECEIVE_SHADOW;
    9598
    96     this.textMesh = Text.getGenotypeMesh(this.genotype.replace("/*4*/ ", ""));
     99        this.genotypeType = genotypeEncoding;
     100    this.textMesh = Text.getGenotypeMesh(this.genotype,this.genotypeType);
    97101    if (bold == true) {
    98       this.textMesh = Text.getFitnessMesh(this.genotype.replace("/*4*/ ", ""));
     102      this.textMesh = Text.getFitnessMesh(this.genotype.replace(`${this.genotypeType} `, ""));
    99103    }
    100104    this.textMesh.position.set(this.position.x, this.position.y, this.position.z + 1);
     105  }
     106
     107  updateGenotype(genotype,genotypeType){
     108        this.genotype = genotype;
     109        this.genotypeType = genotypeType;
     110        this.textMesh = Text.getGenotypeMesh(this.genotype,this.genotypeType);
     111        this.textMesh.position.set(this.position.x, this.position.y, this.position.z + 1);
    101112  }
    102113
     
    137148    texture.repeat.set(Config.Table.FitnessPlank.REPEAT, Config.Table.FitnessPlank.REPEAT);
    138149    texture.anisotropy = Config.Table.FitnessPlank.ANISOTROPY;
     150        texture.colorSpace = THREE.SRGBColorSpace;
    139151
    140152    let geometry = new THREE.BoxGeometry(Config.Table.FitnessPlank.WIDTH,
     
    150162    this.textMesh = Text.getFitnessMesh(this.fitness);
    151163    this.textMesh.position.set(this.position.x, this.position.y, this.position.z + 1);
     164  }
     165
     166  updateFitness(value){
     167        this.fitness = value;
     168        this.textMesh.element.innerHTML = roundNumber(this.fitness,2);
    152169  }
    153170
  • js/standard_expdef_demo/js/world/object/text.js

    r880 r1326  
    66
    77var Text = {
    8   getGenotypeMesh: function(genotype) {
     8        styleRegex: /<style>.*<\/style>/,
     9        numberRegex : /-?\d+(\.\d+)?/g,
     10        roundMatch: function(match) {
     11        return roundNumber(match,2).toString();
     12    },
     13
     14  getGenotypeMesh: function(genotype,genotypeType) {
     15        const genman = new Module.GenMan();
     16        genotype = genotype.replace(this.numberRegex, this.roundMatch);
     17        genotype = genotype.replaceAll("\n","⤶");
    918    if (genotype.length > 20) {
    10       genotype = genotype.slice(0, 20) + "..."
     19       genotype = genotype.slice(0,30) + "..."
    1120    }
    1221    var element = document.createElement("div");
    13     element.className = "genotype";
    14     element.textContent = genotype;
    15     return new THREE.CSS3DObject(element);
     22    element.innerHTML = genman.HTMLize(genotype).c_str();
     23        element.innerHTML = element.innerHTML.replace(this.styleRegex,"").replace(genotypeType,"");
     24        Module.destroy(genman);
     25    return new CSS3DObject(element);
    1626  },
    1727
     
    2030    element.className = "fitness";
    2131    element.textContent = fitness;
    22     return new THREE.CSS3DObject(element);
     32    return new CSS3DObject(element);
    2333  },
    2434
     
    2737    element.className = "info";
    2838    element.textContent = info;
    29     return new THREE.CSS3DObject(element);
     39    return new CSS3DObject(element);
    3040  }
    3141}
  • js/standard_expdef_demo/static/styles.css

    r880 r1326  
    1 .genotype {
     1.geno {
    22  font-size: 40px;
    33  font-weight: 500;
    44  font-family: "Helvetica", "Arial", "Verdana", serif;
    55  text-align: center;
     6  /* white outline to help when displayed on darker background: */
     7  /* text-shadow: -1px 0 white, 0 1px white, 1px 0 white, 0 -1px white */
    68}
    79
     
    2022  width: 8em;
    2123}
     24
     25.neuro-viewer-container{
     26        background-color: black;
     27        border-radius: 0px 30px 0px 0px;
     28        border-color: white;
     29        border-style: double double none none;
     30        border-width: 5px;
     31        pointer-events: none;
     32}
     33
     34#neuro-viewer-2d{
     35        position: absolute;
     36        bottom: 0;
     37        left: 0;
     38        width: 25%;
     39        height: 25%;
     40}
     41
     42#neuro-viewer-3d{
     43        background-color: black;
     44        border-radius: 30px 30px 30px 30px;
     45        border-color: white;
     46        border-style: double double double double;
     47        border-width: 5px;
     48        pointer-events: none;
     49}
     50
     51#neuro-viewer-canvas{
     52        width: 100%;
     53        height: 100%;   
     54}
     55
     56.controls {
     57        position: absolute;
     58        bottom: 0;
     59        right: 0;
     60        background-color: gainsboro;
     61        border-radius: 30px 0px 0px 0px;
     62        border-color: gray;
     63        border-style: double none none double;
     64        border-width: 5px;
     65        font-family: "Sans-serif", Verdana, Geneva, Tahoma, sans-serif;
     66
     67        display: flex;
     68        justify-content: center;
     69        align-items: safe center;
     70}
     71
     72.column {
     73        display: flex;
     74        flex-direction: column;
     75}
     76
     77.row {
     78        display: flex;
     79        flex-direction: row;
     80}
     81
     82.slider-value{
     83        margin-left: 5%;
     84}
     85
     86.slider{
     87        margin-left: 2%;
     88        margin-right: 2%;
     89}
     90
     91.control-container{
     92        margin-top: 2%;
     93        width: 70%;
     94}
     95
     96.rater-button{
     97        padding: 0;
     98        border: none;
     99        background: none;
     100        font-size: 30px;
     101        margin-left: 2%;
     102}
     103
     104button.inactive{
     105        opacity: 0.33;
     106}
     107
     108button:active{
     109        transform: translateY(4px);
     110}
     111
     112button.inactive:active{
     113        transform: translateY(0px);
     114}
Note: See TracChangeset for help on using the changeset viewer.