Skip to main content

Headless X server

ntk apps can run without any real X server: node-x11 (x11 >= 3.1.0) ships a pure-JS X server with the XRender extension built in — everything ntk's rendering model needs. Connect ntk to an in-process server over a stream pair:

import { createClient } from 'ntk';
import xserver from 'x11/lib/xserver/index.js';

const { createServer, createStreamPair } = xserver;

const server = createServer({ width: 640, height: 480 });
const [serverEnd, clientEnd] = createStreamPair();
server.addClientStream(serverEnd);

const app = await createClient({ stream: clientEnd, fontSource });

Everything the 2d context does — path fills (trapezoids), text (glyphsets), gradients, drawImage (picture transforms + bilinear filtering), Porter-Duff composite ops, clipping and globalAlpha masks — renders into the server's in-memory rasters. Read pixels back with ctx.getImageData / GetImage, or composite the screen with server.compose() and present server.root.raster yourself (this is what the browser playground draws to a canvas via node-x11's CanvasPresenter).

Use a StaticFontSource so text works without fontconfig; the node-x11 server keeps no timers, so tests only need await app.close().

Rasterization is antialiased but intentionally not pixel-exact with Xorg — assert on regions/tolerances, not exact edge pixels (see test/xserver.test.js for the patterns; that suite runs ntk end-to-end against this server with no $DISPLAY and no fontconfig).