1
mirror of https://github.com/jakejarvis/jarv.is.git synced 2025-04-26 09:05:22 -04:00

migrate y2k.app to a simple page here

This commit is contained in:
Jake Jarvis 2022-01-28 18:41:56 -05:00
parent b339c8a9f7
commit 0b526fd4d2
27 changed files with 222 additions and 9 deletions

View File

@ -0,0 +1,59 @@
.container {
padding: 1.5em;
/* specific retro wallpaper tile is set randomly by JS onload */
background-repeat: repeat;
background-position: center;
}
.display {
display: block;
margin: auto;
max-width: 800px;
max-height: 600px;
/* fix fuzziness: https://stackoverflow.com/a/13492784 */
image-rendering: optimizeSpeed;
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
image-rendering: pixelated;
-ms-interpolation-mode: nearest-neighbor;
}
.display div {
background: none !important;
}
.display div canvas {
cursor: default !important;
}
.cmd {
display: block;
margin: auto;
width: 700px;
height: 400px;
padding: 12px;
z-index: -100;
background-color: #000000;
color: #cccccc;
font-size: 0.925em;
font-weight: 500;
line-height: 2;
white-space: pre-wrap;
user-select: none;
}
.blink {
animation: blink 1s step-end infinite;
}
@keyframes blink {
50% {
opacity: 0;
}
}

109
components/VNC/VNC.tsx Normal file
View File

@ -0,0 +1,109 @@
import { useRef, useEffect, useState, memo } from "react";
import { useRouter } from "next/router";
import classNames from "classnames";
import RFB from "@novnc/novnc/core/rfb.js";
import styles from "./VNC.module.css";
type Props = {
className?: string;
};
const WEBSOCKETS_SERVER = "wss://socket.y2k.app";
const VNC = ({ className }: Props) => {
const router = useRouter();
// we definitely do NOT want this page to connect more than once!
const [loaded, setLoaded] = useState(false);
// DOS-style box for text
const consoleRef = useRef<HTMLDivElement>(null);
const statusRef = useRef<HTMLSpanElement>(null);
// the actual connection and virtual screen (injected by noVNC when it's ready)
const rfbRef = useRef(null);
const screenRef = useRef<HTMLDivElement>(null);
useEffect(() => {
// end the session when the current page changes
const disconnectVM = () => {
try {
rfbRef.current.disconnect();
} catch (e) {} // eslint-disable-line no-empty
};
// prepare for possible navigation away from this page
router.events.on("routeChangeStart", disconnectVM);
return () => {
// unassign event listener
router.events.off("routeChangeStart", disconnectVM);
};
}, []); // eslint-disable-line react-hooks/exhaustive-deps
useEffect(() => {
if (loaded) {
return;
}
if (!window.WebSocket) {
// browser doesn't support websockets
statusRef.current.textContent =
"WebSockets must be enabled to play in the Y2K Sandbox!!!\n\nPress the Any key to continue.";
return;
}
// https://github.com/novnc/noVNC/blob/master/docs/API.md
rfbRef.current = new RFB(screenRef.current, WEBSOCKETS_SERVER, {
wsProtocols: ["binary", "base64"],
});
// this is the one and only time we're spinning up a VM (hopefully)
setLoaded(true);
// VM connected
rfbRef.current.addEventListener("connect", () => {
console.log("successfully connected to VM socket!");
// hide the console when VM connects
consoleRef.current.style.display = "none";
});
// VM disconnected
rfbRef.current.addEventListener("disconnect", (detail) => {
console.warn("VM ended session remotely:", detail);
// make the console reappear now that the VM has gone poof for whatever reason (doesn't really matter)
try {
consoleRef.current.style.display = "block";
statusRef.current.textContent =
"Oh dear, it looks like something's gone very wrong. Sorry about that.\n\nPress the Any key or refresh the page to continue.";
} catch (e) {} // eslint-disable-line no-empty
});
console.log(
"🤓 Hey, fellow nerd! Want to see how I made this? Check out this post: https://jarv.is/notes/y2k-sandbox/"
);
}, [loaded]);
return (
<div
className={classNames(styles.container, className)}
style={{
// set a random retro wallpaper tile for the content area
background: `url('/static/images/y2k/tiles/tile_${Math.floor(20 * Math.random())}.png')`,
}}
>
<div ref={consoleRef} className={classNames("monospace", styles.cmd)}>
<span ref={statusRef}>Spinning up your very own personal computer, please wait!</span>{" "}
<span className={styles.blink}>_</span>
</div>
<div ref={screenRef} className={styles.display} />
</div>
);
};
export default memo(VNC);

View File

