Quick, interactive, 3D, computer emulator.

James Bray
22 Aug 2023

It had been a year since I had last updated my personal site and I felt it was high time it underwent a refresh. I decided that for this incarnation I wanted to try something new;

  • I wanted it to be kinetic, it had to move in some way.
  • I wanted to try and make it visually appealing on mobile, as well as desktop.
  • It had to be fun.
  • and, maybe most importantly, uniquely me (it is a personal site after all)

I started thinking back to another project I had worked on several years ago, an emulator for a small computer I hand soldered, that checked a lot of my boxes but wasn't very interactive on mobile, or new. Looking around at a few other sites, including the excellent Edward Hinrichsen's, I decided that I would experiment with something 3D.

Enter three.js

I was coming to this project with no experience in 3D, but after some research, I stumbled on three.js, the popular webGL graphics API. After wringing a simple “hello world” (consisting of a green cube drawn on the screen) I located a suitable model and imported it into my ‘scene’.

import * as THREE from 'three';

const aspect = window.innerWidth / window.innerHeight;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000);
renderer.setSize( window.innerWidth, window.innerHeight );


const renderer = new THREE.WebGLRenderer();
const loader = new GLTFLoader();
loader.load('/retro_computer_screen.glb', (gltf) => {
     const model = gltf.scene;
     scene.add(screenSpot);
});

function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
}
animate();

Something on screen

The first task was to use a tool to split out the screen mesh from the rest of the model. I chose to use Blender (a tool I had never used before this project). From there it was a simple task of of moving the UV so the texture would map correctly and exporting the model to a web-friendly format and size.

Blender screenshot
The Model Before UV manipulation
I will not be going over the emulator in this post, todo: write a post about emulator. But once the emulation magic has happened the output is rendered to a html canvas. Using that canvas as input into a canvas texture and then feeding that texture as input into a shader material (a shader is a small program that runs directly on your GPU, capable of modify both the geometry of a mesh, as well the color of each pixel.) I chose to take and modify an existing CRT shader designed for retro games for this task. The shader adds scan lines, an aperture grill, as well as some minor tube distortion, leading to a quite convincing effect.

Finishing touches

Now we had a model displaying a emulator on its screen. The final thing to consider was lighting the scene. To do this I used a variety of different light sources - an ambient light provides a basic fill, with a spotlight helping the highlight details on the model.

A subtle "screen glow" effect is achieved by using a point light positioned just above the screen to cast light on the bezel. To light the keyboard a spotlight was used, positioned at the back of the monitor model and pointing straight out of the screen, this avoided light bleed onto the back of the case model. The hue and intensity of the lights themselves are determined by calculating the average colour of the screen, using each character slot as opposed to each pixel to save valuable milliseconds.

Try it out

at https://www.yarbsemaj.com/

Why not try this BASIC program?

10 FOR A=0 TO 6.2 STEP 0.2
20 PRINT TAB(40+SIN(A)*20);"*"
30 NEXT A
RUN