Semi-stable release (#1)

* dev21w41a

* Added Monkeydo submodule

Added Monkeydo to .gitmodules

* dev21w41b

* Added functional code before manifest and CSS

The JS-part of this demo is now functional to the point where a Monkeydo manifest can be played on the different windows. CSS styling and an actual manifest will still have to be created.

* Create README.md

* Cake

* Update README.md

* Unsynced working example

Everything is cued up and good to go. Now comes the fun part of syncing the lyrics with the song

* Synchronized lyrics with music

So, yeah this totally didn't take 6 hours to do.

* Style changes and log removal

Fixed the scroll direction for lyrics, made the art window's font clamp (and centered) and also removed some loggers.

player.html will redirect to the main page if opened without a hash and will no longer be caught by crawlers that care about robots.txt
This commit is contained in:
Victor Westerlund 2021-10-31 12:40:49 +01:00 committed by GitHub
parent 79d3841af4
commit 1185a744f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 10456 additions and 0 deletions

3
.gitmodules vendored Executable file
View file

@ -0,0 +1,3 @@
[submodule "monkeydo"]
path = assets/js/modules/monkeydo
url = https://github.com/VictorWesterlund/monkeydo.git

3
README.md Normal file
View file

@ -0,0 +1,3 @@
<h1 align="center">Still Alive</h1>
<p align="center">A JavaScript implementation of the <a href="https://web.archive.org/web/20210929222906/https://www.youtube.com/watch?v=Y6ljFaKRTrI">end credits</a> from the video game <a href="https://en.wikipedia.org/wiki/Portal_(video_game)"><code>Portal</code></a></p>
<p align="center"><a href="https://victorwesterlund.github.io/still-alive/"><strong>Take me to the demo 🍰</strong></a></p>

46
assets/css/player.css Normal file
View file

@ -0,0 +1,46 @@
html,
body {
--padding: 40px;
display: initial;
overflow: hidden;
padding: var(--padding);
box-sizing: border-box;
}
#player {
position: absolute;
}
body.credits #player {
bottom: var(--padding);
}
body.art {
display: flex;
justify-content: center;
align-items: center;
}
#player pre,
#player p {
font-size: 16px;
color: rgb(var(--color-accent));
}
body.art #player pre {
font-size: clamp(0px,3vw,3vh);
}
#player p {
margin: 0;
height: 23px;
}
#player p:last-child::after {
content: "_";
animation: blink 500ms alternate infinite;
}
@keyframes blink {
to { opacity: 0; }
}

61
assets/css/style.css Executable file
View file

@ -0,0 +1,61 @@
:root {
--color-background: 0,0,0;
--color-contrast: 255,255,255;
--color-accent: 255,212,0;
}
html,
body {
margin: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: rgb(var(--color-background));
color: rgba(var(--color-contrast));
font-family: "Courier New", Courier, monospace;
}
a {
text-decoration: none;
color: inherit;
}
#play {
display: inline-block;
background-color: rgb(var(--color-contrast));
color: rgba(var(--color-background));
padding: 20px;
font-size: 18px;
}
footer {
position: fixed;
box-sizing: border-box;
padding: 0 20px;
left: 0;
bottom: 0;
}
@media (pointer: fine) {
#play:not(.unsupported) {
cursor: pointer;
}
}
@media (hover: hover) {
#play:not(.unsupported) {
transition: 100ms background-color,100ms color;
cursor: pointer;
}
#play:not(.unsupported):hover {
background-color: rgba(var(--color-contrast),.15);
color: rgb(var(--color-contrast));
}
a:hover {
text-decoration: underline;
}
}

View file

