@aivorynet/slaide 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,19 @@ All notable changes to slaide are recorded here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.0.5] - 2026-07-08
10
+
11
+ ### Fixed
12
+
13
+ - Chart font family now resolves from the slide element when the CSS variable is empty, instead of falling back to a blank string.
14
+ - Chrome logo in the agent skill is opt-in, no longer injected by default.
15
+
16
+ ### Changed
17
+
18
+ - Runtime navigation queue and rescan API for smoother slide transitions.
19
+ - Themes skill rewritten for leaner, more reliable authoring guidance.
20
+ - GitHub Actions release workflow now publishes the OSS viewer binaries.
21
+
9
22
  ## [1.0.4] - 2026-07-06
10
23
 
11
24
  ### Changed
@@ -66,7 +79,8 @@ First public release.
66
79
  - `.slaidec` packing and unpacking, and the `compare` fidelity tool.
67
80
  - The bundled `aurora` theme.
68
81
 
69
- [Unreleased]: https://github.com/aivorynet/slaide/compare/v1.0.4...HEAD
82
+ [Unreleased]: https://github.com/aivorynet/slaide/compare/v1.0.5...HEAD
83
+ [1.0.5]: https://github.com/aivorynet/slaide/compare/v1.0.4...v1.0.5
70
84
  [1.0.4]: https://github.com/aivorynet/slaide/releases/tag/v1.0.4
71
85
  [1.0.3]: https://github.com/aivorynet/slaide/releases/tag/v1.0.3
72
86
  [1.0.2]: https://github.com/aivorynet/slaide/releases/tag/v1.0.2
@@ -36,13 +36,17 @@ export const CHARTS_BOOT_JS = String.raw `
36
36
  // deck's CSS custom properties so charts come out on-brand automatically.
37
37
  function ensure(engine){
38
38
  if(booted[engine]) return booted[engine];
39
- var tag = document.getElementById('sl-'+engine+'-lib');
40
- if(!tag) return null;
41
- try{ (0,eval)(b64decode(tag.textContent)); }
42
- catch(e){ console.error('slaide: failed to boot '+engine, e); return null; }
39
+ var global = engine==='echart' ? window.echarts : engine==='mermaid' ? window.mermaid : null;
40
+ if(!global){
41
+ var tag = document.getElementById('sl-'+engine+'-lib');
42
+ if(!tag) return null;
43
+ try{ (0,eval)(b64decode(tag.textContent)); }
44
+ catch(e){ console.error('slaide: failed to boot '+engine, e); return null; }
45
+ }
43
46
 
44
47
  if(engine==='mermaid' && window.mermaid){
45
- var font = cssVar('--font-sans','system-ui');
48
+ var mSlide = document.querySelector('.sl-slide');
49
+ var font = cssVar('--font-sans','') || (mSlide ? getComputedStyle(mSlide).fontFamily : '') || 'system-ui, sans-serif';
46
50
  window.mermaid.initialize({
47
51
  startOnLoad:false, securityLevel:'strict', theme:'base', fontFamily:font,
48
52
  themeVariables:{
@@ -66,7 +70,8 @@ export const CHARTS_BOOT_JS = String.raw `
66
70
  if(accent && colors.indexOf(accent)<0) colors = [accent].concat(colors);
67
71
  var text = cssVar('--color-text','#ffffff');
68
72
  var muted = cssVar('--color-muted','#8B93A7');
