Skip to content

Commit be16624

Browse files
committed
feat: add bundle format versioning
1 parent 1ce1324 commit be16624

11 files changed

Lines changed: 57 additions & 4 deletions

File tree

.changeset/bundle-version.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"tegaki": minor
3+
---
4+
5+
Add bundle format versioning. Generated bundles now include a `version` field (currently `0`) so the engine can detect incompatible bundles. The engine checks the version when a bundle is registered or resolved and logs a console warning (once per bundle) if the version is missing or unsupported.
6+
7+
New exports: `BUNDLE_VERSION`, `COMPATIBLE_BUNDLE_VERSIONS`. New optional `TegakiBundle` field: `version`. Existing bundles without a version field trigger the warning but continue to work.

packages/generator/src/commands/generate.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import opentype from 'opentype.js';
2-
import type { BBox, FontOutput, LineCap, Point, Stroke } from 'tegaki';
2+
import { type BBox, BUNDLE_VERSION, type FontOutput, type LineCap, type Point, type Stroke } from 'tegaki';
33
import * as z from 'zod/v4';
44
import {
55
charsHash,
@@ -499,6 +499,7 @@ function generateGlyphsModule(
499499
if (hasFull) fontFaceRules.push(`@font-face { font-family: '${esc(fullFamily)}'; src: url(\${fullFontUrl}); }`);
500500

501501
const props = [
502+
` version: ${BUNDLE_VERSION},`,
502503
` family: '${esc(fontFamily)}',`,
503504
...(hasFull ? [` fullFamily: '${esc(fullFamily)}',`] : []),
504505
` lineCap: '${lineCap}',`,

packages/renderer/fonts/caveat/bundle.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import fullFontUrl from './caveat.ttf' with { type: 'url' };
44
import glyphData from './glyphData.json' with { type: 'json' };
55

66
const bundle = {
7+
version: 0,
78
family: 'Caveat Tegaki 3dc76002',
89
fullFamily: 'Caveat',
910
lineCap: 'round',

packages/renderer/fonts/italianno/bundle.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import fullFontUrl from './italianno.ttf' with { type: 'url' };
44
import glyphData from './glyphData.json' with { type: 'json' };
55

66
const bundle = {
7+
version: 0,
78
family: 'Italianno Tegaki 3dc76002',
89
fullFamily: 'Italianno',
910
lineCap: 'round',

packages/renderer/fonts/parisienne/bundle.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import fullFontUrl from './parisienne.ttf' with { type: 'url' };
44
import glyphData from './glyphData.json' with { type: 'json' };
55

66
const bundle = {
7+
version: 0,
78
family: 'Parisienne Tegaki 3dc76002',
89
fullFamily: 'Parisienne',
910
lineCap: 'round',

packages/renderer/fonts/tangerine/bundle.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import fullFontUrl from './tangerine.ttf' with { type: 'url' };
44
import glyphData from './glyphData.json' with { type: 'json' };
55

66
const bundle = {
7+
version: 0,
78
family: 'Tangerine Tegaki 3dc76002',
89
fullFamily: 'Tangerine',
910
lineCap: 'round',

packages/renderer/src/core/bundle-registry.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
1-
import type { TegakiBundle } from '../types.ts';
1+
import { COMPATIBLE_BUNDLE_VERSIONS, type TegakiBundle } from '../types.ts';
22

33
const bundles = new Map<string, TegakiBundle>();
4+
const warnedBundles = new Set<TegakiBundle>();
5+
6+
function checkBundleVersion(bundle: TegakiBundle): void {
7+
if (warnedBundles.has(bundle)) return;
8+
if (bundle.version == null || !COMPATIBLE_BUNDLE_VERSIONS.has(bundle.version)) {
9+
warnedBundles.add(bundle);
10+
console.warn(
11+
`[tegaki] Bundle "${bundle.family}" has version ${bundle.version ?? 'undefined'}, ` +
12+
`but this engine supports versions [${[...COMPATIBLE_BUNDLE_VERSIONS].join(', ')}]. ` +
13+
'The bundle may not render correctly. Regenerate it with a compatible version of tegaki-generator.',
14+
);
15+
}
16+
}
417

518
/** Register a font bundle so it can be referenced by family name. */
619
export function registerBundle(bundle: TegakiBundle): void {
20+
checkBundleVersion(bundle);
721
bundles.set(bundle.family, bundle);
822
}
923

@@ -18,5 +32,6 @@ export function resolveBundle(font: TegakiBundle | string | undefined): TegakiBu
1832
if (!bundle) throw new Error(`TegakiEngine: no bundle registered for "${font}". Call TegakiEngine.registerBundle() first.`);
1933
return bundle;
2034
}
35+
if (font) checkBundleVersion(font);
2136
return font;
2237
}

packages/renderer/src/core/createBundle.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { LineCap, TegakiBundle, TegakiGlyphData } from '../types.ts';
1+
import { BUNDLE_VERSION, type LineCap, type TegakiBundle, type TegakiGlyphData } from '../types.ts';
22

33
/**
44
* Creates a {@link TegakiBundle} from its constituent parts.
@@ -41,6 +41,7 @@ export function createBundle({
4141
rules.push(`@font-face { font-family: '${fullFamily}'; src: url(${fullFontUrl}); }`);
4242
}
4343
return {
44+
version: BUNDLE_VERSION,
4445
family,
4546
fullFamily,
4647
lineCap,

packages/renderer/src/core/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export { computeTextLayout, type TextLayout } from '../lib/textLayout.ts';
55
export { computeTimeline, type Timeline, type TimelineConfig, type TimelineEntry } from '../lib/timeline.ts';
66
export type * from '../types.ts';
77
export type { TegakiEffectConfigs, TegakiEffects } from '../types.ts';
8+
export { BUNDLE_VERSION, COMPATIBLE_BUNDLE_VERSIONS } from '../types.ts';
89
export { getBundle, registerBundle, resolveBundle } from './bundle-registry.ts';
910
export { createBundle } from './createBundle.ts';
1011
export { TegakiEngine } from './engine.ts';

packages/renderer/src/types.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
/**
2+
* Current bundle format version. Incremented when the bundle format changes
3+
* in a way that older engines cannot consume.
4+
*/
5+
export const BUNDLE_VERSION = 0;
6+
7+
/**
8+
* Set of bundle versions that this engine can consume. The engine logs a
9+
* console warning (once per bundle) when it encounters a version outside
10+
* this set.
11+
*/
12+
export const COMPATIBLE_BUNDLE_VERSIONS: ReadonlySet<number> = new Set([BUNDLE_VERSION]);
13+
114
export type LineCap = 'round' | 'butt' | 'square';
215

316
export interface Point {
@@ -108,6 +121,8 @@ export type TegakiEffects<T> = {
108121
};
109122

110123
export interface TegakiBundle {
124+
/** Bundle format version. Used by the engine to warn about incompatible bundles. */
125+
version?: number;
111126
family: string;
112127
/**
113128
* Original font family name, used as a CSS fallback for characters not in

0 commit comments

Comments
 (0)