@ -0,0 +1,116 @@
import { default as PlayerWindow } from "./PlayerWindow.mjs";
import { default as Monkeydo } from "./monkeydo/Monkeydo.mjs";
export default class WindowManager {
constructor(mediaElement) {
const self = this;
this.mediaElement = mediaElement;
// Bi-directional communcation to player windows
this.channels = {
"#lyrics": new BroadcastChannel("#lyrics"),
"#credits": new BroadcastChannel("#credits"),
"#art": new BroadcastChannel("#art")
};
for(const channel of Object.values(this.channels)) {
channel.addEventListener("message",event => this.message(event));
}
// Monkeydo methods
const methods = {
blank: (target) => {
self.channels[target].postMessage(["BLANK",target]);
},
lineFeed: (target) => {
self.channels[target].postMessage(["LINE_FEED"]);
},
textFeed: (text,target = "#lyrics") => {
self.channels[target].postMessage(["TEXT_FEED",text]);
},
drawArt: (index,target = "#art") => {
self.channels[target].postMessage(["DRAW_ART",index]);
},
playCredits: () => {
self.players.credits.do();
}
}
this.players = {
lyrics: new Monkeydo(methods),
credits: new Monkeydo(methods)
}
}
playbackFailed(promiseObject = false) {
console.log(promiseObject);
}
// Attempt to open a new window
async spawnPlayer(type) {
if(!type in this.channels) {
throw new Error(`Inavlid player type "${type}"`);
}
return await new Promise((resolve,reject) => {
const player = new PlayerWindow(type).open();
const channel = this.channels[type];
// Wait for window to emit ready state message before resolving
const ack = channel.addEventListener("message",event => {
if(event.data[0] === "WINDOW_READY" || event.data[1] === type) {
resolve("WINDOW_READY");
}
// Window failed to initialize
if(event.data[0] === "WINDOW_ERROR" || event.data[1][0] === type) {
reject(event.data[1]);
}
return false;
});
channel.removeEventListener("message",ack);
});
}
async play() {
for(const [key,player] of Object.entries(this.players)) {
const manifest = new URL(window.location.href + `monkeydo_${key}.json`);
await player.load(manifest.toString());
}
this.players.lyrics.do();
this.mediaElement.play();
}
// Open player windows and start playback
async init() {
const art = this.spawnPlayer("#art");
const credits = this.spawnPlayer("#credits");
const lyrics = this.spawnPlayer("#lyrics");
const timeout = new Promise(resolve => setTimeout(() => resolve("TIMEOUT")),3000);
const windows = await Promise.allSettled([lyrics,credits,art]);
// Wait for all windows to open and initialize (or timout and fail)
const status = Promise.race([windows,timeout]);
status.then(promises => {
promises.forEach(promiseObject => {
if(promiseObject.status !== "fulfilled") {
this.playbackFailed(promiseObject);
}
});
// Load Monkeydo manifest and start playback
this.play();
});
}
message(event) {
const type = event.data[0];
const data = event.data[1];
switch(type) {
case "PLAY": console.log("PLAY",event); break;
case "WINDOW_CLOSED": console.log("WINDOW_CLOSED",event); break;
}
}
}

View file

@ -0,0 +1,61 @@
const windowPositions = {
"#lyrics": {
width: window.innerWidth / 2,
height: window.innerHeight,
top: 0,
left: 0
},
"#credits": {
width: window.innerWidth / 2,
height: window.innerHeight / 2,
top: 0,
left: window.innerWidth / 2
},
"#art": {
width: window.innerWidth / 2,
height: window.innerHeight / 2,
top: window.innerHeight / 2,
left: window.innerWidth / 2
}
}
export default class PlayerWindow {
constructor(name) {
this.features = {
menubar: false,
location: false,
resizable: false,
scrollbar: false,
status: false
}
this.url = new URL(window.location.href + "player");
this.url.hash = name;
// Copy window size rect into windowFeatures
Object.assign(this.features,windowPositions[this.url.hash]);
}
// Convert windowFeatures object into a CSV DOMString
windowFeatures() {
let output = [];
for(let [key,value] of Object.entries(this.features)) {
if(typeof key === "boolean") {
value = value ? "yes" : "no";
}
output.push(`${key}=${value}`);
}
return output.join(",");
}
open() {
const features = this.windowFeatures();
const open = window.open(this.url.toString(),this.url.hash,features);
// Window failed to open (usually due to pop-up blocking), tell the WindowManager about this
if(!open) {
const channel = new BroadcastChannel(this.url.hash);
channel.postMessage(["WINDOW_ERROR",[this.url.hash,"BLOCKED"]]);
}
}
}

View file

