Skip to content

Instantly share code, notes, and snippets.

@whexy
Last active January 3, 2026 06:07
Show Gist options
  • Select an option

  • Save whexy/445d78035eea2f8f1e320c2c1d1c214a to your computer and use it in GitHub Desktop.

Select an option

Save whexy/445d78035eea2f8f1e320c2c1d1c214a to your computer and use it in GitHub Desktop.
Cloudflare Tunnel SSH (browser rendering) Terminal (xterm.js) Font Override (monkey patch)
// ==UserScript==
// @name Cloudflare xterm.js Font Override
// @namespace cf-xterm-font-override
// @version 1.0.0
// @description Force a custom monospace font in Cloudflare browser terminals by intercepting CanvasRenderingContext2D.font
// @match https://*/cdn-cgi/access/*
// @run-at document-start
// @grant none
// ==/UserScript==
(() => {
'use strict';
/* =========================
* Configuration
* ========================= */
const FONT_FAMILY = `"JetBrains Mono","Fira Code","SF Mono",Menlo,monospace`;
/* =========================
* Helpers
* ========================= */
function isXtermCanvas(canvas) {
if (!canvas || canvas.nodeType !== 1) return false;
if (typeof canvas.className === 'string' && canvas.className.includes('xterm-')) {
return true;
}
return !!canvas.closest?.('.xterm');
}
function rewriteFont(font) {
if (typeof font !== 'string') return font;
// Match everything up through the font-size token, replace family only
const m = font.match(/^(.*?\d+(?:\.\d+)?(?:px|pt|em|rem)(?:\/\d+(?:\.\d+)?)?\s+).+$/i);
return m ? `${m[1]}${FONT_FAMILY}` : font;
}
/* =========================
* Canvas font monkey-patch
* ========================= */
const originalGetContext = HTMLCanvasElement.prototype.getContext;
HTMLCanvasElement.prototype.getContext = function (type, ...args) {
const ctx = originalGetContext.call(this, type, ...args);
if (!ctx || type !== '2d' || ctx.__xtermFontPatched) return ctx;
ctx.__xtermFontPatched = true;
const canvas = this;
let currentFont = ctx.font;
Object.defineProperty(ctx, 'font', {
configurable: true,
enumerable: true,
get() {
return currentFont;
},
set(value) {
const patched = isXtermCanvas(canvas) ? rewriteFont(value) : value;
currentFont = patched;
// Forward to native setter if it exists
const proto = Object.getPrototypeOf(ctx);
const desc = proto && Object.getOwnPropertyDescriptor(proto, 'font');
if (desc?.set) {
desc.set.call(ctx, patched);
}
}
});
// Re-apply initial font if already set
ctx.font = currentFont;
return ctx;
};
/* =========================
* Optional CSS assist
* (measurement element only)
* ========================= */
const style = document.createElement('style');
style.textContent = `
.xterm .xterm-char-measure-element {
font-family: ${FONT_FAMILY} !important;
}
`;
(document.head || document.documentElement).appendChild(style);
})();
@whexy
Copy link
Author

whexy commented Jan 3, 2026

This monkey patch (you can load it via Tampermonkey) can hook canvas events, so it can modify the font. Works well on Cloudflare browser rendered shell (tunnel SSH).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment