rewritten to use position based dynamics

main
Benjamin Kraft 1 year ago
parent c6a43ca622
commit b7491fa07f
  1. BIN
      public/data/images/favicon.ico
  2. 1
      public/data/images/pause.svg
  3. 1
      public/data/images/play.svg
  4. 1
      public/data/images/refresh.svg
  5. 34
      public/data/scripts/ts/init.ts
  6. 49
      public/data/scripts/ts/manager.ts
  7. 132
      public/data/scripts/ts/pendulum.ts
  8. 38
      public/data/scripts/ts/vector.ts
  9. 7
      public/data/settings/libraries.json
  10. 23
      public/data/settings/settings.json
  11. 51
      public/index.html
  12. 375
      public/package-lock.json
  13. 3
      public/package.json
  14. 44
      public/styles.css

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 B

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M531.616-226.463v-507.074h201.921v507.074H531.616Zm-305.153 0v-507.074h201.921v507.074H226.463Zm361.113-55.96h90.001v-395.154h-90.001v395.154Zm-305.153 0h90.001v-395.154h-90.001v395.154Zm0-395.154v395.154-395.154Zm305.153 0v395.154-395.154Z"/></svg>

After

Width:  |  Height:  |  Size: 346 B

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M345.655-245.041v-469.918L714.19-480 345.655-245.041ZM401.615-480Zm0 132.385L609.962-480 401.615-612.385v264.77Z"/></svg>

After

Width:  |  Height:  |  Size: 218 B

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M482.013-187.271q-123.018 0-208.265-85.065-85.247-85.066-85.247-207.634 0-122.568 85.247-207.664 85.247-85.095 208.291-85.095 69.654 0 131.461 31.038 61.808 31.039 102.231 88.193v-119.231h55.96v235.728H535.963v-55.96h153.96q-31.34-57.649-86.798-90.729-55.459-33.079-121.047-33.079-98.924 0-168.27 69.156t-69.346 167.731q0 98.574 69.221 167.613 69.221 69.038 168.29 69.038 75.906 0 137.024-43.192 61.119-43.192 85.883-114.385h59.119q-26.423 95.307-104.688 154.422-78.266 59.115-177.298 59.115Z"/></svg>

After

Width:  |  Height:  |  Size: 598 B