@ -0,0 +1,62 @@
// Encoded in order from: https://blog.kazitor.com/2014/12/portal-ascii/
const artset = [
"%20%20%20%20%20%20%20%20%20%20%20%20%20.%2C-%3A%3B%2F%2F%3B%3A%3D%2C%0A%20%20%20%20%20%20%20%20%20.%20%3AH%40%40%40MM%40M%23H%2F.%2C%2B%25%3B%2C%0A%20%20%20%20%20%20%2C%2FX%2B%20%2BM%40%40M%40MM%25%3D%2C-%25HMMM%40X%2F%2C%0A%20%20%20%20%20-%2B%40MM%3B%20%24M%40%40MH%2B-%2C%3BXMMMM%40MMMM%40%2B-%0A%20%20%20%20%3B%40M%40%40M-%20XM%40X%3B.%20-%2BXXXXXHHH%40M%40M%23%40%2F.%0A%20%20%2C%25MM%40%40MH%20%2C%40%25%3D%20%20%20%20%20%20%20%20%20%20%20%20.---%3D-%3D%3A%3D%2C.%0A%20%20-%40%23%40%40%40MX%20.%2C%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%25HX%24%24%25%25%25%2B%3B%0A%20%3D-.%2F%40M%40M%24%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.%3B%40MMMM%40MM%3A%0A%20X%40%2F%20-%24MM%2F%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.%2BMM%40%40%40M%24%0A%2C%40M%40H%3A%20%3A%40%3A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.%20-X%23%40%40%40%40-%0A%2C%40%40%40MMX%2C%20.%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2FH-%20%3B%40M%40M%3D%0A.H%40%40%40%40M%40%2B%2C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%25MM%2B..%25%23%24.%0A%20%2FMMMM%40MMH%2F.%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20XM%40MH%3B%20-%3B%0A%20%20%2F%25%2B%25%24XHH%40%24%3D%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2C%20.H%40%40%40%40MX%2C%0A%20%20%20.%3D--------.%20%20%20%20%20%20%20%20%20%20%20-%25H.%2C%40%40%40%40%40MX%2C%0A%20%20%20.%25MM%40%40%40HHHXX%24%24%24%25%2B-%20.%3A%24MMX%20-M%40%40MM%25.%0A%20%20%20%20%20%3DXMMM%40MM%40MM%23H%3B%2C-%2BHMM%40M%2B%20%2FMMMX%3D%0A%20%20%20%20%20%20%20%3D%25%40M%40M%23%40%24-.%3D%24%40MM%40%40%40M%3B%20%25M%25%3D%0A%20%20%20%20%20%20%20%20%20%2C%3A%2B%24%2B-%2C%2FH%23MMMMMMM%40-%20-%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3D%2B%2B%25%25%25%25%2B%2F%3A-.",
"%20%20%20%20%20%20%20%20%20%20%20%20%20%3D%2B%24HM%23%23%23%23%40H%25%3B%2C%0A%20%20%20%20%20%20%20%20%20%20%2FH%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23M%24%2C%0A%20%20%20%20%20%20%20%20%20%20%2C%40%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%2B%0A%20%20%20%20%20%20%20%20%20%20%20.H%23%23%23%23%23%23%23%23%23%23%23%23%23%23%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20X%23%23%23%23%23%23%23%23%23%23%23%23%2F%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24%23%23%23%23%23%23%23%23%23%23%2F%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%25%23%23%23%23%23%23%23%23%2F%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2FX%2F%3B%3B%2BX%2F%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-XHHX-%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2C%23%23%23%23%23%23%2C%0A%23%23%23%23%23%23%23%23%23%23%23%23%23X%20%20.M%23%23%23%23M.%20%20X%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%23%23%23%23%23%23%23%23%23%23%23%23%23%23-%20%20%20-%2F%2F-%20%20%20-%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0AX%23%23%23%23%23%23%23%23%23%23%23%23%23%23%25%2C%20%20%20%20%20%20%2C%2B%23%23%23%23%23%23%23%23%23%23%23%23%23%23X%0A-%23%23%23%23%23%23%23%23%23%23%23%23%23%23X%20%20%20%20%20%20%20%20X%23%23%23%23%23%23%23%23%23%23%23%23%23%23-%0A%20%25%23%23%23%23%23%23%23%23%23%23%23%23%25%20%20%20%20%20%20%20%20%20%20%25%23%23%23%23%23%23%23%23%23%23%23%23%25%0A%20%20%25%23%23%23%23%23%23%23%23%23%23%3B%20%20%20%20%20%20%20%20%20%20%20%20%3B%23%23%23%23%23%23%23%23%23%23%25%0A%20%20%20%3B%23%23%23%23%23%23%23M%3D%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3DM%23%23%23%23%23%23%23%3B%0A%20%20%20%20.%2BM%23%23%23%40%2C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2C%40%23%23%23M%2B.%0A%20%20%20%20%20%20%20%3AXH.%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.HX%3A",
"%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3D%2F%3B%3B%2F-%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%3A%20%20%20%20%2F%2F%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%3B%20%20%20%20%20%20%2F%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20-X%20%20%20%20%20%20%20%20H.%0A.%2F%2F%3B%3B%3B%3A%3B%3B-%2C%20%20%20X%3D%20%20%20%20%20%20%20%20%3A%2B%20%20%20.-%3B%3A%3D%3B%3A%3B%25%3B.%0AM-%20%20%20%20%20%20%20%2C%3D%3B%3B%3B%23%3A%2C%20%20%20%20%20%20%2C%3A%23%3B%3B%3A%3D%2C%20%20%20%20%20%20%20%2C%40%0A%3A%25%20%20%20%20%20%20%20%20%20%20%20%3A%25.%3D%2F%2B%2B%2B%2B%2F%3D.%24%3D%20%20%20%20%20%20%20%20%20%20%20%25%3D%0A%20%2C%25%3B%20%20%20%20%20%20%20%20%20%25%2F%3A%2B%2F%3B%2C%2C%2F%2B%2B%3A%2B%2F%20%20%20%20%20%20%20%20%20%3B%2B.%0A%20%20%20%2C%2B%2F.%20%20%20%20%2C%3B%40%2B%2C%20%20%20%20%20%20%20%20%2C%25H%3B%2C%20%20%20%20%2C%2F%2B%2C%0A%20%20%20%20%20%20%3B%2B%3B%3B%2F%3D%20%40.%20%20.H%23%23X%20%20%20-X%20%3A%2F%2F%2F%2B%3B%0A%20%20%20%20%20%20%3B%2B%3D%3B%3B%3B.%40%2C%20%20.XM%40%24.%20%20%3DX.%2F%2F%3B%3D%25%2F.%0A%20%20%20%2C%3B%3A%20%20%20%20%20%20%3A%40%25%3D%20%20%20%20%20%20%20%20%3D%24H%3A%20%20%20%20%20.%2B%25-%0A%20%2C%25%3D%20%20%20%20%20%20%20%20%20%25%3B-%2F%2F%2F%3D%3D%2F%2F%2F-%2F%2F%20%20%20%20%20%20%20%20%20%3D%25%2C%0A%3B%2B%20%20%20%20%20%20%20%20%20%20%20%3A%25-%3B%3B%3B%3B%3B%3B%3B%3B-X-%20%20%20%20%20%20%20%20%20%20%20%2B%3A%0A%40-%20%20%20%20%20%20.-%3B%3B%3B%3BM-%20%20%20%20%20%20%20%20%3DM%2F%3B%3B%3B-.%20%20%20%20%20%20-X%0A%20%3A%3B%3B%3A%3A%3B%3B-.%20%20%20%20%25-%20%20%20%20%20%20%20%20%3A%2B%20%20%20%20%2C-%3B%3B-%3B%3A%3D%3D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2CX%20%20%20%20%20%20%20%20H.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3B%2F%20%20%20%20%20%20%25%3D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%20%20%20%2B%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2C%2F%2F%2F%2F%2C",
"%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.%2C---.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2C%2FXM%23MMMX%3B%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%25%23%23%23%23%23%23%23%23%23%23M%25%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%40%23%23%23%23%23%23%25%20%20%24%23%23%23%40%3D%0A%20%20%20%20%20%20.%2C--%2C%20%20%20%20%20%20%20%20%20-H%23%23%23%23%23%23%23%24%20%20%20%24%23%23%23M%3A%0A%20%20%20%2C%3B%24M%23%23%23MMX%3B%20%20%20%20%20.%3B%23%23%23%23%23%23%23%23%23%23%24%3BHM%23%23%23X%3D%0A%2C%2F%40%23%23%23%23%23%23%23%23%23%23%23H%3D%20%20%20%20%20%20%3B%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%2B%0A-%2B%23%23%23%23%23%23%23%23%23%23%23%23%23M%2F%2C%20%20%20%20%20%20%25%23%23%23%23%23%23%23%23%23%23%23%23%23%23%2B%0A%25M%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%3D%20%20%20%20%20%20%2F%23%23%23%23%23%23%23%23%23%23%23%23%23%23%3A%0AH%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%20%20%20%20%20.M%23%23%23%23%23%23%23%23%23%23%23%23%23%3B.%0A%40%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23M%20%20%20%20%20%20%2C%40%23%23%23%23%23%23%23%23%23%23%23M%3A.%0AX%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%2C%20%20%20%20%20%20-%24%3DX%23%23%23%23%23%23%23%40%3A%0A%2F%40%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%25-%20%20%20%20%20%2B%23%23%23%23%23%23%24-%0A.%3B%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23X%20%20%20%20%20.X%23%23%23%23%23%2B%2C%0A%20.%3BH%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%2F%20%20%20%20%20-X%23%23%23%23%2B.%0A%20%20%20%2C%3BX%23%23%23%23%23%23%23%23%23%23%23%23%23%23%2C%20%20%20%20%20%20%20.MM%2F%0A%20%20%20%20%20%20%2C%3A%2B%24H%40M%23%23%23%23%23%23%23M%23%24-%20%20%20%20.%24%24%3D%0A%20%20%20%20%20%20%20%20%20%20%20.%2C-%3D%3B%2B%24%40%23%23%23X%3A%20%20%20%20%3B%2F%3D.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.%2C%2FX%24%3B%20%20%20.%3A%3A%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.%2C%20%20%20%20..",
"%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%24-%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.H%23%23H%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%23%23%23%23%23%23%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.%2B%23%23%23%23%23%23%23%23%23H.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%24%23%23%23%23%23%23%23%23%23%23%23%23%40.%0A%20%20%20%20%20%20%20%20%20%20%20%20%3DH%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%40%20%20-X%3A%0A%20%20%20%20%20%20%20%20%20%20.%24%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%3A%20%20%40%23%40-%0A%20%20%20%20%20%2C%3B%20%20.M%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%3B%20%20H%23%23%23%3B%0A%20%20%20%3B%40%23%3A%20%20%40%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%40%20%20%2C%23%23%23%23%23%3A%0A%20-M%23%23%23.%20%20M%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%40.%20%20%3B%23%23%23%23%23%23H%0A%20M%23%23%23%23-%20%20%2B%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%24%20%20%20%3D%40%23%23%23%23%23%23%23X%0A%20H%23%23%23%23%24%20%20%20-M%23%23%23%23%23%23%23%23%23%23%23%2B%20%20%20%3A%23%23%23%23%23%23%23%23%23M%2C%0A%20%20%2F%23%23%23%23X-%20%20%20%3D%23%23%23%23%23%23%23%23%25%20%20%20%3AM%23%23%23%23%23%23%23%23%40%2F.%0A%20%20%20%20%2C%3B%25H%40X%3B%20%20%20.%24%23%23%23X%20%20%20%3A%23%23MM%40%25%2B%3B%3A-%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20..%0A%20%20-%2F%3B%3A-%2C.%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2C%2C-%3D%3D%2BM%23%23%23%23%23%23%23%23H%0A%20-%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%40HX%25%25%2B%25%25%24%25%25%25%2B%3A%2C%2C%0A%20%20%20%20.-%2FH%25%25%25%2B%25%25%24H%40%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23M%40%2B%3D%3A%2F%2B%3A%0A%2FXHX%25%3A%23%23%23%23%23MH%25%3D%20%20%20%20%2C---%3A%3B%3B%3B%3B%2F%26%26XHM%2C%3A%23%23%23%24%0A%24%40%23MX%20%25%2B%3B-%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.",
"%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3AX-%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3AX%23%23%23%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3B%40%23%23%23%23%40%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3BM%23%23%23%23%23%23X%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%40%23%23%23%23%23%23%23%23%24%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.%24%23%23%23%23%23%23%23%23%23%23%40%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3DM%23%23%23%23%23%23%23%23%23%23%23%23-%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%23%23%23%23%23%23%23%23%23%23%23%23%23%23%24%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.H%23%23%23%23%23%23%23%23%23%23%23%23%24%3D.%0A%20%20%20%20%20%20%20%20%20%2C%2F%3A%20%20%20%20%20%20%20%20%20%2CM%23%23%23%23%23%23%23%23%23%23M%3B.%0A%20%20%20%20%20%20-%2B%40%23%23%23%3B%20%20%20%20%20%20%20%3D%23%23%23%23%23%23%23%23%23%23M%3B%0A%20%20%20%3D%25M%23%23%23%23%23%23%23%3B%20%20%20%20%20%3A%23%23%23%23%23%23%23%23%23M%2F%0A-%24M%23%23%23%23%23%23%23%23%23%23%23%3B%20%20%20%3A%23%23%23%23%23%23%23%23%2F%0A%20%2C%3BX%23%23%23%23%23%23%23%23%23%23%23%3B%20%3D%23%23%23%23%23%23%23%24.%0A%20%20%20%20%20%3BH%23%23%23%23%23%23%23%23%23%2B%23%23%23%23%23%23M%3D%0A%20%20%20%20%20%20%20%2C%2B%23%23%23%23%23%23%23%23%23%23%23%23%23%2B%0A%20%20%20%20%20%20%20%20%20%20%2FM%23%23%23%23%23%23%23%23%40-%0A%20%20%20%20%20%20%20%20%20%20%20%20%3BM%23%23%23%23%23%25%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%23%23%23%23%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2C%24M-",
"%20%20%20%20%20%20%20%20%20%20%20%20.%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%2FM%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20H%23%40%3A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3B%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%23%23%23H-%20%20%20%20%20%20%20%20%20%20-%40%2F%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%25%23%23%23%23%24.%20%20-%3B%20%20.%25%23X%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20M%23%23%23%23%23%2B%3B%23H%20%3AM%23M.%0A..%20%20%20%20%20%20%20%20%20%20.%2B%2F%3B%25%23%23%23%23%23%23%23%23%23%23%23%23%23-%0A%20-%2F%25H%25%2B%3B-%2C%20%20%20%20%2B%23%23%23%23%23%23%23%23%23%23%23%23%23%23%2F%0A%20%20%20%20.%3A%24M%23%23%23MH%24%25%2B%23%23%23%23%23%23%23%23%23%23%23%23X%20%20%2C--%3D%3B-%0A%20%20%20%20%20%20%20%20-%2FH%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23H%2B%3D.%0A%20%20%20%20%20%20%20%20%20%20%20.%2B%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23X.%0A%20%20%20%20%20%20%20%20%20%3D%25M%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23H%3B.%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%40%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%2B%3B%3B%2F%25%25%3B%2C%0A%20%20%20%20%20%20%20%20%20-%25%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%24%0A%20%20%20%20%20%20%20%3BH%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23M%3D%0A%20%20%20%20%2C%25%23%23%23%23%23MH%24%25%3B%2B%23%23%23%23%23M%23%23%23-%2F%40%23%23%23%23%25%0A%20%20%3A%24H%25%2B%3B%3D-%20%20%20%20%20%20-%23%23%23%23X.%2CH%23%20%20%20-%2BM%23%23%40-%0A%20.%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2C%23%23%23%3B%20%20%20%20%3B%20%20%20%20%20%20%3D%24%23%23%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.%23H%2C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3AXH%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.%3B-",
"%20%20%20%20%20%20%20%20%20%20%20.-%3B%2B%24XHHHHHHX%24%2B%3B-.%0A%20%20%20%20%20%20%20%20%2C%3BX%40%40X%25%2F%3B%3D----%3D%3A%2F%25X%40%40X%2F%2C%0A%20%20%20%20%20%20%3D%24%40%40%25%3D.%20%20%20%20%20%20%20%20%20%20%20%20%20%20.%3D%2BH%40X%3A%0A%20%20%20%20-XMX%3A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3DXMX%3D%0A%20%20%20%2F%40%40%3A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3DH%40%2B%0A%20%20%25%40X%2C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.%24%40%24%0A%20%2B%40X.%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24%40%25%0A-%40%40%2C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.%40%40%3D%0A%25%40%25%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%40%24%0AH%40%3A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3A%40H%0AH%40%3A%20%20%20%20%20%20%20%20%20%3AHHHHHHHHHHHHHHHHHHX%2C%20%20%20%20%3D%40H%0A%25%40%25%20%20%20%20%20%20%20%20%20%3B%40M%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40H-%20%20%20%2B%40%24%0A%3D%40%40%2C%20%20%20%20%20%20%20%20%3A%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%3D%20.%40%40%3A%0A%20%2B%40X%20%20%20%20%20%20%20%20%3A%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40M%40%40%40%40%40%40%3A%25%40%25%0A%20%20%24%40%24%2C%20%20%20%20%20%20%3B%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40M%40%40%40%40%40%40%24.%0A%20%20%20%2B%40%40HHHHHHH%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%2B%0A%20%20%20%20%3DX%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40X%3D%0A%20%20%20%20%20%20%3A%24%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40M%40%40%40%40%24%3A%0A%20%20%20%20%20%20%20%20%2C%3B%24%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40%40X%2F-%0A%20%20%20%20%20%20%20%20%20%20%20.-%3B%2B%24XXHHHHHX%24%2B%3B-.",
"%20%20%20%20%20%20%20%20%20%20%20%20%2C%3A%2F%2B%2F-%0A%20%20%20%20%20%20%20%20%20%20%20%20%2FM%2F%20%20%20%20%20%20%20%20%20%20%20%20%20%20.%2C-%3D%3B%2F%2F%3B-%0A%20%20%20%20%20%20%20.%3A%2F%3D%20%3BMH%2F%2C%20%20%20%20%2C%3D%2F%2B%25%24XH%40MM%23%40%3A%0A%20%20%20%20%20%20-%24%23%23%40%2B%24%23%23%23%40H%40MMM%23%23%23%23%23%23%23H%3A.%20%20%20%20-%2FH%23%0A%20.%2CH%40H%40%20X%23%23%23%23%23%23%40%20-H%23%23%23%23%23%40%2B-%20%20%20%20%20-%2BH%23%23%23%40X%0A%20%20.%2C%40%23%23H%3B%20%20%20%20%20%20%2BXM%23%23M%2F%2C%20%20%20%20%20%3D%25%40%23%23%23%40X%3B-%0AX%25-%20%20%3AM%23%23%23%23%23%23%23%23%23%23%24.%20%20%20%20.%3A%25M%23%23%23%40%25%3A%0AM%23%23H%2C%20%20%20%2BH%40%40%40%24%2F-.%20%20%2C%3B%24M%23%23%23%40%25%2C%20%20%20%20%20%20%20%20%20%20-%0AM%23%23%23%23M%3D%2C%2C---%2C.-%25%25H%23%23%23%23M%24%3A%20%20%20%20%20%20%20%20%20%20%2C%2B%40%23%23%0A%40%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%40%2F.%20%20%20%20%20%20%20%20%20%3A%25H%23%23%40%24-%0AM%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23H%2C%20%20%20%20%20%20%20%20%20%3BHM%23%23M%24%3D%0A%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23.%20%20%20%20.%3D%24M%23%23M%24%3D%0A%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23H..%3BXM%23%23M%24%3D%20%20%20%20%20%20%20%20%20%20.%3A%2B%0AM%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%40%25%3D%20%20%20%20%20%20%20%20%20%20%20%3D%2B%40MH%25%0A%40%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23M%2F.%20%20%20%20%20%20%20%20%20%3D%2BH%23X%25%3D%0A%3D%2BM%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23M%2C%20%20%20%20%20%20%2C%2FX%23H%2B%3A%2C%0A%20%20.%3BXM%23%23%23%23%23%23%23%23%23%23%23H%3D%20%20%20%2C%2FX%23H%2B%3A%3B%0A%20%20%20%20%20.%3D%2BHM%23%23%23%23%23%23%23M%2B%2F%2BHM%40%2B%3D.%0A%20%20%20%20%20%20%20%20%20%2C%3A%2F%25XM%23%23%23%23H%2F.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2C.%3A%3D-.",
"%20%20%20%20%20%20%20%23%2B%20%40%20%20%20%20%20%20%23%20%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20M%23%40%0A%20.%20%20%20%20.X%20%20X.%25%23%23%40%3B%23%20%23%20%20%20%2B%40%23%23%23%23%23%23%23X.%20%40H%25%0A%20%20%20%2C%3D%3D.%20%20%20%2C%23%23%23%23%23%23M%2B%20%20-%23%23%23%23%23%25M%23%23%23%23M-%20%20%20%20%23%0A%20%20%3AH%23%23M%25%3A%3D%23%23%2B%20.M%23%23M%2C%3B%23%23%23%23%23%2F%2B%23%23%23%23%23%23%23%25%20%2CM%23%0A%20.M%23%23%23%23%23%23%23%23%3D%20%20%3D%40%23%40.%3D%23%23%23%23%23M%3DM%23%23%23%23%23%23%23%3D%20%20X%23%0A%20%3A%40%40MMM%23%23M.%20%20-%23%23M.%2C%23%23%23%23%23%23%23M%23%23%23%23%23%23%23.%20%3D%20%20M%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%40%23%23..%23%23%23%3A.%20%20%20%20.H%23%23%23%23.%20%40%40%20X%2C%0A%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%3A%20%23%23%23%2C%2F%23%23%23%23%3B%20%20%2F%23%23%3D%20%40%23.%20M%0A%20%20%20%20%20%20%20%20%20%20%20%2CM%23%23%20%3B%23%23%2C%40%23M%3B%2FM%23M%20%20%40%23%20X%23%25%20X%23%0A.%25%3D%20%20%20%23%23%23%23%23%23M%23%23%20%23%23.M%23%3A%20%20%20.%2F%23M%20%2CM%20%23M%20%2C%23%24%0A%23%23%2F%20%20%20%20%20%20%20%20%20%24%23%23%20%23%2B%3B%23%3A%20%23%23%23%23%20%3B%23%2F%20M%20M-%20%40%23%20%3A%0A%23%2B%20%23M%40MM%23%23%23M-%3BM%20%23%3A%24%23-%23%23%24H%23%20.%23X%20%40%20%2B%20%24%23.%20%23%0A%20%20%20%20%20%20%23%23%23%23%23%23%2F.%3A%20%23%25%3D%23%20M%23%3AMM.%2F%23.-%23%20%20%40%23%3A%20H%23%0A%2B%2C.%3D%20%20%20%40%23%23%23%3A%20%2F%40%20%25%23%2C%40%20%20%23%23%40X%20%23%2C-%23%40.%23%23%25%20.%40%23%0A%23%23%23%23%23%2B%3B%2F%23%23%2F%20%40%23%23%20%20%40%23%2C%2B%20%20%20%20%20%20%20%2F%23M%20%20%20%20.%20X%2C%0A%20%20%20%3B%23%23%23M%23%40%20M%23%23%23H%20.%23M-%20%20%20%20%20%2C%23%23M%20%20%3B%40%40%3B%20%23%23%23%0A%20%20%20.M%23M%23%23H%20%3B%23%23%23%23X%20%2C%40%23%23%23%23%23%23%23M%2F%20-M%23%23%23%24%20%20-H%0A%20%20%20%20.M%23%23%23%25%20%20X%23%23%23%23H%20%20.%40%40MM%40%3B%20%20%3B%40%23M%40%0A%20%20%20%20%20%20H%23M%20%20%20%20%2F%40%23%23%23%23%2F%20%20%20%20%20%20%2C%2B%2B.%20%20%2F%20%3D%3D-%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2C%3D%2F%3A%2C%20.%2BX%40MMH%40%23H%20%20%23%23%23%23%23%24%3D"
];
export default class StillAlivePlayer {
constructor(element) {
this.channel = new BroadcastChannel(window.location.hash);
this.channel.addEventListener("message",event => this.message(event));
this.player = element;
this.channel.postMessage(["WINDOW_READY",window.location.hash]);
}
// Clear the screen from elements
blank() {
while(this.player.firstChild) {
this.player.removeChild(this.player.lastChild);
}
}
// Create a new paragraph and make it the target for textFeed calls
lineFeed() {
this.target = document.createElement("p");
this.player.appendChild(this.target);
}
// Append text to the current target element
textFeed(text) {
this.target.innerText = this.target.innerText + text;
}
// Decode and draw art from artset by key
drawArt(key) {
this.blank();
this.target = document.createElement("pre");
this.target.innerText = window.decodeURIComponent(artset[key]);
this.player.appendChild(this.target);
}
message(event) {
const type = event.data[0];
const data = event.data[1];
switch(type) {
case "LINE_FEED": this.lineFeed(); break;
case "TEXT_FEED": this.textFeed(data); break;
case "DRAW_ART": this.drawArt(data); break;
case "BLANK": this.blank(); break;
}
}
}

