Skip to content

Tech Stack & Rendering Pipeline

Michael Voitovich edited this page Jun 16, 2026 · 2 revisions

The Scanline Engine is built upon a modern, robust web stack designed to ensure high performance and developer ergonomics while faithfully emulating the aesthetic of 1980s CRT monitors. It strictly decouples the game's internal state, semantic text models, and visual presentation.

Here is an in-depth look at the technological foundation, the hybrid rendering pipeline, and the Entity-Component System (ECS) architecture.

1. Core Foundation: React, Vite, and TypeScript

The engine utilizes a modern frontend toolchain to maintain a scalable and easily debuggable codebase:

  • TypeScript: Acts as the primary language for the entire engine and its scripting system. TypeScript is crucial for ensuring type safety across the complex spatial hierarchy, parser resolution, and component data structures.
  • Vite: Powers the build system and local development server. Vite's Hot Module Replacement (HMR) enables rapid iteration, which is particularly beneficial for the hot-reloadable TypeScript scripting system (src/scripts/) that applies gameplay logic changes instantly without requiring a page refresh.
  • React: While the game itself renders to an HTML5 Canvas, React is used extensively for the overarching user interface. This includes the highly interactive Scene Editor and Sprite Editor overlays, as well as the high-resolution "open" text console. By using React and Zustand for immutable UI state management, the engine separates complex DOM updates from the mutable Game singleton and its main render loop.

2. Hybrid Rendering Pipeline

The 2.5D Displacement Model

Objects in the world share standard absolute (X, Y) coordinates, but their visual positions on the screen are dynamically calculated using a 2.5D displacement model . The formula VisualPos = RawPos - Camera * (P - 1) uses a "Parallax Factor" (P) to create a deep, multi-layered environment . Backgrounds move slower than foreground objects, simulating 3D depth. The Render Pass Sequence The rendering logic is isolated in SceneRenderer.ts, which acts as a stateless function taking the current Scene and context to draw the frame without holding state itself. The pipeline executes in the following order:

  • Parallax Setup & Stable Sorting: The engine prepares the context for different depth layers. Entities are sorted stably first by their authored Layer and then by their Screen Space Depth (Visual Y) to ensure correct foreground/background occlusion.
  • Low-Res Canvas2D Buffer: The sorted scene entities (including parallax layers, backgrounds, actors, and the "closed" gameplay command line) are drawn onto a low-resolution HTML5 Canvas2D buffer.
  • WebGL CRT Post-Processing: This 2D buffer is then uploaded as a texture into a WebGL pipeline.
  • A specialized CRT shader applies retro post-processing effects, including screen curvature, chromatic aberrations, scanlines, and a gray background to simulate vintage hardware.
  • React UI & High-Res Overlays: Finally, the React-based UI, editor tooling (like selection handles and debug Walkboxes), and the "open" multi-line text console are rendered as a separate layer over the WebGL canvas. This guarantees that while the game world looks appropriately distorted and low-resolution, massive blocks of text and developer tools remain crisp and readable.

3. Entity-Component System (ECS) Architecture

Scanline structures its game objects using a hybrid Object-Oriented and Entity-Component System approach.

Entity Class Hierarchy

All objects in a scene derive from the base class SceneObject.

PolygonObject: Invisible technical areas that define mechanics, including Walkbox (traversable navigation mesh) and Triggerbox (zones that execute scripts or scene transitions). QuadObject: Four-vertex polygons used to create 2.5D perspective surfaces (like floors and walls) with independent per-vertex parallax, shadowing, and retro-grid rendering. Entity / Static: The standard game object with a sprite, dimensions, coordinates, and layer data. Actor: Extends Entity to add pathfinding, movement speed, animation sets, directional sprites, and the ability to act as the player or an AI-driven NPC.

The Component Model & Type Safety

Rather than relying on deep inheritance trees for gameplay logic, objects attach functional Components. A major architectural refactor introduced strict type safety to this system: the components array utilizes a strict AnyComponent TypeScript union type instead of generic any[] arrays, drastically reducing runtime errors and malformed data.

Standard components include:

  • Subscene: Creates modal "close-up" views of areas, activating specific child objects.
  • Switch / Blocker: Controls the visibility and semantic actionability of spatial children.
  • State: Exposes arbitrary scriptable properties (e.g., power: 'on') that automatically dispatch script events through the StateEventSystem upon mutation.
  • Inventory / Surface: Explicitly defines storage capacity and spatial rules for holding nested items.

The "Actor" Component Marker

An interesting quirk of the Scanline ECS is how it handles the Actor class in the editor. To provide a smooth authoring experience, the editor treats "Actor" as a component marker. If a user attaches the Actor component to a standard Static entity, the editor safely transforms the base class into an Actor instance under the hood, instantly granting it directional sprites and animation sets without breaking the object's identity. Removing the Actor component prompts a destructive confirmation dialog, and if accepted, the engine strips away actor-only properties (like shadows, speeds, and animation states) and safely reverts the object back to a Static entity. Currently, this acts as a powerful editor conversion affordance while retaining the Actor extends Entity class hierarchy in the runtime code.

Clone this wiki locally