@ -1,23 +1,15 @@
'use strict';
let debug = false,
font: any,
settings: any;
let socket: any;
font: any;
let antiCacheQuery = '?_=' + new Date().getTime();
let manager;
let manager: Manager;
const p = new p5((p: p5) => {
p.preload = () => {
settings = p.loadJSON('data/settings/settings.json' + antiCacheQuery, {}, 'json', (json: any) => {
console.log('Local settings loaded: ', json);
}, (error: any) => {
console.log('Local settings failed: ', error);
});
font = p.loadFont('data/styles/fonts/Tajawal/Tajawal-Regular.ttf' + antiCacheQuery, (font: any) => {
console.log('Local font loaded: ', font);
@ -27,13 +19,11 @@ const p = new p5((p: p5) => {
}
p.setup = () => {
interfaceSetup();
canvasSetup();
eventsSetup();
loadDynamicScripts().then(() => {
//Load other stuff
manager = new Manager();
});
manager.init();
interfaceSetup();
}
p.draw = () => {
@ -52,7 +42,6 @@ function debugInformation(){
}
function interfaceSetup(){
}
@ -66,18 +55,3 @@ function canvasSetup(){
canvas.parent('canvas_holder');
p.textFont(font);
}
async function loadDynamicScripts(){
const json = await p.httpGet('data/settings/libraries.json' + antiCacheQuery, 'json') as Object;
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);
}));
}
}
await $.when(...requests);
console.log('All dynamic scripts have been loaded!');
}

@ -1,31 +1,66 @@
class Manager {
nPendula: NPendulum[] = []
pendulums: Pendulum[] = []
h = 0.07
timescale = 1;
gravity = 9.81;
playing = false;
constructor() {
p.colorMode(p.HSB, 100);
let count = 500;
let count = 100;
for (let i = 0; i < count; i++){
let rad = i / count / 1e3 + p.PI * 1.05;
let hue = i / count * 100;
let color = p.color(hue, 100, 100);
this.nPendula.push(
new NPendulum([200, 200], [2, 2], rad, color)
this.pendulums.push(
new Pendulum([1, 1, 1, 1, 1, 1, 1, 1], [50, 50, 50, 50, 50, 50, 50, 100 + i / count / 1000000], color)
);
}
p.colorMode(p.RGB);
}
init(){
// @ts-ignore
const {createApp} = Vue;
createApp({
data() {
return {
gravity: manager.gravity,
timescale: manager.timescale,
playingBtn: "play"
};
},
watch: {
gravity(newGravity: string) {
manager.gravity = parseFloat(newGravity);
},
timescale(newScale: string){
manager.timescale = parseFloat(newScale);
}
},
methods: {
togglePlay(){
manager.playing = !manager.playing;
this.playingBtn = manager.playing ? "pause" : "play";
}
}
}).mount("#simulation");
}
update(){
this.nPendula.forEach(p => p.update(this.h));
if (this.playing) {
const h = this.timescale / (p.frameRate() || 60);
this.pendulums.forEach(p => p.update(h));
}
}
draw(){
p.push()
p.translate(p.width / 2, p.height / 2);
this.nPendula.forEach(p => p.draw());
this.pendulums.forEach(p => p.draw());
p.pop();
}

@ -1,100 +1,88 @@
const g = 9.81
class NPendulum {
pendula: Pendulum[] = []
constructor(lengths, masses, startRad, color) {
switch (lengths.length) {
case 1:
this.pendula.push(new Pendulum(lengths[0], masses[0], startRad, color));
break;
case 2:
let p1 = new Pendulum(lengths[0], masses[0], startRad, color);
let p2 = new Pendulum(lengths[1], masses[1], startRad, color);
p1.calcAcc = function(pendula){
let p2 = pendula[1];
return -g / this.l * p.sin(this.rad) - p2.l * p2.m / this.l / (this.m + p2.m)
* (p.cos(this.rad - p2.rad) * p2.acc + p.sin(this.rad - p2.rad) * p.pow(p2.vel, 2));
}
p2.calcAcc = function (pendula){
let p1 = pendula[0];
return -g / this.l * p.sin(this.rad) - p1.l / this.l
* (p.cos(p1.rad - this.rad) * p1.acc - p.sin(p1.rad - this.rad) * p.pow(p1.vel, 2));
}
this.pendula.push(p1, p2);
break;
}
this.pendula[0].origin = p.createVector(0, 0);
}
class Pendulum {
updateOrigins(){
this.pendula.forEach((p, i) => {
if (i > 0){
let before = this.pendula[i - 1];
p.origin = p5.Vector.add(before.origin, before.pos);
X: Vector[] = [];
V: Vector[] = [];
size: number;
constructor(readonly M: number[], readonly L: number[], readonly color: p5.Color) {
console.assert(M.length === L.length, M, L, "Masses and Lengths are not of equal length!");
this.size = M.length;
let currentPosition = new Vector(0, 0);
for (let i = 0; i < this.size; i++){
let a = Math.sqrt(L[i] * L[i] / 2);
currentPosition.addC(-L[i], 0);
this.X.push(currentPosition.copy());
this.V.push(new Vector(0, 0));
}
});
}
update(h){
this.pendula.forEach((p, i) => {
p.update(h, this.pendula);
});
this.updateOrigins();
}
// using position based dynamics
update(h: number) {
const subSteps = 50;
draw(){
this.pendula.forEach(p => p.draw());
}
h /= subSteps;
}
for (let k = 0; k < subSteps; k++) {
let previousP = new Vector(0, 0);
class Pendulum {
for (let i = 0; i < this.size; i++) {
// apply external force (gravity)
this.V[i].addC(0, manager.gravity * h * 50);
l: number
m: number
// euler step
let currentP = Vector.Add(this.X[i],Vector.Mult(this.V[i], h));
acc: number = 0
vel: number = 0
rad: number
// solve distance constraint
let w1 = i === 0 ? 0 : 1 / this.M[i - 1];
let w2 = 1 / this.M[i];
origin: p5.Vector
let s = Vector.Sub(previousP, currentP);
let n = s.copy();
n.normalize();
let l = s.mag();
color: p5.Color
let deltaP1 = Vector.Mult(n, -w1 / (w1 + w2) * (l - this.L[i]));
let deltaP2 = Vector.Mult(n, w2 / (w1 + w2) * (l - this.L[i]));
previousP.add(deltaP1);
currentP.add(deltaP2);
constructor(l, m, rad, color) {
this.l = l;
this.m = m;
this.rad = rad;
this.color = color;
// integrate
if (i > 0){
this.V[i - 1] = Vector.Mult(Vector.Sub(previousP, this.X[i - 1]), 1 / h);
this.X[i - 1] = previousP;
}
calcAcc(pendula){
return -g / this.l * p.sin(this.rad);
previousP = currentP;
}
update(h, pendula = []){
this.acc = this.calcAcc(pendula);
this.vel += this.acc * h;
this.rad += this.vel * h;
this.V[this.size - 1] = Vector.Mult(Vector.Sub(previousP, this.X[this.size - 1]), 1 / h);
this.X[this.size - 1] = previousP;
}
}
draw(){
let pos = this.pos;
p.push();
p.translate(this.origin);
p.stroke(this.color);
p.strokeWeight(3);
p.line(0, 0, pos.x, pos.y);
p.ellipse(pos.x, pos.y, this.m * 5, this.m * 5);
p.pop();
p.strokeWeight(2);
p.fill(255);
let p1 = new Vector(0, 0);
for (let p2 of this.X){
p.line(p1.x, p1.y, p2.x, p2.y);
p1 = p2.copy();
}
get pos(){
return p5.Vector.mult(p.createVector(p.sin(this.rad), p.cos(this.rad)), this.l);
for (let p2 of this.X){
p.ellipse(p2.x, p2.y, 10, 10);
}
p.pop();
}
}

@ -0,0 +1,38 @@
class Vector {
constructor(public x: number, public y: number) {}
copy(){
return new Vector(this.x, this.y);
}
static Add(v1: Vector, v2: Vector){
return new Vector(v1.x + v2.x, v1.y + v2.y);
}
static Sub(v1: Vector, v2: Vector){
return new Vector(v1.x - v2.x, v1.y - v2.y);
}
static Mult(v: Vector, n: number){
return new Vector(v.x * n, v.y * n);
}
add(v: Vector){
this.x += v.x;
this.y += v.y;
}
addC(x: number, y: number){
this.x += x;
this.y += y;
}
mult(n: number){
this.x *= n;
this.y *= n;
}
mag(){
return Math.sqrt(this.x * this.x + this.y * this.y);
}
normalize(){
this.mult(1 / this.mag());
}
}

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

@ -1,23 +0,0 @@
{
"project": {
"name": "pendulum",
"author": "BenjoCraeft",
"version": "0.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
}
}

@ -4,6 +4,7 @@
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js" type="text/javascript"></script>
<script src="https://code.jquery.com/jquery-3.6.4.min.js" type="text/javascript"></script>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="data/scripts/js/main.js" type="text/javascript"></script>
<link href="styles.css" rel="stylesheet">
<link href="data/styles/color_picker.css" rel="stylesheet">
@ -13,47 +14,23 @@
<body>
<div id="p5_loading"></div>
<div id="content">
<div id="options" style="display: none">
<div id="options">
<fieldset id="preparation">
<legend>Preparation</legend>
</fieldset>
<fieldset id="simulation">
<legend>Simulation</legend>
<label>
<input type="radio" name="type">
Single pendulum
Gravity: {{ gravity }} <sup>N</sup>&frasl;<sub>kg</sub>
<input type="range" v-model="gravity" min="0" max="30" step=".01" autocomplete="off">
</label>
<br>
<label>
<input type="radio" name="type" checked>
Double pendulum
Timescale: x{{ timescale }}
<input type="range" v-model="timescale" min="0.01" max="3" step=".01" autocomplete="off">
</label>
<br>
<label>
Count:
<input type="number" min="1" max="500" value="1">
</label>
<br>
<label>
L1:
<input type="range" min="50" max="400" value="200">
<span>200</span>
</label>
<br>
<label>
L2:
<input type="range" min="50" max="400" value="200">
<span>200</span>
</label>
<br>
<label>
M1:
<input type="range" min="1" max="10" value="1">
<span>1</span>
</label>
<br>
<label>
M2:
<input type="range" min="1" max="10" value="1">
<span>1</span>
</label>
<br>
<input type="button" value="Add">
<button @click="togglePlay" id="play_btn" :class="playingBtn"></button>
</fieldset>
</div>
<div id="canvas_holder"></div>
</div>

@ -7,11 +7,30 @@
"": {
"name": "pendulum",
"version": "1.0.0",
"dependencies": {
"vue": "^3.3.4"
},
"devDependencies": {
"@types/jquery": "^3.5.16",
"typescript": "^5.0.2"
}
},
"node_modules/@babel/parser": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.15.tgz",
"integrity": "sha512-RWmQ/sklUN9BvGGpCDgSubhHWfAx24XDTDObup4ffvxaYsptOg2P3KG0j+1eWKLxpkX0j0uHxmpq2Z1SP/VhxA==",
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"node_modules/@types/jquery": {
"version": "3.5.16",
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz",
@ -27,6 +46,186 @@
"integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
"dev": true
},
"node_modules/@vue/compiler-core": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz",
"integrity": "sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==",
"dependencies": {
"@babel/parser": "^7.21.3",
"@vue/shared": "3.3.4",
"estree-walker": "^2.0.2",
"source-map-js": "^1.0.2"
}
},
"node_modules/@vue/compiler-dom": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz",
"integrity": "sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==",
"dependencies": {
"@vue/compiler-core": "3.3.4",
"@vue/shared": "3.3.4"
}
},
"node_modules/@vue/compiler-sfc": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz",
"integrity": "sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==",
"dependencies": {
"@babel/parser": "^7.20.15",
"@vue/compiler-core": "3.3.4",
"@vue/compiler-dom": "3.3.4",
"@vue/compiler-ssr": "3.3.4",
"@vue/reactivity-transform": "3.3.4",
"@vue/shared": "3.3.4",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.0",
"postcss": "^8.1.10",
"source-map-js": "^1.0.2"
}
},
"node_modules/@vue/compiler-ssr": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz",
"integrity": "sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==",
"dependencies": {
"@vue/compiler-dom": "3.3.4",
"@vue/shared": "3.3.4"
}
},
"node_modules/@vue/reactivity": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz",
"integrity": "sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==",
"dependencies": {
"@vue/shared": "3.3.4"
}
},
"node_modules/@vue/reactivity-transform": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz",
"integrity": "sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==",
"dependencies": {
"@babel/parser": "^7.20.15",
"@vue/compiler-core": "3.3.4",
"@vue/shared": "3.3.4",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.0"
}
},
"node_modules/@vue/runtime-core": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.4.tgz",
"integrity": "sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==",
"dependencies": {
"@vue/reactivity": "3.3.4",
"@vue/shared": "3.3.4"
}
},
"node_modules/@vue/runtime-dom": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.4.tgz",
"integrity": "sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==",
"dependencies": {
"@vue/runtime-core": "3.3.4",
"@vue/shared": "3.3.4",
"csstype": "^3.1.1"
}
},
"node_modules/@vue/server-renderer": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.4.tgz",
"integrity": "sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==",
"dependencies": {
"@vue/compiler-ssr": "3.3.4",
"@vue/shared": "3.3.4"
},
"peerDependencies": {
"vue": "3.3.4"
}
},
"node_modules/@vue/shared": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz",
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
},
"node_modules/csstype": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
},
"node_modules/magic-string": {
"version": "0.30.3",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.3.tgz",
"integrity": "sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
},
"engines": {
"node": ">=12"
}
},
"node_modules/nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"node_modules/postcss": {
"version": "8.4.29",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz",
"integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/typescript": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz",
@ -39,9 +238,31 @@
"engines": {
"node": ">=12.20"
}
},
"node_modules/vue": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz",
"integrity": "sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==",
"dependencies": {
"@vue/compiler-dom": "3.3.4",
"@vue/compiler-sfc": "3.3.4",
"@vue/runtime-dom": "3.3.4",
"@vue/server-renderer": "3.3.4",
"@vue/shared": "3.3.4"
}
}
},
"dependencies": {
"@babel/parser": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.15.tgz",
"integrity": "sha512-RWmQ/sklUN9BvGGpCDgSubhHWfAx24XDTDObup4ffvxaYsptOg2P3KG0j+1eWKLxpkX0j0uHxmpq2Z1SP/VhxA=="
},
"@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"@types/jquery": {
"version": "3.5.16",
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz",
@ -57,11 +278,165 @@
"integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
"dev": true
},
"@vue/compiler-core": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz",
"integrity": "sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==",
"requires": {
"@babel/parser": "^7.21.3",
"@vue/shared": "3.3.4",
"estree-walker": "^2.0.2",
"source-map-js": "^1.0.2"
}
},
"@vue/compiler-dom": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz",
"integrity": "sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==",
"requires": {
"@vue/compiler-core": "3.3.4",
"@vue/shared": "3.3.4"
}
},
"@vue/compiler-sfc": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz",
"integrity": "sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==",
"requires": {
"@babel/parser": "^7.20.15",
"@vue/compiler-core": "3.3.4",
"@vue/compiler-dom": "3.3.4",
"@vue/compiler-ssr": "3.3.4",
"@vue/reactivity-transform": "3.3.4",
"@vue/shared": "3.3.4",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.0",
"postcss": "^8.1.10",
"source-map-js": "^1.0.2"
}
},
"@vue/compiler-ssr": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz",
"integrity": "sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==",
"requires": {
"@vue/compiler-dom": "3.3.4",
"@vue/shared": "3.3.4"
}
},
"@vue/reactivity": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz",
"integrity": "sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==",
"requires": {
"@vue/shared": "3.3.4"
}
},
"@vue/reactivity-transform": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz",
"integrity": "sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==",
"requires": {
"@babel/parser": "^7.20.15",
"@vue/compiler-core": "3.3.4",
"@vue/shared": "3.3.4",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.0"
}
},
"@vue/runtime-core": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.4.tgz",
"integrity": "sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==",
"requires": {
"@vue/reactivity": "3.3.4",
"@vue/shared": "3.3.4"
}
},
"@vue/runtime-dom": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.4.tgz",
"integrity": "sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==",
"requires": {
"@vue/runtime-core": "3.3.4",
"@vue/shared": "3.3.4",
"csstype": "^3.1.1"
}
},
"@vue/server-renderer": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.4.tgz",
"integrity": "sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==",
"requires": {
"@vue/compiler-ssr": "3.3.4",
"@vue/shared": "3.3.4"
}
},
"@vue/shared": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz",
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
},
"csstype": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
},
"estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
},
"magic-string": {
"version": "0.30.3",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.3.tgz",
"integrity": "sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==",
"requires": {
"@jridgewell/sourcemap-codec": "^1.4.15"
}
},
"nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA=="
},
"picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"postcss": {
"version": "8.4.29",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz",
"integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==",
"requires": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
}
},
"source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
},
"typescript": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz",
"integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==",
"dev": true
},
"vue": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz",
"integrity": "sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==",
"requires": {
"@vue/compiler-dom": "3.3.4",
"@vue/compiler-sfc": "3.3.4",
"@vue/runtime-dom": "3.3.4",
"@vue/server-renderer": "3.3.4",
"@vue/shared": "3.3.4"
}
}
}
}

