JSFiddle - React, Tailwind, and code Playground

by Gwyn Milcote

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r125/three.min.js"></script>

<div id='container'>

    <div id='game-container'></div>
    
    <div id='game-controls'>
        <button class='uh' data-key='A'>Left</button>
        <button class='uh' data-key='W'>Up</button>
        <button class='uh' data-key='S'>Down</button>
        <button class='uh' data-key='D'>Right</button>
        &nbsp; &nbsp; 
        <button class='uh' data-key='Sp'>Space</button>
        &nbsp; &nbsp; 
        <button class='uh' data-key='Q'>Q</button>
        <button class='uh' data-key='E'>E</button>
        <button class='uh' data-key='Z'>Z</button>
        <button class='uh' data-key='X'>X</button>
        &nbsp; &nbsp;
        <button id='pause-btn'>Pause</button>
    </div>

    <table id='game-status'>
        <tr>
           <td colspan='1'><b>GS:</b> <span id='status-gameState'></span></td>
           <td colspan='1'><b>MS:</b> <span id='status-moveState'></span></td>
           <td colspan='1'><b>Ticks:</b> <span id='status-ticks'>0</span></td>
        </tr>
        <tr>
           <td colspan='2'><b>Keys down:</b> <span id='status-keys'></span></td>
            <td colspan='1'><b>Angle:</b> <span id='angle'>?</span> deg</td>
        </tr>
        <tr>
            <th colspan='3'>Player position</th>
        </tr>
        <tr>
            <td><b>X:</b> <span id='posX'></span></td>
            <td><b>Y:</b> <span id='posY'></span></td>
            <td><b>Z:</b> <span id='posZ'></span></td>
        </tr>
        <tr>
            <th colspan='3'>Player rotation</th>
        </tr>
        <tr>
            <td><b>X:</b> <span id='rotX'></span></td>
            <td><b>Y:</b> <span id='rotY'></span></td>
            <td><b>Z:</b> <span id='rotZ'></span></td>
        </tr>
        <tr>
            <th colspan='3'>Player speed</th>
        </tr>
        <tr>
            <td><b>X:</b> <span id='spX'></span></td>
            <td><b>Y:</b> <span id='spY'></span></td>
     ...

CSS

#container {
    width: 420px;
    background-color: #eee;
    padding: 20px;
}
#container table {
    width: 360px;
    margin: 15px 0;
    border-collapse: collapse;
}
#container table td {
    background-color: #fff;
    border: 1px solid grey;
    width: 33%;
    padding: 2px 5px;
}
#container table th {
    background-color: #eee;
    border: 1px solid grey;
}


#game-container {
    width: 360px;
    height: 280px;
    background-color: grey;
}
/* #game-canvas same size  */

#game-controls {
    margin: 15px 0;
}

#load-status {
    display: flex;
    justify-content: space-between;
}
#load-status > div {
    width: 30%;
}
#load-statuc .load-bar {
    height: 25px;
    border: 1px solid black;
}
#load-status .load-bar-inner {
    height: 100%;
    background-color: green;
}

JavaScript

const db = {
    
    worlds: [
        {id: 1, name: "World 1"},
        {id: 2, name: "World 2"},
        {id: 3, name: "World 3"},
        {id: 4, name: "World 4"},
        {id: 5, name: "World 5"},
        {id: 6, name: "World 6"}
    ],
    
    /*
    * Levels. Which assets to load/use.
    * Arrays of scenery objects to arrange.
    */
    levels: [
        {
            id: 1, world: 1, name: "Homeworld 1", tex: "darksand",
            // First state spyro should be in
            moveState: "Idle",
            isFlightEnabled: false,
            isSuperchargeEnabled: false,
            startX: 0, startY: 0, startZ: 0,
            rotX: 0, // assume no Y/Z rotation
            
            skybox: "2",
            music: "",
            
            // Every level needs one hemisphere light.
            // Colours can differ.
            // Directional lights only used if enableShadows.
            lights: [
                {
                    type: "hemi",
                    skyColour: 0x6666aa,
                    groundColour: 0x443322,
                    intensity: 1
                },{
                    type: "dir",
                    colour: 0xeeddcc,
                    intensity: 1,
                    posX: 25, posY: 25, posZ: 25
                }
            ],
            
            // What to build. Later use proper models.
            geometry: [
                {
                    type: "plane", texture: "grass",
                    width: 100, height: 100,
                },{
                    type: "box", texture: "stone",
                    width: 10, height: 5, depth: 10,
                    x: 20, y: 0, z: 20
                }
            ],
            
            // temporary.
            // could be other repeating scenery bits.
            trees: [
                {height: 1.3, width: 1.1, sink: 0.5, type: "tree1", x: 7, z: 7},
                {height: 1.7, width: 0.7, sink: 0.2, type: "tree1", x: 12, z: 17},
        ...