Files
multica/apps/desktop/package.json
Jiayuan Zhang 4f70480039 fix(typography): real Inter italic + variable Geist Mono on desktop (MUL-5449) (#6105)
* fix(typography): load real Inter italic on web and desktop (MUL-5449)

Neither platform loaded an Inter italic face: next/font defaults to
`style: ["normal"]`, and desktop imported `@fontsource-variable/inter`
without `wght-italic.css`. Every `italic` in the product was therefore
browser-synthesized oblique — the ~20 semantic UI labels (chat empty
states, model-picker's "Managed by runtime", dashboard/squad
placeholders) plus all markdown <em> and blockquotes, which are user
content.

Load the real face on both, mirroring how Source Serif 4 is already
wired.

Also set `font-synthesis: style` on html, which forbids weight synthesis
while leaving style synthesis on. Weight synthesis is pure loss now that
every loaded face has real weights, and it is actively harmful on the CJK
tail of --font-sans: `font-bold` against PingFang SC (which stops at
Semibold) makes Chromium smear a fake 700 that closes up the counters of
dense Han glyphs.

Style synthesis stays on deliberately. `auto` only synthesizes when no
real italic matches, so the newly loaded Inter Italic already wins for
Latin. The only stacks still synthesizing are the two that ship no italic
at all — CJK fallbacks and Geist Mono — where `font-style: italic` has no
other visual carrier; a blanket `font-synthesis: none` would silently
flatten every Chinese <em>, every editor italic mark and every hljs
comment to upright.

Co-authored-by: multica-agent <github@multica.ai>

* fix(typography): give desktop the variable Geist Mono (MUL-5449)

Web gets a variable Geist Mono from next/font (`font-weight: 100 900`,
verified in the emitted CSS), but desktop loaded only the discrete 400
and 700 cuts. Any weight in between silently snapped to the nearest one
desktop had, so the same shared component rendered at two different
weights on the two platforms:

- `font-mono font-medium` (500) fell back to 400 in chart.tsx,
  webhook-event-filter-section.tsx and keyboard-shortcuts-tab.tsx.
- Inline <code> in rendered markdown has no explicit weight, so inside a
  <strong>, heading or <th> — all `font-semibold` — it inherits 600 and
  resolved up to 700.

Loading `@fontsource/geist-mono/500.css` would have fixed only the first
of those. Switching to `@fontsource-variable/geist-mono` covers 100-900
in one file and closes the whole class, matching how Inter and Source
Serif 4 are already wired on desktop.

The latin subset is also smaller than the two static cuts it replaces:
22.6 KB vs 14.4 + 14.9 KB.

Co-authored-by: multica-agent <github@multica.ai>

* docs(typography): correct stale Geist Mono note in font-synthesis comment

The comment was written when desktop still loaded discrete 400/700 cuts.
The following commit swapped desktop to @fontsource-variable/geist-mono,
so Geist Mono is now variable on both platforms and the "ships discrete
cuts" clause was false. Also name landing's 400-only Instrument Serif so
the "every face we load has real weights" claim is complete.

Co-authored-by: multica-agent <github@multica.ai>

---------

Co-authored-by: Lambda <lambda@multica.ai>
Co-authored-by: multica-agent <github@multica.ai>
2026-07-29 16:29:05 +08:00

82 lines
2.7 KiB
JSON

{
"name": "@multica/desktop",
"productName": "Multica",
"version": "0.1.0",
"private": true,
"description": "Multica Desktop — native desktop client for the Multica platform.",
"homepage": "https://multica.ai",
"repository": {
"type": "git",
"url": "https://github.com/multica-ai/multica.git",
"directory": "apps/desktop"
},
"author": {
"name": "Multica",
"email": "support@multica.ai"
},
"license": "UNLICENSED",
"main": "./out/main/index.js",
"scripts": {
"bundle-cli": "node scripts/bundle-cli.mjs",
"brand-dev-electron": "node scripts/brand-dev-electron.mjs",
"dev": "node scripts/dev.mjs",
"dev:staging": "node scripts/dev.mjs --mode staging",
"build": "pnpm run bundle-cli && electron-vite build",
"typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
"typecheck:web": "tsc --noEmit -p tsconfig.web.json --composite false",
"typecheck": "pnpm run typecheck:node && pnpm run typecheck:web",
"preview": "electron-vite preview",
"package": "node scripts/package.mjs",
"package:all": "node scripts/package.mjs --all-platforms --publish never",
"lint": "eslint .",
"test": "vitest run",
"postinstall": "electron-builder install-app-deps"
},
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/modifiers": "^9.0.0",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@electron-toolkit/preload": "^3.0.2",
"@electron-toolkit/utils": "^4.0.0",
"@fontsource-variable/geist-mono": "^5.3.0",
"@fontsource-variable/inter": "^5.2.5",
"@fontsource-variable/source-serif-4": "^5.2.9",
"@multica/core": "workspace:*",
"@multica/ui": "workspace:*",
"@multica/views": "workspace:*",
"@tanstack/react-query": "catalog:",
"electron-updater": "^6.8.3",
"fix-path": "^5.0.0",
"lucide-react": "catalog:",
"motion": "^12.38.0",
"react": "catalog:",
"react-dom": "catalog:",
"react-router-dom": "^7.6.0",
"shadcn": "^4.1.0",
"sonner": "^2.0.7",
"tw-animate-css": "^1.4.0",
"zustand": "catalog:"
},
"devDependencies": {
"@electron-toolkit/tsconfig": "^2.0.0",
"@multica/eslint-config": "workspace:*",
"@multica/tsconfig": "workspace:*",
"@tailwindcss/vite": "^4",
"@testing-library/jest-dom": "catalog:",
"@testing-library/react": "catalog:",
"@types/node": "catalog:",
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
"@vitejs/plugin-react": "^5.1.1",
"electron": "^39.2.6",
"electron-builder": "^26.0.12",
"electron-vite": "^5.0.0",
"globals": "^16.0.0",
"jsdom": "catalog:",
"tailwindcss": "^4",
"typescript": "catalog:",
"vitest": "catalog:"
}
}