Files
doodle-mini/miniprogram/englishPages/shared/data/fontProfiles.ts
T

190 lines
6.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 字体渲染配置(Font Profile
*
* 不同手写字体的字形设计差异很大,同一 fontSize 下各字母的视觉高度、
* 基线位置各不相同。为每种字体维护一份 profile,按字母分类配置
* 缩放因子和 Y 轴偏移,保证字母在四线三格中视觉准确。
*
* 设计思路(参考 Excalidraw 的 hardcoded font metrics):
* - 缩放和偏移均为相对值(基于 gridH),换字体只需新增/调整 profile
* - 按字母分类给出默认值,可通过 letterOverrides 对单个字母做精细微调
*/
/** 字母分类 */
export type LetterCategory =
| 'uppercase'
| 'tallLower'
| 'descender'
| 'lowercase';
/** 单个分类的渲染参数 */
export interface CategoryMetrics {
/** fontSize = gridH * scale */
scale: number;
/** 基线 Y 偏移修正(相对于 gridH,正值=下移) */
baselineOffset: number;
}
/** 单个字母的渲染微调(覆盖所属分类的默认值) */
export interface LetterOverride {
scale?: number;
baselineOffset?: number;
}
/** 一套完整的字体渲染配置 */
export interface FontProfile {
/** 字体 URL */
url: string;
/** 各分类的默认渲染参数 */
categories: Record<LetterCategory, CategoryMetrics>;
/** 按字母精细微调(优先级高于分类默认值) */
letterOverrides?: Record<string, LetterOverride>;
}
// ── 字母分类集合 ──
const TALL_LOWERCASE = new Set(['b', 'd', 'h', 'k', 'l']);
const DESCENDERS = new Set(['g', 'p', 'q', 'y']);
export { TALL_LOWERCASE, DESCENDERS };
/** 判断字母所属分类 */
export function getLetterCategory(letter: string): LetterCategory {
if (letter >= 'A' && letter <= 'Z') return 'uppercase';
if (TALL_LOWERCASE.has(letter)) return 'tallLower';
if (DESCENDERS.has(letter)) return 'descender';
return 'lowercase';
}
/** 获取某个字母的最终渲染参数(分类默认 + 单字母微调合并) */
export function getLetterMetrics(
letter: string,
profile: FontProfile,
): CategoryMetrics {
const cat = getLetterCategory(letter);
const base = profile.categories[cat];
const override = profile.letterOverrides?.[letter];
if (!override) return base;
return {
scale: override.scale ?? base.scale,
baselineOffset: override.baselineOffset ?? base.baselineOffset,
};
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 字体配置表
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
/**
* 四线三格字母分类目标占位(所有字体通用):
* 顶线 ─── 第一格 ─── 中线 ─── 第二格 ─── 基线 ─── 第三格 ─── 底线
*
* uppercase / tallLower : 第一格 + 第二格(顶线 → 基线)
* descender (g,p,q,y) : 第二格 + 第三格(中线 → 底线)
* lowercase : 第二格(中线 → 基线)
*
* f / t / j 等需跨格占位的字母不在分类里单独建模,统一走 lowercase,
* 在 letterOverrides 里按字体微调(与 i 相同方式)。
*/
/** ZhiyongWrite 手写字体 */
export const ZHIYONG_WRITE: FontProfile = {
url: 'https://cdn.joeyone.cn/doodle/fonts/ZhiyongWrite.ttf',
categories: {
uppercase: { scale: 0.93, baselineOffset: 0 },
tallLower: { scale: 0.95, baselineOffset: 0 },
descender: { scale: 1.12, baselineOffset: 0.18 },
lowercase: { scale: 0.83, baselineOffset: 0.03 },
},
letterOverrides: {
i: { scale: 0.78, baselineOffset: 0.02 },
f: { scale: 1.37, baselineOffset: 0.34 },
t: { scale: 0.85, baselineOffset: 0 },
j: { scale: 1, baselineOffset: 0.15 },
},
};
/** Handlee Regular — Google 手写风格 */
export const HANDLEE_REGULAR: FontProfile = {
url: 'https://cdn.joeyone.cn/doodle/fonts/Handlee-Regular.ttf',
categories: {
uppercase: { scale: 0.9, baselineOffset: 0 },
tallLower: { scale: 0.73, baselineOffset: 0.03 },
descender: { scale: 0.8, baselineOffset: 0.05 },
lowercase: { scale: 0.73, baselineOffset: 0.02 },
},
letterOverrides: {
i: { scale: 0.78, baselineOffset: 0.02 },
f: { scale: 0.82, baselineOffset: 0 },
t: { scale: 0.77, baselineOffset: 0.04 },
j: { scale: 0.85, baselineOffset: 0.08 },
},
};
/** Print Clearly Regular */
export const PRINT_CLEARLY_REGULAR: FontProfile = {
url: 'https://cdn.joeyone.cn/doodle/fonts/print_clearly_regular_tt.ttf',
categories: {
uppercase: { scale: 0.95, baselineOffset: 0 },
tallLower: { scale: 0.95, baselineOffset: 0 },
descender: { scale: 1.05, baselineOffset: 0 },
lowercase: { scale: 0.85, baselineOffset: 0 },
},
letterOverrides: {
f: { scale: 1.35, baselineOffset: 0 },
t: { scale: 0.85, baselineOffset: 0 },
j: { scale: 1.15, baselineOffset: 0 },
},
};
/** Print Clearly Bold */
export const PRINT_CLEARLY_BOLD: FontProfile = {
url: 'https://cdn.joeyone.cn/doodle/fonts/print_clearly_bold_tt.ttf',
categories: {
uppercase: { scale: 0.95, baselineOffset: 0 },
tallLower: { scale: 0.95, baselineOffset: 0 },
descender: { scale: 1.05, baselineOffset: 0 },
lowercase: { scale: 0.85, baselineOffset: 0 },
},
letterOverrides: {
f: { scale: 1.35, baselineOffset: 0 },
t: { scale: 0.85, baselineOffset: 0 },
j: { scale: 1.15, baselineOffset: 0 },
},
};
/** Print Clearly Dashed — 虚线描红字体 */
export const PRINT_CLEARLY_DASHED: FontProfile = {
url: 'https://cdn.joeyone.cn/doodle/fonts/print_clearly_dashed_tt.ttf',
categories: {
uppercase: { scale: 0.95, baselineOffset: 0 },
tallLower: { scale: 0.95, baselineOffset: 0 },
descender: { scale: 1.05, baselineOffset: 0 },
lowercase: { scale: 0.85, baselineOffset: 0 },
},
letterOverrides: {
f: { scale: 1.35, baselineOffset: 0 },
t: { scale: 0.85, baselineOffset: 0 },
j: { scale: 1.15, baselineOffset: 0 },
},
};
/** Num 数字字体 */
export const NUM_FONT: FontProfile = {
url: 'https://cdn.joeyone.cn/doodle/fonts/num.woff2',
categories: {
uppercase: { scale: 0.95, baselineOffset: 0 },
tallLower: { scale: 0.95, baselineOffset: 0 },
descender: { scale: 1.05, baselineOffset: 0 },
lowercase: { scale: 0.85, baselineOffset: 0 },
},
letterOverrides: {
f: { scale: 1.35, baselineOffset: 0 },
t: { scale: 0.85, baselineOffset: 0 },
j: { scale: 1.15, baselineOffset: 0 },
},
};
/** 当前激活的字体配置(切换字体只需修改这里) */
// export const ACTIVE_FONT_PROFILE = ZHIYONG_WRITE;
export const ACTIVE_FONT_PROFILE = HANDLEE_REGULAR;