main v1.0
Benjamin Kraft 2 years ago
commit b58d52529b
  1. 2
      .gitignore
  2. 6
      project.json
  3. BIN
      public/data/images/favicon.ico
  4. 321
      public/data/scripts/algorithm.js
  5. 29
      public/data/scripts/events.js
  6. 111
      public/data/scripts/game.js
  7. 160
      public/data/scripts/grid.js
  8. 87
      public/data/scripts/init.js
  9. 10
      public/data/scripts/online.js
  10. 8
      public/data/settings/libraries.json
  11. 32
      public/data/settings/settings.json
  12. 88
      public/data/styles/color_picker.css
  13. BIN
      public/data/styles/font.ttf
  14. 88
      public/data/styles/range_input.css
  15. 66
      public/index.html
  16. 85
      public/styles.css
  17. BIN
      public/thumbnail.png

2
.gitignore vendored

@ -0,0 +1,2 @@
.idea

@ -0,0 +1,6 @@
{
"display_name": "Pathfinder",
"info_text": "A graphical demonstration of some pathfinder algorithms",
"visible": true,
"tags": ["Simulation", "Tool"]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

@ -0,0 +1,321 @@
class Algorithm{
constructor(){
this.startNode = game.startNode;
this.targetNode = game.targetNode;
this.grid = game.grid;
this.startDate = new Date();
this.timeDiff = 0;
}
get running(){
return !this.hasSucceeded && !this.hasFailed;
}
display(){
push();
scale(1 / this.grid.nodeSize.x, 1 / this.grid.nodeSize.y);
fill(0);
textSize(20);
textAlign(CENTER, TOP);
text('Time: ' + this.timeDiff / 1000 + 's', this.grid.size / 2, -this.grid.nodeSize.y / 2 - 50);
pop();
}
update(){
this.timeDiff = new Date().getTime() - this.startDate.getTime();
}
success(){
console.log('Success!');
this.hasSucceeded = true;
}
failed(){
console.log('Failed!');
this.hasFailed = true;
}
}
function startAlgorithm(){
switch ($('#algorithm_type').val()){
case 'astar':
game.start(new AStar());
break;
case 'dijkstra':
game.start(new Dijkstra());
break;
case 'dstar':
game.start(new DStar());
break;
}
}
class DStar extends Algorithm{
constructor() {
super();
this.openList = []
}
}
class AStar extends Algorithm{
constructor(){
super();
this.startNode.f = 0;
this.startNode.g = 0;
this.openList = [this.startNode];
this.closedList = [];
}
get minFNodeIndex(){
let f = this.openList[0].f, index = 0;
this.openList.forEach((n, i) => {
if (n.f < f){
f = n.f;
index = i;
}
});
return index;
}
update(){
if (!this.running){
return;
}
super.update();
if (!this.openList.length){
this.failed();
} else {
let index = this.minFNodeIndex;
let currentNode = this.openList[index];
this.openList.splice(index, 1);
if (currentNode === this.targetNode){
this.success();
} else {
this.closedList.push(currentNode);
currentNode.successors.forEach(successor => {
if (this.closedList.find(n => n === successor)){
return;
}
let provisionalG = currentNode.g + currentNode.pos.dist(successor.pos);
if (this.openList.find(n => n === successor) && provisionalG >= successor.g){
return;
}
successor.predecessor = currentNode
successor.g = provisionalG;
successor.f = provisionalG + successor.distanceToTarget;
if (!this.openList.find(n => n === successor)){
this.openList.push(successor);
}
});
}
}
}
display(appearance, isInformationVisible, pathSmoothness){
super.display();
if (isInformationVisible){
if (appearance === 'Circles'){
let r = 0.5;
fill(200);
this.openList.forEach(n => {
ellipse(n.pos.x, n.pos.y, r * 2);
});
fill(100);
this.closedList.forEach(n => {
if (n === this.startNode)
return;
ellipse(n.pos.x, n.pos.y, r * 2);
});
}
if (appearance === 'Rectangles'){
fill(200);
this.openList.forEach(n => {
rect(n.pos.x - 0.5, n.pos.y - 0.5, 1, 1);
});
fill(100);
this.closedList.forEach(n => {
if (n === this.startNode)
return;
rect(n.pos.x - 0.5, n.pos.y - 0.5, 1, 1);
});
}
}
noFill();
stroke(50, 255, 50);
strokeWeight(0.2);
let node;
if (!this.openList.length){
node = this.closedList[this.closedList.length - 1];
} else {
node = this.openList[this.minFNodeIndex];
}
if (this.hasSucceeded){
node = this.targetNode;
}
if (node){
if (pathSmoothness){
beginShape();
vertex(node.pos.x, node.pos.y);
while (node.predecessor){
node = node.predecessor;
if (!node.predecessor){
quadraticVertex(node.pos.x, node.pos.y, node.pos.x, node.pos.y);
endShape();
} else {
let cx = (node.pos.x + node.predecessor.pos.x) / 2;
let cy = (node.pos.y + node.predecessor.pos.y) / 2;
quadraticVertex(node.pos.x, node.pos.y, cx, cy);
}
}
} else {
while (node.predecessor){
line(node.pos.x, node.pos.y, node.predecessor.pos.x, node.predecessor.pos.y);
node = node.predecessor;
}
}
}
}
}
class Dijkstra extends Algorithm{
constructor(){
super();
this.nodes = this.grid.allowedNodes.slice();
this.nodes.forEach(n => n.distance = Infinity);
this.startNode.distance = 0;
}
get minDistanceNodeIndex(){
let index = 0, distance = this.nodes[0].distance;
this.nodes.forEach((n, i) => {
if (n.distance < distance){
index = i;
distance = n.distance;
}
});
return index;
}
update(){
if (!this.running){
return;
}
super.update();
let index = this.minDistanceNodeIndex;
let currentNode = this.nodes[index];
this.nodes.splice(index, 1);
if (currentNode === this.targetNode){
this.success();
}
currentNode.successors.forEach(s => {
if (this.nodes.find(n => n === s)){
let alternativeDistance = currentNode.distance + currentNode.pos.dist(s.pos);
if (alternativeDistance < s.distance){
s.distance = alternativeDistance;
s.predecessor = currentNode;
}
}
})
}
display(appearance, isInformationVisible, pathSmoothness){
super.display();
if (isInformationVisible){
if (appearance === 'Circles'){
let r = 0.5;
fill(100);
this.nodes.forEach(n => {
if (n === this.startNode || n === this.targetNode)
return;
ellipse(n.pos.x, n.pos.y, r * 2);
});
}
if (appearance === 'Rectangles'){
fill(100);
this.nodes.forEach(n => {
if (n === this.startNode || n === this.targetNode)
return;
rect(n.pos.x - 0.5, n.pos.y - 0.5, 1, 1);
});
}
}
noFill();
stroke(50, 255, 50);
strokeWeight(0.2);
let node = this.nodes[this.minDistanceNodeIndex];
if (this.hasSucceeded){
node = this.targetNode;
}
if (node){
if (pathSmoothness){
beginShape();
vertex(node.pos.x, node.pos.y);
while (node.predecessor){
node = node.predecessor;
if (!node.predecessor){
quadraticVertex(node.pos.x, node.pos.y, node.pos.x, node.pos.y);
endShape();
} else {
let cx = (node.pos.x + node.predecessor.pos.x) / 2;
let cy = (node.pos.y + node.predecessor.pos.y) / 2;
quadraticVertex(node.pos.x, node.pos.y, cx, cy);
}
}
} else {
while (node.predecessor){
line(node.pos.x, node.pos.y, node.predecessor.pos.x, node.predecessor.pos.y);
node = node.predecessor;
}
}
}
}
}

@ -0,0 +1,29 @@
'use strict';
function keyPressed(){
}
function keyReleased(){
}
function mouseMoved(){
}
function mouseDragged(){
}
function mousePressed(){
}
function mouseReleased(){
}
function windowResized(){
resizeCanvas($('#canvas-holder').width(), $('#canvas-holder').height());
}

@ -0,0 +1,111 @@
class Game{
constructor(){
this.generateGrid();
this.updateVelocity();
this.updateDifficulty();
this.updateVisibilities();
}
generateGrid(){
this.algorithm = null;
let count = parseInt($('#cell_count').val());
let movement = $('#movement').val();
let difficulty = parseInt($('#difficulty').val());
let hasRandomDirection = $('#direction').is(':checked');
this.grid = new Grid(localSettings.app.grid, count, difficulty, hasRandomDirection);
$('#cell_count_text').text(count + 'x' + count + ' nodes');
//Two main nodes, start and target
if (hasRandomDirection){
this.startNode = random(this.grid.allowedNodes);
this.targetNode = random(this.grid.getAllowedNodesDistantTo(this.startNode)
.filter(n => {
if (movement === '1'){
return n.pos.x % 2 === this.startNode.pos.x % 2
&& n.pos.y % 2 === this.startNode.pos.y % 2;
}
return true;
})
);
} else {
this.startNode = this.grid.nodes[0][0];
this.targetNode = this.grid.nodes[count - 1][count - 1];
}
this.updateTester = 0;
}
update(){
if (this.algorithm){
this.updateTester += this.movesPerSecond / frameRate();
let i = 0;
for (; i < floor(this.updateTester); i++){
this.algorithm.update();
}
this.updateTester -= i;
}
}
display(){
this.grid.display(this.appearance, this.linesAreVisible);
if (this.appearance === 'Circles'){
let r = 0.5;
fill(50, 50, 255);
ellipse(this.startNode.pos.x, this.startNode.pos.y, r * 2);
fill(50, 255, 50);
ellipse(this.targetNode.pos.x, this.targetNode.pos.y, r * 2);
}
if (this.appearance === 'Rectangles'){
fill(50, 50, 255);
rect(this.startNode.pos.x - 0.5, this.startNode.pos.y - 0.5, 1, 1);
fill(50, 255, 50);
rect(this.targetNode.pos.x - 0.5, this.targetNode.pos.y - 0.5, 1, 1);
}
if (this.algorithm)
this.algorithm.display(this.appearance, this.isInformationVisible, this.pathSmoothness);
}
start(algorithm){
this.algorithm = algorithm;
let movement = $('#movement').val();
this.grid.nodes.forEach(x => x.forEach(n => {
n.setMovement(movement);
n.connectToSuccessors(this.grid.nodes);
}));
}
updateVelocity(){
let value = parseInt($('#velocity').val());
$('#velocity_text').text(value + ' moves per second');
this.movesPerSecond = value;
}
updateDifficulty(){
let value = parseInt($('#difficulty').val());
$('#difficulty_text').text('Difficulty: ' + value);
this.generateGrid();
}
updateVisibilities(){
let appearance = $('input[name=appearance]:checked').val();
let displayGrid = $('#gridVisibility').is(':checked');
let displayInformation = $('#information').is(':checked');
let pathSmoothness = $('#pathSmoothness').is(':checked');
if (!appearance)
appearance = $('input[name=appearance]:eq(0)').val();
this.appearance = appearance;
this.linesAreVisible = displayGrid;
this.isInformationVisible = displayInformation;
this.pathSmoothness = pathSmoothness;
}
}

@ -0,0 +1,160 @@
class Grid{
constructor(settings, cellCount, difficulty, randomDirection){
this.margin = settings.margin;
this.cellCount = createVector(cellCount, cellCount);
this.nodes = [];
for (let x = 0; x < this.cellCount.x; x++){
let column = [];
for (let y = 0; y < this.cellCount.y; y++){
let forbidden = ranBool(7 - difficulty);
if (!randomDirection){
let allowed = [
{x: 0, y: 0},
{x: 1, y: 0},
{x: 1, y: 1},
{x: 0, y: 1},
{x: this.cellCount.x - 1, y: this.cellCount.y - 1},
{x: this.cellCount.x - 1, y: this.cellCount.y - 2},
{x: this.cellCount.x - 2, y: this.cellCount.y - 2},
{x: this.cellCount.x - 2, y: this.cellCount.y - 1},
];
allowed.forEach(a => {
if (x === a.x && y === a.y){
forbidden = false;
}
});
}
column.push(new PathNode(x, y, forbidden));
}
this.nodes.push(column);
}
this.nodes.forEach(x => x.forEach(n => n.connectToSuccessors(this.nodes)));
let nodes = [];
this.nodes.forEach(x => nodes.push(...x.filter(n => n.isForbidden)));
this.forbiddenNodes = nodes;
nodes = [];
this.nodes.forEach(x => nodes.push(...x.filter(n => !n.isForbidden)));
this.allowedNodes = nodes;
}
get size(){
return Math.min(width - this.margin * 2, height - this.margin * 2);
}
get nodeSize(){
return {
x: this.size / this.cellCount.x,
y: this.size / this.cellCount.y
};
}
display(appearance, linesAreVisible){
translate(this.margin, this.margin);
if (linesAreVisible){
let size = this.size;
stroke(100);
strokeWeight(1);
for (let x = 0; x <= size + 1; x += size / this.cellCount.x){
line(x, 0, x, size);
}
for (let y = 0; y <= size + 1; y += size / this.cellCount.y){
line(0, y, size, y);
}
}
translate(this.nodeSize.x / 2, this.nodeSize.y / 2);
scale(this.nodeSize.x, this.nodeSize.y);
noStroke();
fill(200, 50, 50);
for (let n of this.forbiddenNodes){
let x = n.pos.x;
let y = n.pos.y;
if (appearance === 'Circles'){
let r = 0.5;
ellipse(x, y, r * 2);
}
if (appearance === 'Rectangles'){
rect(x - 0.5, y - 0.5, 1, 1);
}
}
}
getAllowedNodesDistantTo(otherNode){
return this.allowedNodes.filter(n => n.pos.dist(otherNode.pos) > Math.max(this.cellCount.x, this.cellCount.y) / 2);
}
}
class PathNode{
constructor(x, y, isForbidden){
this.pos = createVector(x, y);
this.isForbidden = isForbidden;
}
get distanceToTarget(){
return this.pos.dist(game.targetNode.pos);
}
setMovement(movement){
this.isDiagonalAllowed = false;
this.isStraightAllowed = false;
switch (movement){
case "0":
this.isStraightAllowed = true;
break;
case "1":
this.isDiagonalAllowed = true;
break;
case "2":
this.isStraightAllowed = true;
this.isDiagonalAllowed = true;
break;
}
}
connectToSuccessors(nodes){
let allowed = [], successors = [];
if (this.isStraightAllowed){
allowed.push(
{x: 1, y: 0},
{x: 0, y: 1},
{x: -1, y: 0},
{x: 0, y: -1}
);
}
if (this.isDiagonalAllowed){
allowed.push(
{x: 1, y: 1},
{x: 1, y: -1},
{x: -1, y: 1},
{x: -1, y: -1}
);
}
allowed.forEach(a => {
let column = nodes[this.pos.x + a.x];
if (column){
let node = column[this.pos.y + a.y];
if (node){
if (!node.isForbidden){
successors.push(node);
}
}
}
});
this.successors = successors;
}
}

@ -0,0 +1,87 @@
'use strict';
let debug = false,
font,
localSettings,
loader;
//Only for online games
let socket;
let antiCacheQuery = '?_=' + new Date().getTime();
let game;
function preload(){
localSettings = loadJSON('data/settings/settings.json' + antiCacheQuery, json => {
console.log('Local settings loaded: ', json);
}, error => {
console.log('Local settings failed: ', error);
});
font = loadFont('data/styles/font.ttf', json => {
console.log('Local font loaded: ', json);
}, error => {
console.log('Local font failed: ', error);
});
}
function setup(){
canvasSetup();
interfaceSetup();
loadDynamicScripts().then(() => game = new Game());
}
function draw(){
background(40);
if (game){
game.update();
game.display();
}
if (loader){
loader.update();
loader.display();
}
if (debug) debugInformation();
}
function canvasSetup(){
setFrameRate(60);
let w = $('#canvas-holder').width(),
h = $('#canvas-holder').height();
let canvas = createCanvas(w, h);
canvas.parent('canvas-holder');
textFont(font);
}
function interfaceSetup(){
$('#cell_count').attr({
'min': localSettings.app.grid.size.min,
'max': localSettings.app.grid.size.max
});
}
function loadDynamicScripts(){
return httpGet('data/settings/libraries.json' + antiCacheQuery, 'json')
.then(json => {
let requests = [];
for (let script in json){
if (json[script]){
let url = '/lib/benjocraeft/' + script + '.js'
requests.push($.getScript(url, () => {
console.log('Successfully loaded script: ', url)
}));
}
}
return $.when(...requests);
})
.then(() => {
console.log("All dynamic scripts have been loaded!");
});
}

@ -0,0 +1,10 @@
'use strict';
function socketConnect(project, name = "noone"){
let urlQueries = '?game=' + project.name + '&name=' + name;
let port = 3000;
let url = location.hostname + ":" + port + urlQueries;
socket = io.connect(url);
socket.on('connect', () => console.log('Connected to ', url));
}

@ -0,0 +1,8 @@
{
"collision": false,
"colorPicker": false,
"cookie": false,
"loader": false,
"prototypes": false,
"technical": true
}

@ -0,0 +1,32 @@
{
"project": {
"name": "pathfinder",
"author": "BenjoCraeft",
"version": "1.0.0",
"playerCounts": [],
"online": {
"iceServers": [
{"urls": "stun:stun.l.google.com:19302"},
{
"urls": "turn:numb.viagenie.ca",
"credential": "muazkh",
"username": "webrtc@live.com"
}
]
}
},
"frameWork": {
"frameRate": 60,
"width": null,
"height": null
},
"app": {
"grid": {
"margin": 50,
"size": {
"min": 20,
"max": 100
}
}
}
}

@ -0,0 +1,88 @@
#color_picker{
width: 300px;
height: 25%;
margin: 20px;
margin-top: 50px;
border: 5px solid #000;
background-color: #000;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
position: relative;
}
#color_picker_numeric{
width: 80%;
padding: 5%;
margin: 5%;
background-color: #888;
border-radius: 10px;
overflow: hidden;
}
.color_picker_rgb{
float: left;
width: 22%;
height: 35px;
font-size: 25px;
color: #000;
}
.color_picker_rgb:nth-child(1){
margin-right: 10%;
margin-left: 3%;
background-color: #F00;
}
.color_picker_rgb:nth-child(2){
background-color: #0F0;
}
.color_picker_rgb:nth-child(3){
margin-left: 10%;
background-color: #00F;
color: #FFF;
}
#color_picker_hex{
width: 50%;
height: 30px;
font-size: 25px;
margin: 10% 25% 0 25%;
}
#saturation{
position: relative;
width: calc(100% - 33px);
height: 100%;
background: linear-gradient(to right, #FFF 0%, #F00 100%);
float: left;
margin-right: 6px;
}
#value {
width: 100%;
height: 100%;
background: linear-gradient(to top, #000 0%, rgba(255,255,255,0) 100%);
}
#sb_picker{
border: 2px solid;
border-color: #FFF;
position: absolute;
width: 14px;
height: 14px;
border-radius: 10px;
bottom: 50px;
left: 50px;
box-sizing: border-box;
z-index: 10;
}
#hue {
width: 27px;
height: 100%;
position: relative;
float: left;
background: linear-gradient(to bottom, #F00 0%, #F0F 17%, #00F 34%, #0FF 50%, #0F0 67%, #FF0 84%, #F00 100%);
}
#hue_picker {
position: absolute;
background: #000;
border-bottom: 1px solid #000;
top: 0;
width: 27px;
height: 2px;
}