@ -12,10 +12,10 @@ image: "/static/images/notes/y2k-sandbox/screenshot.png"
A few months ago, I stumbled upon [my first website ever](https://jakejarvis.github.io/my-first-website/) on an old floppy disk. Despite the instant cringing, I [uploaded it](https://github.com/jakejarvis/my-first-website) to GitHub, [collected other iterations](/previously/), and made an [#awesome-list](https://github.com/jakejarvis/awesome-first-code) of others who were brave and/or shameless enough to do the same. But why not take that ~~one~~ 1,000 steps further?
Introducing the [**Y2K Sandbox**](https://y2k.app/) — with fully-featured, fully-isolated, on-demand [**Windows Millennium Edition®**](https://www.youtube.com/watch?v=CaNDeyYP98A) virtual machines, simply to experience my first website in its natural Internet Explorer 5 habitat. And maybe play some [3D Pinball: Space Cadet](https://en.wikipedia.org/wiki/Full_Tilt!_Pinball#3D_Pinball_for_Windows_%E2%80%93_Space_Cadet). Oh, and [Microsoft Bob](https://en.wikipedia.org/wiki/Microsoft_Bob) is there too if you want to say hello and catch up. 🤓
Introducing the [**Y2K Sandbox**](/y2k/) — with fully-featured, fully-isolated, on-demand [**Windows Millennium Edition®**](https://www.youtube.com/watch?v=CaNDeyYP98A) virtual machines, simply to experience my first website in its natural Internet Explorer 5 habitat. And maybe play some [3D Pinball: Space Cadet](https://en.wikipedia.org/wiki/Full_Tilt!_Pinball#3D_Pinball_for_Windows_%E2%80%93_Space_Cadet). Oh, and [Microsoft Bob](https://en.wikipedia.org/wiki/Microsoft_Bob) is there too if you want to say hello and catch up. 🤓
<Figure src="/public/static/images/notes/y2k-sandbox/screenshot.png" width="865" height="649" priority>
[**Play in the Y2K Sandbox, at your own risk.**](https://y2k.app/)
[**Play in the Y2K Sandbox, at your own risk.**](/y2k/)
</Figure>
The backend is powered by [**QEMU**](https://www.qemu.org/) (as a Pentium III emulator) inside isolated **Docker** containers, [**websocketd**](https://github.com/joewalnes/websocketd) (an **_awesome_** lightweight WebSockets server written in Go), and [**Cloudflare Tunnels**](https://www.cloudflare.com/products/tunnel/) (for some protection), all tied together with some [Ruby code](https://github.com/jakejarvis/y2k/blob/main/container/bin/boot.rb) and [shell scripts](https://github.com/jakejarvis/y2k/tree/main/host). ~~I'll push the backend scripts up to GitHub once I have a chance to untangle the spaghetti code. 🍝~~

View File

@ -29,6 +29,7 @@
"@giscus/react": "^1.0.1",
"@hcaptcha/react-hcaptcha": "^1.1.0",
"@next/bundle-analyzer": "^12.0.9",
"@novnc/novnc": "1.3.0",
"@octokit/graphql": "^4.8.0",
"@primer/octicons": "^16.3.0",
"@sentry/node": "^6.17.3",

View File

@ -1,3 +1,4 @@
import Link from "next/link";
import { NextSeo } from "next-seo";
import Content from "../components/Content/Content";
import PageTitle from "../components/PageTitle/PageTitle";
@ -53,13 +54,15 @@ const Previously = () => (
color: <span className="limegreen">limegreen</span>
</code>
...{" "}
<a href="https://y2k.app/" target="_blank" rel="noopener noreferrer">
<Link href="/y2k/" prefetch={false}>
<a>
Click for the{" "}
<strong>
<em>FULL</em>
</strong>{" "}
experience anyway.
</a>
</Link>
</p>
<IFrame

36
pages/y2k.tsx Normal file
View File

@ -0,0 +1,36 @@
import dynamic from "next/dynamic";
import { NextSeo } from "next-seo";
// obviously, an interactive VNC display will not work even a little bit server-side
const VNC = dynamic(() => import("../components/VNC/VNC"), { ssr: false });
const Y2K = () => (
<>
<NextSeo
title="Y2K Sandbox: Powered by Windows Me™ 💾"
description="My first website on a Windows Me-powered time machine. You've been warned."
openGraph={{
title: "Y2K Sandbox: Powered by Windows Me™",
}}
/>
<VNC />
<style jsx global>{`
/* make the viewport a bit larger by un-sticking the nav bar */
header {
position: relative !important;
}
/* make an exception for the wrapper (and its background) to fill up the normal content area */
main {
padding: 0 !important;
}
main > div {
max-width: 100% !important;
}
`}</style>
</>
);
export default Y2K;

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 B

View File

@ -1214,6 +1214,11 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@novnc/novnc@1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@novnc/novnc/-/novnc-1.3.0.tgz#06db5ff55eae646a623d3717d8bffaf131ffb93a"
integrity sha512-tR87mY5ADtaELadmZfW937JO/p8fRdz3wkPoqwhqB/vY1XnTQeLSWwkp4yMlr4iIDY0iCficfzFYX5EHMh4MHw==
"@octokit/endpoint@^6.0.1":
version "6.0.12"
resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658"