Last active
January 3, 2026 06:07
-
-
Save whexy/445d78035eea2f8f1e320c2c1d1c214a to your computer and use it in GitHub Desktop.
Cloudflare Tunnel SSH (browser rendering) Terminal (xterm.js) Font Override (monkey patch)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==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); | |
| })(); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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).