The patches

Every line release v0.1.0 changes in the code it began from, as a diff.

The kit began as files on two other sites. These are the exact differences between those files and release v0.1.0, computed by the build from tools/upstream/ (each checked against its recorded SHA-256) and the published folder. Every other line is the upstream code, unchanged.

storyboard.js

Upstream: gen-z-developers.sgit.ai assets/storyboard.js (sha256 86212ff563e0bb02…). Four marked API PATCHes: prop packs, the preferences key, the vocabulary with VERSION and wire(), and an embed's start view.

--- gen-z-developers.sgit.ai assets/storyboard.js
+++ v0/v0.1/v0.1.0/storyboard.js
@@ -1,4 +1,8 @@
-/* Storyboards for Generation Z Developers: a storyboard is data (admin/content/storyboards/<slug>.json), the cast is data
- * (admin/content/storyboards/cast.json), and this file draws both, programmatically, as sketchy SVG panels with Rough.js.
+/* The storyboard kit, served by api.storyboards.sgit.ai at an immutable path per version (/vX/vX.Y/vX.Y.Z/storyboard.js).
+ * It began as gen-z-developers.sgit.ai's assets/storyboard.js (commit e2a71808, sha256 86212ff5...); the changes since are
+ * marked API PATCH below and listed in this release's manifest.json. Nothing else in the drawing was touched.
+ *
+ * Storyboards: a storyboard is data (<slug>.json), the cast is data (cast.json), and this file draws both,
+ * programmatically, as sketchy SVG panels with Rough.js.
  * Nothing is an image file and nothing is generated by a model: a panel is text that can be corrected and redrawn.
  *
@@ -237,4 +241,8 @@
     return { w, h };
   }
+  // API PATCH 1 (from pki.sgit.ai's one local patch, generalised): prop packs. A pack is a function that receives the
+  // drawing primitives and returns { kind: drawFn }. Packs are read from window.StoryboardPropPacks (an array, so several
+  // can load) and window.StoryboardExtraProps (pki.sgit.ai's original single hook), and StoryboardKit.addProps(pack)
+  // adds one after this file has loaded. The kit's own props always win a name clash.
   const PROPS = {
     laptop(g, rc, x, y, s) {
@@ -263,4 +271,14 @@
     },
   };
+  const CORE_PROPS = Object.keys(PROPS);
+  function addProps(pack) {
+    const got = typeof pack === 'function' ? pack({ draw, el, textBlock, wrap, INK, PAPER, FONT, TITLE, W, H, FLOOR }) : (pack || {});
+    for (const k in got) if (!CORE_PROPS.includes(k)) PROPS[k] = got[k];
+    return Object.keys(PROPS);
+  }
+  if (typeof window !== 'undefined') {
+    if (window.StoryboardExtraProps) addProps(window.StoryboardExtraProps);
+    (window.StoryboardPropPacks || []).forEach(addProps);
+  }
 
   // ------------------------------------------------------------ badges: explorer, villager, town planner
@@ -518,5 +536,6 @@
   // How you like to look at panels (animation, view, panels per row, text under panels) is remembered here and nowhere
   // else; a private window or blocked storage just gets the defaults. ?view=deck|grid|script overrides it for one visit.
-  const PREFS_KEY = 'genz.storyboards.v1';
+  // API PATCH 2: the key is the page's to name (window.StoryboardPrefsKey), so two sites never share one viewer's settings
+  const PREFS_KEY = (typeof window !== 'undefined' && window.StoryboardPrefsKey) || 'storyboards.v1';
   const VIEWS = ['deck', 'grid', 'script'];
   const POSES = ['stand', 'point', 'wave', 'arms-up', 'shrug', 'think', 'sit'];
@@ -772,5 +791,6 @@
   function viewer(root) {
     const data = JSON.parse(root.querySelector('script.sb-data').textContent);
-    const prefs = loadPrefs(), asked = new URLSearchParams(location.search).get('view');
+    // API PATCH 4: an embed may ask for a view (data-start-view), which the address bar's ?view= still overrides
+    const prefs = loadPrefs(), asked = new URLSearchParams(location.search).get('view') || root.dataset.startView;
     if (VIEWS.includes(asked)) prefs.view = asked;
     if (!VIEWS.includes(prefs.view)) prefs.view = 'deck';
@@ -929,12 +949,26 @@
   }
 
-  window.StoryboardKit = { drawScene, drawCharacter, drawMap, drawGraph, badge, deck, grid, script, viewer, contact, modelSheet, castSheet, shelf, figure, sceneText, play, MOODS, POSES, W, H };
-  document.addEventListener('DOMContentLoaded', () => {
-    document.querySelectorAll('.sb-viewer').forEach(viewer);
-    document.querySelectorAll('.sb-deck').forEach(d => { if (!d.closest('.sb-viewer')) deck(d); });
-    document.querySelectorAll('.sb-contact').forEach(contact);
-    document.querySelectorAll('.sb-sheet').forEach(modelSheet);
-    document.querySelectorAll('.sb-cast').forEach(castSheet);
-    document.querySelectorAll('.sbx').forEach(shelf);
-  });
+  // API PATCH 3: the vocabulary the renderer knows, as data (formats.js validates against it), the version, addProps,
+  // and wire(root): the page wiring, callable on any root, which runs on DOMContentLoaded as before or at once when the
+  // file is loaded after it (an embed loads it late). A root is wired once.
+  const VOCAB = {
+    kinds: ['cover', 'scene', 'evidence', 'punchline', 'spectrum', 'map', 'graph'],
+    poses: POSES, moods: MOODS,
+    settings: ['none', 'office', 'interview', 'street', 'night', 'classroom'],
+    props: () => Object.keys(PROPS),
+  };
+  function wire(root) {
+    root = root || document;
+    const once = (sel, fn) => root.querySelectorAll(sel).forEach(e => { if (!e.dataset.sbWired) { e.dataset.sbWired = '1'; fn(e); } });
+    once('.sb-viewer', viewer);
+    once('.sb-deck', d => { if (!d.closest('.sb-viewer')) deck(d); });
+    once('.sb-contact', contact);
+    once('.sb-sheet', modelSheet);
+    once('.sb-cast', castSheet);
+    once('.sbx', shelf);
+  }
+  window.StoryboardKit = { drawScene, drawCharacter, drawMap, drawGraph, badge, deck, grid, script, viewer, contact, modelSheet, castSheet, shelf, figure, sceneText, play, MOODS, POSES, W, H,
+    addProps, wire, VOCAB, PAPER, INK, VERSION: 'v0.1.0' };
+  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', () => wire(document));
+  else wire(document);
 })();

props/security.js

Upstream: pki.sgit.ai assets/storyboard/pki-props.js (sha256 a21f0a5eadef451e…). The header comment, and registering as a pack instead of the single window.StoryboardExtraProps hook.

--- pki.sgit.ai assets/storyboard/pki-props.js
+++ v0/v0.1/v0.1.0/props/security.js
@@ -1,5 +1,7 @@
-/* pki-props.js: the props pki.sgit.ai's storyboards need and the gen-z kit does not have, drawn the same way (Rough.js,
- * sketchy, nothing an image). Loaded before assets/storyboard/storyboard.js, which merges them into its PROPS through
- * the one local patch in that file. Every prop is (g, rc, x, y, s, p): x the centre, y the line it stands on, s a
+/* props/security.js: the security prop pack (keys, vaults, QR codes, envelopes, signed records, servers, terminals),
+ * written for pki.sgit.ai's storyboards as assets/storyboard/pki-props.js (commit ab6affc9) and drawn the same way as the
+ * kit's own props (Rough.js, sketchy, nothing an image). Load it before or after storyboard.js: before, it waits in
+ * window.StoryboardPropPacks; after, it registers itself with StoryboardKit.addProps. API PATCH: only that registration
+ * (the last lines) differs from the pki.sgit.ai file. Every prop is (g, rc, x, y, s, p): x the centre, y the line it stands on, s a
  * scale, p the scene's entry. A prop that names a `label` writes it under (or on) itself.
  *
@@ -19,5 +21,5 @@
 (function () {
   'use strict';
-  window.StoryboardExtraProps = function (k) {
+  const pack = function (k) {
     const { draw, el, textBlock, wrap, INK, W } = k;
     const ink = (o) => Object.assign({ stroke: INK, strokeWidth: 2.4 }, o || {});
@@ -134,3 +136,6 @@
     };
   };
+  // API PATCH: register as a pack (several packs can load), at once if the kit is already here
+  if (window.StoryboardKit && window.StoryboardKit.addProps) window.StoryboardKit.addProps(pack);
+  else (window.StoryboardPropPacks = window.StoryboardPropPacks || []).push(pack);
 })();

storyboard.css

Upstream: gen-z-developers.sgit.ai assets/storyboard.css (sha256 6d8c968a1c3ba7f3…). Unchanged.

No difference: the bytes are the same.