mirror of
https://codeberg.org/vlw/crtjs.git
synced 2025-09-13 18:03:40 +02:00
Working demo
Down on you knees!
This commit is contained in:
parent
3501d1b0fa
commit
fa0c46d5c7
8 changed files with 144 additions and 51 deletions
|
@ -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 */
|
||||||
|
|
44
js/main.js
44
js/main.js
|
@ -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();
|
||||||
|
|
31
js/modules/ElectronGun.mjs
Normal file
31
js/modules/ElectronGun.mjs
Normal 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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
4
js/modules/Helper.mjs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export async function fetchJSON(url) {
|
||||||
|
const response = await fetch(url);
|
||||||
|
return response.json();
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
});
|
});
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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"
|
||||||
|
]
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue