commit 2dfb26bf137b588705a7c07d958205651d607059 Author: Mal Date: Fri Jan 13 00:25:05 2023 +0100 Init diff --git a/public/graphics/icon-delete.svg b/public/graphics/icon-delete.svg new file mode 100644 index 0000000..cfcde20 --- /dev/null +++ b/public/graphics/icon-delete.svg @@ -0,0 +1,111 @@ + + + + diff --git a/public/graphics/icon-play.svg b/public/graphics/icon-play.svg new file mode 100644 index 0000000..e70f39d --- /dev/null +++ b/public/graphics/icon-play.svg @@ -0,0 +1,49 @@ + + + + + + + + + + diff --git a/public/graphics/icon-stop.svg b/public/graphics/icon-stop.svg new file mode 100644 index 0000000..cd07250 --- /dev/null +++ b/public/graphics/icon-stop.svg @@ -0,0 +1,51 @@ + + + + + + + + + + diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..d30097d --- /dev/null +++ b/public/index.html @@ -0,0 +1,163 @@ + + + + + LED Cube + + + + + + +
+
+ +
+
+ +
+
+ + + +
+
Frame: 1/1
+ +
+ + + + + +
+
+ + \ No newline at end of file diff --git a/public/index.js b/public/index.js new file mode 100644 index 0000000..ce0994c --- /dev/null +++ b/public/index.js @@ -0,0 +1,131 @@ +const Frame = function (duration) { + this.layers = []; + this.duration = duration; +} + +const FrameFactory = function (width, depth, height) { + this.width = width; + this.depth = depth; + this.height = height; + + this.getFrame = function (duration) { + const frame = new Frame(duration); + + for (let z = 0; z < this.height; z++) { + const layer = []; + + for (let led = 0; led < this.width * this.depth; led++) { + layer.push(false); + } + + frame.layers.push(layer); + } + + return frame; + } +} + +const Cube = function (width, depth, height) { + this.width = width; + this.depth = depth; + this.height = height; + this.html = document.getElementById('cube'); + this.frames = []; + this.currentFrame = 0; + + this.setup = function () { + this._setupHtml(); + } + + this.setCurrentFrame = function (frameIndex) { + this.currentFrame = frameIndex; + + this._loadFrame(frameIndex); + } + + this.switchLed = function (layerIndex, ledIndex) { + console.log(layerIndex); + this.frames[this.currentFrame].layers[layerIndex][ledIndex] = !this.frames[this.currentFrame].layers[layerIndex][ledIndex]; + } + + this.setLayer = function (layerIndex, state) { + for (let index = 0; index < this.width * this.depth; index++) { + this.frames[this.currentFrame].layers[layerIndex][index] = state; + } + + for (const row of this.html.children[this.height - layerIndex - 1].children) { + for (const led of row.children) { + this._setLed(led, state); + } + } + } + + this._loadFrame = function (frameIndex) { + for (let layer = 0; layer < this.frames[frameIndex].layers.length; layer++) { + for (let row = 0; row < this.depth; row++) { + for (let led = 0; led < this.width; led++) { + const state = this.frames[frameIndex].layers[layer][row * this.depth + led]; + + this._setLed(this.html.children[layer].children[row].children[led], state); + } + } + } + } + + this._setupHtml = function () { + for (let z = 0; z < this.height; z++) { + const layerElement = document.createElement('div'); + layerElement.classList.add('layer'); + + for (let y = 0; y < this.depth; y++) { + const row = document.createElement('div'); + row.classList.add('row'); + + for (let x = 0; x < this.width; x++) { + const led = document.createElement('div'); + led.classList.add('led', 'led-off'); + + led.addEventListener( + 'click', + (event) => { + const index = y * this.depth + x; + const layer = this.height - z - 1; + + this.switchLed(layer, index); + this._setLed(event.target, this.frames[this.currentFrame].layers[layer][index]); + } + ); + + row.appendChild(led); + } + + layerElement.appendChild(row); + } + + this.html.appendChild(layerElement); + } + } + + this._setLed = function (ledHtml, state) { + if (state) { + ledHtml.classList.remove('led-off'); + } else { + ledHtml.classList.add('led-off'); + } + } +} + +const WIDTH = 4; +const DEPTH = 4; +const HEIGHT = 4; + +const cube = new Cube(WIDTH, DEPTH, HEIGHT); +cube.setup(); + +console.log(cube.html.children); + +const frameFactory = new FrameFactory(WIDTH, DEPTH, HEIGHT); + +cube.frames.push(frameFactory.getFrame(100)); +cube.setCurrentFrame(0); +cube.setLayer(2, true); \ No newline at end of file diff --git a/public/style.css b/public/style.css new file mode 100644 index 0000000..24df7ab --- /dev/null +++ b/public/style.css @@ -0,0 +1,208 @@ +* { + box-sizing: border-box; +} + +html { + min-height: 100%; +} + +body { + width: 100%; + height: 100%; + padding: 0; + margin: 0; + background-color: black; + color: white; + font-family: sans-serif; +} + +input { + border: 2px solid white; + background-color: transparent; + color: white; + padding: 5px; + border-radius: 10px; + font-size: 16px; + outline: none; +} + +input[type=number] { + max-width: 100px; +} + +button { + background-color: #164cff; + border: none; + border-radius: 10px; + padding: 0 20px; + color: white; + font-weight: bold; + font-size: 16px; + cursor: pointer; + height: 32px; +} + +.suffix-ms::after { + content: "ms"; +} + +.icon-button { + background-color: transparent; + height: 32px; + background-position: center center; + background-repeat: no-repeat; + background-size: auto 32px; + border-radius: 0; +} + +.icon-button:hover { + background-color: transparent; +} + +.icon-button-play { + background-image: url("graphics/icon-play.svg"); +} + +.icon-button-stop { + background-image: url("graphics/icon-stop.svg"); +} + +.icon-button-delete { + background-image: url("graphics/icon-delete.svg"); +} + +button:hover { + background-color: #3765ff; +} + +#cube-window { + display: flex; + justify-content: center; + align-items: center; + background-color: black; +} + +#animation-window { + display: flex; + justify-content: center; + align-items: center; +} + +#frame-menu { + border: 2px solid white; + border-radius: 20px; + padding: 20px; + display: flex; + align-items: center; +} + +#frame-menu > * { + margin: 0 10px; +} + +#frame-display { + text-align: center; +} + +#frame-slider { + width: 250px; +} + +#cube { + display: block; + padding-bottom: 80px; +} + +.layer { + position: relative; + transform: scale(1.0, 0.4) rotate(-45deg); + margin-bottom: -40%; + border: 2px solid transparent; + border-radius: 20px; + background-color: black; +} + +.layer:hover { + border: 2px solid white; + border-radius: 20px; +} + +.layer-submenu { + position: absolute; + left: 67%; + bottom: -74px; + display: flex; + align-items: center; + transform: rotate(45deg) scale(1.0, 2.1); + visibility: hidden; + padding-left: 58px; +} + +.submenu-line { + border: 1px solid white; + width: 80px; +} + +.layer:hover .layer-submenu { + visibility: visible; +} + +.layer-buttons { + display: flex; + border: solid 2px white; + padding: 10px; + border-radius: 10px; +} + +.layer-button { + border-radius: 50%; + border: 2px solid white; + width: 32px; + height: 32px; + margin: 5px; + cursor: pointer; +} + +.layer-button-on { + background-color: red; +} + +.layer-button-off { + background-color: black; +} + +.led { + border-radius: 50%; + background-color: red; + width: 32px; + height: 48px; + margin: 8px 16px; + transform: rotate(45deg); + cursor: pointer; + box-shadow: 0 0 10px red; +} + +.led-off { + opacity: 0.25; + box-shadow: none; +} + +.led-previous { + opacity: 0.5; +} + +.led-red { + background-color: red; +} + +.led-blue { + background-color: #3333ff; +} + +.led-green { + background-color: #00ff00; +} + +.row { + display: flex; +} \ No newline at end of file