69
- var font = cssVar('--font-sans','system-ui');
73
+ var slideEl = document.querySelector('.sl-slide');
74
+ var font = cssVar('--font-sans','') || (slideEl ? getComputedStyle(slideEl).fontFamily : '') || 'system-ui, sans-serif';
70
75
  var axis = {
71
76
  axisLine:{lineStyle:{color:muted}},
72
77
  axisTick:{lineStyle:{color:muted}},
@@ -1 +1 @@
1
- {"version":3,"file":"charts.js","sourceRoot":"","sources":["../../src/render/charts.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,sCAAsC;AACtC,kFAAkF;AAClF,EAAE;AACF,yFAAyF;AACzF,yFAAyF;AACzF,0FAA0F;AAC1F,wFAAwF;AACxF,yFAAyF;AACzF,oDAAoD;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,oFAAoF;AACpF,mEAAmE;AACnE,uFAAuF;AACvF,iEAAiE;AACjE,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyJvC,CAAC"}
1
+ {"version":3,"file":"charts.js","sourceRoot":"","sources":["../../src/render/charts.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,sCAAsC;AACtC,kFAAkF;AAClF,EAAE;AACF,yFAAyF;AACzF,yFAAyF;AACzF,0FAA0F;AAC1F,wFAAwF;AACxF,yFAAyF;AACzF,oDAAoD;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,oFAAoF;AACpF,mEAAmE;AACnE,uFAAuF;AACvF,iEAAiE;AACjE,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8JvC,CAAC"}
@@ -7,10 +7,12 @@ export const RUNTIME_JS = String.raw `
7
7
  var stage = document.querySelector('.sl-stage');
8
8
  if(!stage) return;
9
9
  var vp = document.querySelector('.sl-viewport');
10
- var slides = Array.prototype.slice.call(document.querySelectorAll('.sl-slide'));
10
+ // Scope to the stage: a host (web editor) may clone .sl-slide into a filmstrip elsewhere in the
11
+ // document; collecting from the whole document would pollute the count/index and navigation.
12
+ var slides = Array.prototype.slice.call(stage.querySelectorAll('.sl-slide'));
11
13
  var CW = parseFloat(stage.dataset.w)||1280, CH = parseFloat(stage.dataset.h)||720;
12
14
  var notes = (window.__SLAIDE_NOTES__)||[];
13
- var cur = 0, step = 0, busy = false;
15
+ var cur = 0, step = 0, busy = false, pendingNav = null;
14
16
  var zoomFactor = 1, panX = 0, panY = 0;
15
17
  // When false, taps don't advance and drag-pan is off (for interactive embeds,
16
18
  // kiosk mode, or a host that drives navigation itself). Default: on.
@@ -118,24 +120,28 @@ export const RUNTIME_JS = String.raw `
118
120
  if(dir<0){ newSlide.classList.add('sl-anim-rev'); oldSlide.classList.add('sl-anim-rev'); }
119
121
  step = dir<0 ? buildCount(i) : 0; applyBuilds(newSlide, step);
120
122
  var done=0;
121
- function endOld(){ oldSlide.classList.remove('sl-active', outC, 'sl-anim-rev'); oldSlide.removeEventListener('animationend', endOld); next(); }
122
- function endNew(){ newSlide.classList.remove(inC, 'sl-anim-rev'); newSlide.removeEventListener('animationend', endNew); next(); }
123
- function next(){ if(++done>=2){ busy=false; } }
123
+ function endOld(){ if(done&1) return; done|=1; oldSlide.classList.remove('sl-active', outC, 'sl-anim-rev'); oldSlide.removeEventListener('animationend', endOld); fin(); }
124
+ function endNew(){ if(done&2) return; done|=2; newSlide.classList.remove(inC, 'sl-anim-rev'); newSlide.removeEventListener('animationend', endNew); fin(); }
125
+ function fin(){ if((done&3)===3){ busy=false; if(pendingNav){ var p=pendingNav; pendingNav=null; if(p==='fwd') forward(); else backward(); } } }
124
126
  oldSlide.addEventListener('animationend', endOld);
125
127
  newSlide.addEventListener('animationend', endNew);
126
- // safety timeout
127
- setTimeout(function(){ if(busy){ oldSlide.classList.remove('sl-active',outC,'sl-anim-rev'); newSlide.classList.remove(inC,'sl-anim-rev'); busy=false; } }, 1200);
128
+ requestAnimationFrame(function(){
129
+ var cs1=getComputedStyle(oldSlide),cs2=getComputedStyle(newSlide);
130
+ if(!cs1.animationName||cs1.animationName==='none'||cs1.animationDuration==='0s') endOld();
131
+ if(!cs2.animationName||cs2.animationName==='none'||cs2.animationDuration==='0s') endNew();
132
+ });
133
+ setTimeout(function(){ if(busy){ endOld(); endNew(); } }, 800);
128
134
  cur=i; updateChrome(); sync();
129
135
  }
130
136
 
131
137
  function forward(){
132
- if(busy) return;
138
+ if(busy){ pendingNav='fwd'; return; }
133
139
  if(blanked) blank('');
134
140
  if(step < buildCount(cur)){ step++; applyBuilds(slides[cur], step); updateChrome(); sync(); return; }
135
141
  goTo(cur+1, 1);
136
142
  }
137
143
  function backward(){
138
- if(busy) return;
144
+ if(busy){ pendingNav='bwd'; return; }
139
145
  if(blanked) blank('');
140
146
  if(step > 0){ step--; applyBuilds(slides[cur], step); updateChrome(); sync(); return; }
141
147
  goTo(cur-1, -1);
@@ -384,7 +390,20 @@ export const RUNTIME_JS = String.raw `
384
390
  prev: backward,
385
391
  goTo: function(i){ goTo(i, i>cur?1:-1); },
386
392
  relayout: function(){ scale(); }, // recompute the stage fit (e.g. after the dock opens/closes)
387
- show: function(i){ if(i<0||i>=slides.length) return; activate(i, true); cur=i; updateChrome(); },
393
+ show: function(i){ if(!slides.length) return; i=Math.max(0,Math.min(slides.length-1,i)); activate(i, true); cur=i; updateChrome(); },
394
+ // Re-collect slides after the host appended/replaced .sl-slide nodes in the stage (live agent
395
+ // build: new slides stream in one by one). Preserve the current index; re-assert active + builds
396
+ // + chrome. Returns the new slide count.
397
+ rescan: function(){
398
+ slides = Array.prototype.slice.call(stage.querySelectorAll(':scope > .sl-slide'));
399
+ if(!slides.length) return 0;
400
+ cur = Math.max(0, Math.min(cur, slides.length-1));
401
+ slides.forEach(function(s,idx){ s.classList.toggle('sl-active', idx===cur); });
402
+ if(step > buildCount(cur)) step = buildCount(cur);
403
+ applyBuilds(slides[cur], step);
404
+ scale(); updateChrome();
405
+ return slides.length;
406
+ },
388
407
  setInteractive: function(on){ navEnabled = on!==false; },
389
408
  toggleNotes: function(){ toggleNotes(); },
390
409
  toggleHelp: function(){ toggle('.sl-help'); },
@@ -415,6 +434,7 @@ export const RUNTIME_JS = String.raw `
415
434
  scale(); updateChrome();
416
435
  if(AM_PRESENTER) buildPresenter(); // this window is the presenter view
417
436
  if(AM_AUDIENCE){ document.body.classList.add('slv-presenting'); navEnabled = false; } // clean mirror, host-driven
437
+ if(document.body.classList.contains('sl-editing')) navEnabled = false;
418
438
  })();
419
439
  `;
420
440
  //# sourceMappingURL=runtime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/render/runtime.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,sCAAsC;AACtC,8EAA8E;AAC9E,uFAAuF;AACvF,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8ZnC,CAAC"}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/render/runtime.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,sCAAsC;AACtC,8EAA8E;AAC9E,uFAAuF;AACvF,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkbnC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aivorynet/slaide",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "An AI-authorable slide language with beautiful web + PDF output",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -48,7 +48,7 @@ layout: title-content
48
48
  - Charts: ` ```echart ` (data viz, ECharts option as JSON) and ` ```mermaid ` (diagrams) → theme-coloured SVG. Put a chart in a slot with height (a `1fr` row).
49
49
 
50
50
  ## The master (theme)
51
- Use the bundled theme — omit `master:` or set `master: aurora` — or author your own (preferred for branded decks). **Read `themes.md` for the format before writing one**: fonts, a type scale, two-tier colour (palette + roles), gradients, backgrounds, grid layouts, chrome — all data. Reference **roles, not hex**, so a reskin is a palette swap. Past "tidy", give the deck **one signature** (a faint logo-derived motif or a recurring accent panel) and vary composition slide to slide. The load-bearing footguns — dark-on-dark text, hollow `box:` cards, chrome-corner collisions — are flagged in `themes.md`; heed them. A deck about slaide itself: use the shipped brand in the sibling `slaide-hugo` repo, don't invent one.
51
+ Use the bundled theme — omit `master:` or set `master: aurora` — or author your own (preferred for branded decks). **Read `themes.md` for the format before writing one**: fonts, a type scale, two-tier colour (palette + roles), gradients, backgrounds, grid layouts, chrome — all data. Reference **roles, not hex**, so a reskin is a palette swap. Past "tidy", give the deck **one signature** (a recurring accent panel, a distinctive layout rhythm, or a colour-block motif) and vary composition slide to slide. Chrome `logo:` is opt-in — only add it when the user supplies a real brand logo; do NOT invent a generic icon. The load-bearing footguns — dark-on-dark text, hollow `box:` cards, chrome-corner collisions — are flagged in `themes.md`; heed them. A deck about slaide itself: use the shipped brand in the sibling `slaide-hugo` repo, don't invent one.
52
52
 
53
53
  ## Commands (prefix `npx @aivorynet/slaide`)
54
54
  | Command | Does |
@@ -212,6 +212,7 @@ Inline `[text]{.class}` resolves against this master: **colour** = any `palette`
212
212
  ## Tips for AI authors
213
213
 
214
214
  - Use **roles** and **scale steps**, not raw hex/px — reskin = palette swap.
215
+ - **Chrome `logo:` is opt-in.** Only add it when the user supplies a real brand logo. Do NOT invent a generic icon/monogram — a tiny aimless mark in the corner of every slide is the #1 amateur tell.
215
216
  - **Cards (`box:`):** bg + padding + radius only (no gradient/shadow/border). Without `valign` a card stretches full-height and pins text top (hollow). Fix: `valign: center` to shrink-wrap, or put cards in an `auto` row with `1fr` spacers. Tint card surface off-white vs the page.
216
217
  - **Cover = dramatic hero.** Visual slot FILLS — bold brand SVG, product mock, or illustrated motif at ≥ half the slide, not a small icon. Think Apple keynote: few bold shapes at large scale. Centred text on a gradient is a section divider, not a cover. Never `.grad` text on a gradient bg (vanishes). **Closing** = bold CTA or contact slide (name/role/email/URL for pitch/agency decks). Both must feel intentional.
217
218
  - **Brand ground dominates.** Most slides use the brand's background role (warm cream, tinted neutral — not generic white). Dark/gradient = accent moments only (cover, one stat, closing).