All files / web/src/lib server-canvas.ts

0% Statements 0/64
0% Branches 0/1
0% Functions 0/1
0% Lines 0/64

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65                                                                                                                                 
/**
 * Server-side canvas factory using @napi-rs/canvas.
 *
 * Registers the bundled Inter font at module load time so that
 * renderNumberLine() can produce identical output in Node.js.
 */

import { createCanvas, GlobalFonts } from '@napi-rs/canvas'
import path from 'node:path'
import fs from 'node:fs'

// Register Inter Variable font — try multiple paths for dev vs production.
// Also register under system font aliases so that renderNumberLine()'s
// hardcoded "-apple-system, BlinkMacSystemFont, ..." font stack resolves
// to Inter instead of producing garbled glyphs.
const candidates = [
  path.join(process.cwd(), 'src', 'lib', 'fonts', 'Inter-Variable.ttf'),
  path.join(process.cwd(), 'apps', 'web', 'src', 'lib', 'fonts', 'Inter-Variable.ttf'),
]
const FONT_ALIASES = [
  'Inter',
  '-apple-system',
  'BlinkMacSystemFont',
  'Segoe UI',
  'Roboto',
  'sans-serif',
]
for (const fontPath of candidates) {
  if (fs.existsSync(fontPath)) {
    for (const alias of FONT_ALIASES) {
      GlobalFonts.registerFromPath(fontPath, alias)
    }
    break
  }
}

// Register an emoji font so that emoji characters (🎯, 🌟, etc.) render
// instead of showing NOGLYPH boxes. Try platform-specific paths.
const emojiFontCandidates = [
  // macOS
  '/System/Library/Fonts/Apple Color Emoji.ttc',
  // Linux (common locations)
  '/usr/share/fonts/truetype/noto/NotoColorEmoji.ttf',
  '/usr/share/fonts/noto-emoji/NotoColorEmoji.ttf',
  // Bundled fallback
  path.join(process.cwd(), 'src', 'lib', 'fonts', 'NotoColorEmoji.ttf'),
  path.join(process.cwd(), 'apps', 'web', 'src', 'lib', 'fonts', 'NotoColorEmoji.ttf'),
]
for (const emojiPath of emojiFontCandidates) {
  if (fs.existsSync(emojiPath)) {
    GlobalFonts.registerFromPath(emojiPath, 'Emoji')
    break
  }
}

/** Font family name to use in server-side Canvas 2D `ctx.font` strings. */
export const SERVER_FONT = 'Inter'

/** Create a server-side Canvas 2D surface backed by @napi-rs/canvas. */
export function createServerCanvas(width: number, height: number) {
  return createCanvas(width, height)
}

export { GlobalFonts }