feat(desktop): embed BoosAPI Desktop client as a subproject

Vendor the rebranded BoosAPI Desktop client (Tauri + Vue) into metapi as
a monorepo subdirectory under desktop/. Source only — node_modules,
dist, Cargo target and the upstream .git history are excluded.

desktop/ keeps its own independent Cargo workspace (desktop/src-tauri
with crates/*); it is not part of the backend boosapi crate, so a
`cargo check` at the metapi root still compiles only the backend. Build
the desktop app from desktop/src-tauri per desktop/README.md.

Note: app icons are still placeholder assets pending the final BoosAPI
logo. The updater signing keys live outside the repo and are not
included.
This commit is contained in:
boos
2026-06-22 11:32:57 +08:00
parent d9c78ecc73
commit e0a5f57793
2305 changed files with 449355 additions and 0 deletions
@@ -0,0 +1,102 @@
#!/usr/bin/env node
/**
* Measure KaTeX render time and recommend a worker threshold N
* N ≈ B / (R × (1 - H))
* - B: main-thread budget (ms) — defaults to 50ms and 16.7ms
* - R: avg render time per unique formula (ms)
* - H: cache hit rate (0~1). For first paint assume H=0
*/
import { performance } from 'node:perf_hooks'
import process from 'node:process'
async function getKatex() {
try {
const k = await import('katex')
return k.default || k
}
catch {
console.error('[measure-katex-threshold] KaTeX not installed. pnpm add katex -D')
process.exit(1)
}
}
const FORMULAS = {
simple: [
'x',
'a + b',
'E = mc^2',
],
medium: [
'\\sum_{i=1}^{n} i = \\frac{n(n+1)}{2}',
'\\frac{a}{b} + \\sqrt{x}',
'\\lim_{x \\to 0} \\frac{\\sin x}{x}',
],
complex: [
'\\int_{-\\infty}^{\\infty} e^{-x^2} \\, dx = \\sqrt{\\pi}',
'\\begin{pmatrix} a & b \\\\ c & d \\end{pmatrix}',
'\\frac{d}{dx}\\left(\\int_{a}^{x} f(t)\\,dt\\right) = f(x)',
],
}
function bench(katex, formulas, iterations = 50) {
// warm-up
for (let i = 0; i < 10; i++) {
for (const f of formulas) katex.renderToString(f, { throwOnError: false, displayMode: true })
}
const start = performance.now()
for (let i = 0; i < iterations; i++) {
for (const f of formulas) katex.renderToString(f, { throwOnError: false, displayMode: true })
}
const end = performance.now()
const total = end - start
const renders = iterations * formulas.length
return { avg: total / renders, total, renders }
}
function recommend({ R, H = 0, B = 50 }) {
const denom = R * (1 - H) || 1e-6
const N = B / denom
return Math.max(1, Math.floor(N))
}
function fmt(n, digits = 2) {
return Number(n).toFixed(digits)
}
(async () => {
const katex = await getKatex()
const s = bench(katex, FORMULAS.simple)
const m = bench(katex, FORMULAS.medium)
const c = bench(katex, FORMULAS.complex)
const rec50 = {
simple: recommend({ R: s.avg, B: 50 }),
medium: recommend({ R: m.avg, B: 50 }),
complex: recommend({ R: c.avg, B: 50 }),
}
const rec16 = {
simple: recommend({ R: s.avg, B: 16.7 }),
medium: recommend({ R: m.avg, B: 16.7 }),
complex: recommend({ R: c.avg, B: 16.7 }),
}
console.log('\nKaTeX Rendering Benchmark (ms per render)')
console.table({
simple: fmt(s.avg),
medium: fmt(m.avg),
complex: fmt(c.avg),
})
console.log('\nRecommended worker thresholds (N = floor(B / R))')
console.table({
'B=50ms (no cache)': rec50,
'B=16.7ms (no cache)': rec16,
})
console.log('\nNotes:')
console.log('- Thresholds are for first paint (H=0). With cache, N increases roughly by 1/(1-H).')
console.log('- Use medium thresholds as default. Drop to complex thresholds if many matrices/integrals.')
console.log('- If your content is very simple, you can raise the threshold accordingly.')
})()