perf: Minify JSON save keys to reduce serialized state size
Replace verbose key names with short identifiers in collectData/applyData (e.g. name→n, zenit→z, heroicSkills→hs). Nested bond, class, and spell objects are mapped at the boundary so in-memory state and rendering code are unchanged. applyData uses ?? fallbacks to remain compatible with data saved under the old key names. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -248,35 +248,54 @@ function addSpell() { spells.push({}); renderSpells(); }
|
|||||||
function removeSpell(i) { spells.splice(i, 1); renderSpells(); }
|
function removeSpell(i) { spells.splice(i, 1); renderSpells(); }
|
||||||
|
|
||||||
// ── SAVE / LOAD ────────────────────────────────────
|
// ── SAVE / LOAD ────────────────────────────────────
|
||||||
|
// Short key legend (serialized form only; in-memory objects use full names):
|
||||||
|
// n=name, pn=pronouns, id=identity, th=theme, og=origin, tr=traits
|
||||||
|
// lv=level, xp=xp, z=zenit
|
||||||
|
// im=initMod, df=defense, md=magDef
|
||||||
|
// dxb=dexBase, dxc=dexCur, inb=insBase, inc=insCur
|
||||||
|
// mgb=migBase, mgc=migCur, wpb=wlpBase, wpc=wlpCur
|
||||||
|
// hx=hpMax, hc=hpCur, mx=mpMax, mc=mpCur, ix=ipMax, ic=ipCur
|
||||||
|
// fp=fp, bp=backpack
|
||||||
|
// acn=accName, acd=accDesc, amn=armName, amd=armDesc
|
||||||
|
// mhn=mhName, mhd=mhDesc, ohn=ohName, ohd=ohDesc
|
||||||
|
// hs=heroicSkills, rn=ritualsNotes
|
||||||
|
// sa=statusesActive, ma=martialChecked, da=disciplinesChecked
|
||||||
|
// bo=bonds, pc=primaryClasses, oc=otherClasses, sp=spells
|
||||||
|
// Nested bonds: n=name, f=feelings
|
||||||
|
// Nested classes: n=name, b=benefits, s=skills
|
||||||
|
// Nested spells: n=name, nt=notes, mp=mp, tg=targets, dr=duration
|
||||||
function collectData() {
|
function collectData() {
|
||||||
const get = id => { const el = document.getElementById(id); return el ? el.value : ''; };
|
const get = id => { const el = document.getElementById(id); return el ? el.value : ''; };
|
||||||
const statusesActive = [...document.querySelectorAll('.status-item.active-status')].map(el => el.dataset.status);
|
const sa = [...document.querySelectorAll('.status-item.active-status')].map(el => el.dataset.status);
|
||||||
const martialChecked = [...document.querySelectorAll('.martial-item.checked')].map(el => el.querySelector('span').textContent);
|
const ma = [...document.querySelectorAll('.martial-item.checked')].map(el => el.querySelector('span').textContent);
|
||||||
const disciplinesChecked = [...document.querySelectorAll('.disc-item.checked')].map(el => el.querySelector('span').textContent);
|
const da = [...document.querySelectorAll('.disc-item.checked')].map(el => el.querySelector('span').textContent);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: get('charName'), pronouns: get('charPronouns'),
|
n: get('charName'), pn: get('charPronouns'),
|
||||||
identity: get('charIdentity'), theme: get('charTheme'), origin: get('charOrigin'),
|
id: get('charIdentity'), th: get('charTheme'), og: get('charOrigin'),
|
||||||
traits: get('charTraits'),
|
tr: get('charTraits'),
|
||||||
level, xp: get('xpCurrent'), zenit: get('zenit'),
|
lv: level, xp: get('xpCurrent'), z: get('zenit'),
|
||||||
initMod: get('initMod'), defense: get('defense'), magDef: get('magDef'),
|
im: get('initMod'), df: get('defense'), md: get('magDef'),
|
||||||
dexBase: get('dex-base'), dexCur: get('dex-cur'),
|
dxb: get('dex-base'), dxc: get('dex-cur'),
|
||||||
insBase: get('ins-base'), insCur: get('ins-cur'),
|
inb: get('ins-base'), inc: get('ins-cur'),
|
||||||
migBase: get('mig-base'), migCur: get('mig-cur'),
|
mgb: get('mig-base'), mgc: get('mig-cur'),
|
||||||
wlpBase: get('wlp-base'), wlpCur: get('wlp-cur'),
|
wpb: get('wlp-base'), wpc: get('wlp-cur'),
|
||||||
hpMax: get('hpMax'), hpCur: get('hpCur'),
|
hx: get('hpMax'), hc: get('hpCur'),
|
||||||
mpMax: get('mpMax'), mpCur: get('mpCur'),
|
mx: get('mpMax'), mc: get('mpCur'),
|
||||||
ipMax: get('ipMax'), ipCur: get('ipCur'),
|
ix: get('ipMax'), ic: get('ipCur'),
|
||||||
fp: get('fpCount'),
|
fp: get('fpCount'),
|
||||||
backpack: get('backpack'),
|
bp: get('backpack'),
|
||||||
accName: get('acc-name'), accDesc: get('acc-desc'),
|
acn: get('acc-name'), acd: get('acc-desc'),
|
||||||
armName: get('arm-name'), armDesc: get('arm-desc'),
|
amn: get('arm-name'), amd: get('arm-desc'),
|
||||||
mhName: get('mh-name'), mhDesc: get('mh-desc'),
|
mhn: get('mh-name'), mhd: get('mh-desc'),
|
||||||
ohName: get('oh-name'), ohDesc: get('oh-desc'),
|
ohn: get('oh-name'), ohd: get('oh-desc'),
|
||||||
heroicSkills: get('heroicSkills'),
|
hs: get('heroicSkills'),
|
||||||
ritualsNotes: get('ritualsNotes'),
|
rn: get('ritualsNotes'),
|
||||||
statusesActive, martialChecked, disciplinesChecked,
|
sa, ma, da,
|
||||||
bonds, primaryClasses, otherClasses, spells
|
bo: bonds.map(b => ({ n: b.name, f: b.feelings })),
|
||||||
|
pc: primaryClasses.map(c => ({ n: c.name, b: c.benefits, s: c.skills })),
|
||||||
|
oc: otherClasses.map(c => ({ n: c.name, b: c.benefits, s: c.skills })),
|
||||||
|
sp: spells.map(s => ({ n: s.name, nt: s.notes, mp: s.mp, tg: s.targets, dr: s.duration })),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,54 +321,74 @@ function loadSheet() {
|
|||||||
|
|
||||||
function applyData(d) {
|
function applyData(d) {
|
||||||
const set = (id, val) => { const el = document.getElementById(id); if (el && val !== undefined) el.value = val; };
|
const set = (id, val) => { const el = document.getElementById(id); if (el && val !== undefined) el.value = val; };
|
||||||
set('charName', d.name); set('charPronouns', d.pronouns);
|
set('charName', d.n ?? d.name); set('charPronouns', d.pn ?? d.pronouns);
|
||||||
set('charIdentity', d.identity); set('charTheme', d.theme); set('charOrigin', d.origin);
|
set('charIdentity',d.id ?? d.identity); set('charTheme', d.th ?? d.theme);
|
||||||
set('charTraits', d.traits);
|
set('charOrigin', d.og ?? d.origin); set('charTraits', d.tr ?? d.traits);
|
||||||
level = d.level || 1;
|
level = d.lv ?? d.level ?? 1;
|
||||||
document.getElementById('levelDisplay').textContent = level;
|
document.getElementById('levelDisplay').textContent = level;
|
||||||
set('xpCurrent', d.xp); set('zenit', d.zenit);
|
set('xpCurrent', d.xp); set('zenit', d.z ?? d.zenit);
|
||||||
set('initMod', d.initMod); set('defense', d.defense); set('magDef', d.magDef);
|
set('initMod', d.im ?? d.initMod); set('defense', d.df ?? d.defense);
|
||||||
set('dex-base', d.dexBase); set('dex-cur', d.dexCur);
|
set('magDef', d.md ?? d.magDef);
|
||||||
set('ins-base', d.insBase); set('ins-cur', d.insCur);
|
set('dex-base', d.dxb ?? d.dexBase); set('dex-cur', d.dxc ?? d.dexCur);
|
||||||
set('mig-base', d.migBase); set('mig-cur', d.migCur);
|
set('ins-base', d.inb ?? d.insBase); set('ins-cur', d.inc ?? d.insCur);
|
||||||
set('wlp-base', d.wlpBase); set('wlp-cur', d.wlpCur);
|
set('mig-base', d.mgb ?? d.migBase); set('mig-cur', d.mgc ?? d.migCur);
|
||||||
set('hpMax', d.hpMax); set('hpCur', d.hpCur);
|
set('wlp-base', d.wpb ?? d.wlpBase); set('wlp-cur', d.wpc ?? d.wlpCur);
|
||||||
set('mpMax', d.mpMax); set('mpCur', d.mpCur);
|
set('hpMax', d.hx ?? d.hpMax); set('hpCur', d.hc ?? d.hpCur);
|
||||||
set('ipMax', d.ipMax); set('ipCur', d.ipCur);
|
set('mpMax', d.mx ?? d.mpMax); set('mpCur', d.mc ?? d.mpCur);
|
||||||
set('fpCount', d.fp);
|
set('ipMax', d.ix ?? d.ipMax); set('ipCur', d.ic ?? d.ipCur);
|
||||||
set('backpack', d.backpack);
|
set('fpCount', d.fp);
|
||||||
set('acc-name', d.accName); set('acc-desc', d.accDesc);
|
set('backpack', d.bp ?? d.backpack);
|
||||||
set('arm-name', d.armName); set('arm-desc', d.armDesc);
|
set('acc-name', d.acn ?? d.accName); set('acc-desc', d.acd ?? d.accDesc);
|
||||||
set('mh-name', d.mhName); set('mh-desc', d.mhDesc);
|
set('arm-name', d.amn ?? d.armName); set('arm-desc', d.amd ?? d.armDesc);
|
||||||
set('oh-name', d.ohName); set('oh-desc', d.ohDesc);
|
set('mh-name', d.mhn ?? d.mhName); set('mh-desc', d.mhd ?? d.mhDesc);
|
||||||
set('heroicSkills', d.heroicSkills);
|
set('oh-name', d.ohn ?? d.ohName); set('oh-desc', d.ohd ?? d.ohDesc);
|
||||||
set('ritualsNotes', d.ritualsNotes);
|
set('heroicSkills', d.hs ?? d.heroicSkills);
|
||||||
|
set('ritualsNotes', d.rn ?? d.ritualsNotes);
|
||||||
|
|
||||||
// Statuses
|
// Statuses
|
||||||
|
const sa = d.sa ?? d.statusesActive ?? [];
|
||||||
document.querySelectorAll('.status-item').forEach(el => {
|
document.querySelectorAll('.status-item').forEach(el => {
|
||||||
const active = (d.statusesActive || []).includes(el.dataset.status);
|
const active = sa.includes(el.dataset.status);
|
||||||
el.classList.toggle('active-status', active);
|
el.classList.toggle('active-status', active);
|
||||||
el.querySelector('.status-check').textContent = active ? '✗' : '';
|
el.querySelector('.status-check').textContent = active ? '✗' : '';
|
||||||
});
|
});
|
||||||
|
|
||||||
// Martial
|
// Martial
|
||||||
|
const ma = d.ma ?? d.martialChecked ?? [];
|
||||||
document.querySelectorAll('.martial-item').forEach(el => {
|
document.querySelectorAll('.martial-item').forEach(el => {
|
||||||
const checked = (d.martialChecked || []).includes(el.querySelector('span').textContent);
|
const checked = ma.includes(el.querySelector('span').textContent);
|
||||||
el.classList.toggle('checked', checked);
|
el.classList.toggle('checked', checked);
|
||||||
el.querySelector('.martial-box').textContent = checked ? '✓' : '';
|
el.querySelector('.martial-box').textContent = checked ? '✓' : '';
|
||||||
});
|
});
|
||||||
|
|
||||||
// Disciplines
|
// Disciplines
|
||||||
|
const da = d.da ?? d.disciplinesChecked ?? [];
|
||||||
document.querySelectorAll('.disc-item').forEach(el => {
|
document.querySelectorAll('.disc-item').forEach(el => {
|
||||||
const checked = (d.disciplinesChecked || []).includes(el.querySelector('span').textContent);
|
const checked = da.includes(el.querySelector('span').textContent);
|
||||||
el.classList.toggle('checked', checked);
|
el.classList.toggle('checked', checked);
|
||||||
el.querySelector('.disc-box').textContent = checked ? '✓' : '';
|
el.querySelector('.disc-box').textContent = checked ? '✓' : '';
|
||||||
});
|
});
|
||||||
|
|
||||||
if (d.bonds) { bonds = d.bonds; renderBonds(); }
|
const rawBonds = d.bo ?? d.bonds;
|
||||||
if (d.primaryClasses) { primaryClasses = d.primaryClasses; renderPrimaryClasses(); }
|
if (rawBonds) {
|
||||||
if (d.otherClasses) { otherClasses = d.otherClasses; renderOtherClasses(); }
|
bonds = rawBonds.map(b => ({ name: b.n ?? b.name, feelings: b.f ?? b.feelings ?? [] }));
|
||||||
if (d.spells) { spells = d.spells; renderSpells(); }
|
renderBonds();
|
||||||
|
}
|
||||||
|
const rawPrimary = d.pc ?? d.primaryClasses;
|
||||||
|
if (rawPrimary) {
|
||||||
|
primaryClasses = rawPrimary.map(c => ({ name: c.n ?? c.name, benefits: c.b ?? c.benefits, skills: c.s ?? c.skills }));
|
||||||
|
renderPrimaryClasses();
|
||||||
|
}
|
||||||
|
const rawOther = d.oc ?? d.otherClasses;
|
||||||
|
if (rawOther) {
|
||||||
|
otherClasses = rawOther.map(c => ({ name: c.n ?? c.name, benefits: c.b ?? c.benefits, skills: c.s ?? c.skills }));
|
||||||
|
renderOtherClasses();
|
||||||
|
}
|
||||||
|
const rawSpells = d.sp ?? d.spells;
|
||||||
|
if (rawSpells) {
|
||||||
|
spells = rawSpells.map(s => ({ name: s.n ?? s.name, notes: s.nt ?? s.notes, mp: s.mp, targets: s.tg ?? s.targets, duration: s.dr ?? s.duration }));
|
||||||
|
renderSpells();
|
||||||
|
}
|
||||||
|
|
||||||
renderFP();
|
renderFP();
|
||||||
updateXPBar();
|
updateXPBar();
|
||||||
@@ -363,7 +402,7 @@ function exportSheet() {
|
|||||||
const blob = new Blob([json], { type: 'application/json' });
|
const blob = new Blob([json], { type: 'application/json' });
|
||||||
const url = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
const charName = (data.name || 'character').replace(/[^a-z0-9_\- ]/gi, '').trim() || 'character';
|
const charName = (data.n || 'character').replace(/[^a-z0-9_\- ]/gi, '').trim() || 'character';
|
||||||
a.href = url;
|
a.href = url;
|
||||||
a.download = charName + '-fabula-ultima.json';
|
a.download = charName + '-fabula-ultima.json';
|
||||||
a.click();
|
a.click();
|
||||||
|
|||||||
Reference in New Issue
Block a user