feat(players): app Players library and circular NPC tokens on scenes
Add userData players/teams, scene npcTokens with hex-inscribed sizing, session scale synced to presentation, and Playwright e2e coverage. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
||||
asNpcRelationId,
|
||||
asProjectId,
|
||||
asSceneId,
|
||||
asSceneNpcTokenId,
|
||||
asTokenId,
|
||||
} from '../types/ids';
|
||||
|
||||
@@ -291,6 +292,15 @@ export function buildPartialExportProject(
|
||||
npcs: exportedNpcs.map((n) => ({ ...n })),
|
||||
npcGroups: exportedGroups.map((g) => ({ ...g })),
|
||||
npcRelations: exportedRelations.map((r) => ({ ...r })),
|
||||
scenes: Object.fromEntries(
|
||||
Object.entries(draft.scenes).map(([sid, sc]) => [
|
||||
sid,
|
||||
{
|
||||
...sc,
|
||||
npcTokens: (sc.npcTokens ?? []).filter((t) => exportedNpcIds.has(t.npcId)),
|
||||
},
|
||||
]),
|
||||
) as Project['scenes'],
|
||||
};
|
||||
|
||||
const assetIds = collectReferencedAssetIdsForProject(draft);
|
||||
@@ -686,11 +696,38 @@ export function mergeStorylinesIntoProject(
|
||||
x: n.x,
|
||||
y: n.y,
|
||||
groupId: mappedGroupId && npcGroups.some((g) => g.id === mappedGroupId) ? mappedGroupId : null,
|
||||
ringColor: n.ringColor ?? '#c9a227',
|
||||
imageOffset: n.imageOffset ?? { x: 0, y: 0 },
|
||||
imageScale: typeof n.imageScale === 'number' && Number.isFinite(n.imageScale) ? n.imageScale : 1,
|
||||
});
|
||||
npcNameKeys.add(name.toLowerCase());
|
||||
npcsCreated += 1;
|
||||
}
|
||||
|
||||
// Remap npcTokens on newly created scenes to imported NPC ids.
|
||||
for (const sid of sourceSceneIds) {
|
||||
const res = resolutionBySource.get(sid);
|
||||
if (res?.mode === 'use') continue;
|
||||
const newSid = sceneIdMap.get(sid);
|
||||
if (!newSid) continue;
|
||||
const sc = scenes[newSid];
|
||||
if (!sc) continue;
|
||||
scenes[newSid] = {
|
||||
...sc,
|
||||
npcTokens: (sc.npcTokens ?? [])
|
||||
.map((t) => {
|
||||
const mappedNpc = npcIdMap.get(t.npcId);
|
||||
if (!mappedNpc) return null;
|
||||
return {
|
||||
...t,
|
||||
id: asSceneNpcTokenId(`snt_${generateId()}`),
|
||||
npcId: asNpcId(mappedNpc),
|
||||
};
|
||||
})
|
||||
.filter((t): t is NonNullable<typeof t> => Boolean(t)),
|
||||
};
|
||||
}
|
||||
|
||||
const npcRelations = [...(target.npcRelations ?? [])];
|
||||
const exportedNpcIdSet = new Set(exportedNpcs.map((n) => n.id));
|
||||
for (const r of source.npcRelations ?? []) {
|
||||
|
||||
Reference in New Issue
Block a user