Binary file not shown.

@ -0,0 +1,88 @@
input[type=range] {
-webkit-appearance: none;
margin: 18px 0;
width: 100%;
background: none;
}
input[type=range]:focus {
outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 8.4px;
cursor: pointer;
animate: 0.2s;
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
background: #3071a9;
border-radius: 1.3px;
border: 0.2px solid #010101;
}
input[type=range]::-webkit-slider-thumb {
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
border: 1px solid #000000;
height: 36px;
width: 16px;
border-radius: 3px;
background: #ffffff;
cursor: pointer;
-webkit-appearance: none;
margin-top: -14px;
}
input[type=range]:focus::-webkit-slider-runnable-track {
background: #367ebd;
}
input[type=range]::-moz-range-track {
width: 100%;
height: 8.4px;
cursor: pointer;
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
background: #3071a9;
border-radius: 1.3px;
border: 0.2px solid #010101;
}
input[type=range]::-moz-range-thumb {
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
border: 1px solid #000000;
height: 36px;
width: 16px;
border-radius: 3px;
background: #302a86;
cursor: pointer;
}
input[type=range]::-ms-track {
width: 100%;
height: 8.4px;
cursor: pointer;
animate: 0.2s;
background: transparent;
border-color: transparent;
border-width: 16px 0;
color: transparent;
}
input[type=range]::-ms-fill-lower {
background: #2a6495;
border: 0.2px solid #010101;
border-radius: 2.6px;
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
}
input[type=range]::-ms-fill-upper {
background: #3071a9;
border: 0.2px solid #010101;
border-radius: 2.6px;
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
}
input[type=range]::-ms-thumb {
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
border: 1px solid #000000;
height: 36px;
width: 16px;
border-radius: 3px;
background: #ffffff;
cursor: pointer;
}
input[type=range]:focus::-ms-fill-lower {
background: #3071a9;
}
input[type=range]:focus::-ms-fill-upper {
background: #367ebd;
}