18
assets/js/player.mjs Normal file
View file

@ -0,0 +1,18 @@
import { default as Player } from "./modules/StillAlivePlayer.mjs";
// Go to start page if location.hash is omitted
if(!window.location.hash) {
// Close this window, if we can
window.close();
// Otherwise redirect to main page
const page = window.location.pathname.split("/");
const url = window.location.href.replace(page[page.length - 1],"");
window.location.replace(url);
}
// Add location.hash to body classList
document.body.classList.add(window.location.hash.substring(1));
const element = document.getElementById("player");
const player = new Player(element);

21
assets/js/script.mjs Executable file
View file

@ -0,0 +1,21 @@
import { default as Player } from "./modules/PlayerManager.mjs";
const play = document.getElementById("play");
try {
if(typeof BroadcastChannel !== "function") {
throw new Error("BroadcastChannel API is not supported");
}
const mediaElement = document.getElementById("still-alive");
const player = new Player(mediaElement);
play.addEventListener("click",() => player.init());
} catch(error) {
const message = document.getElementById("message");
play.classList.add("unsupported");
play.innerText = "Your browser can not play this demo";
message.innerText = error;
}

Binary file not shown.

22
index.html Executable file
View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="End credits from 'Portal' - the video game, recreated with JS and browser windows.">
<title>Still Alive</title>
<link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<main>
<p id="play">Still Alive</p>
<p id="message"></p>
</main>
<footer>
<a href="https://github.com/VictorWesterlund/still-alive">Source on GitHub</p>
</footer>
<audio id="still-alive" src="assets/media/still-alive.webm"></audio>
<script type="module" src="assets/js/script.mjs"></script>
</body>
</html>

1
monkeydo_credits.json Normal file

File diff suppressed because one or more lines are too long

10022
monkeydo_lyrics.json Normal file

File diff suppressed because it is too large Load diff

15
player.html Executable file
View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>&ZeroWidthSpace;</title>
<link rel="stylesheet" href="assets/css/style.css">
<link rel="stylesheet" href="assets/css/player.css">
</head>
<body>
<div id="player"></div>
<script type="module" src="assets/js/player.mjs"></script>
</body>
</html>

5
robots.txt Normal file
View file

@ -0,0 +1,5 @@
User-Agent: *
Allow: /
Disallow: /player