Working demo

Down on you knees!
This commit is contained in:
Victor Westerlund 2021-01-26 05:47:26 +01:00
parent 3501d1b0fa
commit fa0c46d5c7
8 changed files with 144 additions and 51 deletions

View file

@ -4,7 +4,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/style.css"> <link rel="stylesheet" href="css/style.css">
<title>Cathode Ray</title> <title>CRT</title>
<style> <style>
:root { :root {
/* Screen */ /* Screen */

View file

@ -1,7 +1,43 @@
import { FluorescentScreen } from "./modules/Screen.mjs"; import { FluorescentScreen } from "./modules/Screen.mjs";
import { RasterScan } from "./modules/Gun.mjs"; import { RasterScan } from "./modules/ElectronGun.mjs";
const screen = new FluorescentScreen(document.getElementById("screen")); class CRT {
const CRT = new RasterScan(screen.pixels); constructor(element) {
CRT.load("../../tapes/sample"); this.element = element;
this.initScreen();
this.raster = new RasterScan(this.screen.pixels);
}
async fetchJSON(url) {
const response = await fetch(url);
return response.json();
}
loadTape(ref) {
this.fetchJSON(ref + "/header.json").then(headers => {
// Reinitialize player with resolution from tape header
if(headers.resolution[0] !== this.element.clientWidth || headers.resolution[1] !== this.element.clientHeight) {
this.element.style.setProperty("width",headers.resolution[0] + "px");
this.element.style.setProperty("height",headers.resolution[1] + "px");
this.initScreen();
this.raster.pixels = this.screen.pixels;
}
this.raster.load(headers);
});
}
play() {
this.raster.playstate("play");
}
initScreen() {
this.screen = new FluorescentScreen(this.element);
}
}
window.video = new CRT(document.getElementById("screen"));
window.video.loadTape("tapes/sample");
window.video.play();

View file

@ -0,0 +1,31 @@
export class RasterScan {
constructor(pixels) {
this.pixels = pixels;
this.signal = new Worker("./js/modules/Raster.mjs");
this.signal.addEventListener("message",event => {
this.fire(event.data);
});
}
fire(pixel) {
this.pixels[pixel.index].style.setProperty("background",pixel.color);
//this.pixels[data.pixel].style.setProperty("animation",`decay 10ms ${data.pixel} linear forwards`);
}
load(headers) {
this.signal.postMessage({
type: "headers",
payload: headers
});
}
playstate(state) {
this.signal.postMessage({
type: "playstate",
payload: state
});
}
}

View file

@ -1,24 +0,0 @@
export class RasterScan {
constructor(pixels) {
this.pixels = pixels;
this.coils = new Worker("./js/modules/Raster.mjs");
this.coils.addEventListener("message",event => {
this.fire(event.data);
});
}
fire(data) {
this.pixels[data.pixel].style.setProperty("background",data.color);
this.pixels[data.pixel].style.setProperty("animation",`decay 10ms ${data.pixel} linear forwards`);
}
load(tape) {
this.coils.postMessage({
density: this.pixels.length,
tape: tape
});
}
}

4
js/modules/Helper.mjs Normal file
View file

@ -0,0 +1,4 @@
export async function fetchJSON(url) {
const response = await fetch(url);
return response.json();
}

View file

@ -1,17 +1,16 @@
let field; let meta = {
let clock; fields: 0,
pixels: 0,
framerate: 100
};
let tape = { let clock = null;
header: (data) => {
clock = data.framerate;
this.format = format;
self.postMessage({ let tape = null;
type: "resolutionUpdate", let stream = (stream) => {
data: resolution meta.fields = Math.floor(stream.length / meta.pixels);
}); tape = stream;
}, return true;
stream: []
} }
async function fetchJSON(url) { async function fetchJSON(url) {
@ -19,11 +18,47 @@ async function fetchJSON(url) {
return response.json(); return response.json();
} }
function loadTape(ref) { function scan() {
fetchJSON(ref + "/header.json").then(data => tape.header(data)); let pixel = 0;
fetchJSON(ref + "/data.json").then(data => tape.stream = data);
for(let head = 0; head < tape.length; head++) {
if(pixel == meta.pixels) {
pixel = 0;
}
self.postMessage({
index: pixel,
color: tape[head]
});
pixel++;
}
}
function playstate(state) {
if(state == "play") {
clock = setInterval(scan,meta.framerate);
return;
}
clock = null;
} }
self.addEventListener("message",event => { self.addEventListener("message",event => {
loadTape(event.data.tape); const payload = event.data.payload;
switch(event.data.type) {
case "headers":
meta.pixels = payload.resolution[0] * payload.resolution[1];
meta.framerate = payload.framerate;
const segmentURL = new Array("../../tapes",payload.manifest,payload.segments[0]).join("/");
fetchJSON(segmentURL).then(tape => stream(tape));
break;
case "playstate":
playstate(payload);
break;
default: console.warn("Unknown instruction: " + event.data.type); break;
}
}); });

View file

@ -4,6 +4,7 @@ export class FluorescentScreen {
this.screen = screen; this.screen = screen;
this.pixels = []; this.pixels = [];
this.destroyPixels();
this.spawnPixels(); this.spawnPixels();
} }
@ -26,4 +27,10 @@ export class FluorescentScreen {
this.createMatrix(); this.createMatrix();
} }
destroyPixels() {
while(this.screen.firstChild) {
this.screen.removeChild(this.screen.lastChild);
}
}
} }

View file

@ -1,5 +1,9 @@
{ {
"manifest": "sample",
"format": "signed-hex", "format": "signed-hex",
"resolution": ["64","64"], "resolution": ["32","32"],
"framerate": 10 "framerate": 100,
"segments": [
"data.json"
]
} }