@ -0,0 +1,66 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="https://code.jquery.com/jquery-3.6.4.min.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js" type="text/javascript"></script>
<script src="data/scripts/init.js" type="text/javascript"></script>
<script src="data/scripts/events.js" type="text/javascript"></script>
<script src="data/scripts/online.js" type="text/javascript"></script>
<script src="data/scripts/game.js" type="text/javascript"></script>
<script src="data/scripts/algorithm.js" type="text/javascript"></script>
<script src="data/scripts/grid.js" type="text/javascript"></script>
<link href="styles.css" rel="stylesheet">
<link href="data/styles/color_picker.css" rel="stylesheet">
<link href="data/styles/range_input.css" rel="stylesheet">
<title>Pathfinding Algorithms</title>
</head>
<body>
<div id="p5_loading"></div>
<div id="content">
<div id="canvas-holder"></div>
<div id="interface">
<form onchange="game.updateVisibilities();">
<label for="circles">Circles</label>
<input id="circles" name="appearance" type="radio" value="Circles">
<br>
<label for="rectangles">Rectangles</label>
<input id="rectangles" name="appearance" type="radio" value="Rectangles">
</form>
<div onchange="game.updateVisibilities();">
<label for="pathSmoothness">Smooth path: </label>
<input id="pathSmoothness" type="checkbox">
</div>
<div onchange="game.updateVisibilities();">
<label for="gridVisibility">Grid: </label>
<input id="gridVisibility" type="checkbox">
</div>
<div onchange="game.updateVisibilities();">
<label for="information">Additional information: </label>
<input id="information" type="checkbox">
</div>
<div onchange="game.generateGrid();">
<label for="direction">Random direction: </label>
<input id="direction" type="checkbox">
</div>
<select id="movement">
<option value="0">Only Straight</option>
<option value="1">Only Diagonal</option>
<option value="2">Straight and Diagonal</option>
</select>
<input id="difficulty" max="5" min="1" oninput="game.updateDifficulty()" type="range">
<span id="difficulty_text"></span>
<input id="velocity" max="60" min="1" oninput="game.updateVelocity()" type="range">
<span id="velocity_text"></span>
<input id="cell_count" onchange="game.generateGrid();" type="range">
<span id="cell_count_text"></span>
<select id="algorithm_type">
<option value="astar">A* Algorithm</option>
<option value="dijkstra">Dijkstra Algorithm</option>
</select>
<button onclick="startAlgorithm();">Start</button>
<button onclick="game.generateGrid();">Generate</button>
</div>
</div>
</body>
</html>

@ -0,0 +1,85 @@
a:link, a:hover, a:active, a:visited{color: #000;}
html, body{margin: 0; padding: 0; height: 100%; width: 100%;}
canvas{margin: 0; padding: 0; border: none; display: block;}
button:hover{cursor: pointer;}
@font-face{
font-family: "Rametto";
src: url("data/styles/font.ttf");
}
*{
font-family: "Rametto", serif;
color: #000;
font-size: 17px;
}
:root{
--width: 100vw;
--height: 100vh;
}
/**
* Standard styles
*/
#canvas-holder{
position: relative;
width: 100vh;
height: 100vh;
float: left;
}
#canvas-holder canvas{
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: inherit;
}
#p5_loading{
display: none;
}
/**
* Interface
*/
#interface{
width: calc(100% - 100vh);
height: 80vh;
padding: 10vh 0;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
float: left;
background-color: rgb(40, 40, 40);
}
#interface > *{
margin: 10px;
width: 300px;
text-align: center;
}
span, label, select{
color: rgb(0, 0, 0);
}
button{
background-color: rgb(50, 200, 50);
border: 2px solid #000;
}
button:hover{
background-color: rgb(20, 100, 20);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Loading…
Cancel
Save