From b7491fa07f15d2b08d9a5ac87600c2ec407ad8be Mon Sep 17 00:00:00 2001 From: Benjamin Kraft Date: Tue, 5 Sep 2023 23:01:06 +0200 Subject: [PATCH] rewritten to use position based dynamics --- public/data/images/favicon.ico | Bin 318 -> 0 bytes public/data/images/pause.svg | 1 + public/data/images/play.svg | 1 + public/data/images/refresh.svg | 1 + public/data/scripts/ts/init.ts | 38 +-- public/data/scripts/ts/manager.ts | 49 +++- public/data/scripts/ts/pendulum.ts | 140 +++++------ public/data/scripts/ts/vector.ts | 38 +++ public/data/settings/libraries.json | 7 - public/data/settings/settings.json | 23 -- public/index.html | 59 ++--- public/package-lock.json | 375 ++++++++++++++++++++++++++++ public/package.json | 3 + public/styles.css | 44 +++- 14 files changed, 587 insertions(+), 192 deletions(-) delete mode 100644 public/data/images/favicon.ico create mode 100644 public/data/images/pause.svg create mode 100644 public/data/images/play.svg create mode 100644 public/data/images/refresh.svg create mode 100644 public/data/scripts/ts/vector.ts delete mode 100644 public/data/settings/libraries.json delete mode 100644 public/data/settings/settings.json diff --git a/public/data/images/favicon.ico b/public/data/images/favicon.ico deleted file mode 100644 index 3172667d2925fa58eae7e1b1767b3ef11fd8a37d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 318 zcmbtPISzm@408$tW3n(;o%&2Z!e96lGuRxJU_-b{+&XoX0LJ6)%sr|BBY?_qMrKGC zrX!z8wT5*7=B+({UrNd9k;oR|sc?pfNL0=7}mX3RI=dX}Q F-W`Jp3Z(!5 diff --git a/public/data/images/pause.svg b/public/data/images/pause.svg new file mode 100644 index 0000000..584a801 --- /dev/null +++ b/public/data/images/pause.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/data/images/play.svg b/public/data/images/play.svg new file mode 100644 index 0000000..da059ed --- /dev/null +++ b/public/data/images/play.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/data/images/refresh.svg b/public/data/images/refresh.svg new file mode 100644 index 0000000..dec3a89 --- /dev/null +++ b/public/data/images/refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/data/scripts/ts/init.ts b/public/data/scripts/ts/init.ts index bd7707d..5107847 100644 --- a/public/data/scripts/ts/init.ts +++ b/public/data/scripts/ts/init.ts @@ -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 = new Manager(); + manager.init(); + interfaceSetup(); } p.draw = () => { @@ -52,9 +42,8 @@ function debugInformation(){ } - function interfaceSetup(){ - + } function canvasSetup(){ @@ -65,19 +54,4 @@ function canvasSetup(){ let canvas = p.createCanvas(w, h); 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!'); } \ No newline at end of file diff --git a/public/data/scripts/ts/manager.ts b/public/data/scripts/ts/manager.ts index 683a8a1..012b94a 100644 --- a/public/data/scripts/ts/manager.ts +++ b/public/data/scripts/ts/manager.ts @@ -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(); } diff --git a/public/data/scripts/ts/pendulum.ts b/public/data/scripts/ts/pendulum.ts index b194e1e..5aeddbd 100644 --- a/public/data/scripts/ts/pendulum.ts +++ b/public/data/scripts/ts/pendulum.ts @@ -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[] = []; - update(h){ - this.pendula.forEach((p, i) => { - p.update(h, this.pendula); - }); - this.updateOrigins(); - } + size: number; - draw(){ - this.pendula.forEach(p => p.draw()); + 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)); + } } -} + // using position based dynamics + update(h: number) { + const subSteps = 50; + h /= subSteps; -class Pendulum { + for (let k = 0; k < subSteps; k++) { - l: number - m: number + let previousP = new Vector(0, 0); - acc: number = 0 - vel: number = 0 - rad: number + for (let i = 0; i < this.size; i++) { + // apply external force (gravity) + this.V[i].addC(0, manager.gravity * h * 50); - origin: p5.Vector + // euler step + let currentP = Vector.Add(this.X[i],Vector.Mult(this.V[i], h)); - color: p5.Color + // solve distance constraint + let w1 = i === 0 ? 0 : 1 / this.M[i - 1]; + let w2 = 1 / this.M[i]; + let s = Vector.Sub(previousP, currentP); + let n = s.copy(); + n.normalize(); + let l = s.mag(); - constructor(l, m, rad, color) { - this.l = l; - this.m = m; - this.rad = rad; - this.color = 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])); - calcAcc(pendula){ - return -g / this.l * p.sin(this.rad); - } + previousP.add(deltaP1); + currentP.add(deltaP2); + + // integrate + if (i > 0){ + this.V[i - 1] = Vector.Mult(Vector.Sub(previousP, this.X[i - 1]), 1 / h); + this.X[i - 1] = previousP; + } - update(h, pendula = []){ - this.acc = this.calcAcc(pendula); - this.vel += this.acc * h; - this.rad += this.vel * h; + previousP = currentP; + } + + 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(); } } \ No newline at end of file diff --git a/public/data/scripts/ts/vector.ts b/public/data/scripts/ts/vector.ts new file mode 100644 index 0000000..64b1d0c --- /dev/null +++ b/public/data/scripts/ts/vector.ts @@ -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()); + } +} \ No newline at end of file diff --git a/public/data/settings/libraries.json b/public/data/settings/libraries.json deleted file mode 100644 index 3e20604..0000000 --- a/public/data/settings/libraries.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "collision": false, - "colorPicker": false, - "cookie": false, - "prototypes": false, - "technical": false -} \ No newline at end of file diff --git a/public/data/settings/settings.json b/public/data/settings/settings.json deleted file mode 100644 index 84cbdc3..0000000 --- a/public/data/settings/settings.json +++ /dev/null @@ -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 - } -} \ No newline at end of file diff --git a/public/index.html b/public/index.html index a4e1fc1..d981ef9 100644 --- a/public/index.html +++ b/public/index.html @@ -4,6 +4,7 @@ + @@ -13,47 +14,23 @@
- diff --git a/public/package-lock.json b/public/package-lock.json index 2e1b558..8ef431f 100644 --- a/public/package-lock.json +++ b/public/package-lock.json @@ -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" + } } } } diff --git a/public/package.json b/public/package.json index cf290ea..d03baec 100644 --- a/public/package.json +++ b/public/package.json @@ -4,5 +4,8 @@ "devDependencies": { "@types/jquery": "^3.5.16", "typescript": "^5.0.2" + }, + "dependencies": { + "vue": "^3.3.4" } } diff --git a/public/styles.css b/public/styles.css index 6fbb4f5..1774aa5 100644 --- a/public/styles.css +++ b/public/styles.css @@ -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"); +} +