cool-retro-term-renderer
v1.0.1
Published
A WebGL-based CRT terminal renderer for XTerm.js with authentic retro effects
Maintainers
Readme
cool-retro-term-renderer
A WebGL-based CRT terminal renderer for XTerm.js. This library provides authentic retro CRT visual effects for terminal applications, including screen curvature, phosphor glow, scanlines, and more.
Preview
![]()
Live demo available at https://remojansen.github.io/
Installation
npm install cool-retro-term-rendererPeer Dependencies
This library requires three and @xterm/xterm as peer dependencies:
npm install three @xterm/xtermQuick Start
import { CRTTerminal } from 'cool-retro-term-renderer';
import { Terminal } from '@xterm/xterm';
// Create a container element
const container = document.getElementById('terminal')!;
// Initialize the CRT renderer
const crt = new CRTTerminal({ container });
// Create and configure your XTerm instance
const xterm = new Terminal({
cols: 80,
rows: 24,
cursorBlink: false,
});
// XTerm needs a DOM element to attach to (can be hidden)
const hiddenContainer = document.createElement('div');
hiddenContainer.style.position = 'absolute';
hiddenContainer.style.left = '-9999px';
document.body.appendChild(hiddenContainer);
xterm.open(hiddenContainer);
// Attach XTerm to the CRT renderer
crt.attachXTerm(xterm);
// Now use XTerm as normal - output will render with CRT effects
xterm.write('Hello, CRT World!\r\n');
xterm.write('$ ');Advanced Usage (Low-Level API)
For more control over the rendering pipeline (e.g., custom Three.js scenes, audio integration, or custom terminal adapters), you can use the lower-level components directly:
import * as THREE from 'three';
import { TerminalFrame, TerminalText } from 'cool-retro-term-renderer';
import { Terminal } from '@xterm/xterm';
const container = document.getElementById('terminal')!;
// Create your own Three.js scene
const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0.1, 10);
camera.position.z = 1;
// Create the renderer
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(0x000000);
container.appendChild(renderer.domElement);
// Create the terminal text renderer (handles character rendering and effects)
const terminalText = new TerminalText(window.innerWidth, window.innerHeight);
terminalText.mesh.position.z = 0;
scene.add(terminalText.mesh);
// Create the terminal frame (CRT bezel/border)
const terminalFrame = new TerminalFrame(window.innerWidth, window.innerHeight);
terminalFrame.mesh.position.z = 0.1;
scene.add(terminalFrame.mesh);
// Create XTerm instance (hidden, used as input handler)
const xterm = new Terminal({ cols: 80, rows: 24 });
const hiddenContainer = document.createElement('div');
hiddenContainer.style.position = 'absolute';
hiddenContainer.style.left = '-9999px';
document.body.appendChild(hiddenContainer);
xterm.open(hiddenContainer);
// Sync XTerm dimensions with the calculated terminal grid size
const gridSize = terminalText.getGridSize();
if (gridSize.cols > 0 && gridSize.rows > 0) {
xterm.resize(gridSize.cols, gridSize.rows);
}
// Listen for grid size changes and resize XTerm
terminalText.onGridSizeChange((cols, rows) => {
if (cols > 0 && rows > 0) {
xterm.resize(cols, rows);
}
});
// Handle window resize
window.addEventListener('resize', () => {
renderer.setSize(window.innerWidth, window.innerHeight);
terminalFrame.updateSize(window.innerWidth, window.innerHeight);
terminalText.updateSize(window.innerWidth, window.innerHeight);
});
// Animation loop
function animate() {
terminalText.updateTime(performance.now());
terminalText.renderStaticPass(renderer);
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();Low-Level Components
| Export | Description |
|--------|-------------|
| TerminalText | Renders terminal characters with CRT effects (shaders, bloom, etc.) |
| TerminalFrame | Renders the CRT monitor bezel/frame |
| XTermConnector | Syncs an XTerm.js buffer to TerminalText (optional helper) |
TerminalText Methods
| Method | Description |
|--------|-------------|
| getGridSize() | Get terminal dimensions { cols, rows } |
| onGridSizeChange(callback) | Register callback for grid size changes |
| updateSize(width, height) | Update renderer dimensions |
| updateTime(time) | Update time uniform for animated effects |
| renderStaticPass(renderer) | Render effects that don't change per-frame |
| setFontColor(color) | Set font color (hex string) |
| setBackgroundColor(color) | Set background color (hex string) |
| setScreenCurvature(value) | Set screen curvature (0-1) |
| setBloom(value) | Set bloom intensity (0-1) |
| setBrightness(value) | Set brightness (0-1) |
| setFlickering(value) | Set flickering intensity (0-1) |
| setStaticNoise(value) | Set static noise (0-1) |
| setBurnIn(value) | Set burn-in persistence (0-1) |
| setRasterizationMode(mode) | Set scanline mode (0-3) |
| dispose() | Clean up resources |
API Reference
CRTTerminal
The main class that creates the WebGL renderer and manages the CRT effect pipeline.
Constructor
new CRTTerminal(options: CRTTerminalSettings)CRTTerminalSettings
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| container | HTMLElement | required | The container element to render into |
| fontColor | string | "#0ccc68" | Font color in hex format (green) |
| backgroundColor | string | "#000000" | Background color in hex format |
| screenCurvature | number | 0.3 | Screen curvature amount (0-1) |
| rgbShift | number | 0 | RGB shift/chromatic aberration (0-0.01) |
| bloom | number | 0.5538 | Bloom intensity (0-1) |
| brightness | number | 0.5 | Brightness level (0-1) |
| ambientLight | number | 0.2 | Ambient light glow (0-1) |
| chromaColor | number | 0 | Chroma color (0=mono, 1=full color) |
| flickering | number | 0.1 | Flickering intensity (0-1) |
| horizontalSync | number | 0.08 | Horizontal sync distortion (0-1) |
| jitter | number | 0.1997 | Jitter/displacement (0-1) |
| staticNoise | number | 0.1198 | Static noise intensity (0-1) |
| glowingLine | number | 0.2 | Scanning beam intensity (0-1) |
| burnIn | number | 0.2517 | Phosphor burn-in persistence (0-1) |
| rasterizationMode | number | 1 | 0=none, 1=scanline, 2=pixel, 3=subpixel |
| rasterizationIntensity | number | 0.5 | Scanline intensity (0-1) |
Methods
| Method | Description |
|--------|-------------|
| attachXTerm(xterm: Terminal) | Attach an XTerm.js terminal instance |
| detachXTerm() | Detach the currently attached XTerm instance |
| getGridSize() | Get the terminal grid size { cols, rows } |
| focus() | Focus the attached XTerm terminal |
| dispose() | Clean up all resources |
Advanced Access
For advanced usage, you can access the underlying components:
crt.getTerminalText() // TerminalText renderer
crt.getRenderer() // THREE.WebGLRenderer
crt.getScene() // THREE.Scene
crt.getCamera() // THREE.OrthographicCameraVisual Effects
The library implements a two-pass rendering pipeline that replicates the visual characteristics of CRT monitors:
Static Pass (Pass 1)
- Screen curvature distortion
- RGB shift (chromatic aberration)
- Bloom (phosphor glow)
- Brightness adjustment
Dynamic Pass (Pass 2)
- Horizontal sync distortion
- Jitter (random displacement)
- Burn-in (phosphor persistence)
- Static noise
- Glowing line (scanning beam)
- Rasterization (scanlines)
- Flickering
- Ambient light
Examples
Custom Green Theme (Default)
const crt = new CRTTerminal({
container,
fontColor: '#0ccc68',
bloom: 0.6,
screenCurvature: 0.3,
});Amber Terminal
const crt = new CRTTerminal({
container,
fontColor: '#ffb000',
bloom: 0.5,
burnIn: 0.3,
});High-Fidelity CRT
const crt = new CRTTerminal({
container,
screenCurvature: 0.4,
flickering: 0.15,
horizontalSync: 0.1,
staticNoise: 0.15,
burnIn: 0.3,
rasterizationMode: 1,
rasterizationIntensity: 0.6,
});Minimal Effects
const crt = new CRTTerminal({
container,
screenCurvature: 0,
flickering: 0,
horizontalSync: 0,
jitter: 0,
staticNoise: 0,
burnIn: 0,
rasterizationMode: 0,
});Browser Support
Requires WebGL support. Works in all modern browsers:
- Chrome 56+
- Firefox 51+
- Safari 15+
- Edge 79+
Development
# Install dependencies
npm install
# Generate assets (fonts and textures)
npm run generate-assets
# Build the library
npm run build
# Build in watch mode
npm run dev
# Lint and format
npm run lint-and-formatLicense
GPL-3.0
Credits
This project is a port to WebGL from cool-retro-term by Filippo Scognamiglio.
This library uses the Terminus Font by Dimitar Zhekov, licensed under the SIL Open Font License (OFL).