@ -4,5 +4,8 @@
"devDependencies": {
"@types/jquery": "^3.5.16",
"typescript": "^5.0.2"
},
"dependencies": {
"vue": "^3.3.4"
}
}

@ -24,10 +24,14 @@ button:hover{cursor: pointer;}
:root{
--width: 100vw;
--height: 100vh;
--opt-width: 400px;
--opt-padding: 10px;
--opt-border: 5px;
--canvas-width: calc(100vw - (var(--opt-width) + var(--opt-padding) * 2 + var(--opt-border)))
}
body {
overflow: hidden;
overflow: auto;
}
/**
@ -36,7 +40,7 @@ body {
#canvas_holder{
position: relative;
width: calc(var(--width)); /* -325px);*/
width: var(--canvas-width);
height: var(--height);
float: left;
}
@ -55,18 +59,46 @@ body {
#options {
float: left;
width: 300px;
height: 100vh;
padding: 10px;
border-right: 5px solid rgb(150, 150, 150);
width: var(--opt-width);
height: calc(100vh - var(--opt-padding) * 2);
padding: var(--opt-padding);
border-right: var(--opt-border) solid rgb(150, 150, 150);
background-color: rgb(40, 40, 40);
}
#options *:not(input[type=number], input[type=button]){
color: white;
}
fieldset {
border-radius: 5px;
}
input {
margin: 5px;
}
input[type=button]{
border: 3px solid #0060df;
border-radius: 5px;
line-height: 30px;
font-size: 30px;
}
#play_btn {
width: 100%;
border: 4px solid cornflowerblue;
border-radius: 5px;
height: 50px;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
#play_btn.play {
background-image: url("data/images/play.svg");
}
#play_btn.pause {
background-image: url("data/images/pause.svg");
}

Loading…
Cancel
Save