feat(web): finish RE 5000PBR lesson video and fix non-ASCII GLB import
- Add 11:07 Chinese-narrated lesson video, VTT, poster and 13 chapter screenshots. - Regenerate 20-render WebGL2 matrix and 15 operation captures on RTX 4060. - Fix WASM staging for non-ASCII import filenames (猴头.glb); rebuild web_engine. - Harden lesson video recording pipeline; fix stale lesson-link E2E selector. - Add RE PBR derived libraries, lesson page, evidence and status report. Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -472,3 +472,52 @@ export async function createAssetCatalogManifestV2FromDesktop(value: unknown, re
|
||||
const manifest = { schemaVersion: ASSET_CATALOG_SCHEMA, revision, catalogs, assets, libraries: [] };
|
||||
return parseAssetCatalogManifestV2(manifest);
|
||||
}
|
||||
|
||||
export interface AssetCatalogMergeResult {
|
||||
manifest: AssetCatalogManifestV2IR;
|
||||
conflicts: string[];
|
||||
added: { catalogs: number; assets: number; libraries: number };
|
||||
}
|
||||
|
||||
/** Merge an independently generated library into the existing global catalog. */
|
||||
export async function mergeAssetCatalogManifests(existingValue: unknown, incomingValue: unknown): Promise<AssetCatalogMergeResult> {
|
||||
const existing = await parseAssetCatalogManifestV2(existingValue);
|
||||
const incoming = await parseAssetCatalogManifestV2(incomingValue);
|
||||
const conflicts: string[] = [];
|
||||
const mergeList = <T>(base: readonly T[], extra: readonly T[], key: (value: T) => string, label: string): T[] => {
|
||||
const merged = new Map(base.map((value) => [key(value), value]));
|
||||
for (const value of extra) {
|
||||
const id = key(value);
|
||||
const current = merged.get(id);
|
||||
if (!current) {
|
||||
merged.set(id, structuredClone(value) as T);
|
||||
} else if (JSON.stringify(current) !== JSON.stringify(value)) {
|
||||
conflicts.push(`${label}:${id}`);
|
||||
}
|
||||
}
|
||||
return [...merged.values()];
|
||||
};
|
||||
const catalogs = mergeList(existing.catalogs, incoming.catalogs, (value) => value.catalogId, "catalog");
|
||||
const assets = mergeList(existing.assets, incoming.assets, (value) => value.assetId, "asset");
|
||||
const libraries = mergeList(existing.libraries, incoming.libraries, (value) => value.libraryId, "library");
|
||||
const revision = Math.max(existing.revision, incoming.revision) + 1;
|
||||
if (revision > Number.MAX_SAFE_INTEGER) {
|
||||
throw new AssetCatalogV2ValidationError("ASSET_BUDGET_EXCEEDED", "asset catalog revision overflow");
|
||||
}
|
||||
const manifest = await parseAssetCatalogManifestV2({
|
||||
schemaVersion: ASSET_CATALOG_SCHEMA,
|
||||
revision,
|
||||
catalogs,
|
||||
assets,
|
||||
libraries,
|
||||
});
|
||||
return {
|
||||
manifest,
|
||||
conflicts,
|
||||
added: {
|
||||
catalogs: catalogs.length - existing.catalogs.length,
|
||||
assets: assets.length - existing.assets.length,
|
||||
libraries: libraries.length - existing.libraries.length,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user