@jokerized/decksmith 0.1.2 → 0.1.4

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/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { cp, mkdir as mkdir7, readdir as readdir3, readFile as readFile13, stat, writeFile as writeFile8 } from "node:fs/promises";
5
- import { createRequire as createRequire2 } from "node:module";
5
+ import { createRequire as createRequire3 } from "node:module";
6
6
  import { dirname as dirname4, join as join12, relative as relative2, resolve as resolve3 } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { Command } from "commander";
@@ -1053,24 +1053,55 @@ var ADVANCE = {
1053
1053
  var KERN_SLACK = 1.007;
1054
1054
  var TABULAR_FIGURE = 0.649;
1055
1055
  var TABULAR_SEPARATOR = 0.269;
1056
+ var BLOCK_ADVANCE = [
1057
+ [12288, 12351, 1],
1058
+ // CJK symbols and punctuation
1059
+ [12352, 12447, 1],
1060
+ // hiragana
1061
+ [12448, 12543, 1],
1062
+ // katakana
1063
+ [12592, 12687, 0.92],
1064
+ // Hangul compatibility jamo
1065
+ [13312, 19903, 1],
1066
+ // CJK unified ideographs, extension A
1067
+ [19968, 40959, 1],
1068
+ // CJK unified ideographs
1069
+ [44032, 55203, 0.92],
1070
+ // Hangul syllables
1071
+ [63744, 64255, 1],
1072
+ // CJK compatibility ideographs
1073
+ [65281, 65376, 1]
1074
+ // full-width forms
1075
+ ];
1076
+ var UNMEASURED = 1.02;
1056
1077
  function charUnits(c, tabular) {
1057
1078
  if (tabular) {
1058
- if (c >= "0" && c <= "9") return TABULAR_FIGURE;
1059
- if (c === "." || c === ",") return TABULAR_SEPARATOR;
1079
+ if (c >= "0" && c <= "9") return [TABULAR_FIGURE, true];
1080
+ if (c === "." || c === ",") return [TABULAR_SEPARATOR, true];
1060
1081
  }
1061
- return ADVANCE[c] ?? 1.02;
1082
+ const measured = ADVANCE[c];
1083
+ if (measured !== void 0) return [measured, true];
1084
+ const cp2 = c.codePointAt(0) ?? 0;
1085
+ for (const [lo, hi, units] of BLOCK_ADVANCE) if (cp2 >= lo && cp2 <= hi) return [units, false];
1086
+ return [UNMEASURED, true];
1062
1087
  }
1063
1088
  function weightFactor(weight) {
1064
1089
  return weight >= 700 ? 1.045 : weight >= 600 ? 1.03 : weight >= 500 ? 1.015 : 1;
1065
1090
  }
1066
1091
  function textWidth(text2, fontSize, weight = 400, tracking = 0, tabular = false) {
1067
- let units = 0;
1092
+ let weighted = 0;
1093
+ let emGrid = 0;
1068
1094
  let chars = 0;
1069
1095
  for (const c of text2) {
1070
- units += charUnits(c, tabular);
1096
+ const [units, scalesWithWeight] = charUnits(c, tabular);
1097
+ if (scalesWithWeight) weighted += units;
1098
+ else emGrid += units;
1071
1099
  chars++;
1072
1100
  }
1073
- return units * KERN_SLACK * fontSize * weightFactor(weight) + tracking * fontSize * chars;
1101
+ if (emGrid === 0) {
1102
+ return weighted * KERN_SLACK * fontSize * weightFactor(weight) + tracking * fontSize * chars;
1103
+ }
1104
+ return (weighted * weightFactor(weight) + emGrid) * KERN_SLACK * fontSize + tracking * fontSize * chars;
1074
1105
  }
1075
1106
  function wrap(text2, fontSize, maxWidth, weight = 400, tracking = 0) {
1076
1107
  if (maxWidth <= 0) return [text2];
@@ -4620,7 +4651,7 @@ var SENTENCES_PER_BEAT = 2;
4620
4651
  var FF_BEAT_SECONDS = 8;
4621
4652
  var MIN_BEAT_SECONDS = 4;
4622
4653
  var SHORT_FORM_CPS = 22;
4623
- var CUE_OVERHEAD = 1.28;
4654
+ var CUE_OVERHEAD = 1.3;
4624
4655
  var COMFORTABLE_CPS = 17;
4625
4656
  var MAX_PLAYBACK = 1.25;
4626
4657
  var SPEAKING_STOPS = {
@@ -4630,10 +4661,10 @@ var SPEAKING_STOPS = {
4630
4661
  };
4631
4662
  var RATE_STEPS = [
4632
4663
  ["+0%", 1],
4633
- ["+10%", 1.187],
4634
- ["+20%", 1.252],
4635
- ["+30%", 1.394],
4636
- ["+40%", 1.533]
4664
+ ["+10%", 1.086],
4665
+ ["+20%", 1.182],
4666
+ ["+30%", 1.278],
4667
+ ["+40%", 1.393]
4637
4668
  ];
4638
4669
  function durationPlan(prefs) {
4639
4670
  const speakingStops = SPEAKING_STOPS[prefs.narration.density];
@@ -8340,6 +8371,10 @@ async function readCompositions(dir) {
8340
8371
  );
8341
8372
  }
8342
8373
 
8374
+ // src/version.ts
8375
+ import { createRequire as createRequire2 } from "node:module";
8376
+ var VERSION = createRequire2(import.meta.url)("../package.json").version;
8377
+
8343
8378
  // src/cli.ts
8344
8379
  var AUDIO_DIR = "audio";
8345
8380
  var NARRATION_FILE = "narration.json";
@@ -8353,7 +8388,7 @@ async function deckRuntime() {
8353
8388
  }
8354
8389
  }
8355
8390
  function playerBundle() {
8356
- const require2 = createRequire2(import.meta.url);
8391
+ const require2 = createRequire3(import.meta.url);
8357
8392
  try {
8358
8393
  return join12(dirname4(require2.resolve("hyperframes/package.json")), "dist", PLAYER_FILE);
8359
8394
  } catch {
@@ -8361,7 +8396,7 @@ function playerBundle() {
8361
8396
  }
8362
8397
  }
8363
8398
  async function vendorKatex(out) {
8364
- const require2 = createRequire2(import.meta.url);
8399
+ const require2 = createRequire3(import.meta.url);
8365
8400
  const dist = join12(dirname4(require2.resolve("katex/package.json")), "dist");
8366
8401
  const css = await readFile13(join12(dist, "katex.min.css"), "utf8");
8367
8402
  await mkdir7(join12(out, "katex/fonts"), { recursive: true });
@@ -8376,7 +8411,7 @@ async function vendorKatex(out) {
8376
8411
  await writeFile8(join12(out, "katex/katex.min.css"), woff2Only);
8377
8412
  }
8378
8413
  async function vendorScripts(out) {
8379
- const require2 = createRequire2(import.meta.url);
8414
+ const require2 = createRequire3(import.meta.url);
8380
8415
  await mkdir7(join12(out, "vendor"), { recursive: true });
8381
8416
  for (const [pkg, rel, name] of [
8382
8417
  ["gsap/package.json", "dist/gsap.min.js", "gsap.min.js"],
@@ -8435,7 +8470,7 @@ function stated(prefs, key) {
8435
8470
  return prefs[key] === DEFAULTS[key] ? void 0 : prefs[key];
8436
8471
  }
8437
8472
  var program = new Command();
8438
- program.name("decksmith").description("Turn a source document into an animated explanation deck.").version("0.1.0");
8473
+ program.name("decksmith").description("Turn a source document into an animated explanation deck.").version(VERSION);
8439
8474
  program.command("ingest").description("Parse a document into source.json, localising its figures and font.").argument("<input>", "source document (markdown)").requiredOption("-o, --out <file>", "where to write source.json").option("--lang <bcp47>", "override the sniffed language").action(async (input, o) => {
8440
8475
  const md = await readFile13(resolve3(input), "utf8").catch(() => {
8441
8476
  throw new Error(`Cannot read ${input}.`);
package/dist/index.js CHANGED
@@ -1053,24 +1053,55 @@ var ADVANCE = {
1053
1053
  var KERN_SLACK = 1.007;
1054
1054
  var TABULAR_FIGURE = 0.649;
1055
1055
  var TABULAR_SEPARATOR = 0.269;
1056
+ var BLOCK_ADVANCE = [
1057
+ [12288, 12351, 1],
1058
+ // CJK symbols and punctuation
1059
+ [12352, 12447, 1],
1060
+ // hiragana
1061
+ [12448, 12543, 1],
1062
+ // katakana
1063
+ [12592, 12687, 0.92],
1064
+ // Hangul compatibility jamo
1065
+ [13312, 19903, 1],
1066
+ // CJK unified ideographs, extension A
1067
+ [19968, 40959, 1],
1068
+ // CJK unified ideographs
1069
+ [44032, 55203, 0.92],
1070
+ // Hangul syllables
1071
+ [63744, 64255, 1],
1072
+ // CJK compatibility ideographs
1073
+ [65281, 65376, 1]
1074
+ // full-width forms
1075
+ ];
1076
+ var UNMEASURED = 1.02;
1056
1077
  function charUnits(c, tabular) {
1057
1078
  if (tabular) {
1058
- if (c >= "0" && c <= "9") return TABULAR_FIGURE;
1059
- if (c === "." || c === ",") return TABULAR_SEPARATOR;
1079
+ if (c >= "0" && c <= "9") return [TABULAR_FIGURE, true];
1080
+ if (c === "." || c === ",") return [TABULAR_SEPARATOR, true];
1060
1081
  }
1061
- return ADVANCE[c] ?? 1.02;
1082
+ const measured = ADVANCE[c];
1083
+ if (measured !== void 0) return [measured, true];
1084
+ const cp2 = c.codePointAt(0) ?? 0;
1085
+ for (const [lo, hi, units] of BLOCK_ADVANCE) if (cp2 >= lo && cp2 <= hi) return [units, false];
1086
+ return [UNMEASURED, true];
1062
1087
  }
1063
1088
  function weightFactor(weight) {
1064
1089
  return weight >= 700 ? 1.045 : weight >= 600 ? 1.03 : weight >= 500 ? 1.015 : 1;
1065
1090
  }
1066
1091
  function textWidth(text2, fontSize, weight = 400, tracking = 0, tabular = false) {
1067
- let units = 0;
1092
+ let weighted = 0;
1093
+ let emGrid = 0;
1068
1094
  let chars = 0;
1069
1095
  for (const c of text2) {
1070
- units += charUnits(c, tabular);
1096
+ const [units, scalesWithWeight] = charUnits(c, tabular);
1097
+ if (scalesWithWeight) weighted += units;
1098
+ else emGrid += units;
1071
1099
  chars++;
1072
1100
  }
1073
- return units * KERN_SLACK * fontSize * weightFactor(weight) + tracking * fontSize * chars;
1101
+ if (emGrid === 0) {
1102
+ return weighted * KERN_SLACK * fontSize * weightFactor(weight) + tracking * fontSize * chars;
1103
+ }
1104
+ return (weighted * weightFactor(weight) + emGrid) * KERN_SLACK * fontSize + tracking * fontSize * chars;
1074
1105
  }
1075
1106
  function wrap(text2, fontSize, maxWidth, weight = 400, tracking = 0) {
1076
1107
  if (maxWidth <= 0) return [text2];
@@ -5131,7 +5162,7 @@ var SENTENCES_PER_BEAT = 2;
5131
5162
  var FF_BEAT_SECONDS = 8;
5132
5163
  var MIN_BEAT_SECONDS = 4;
5133
5164
  var SHORT_FORM_CPS = 22;
5134
- var CUE_OVERHEAD = 1.28;
5165
+ var CUE_OVERHEAD = 1.3;
5135
5166
  var COMFORTABLE_CPS = 17;
5136
5167
  var MAX_PLAYBACK = 1.25;
5137
5168
  var SPEAKING_STOPS = {
@@ -5141,10 +5172,10 @@ var SPEAKING_STOPS = {
5141
5172
  };
5142
5173
  var RATE_STEPS = [
5143
5174
  ["+0%", 1],
5144
- ["+10%", 1.187],
5145
- ["+20%", 1.252],
5146
- ["+30%", 1.394],
5147
- ["+40%", 1.533]
5175
+ ["+10%", 1.086],
5176
+ ["+20%", 1.182],
5177
+ ["+30%", 1.278],
5178
+ ["+40%", 1.393]
5148
5179
  ];
5149
5180
  function durationPlan(prefs) {
5150
5181
  const speakingStops = SPEAKING_STOPS[prefs.narration.density];
package/dist/mcp.js CHANGED
@@ -7,6 +7,10 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
7
7
  import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
8
8
  import { z as z4 } from "zod";
9
9
 
10
+ // src/version.ts
11
+ import { createRequire } from "node:module";
12
+ var VERSION = createRequire(import.meta.url)("../package.json").version;
13
+
10
14
  // src/mcp/tools.ts
11
15
  import { randomBytes } from "node:crypto";
12
16
  import { mkdir as mkdir9, readFile as readFile10 } from "node:fs/promises";
@@ -16,7 +20,7 @@ import { z as z3 } from "zod";
16
20
 
17
21
  // src/index.ts
18
22
  import { cp, mkdir as mkdir7, readdir, readFile as readFile8, stat, writeFile as writeFile8 } from "node:fs/promises";
19
- import { createRequire } from "node:module";
23
+ import { createRequire as createRequire2 } from "node:module";
20
24
  import { dirname as dirname3, join as join7, resolve as resolve2 } from "node:path";
21
25
  import { fileURLToPath } from "node:url";
22
26
 
@@ -1053,24 +1057,55 @@ var ADVANCE = {
1053
1057
  var KERN_SLACK = 1.007;
1054
1058
  var TABULAR_FIGURE = 0.649;
1055
1059
  var TABULAR_SEPARATOR = 0.269;
1060
+ var BLOCK_ADVANCE = [
1061
+ [12288, 12351, 1],
1062
+ // CJK symbols and punctuation
1063
+ [12352, 12447, 1],
1064
+ // hiragana
1065
+ [12448, 12543, 1],
1066
+ // katakana
1067
+ [12592, 12687, 0.92],
1068
+ // Hangul compatibility jamo
1069
+ [13312, 19903, 1],
1070
+ // CJK unified ideographs, extension A
1071
+ [19968, 40959, 1],
1072
+ // CJK unified ideographs
1073
+ [44032, 55203, 0.92],
1074
+ // Hangul syllables
1075
+ [63744, 64255, 1],
1076
+ // CJK compatibility ideographs
1077
+ [65281, 65376, 1]
1078
+ // full-width forms
1079
+ ];
1080
+ var UNMEASURED = 1.02;
1056
1081
  function charUnits(c, tabular) {
1057
1082
  if (tabular) {
1058
- if (c >= "0" && c <= "9") return TABULAR_FIGURE;
1059
- if (c === "." || c === ",") return TABULAR_SEPARATOR;
1083
+ if (c >= "0" && c <= "9") return [TABULAR_FIGURE, true];
1084
+ if (c === "." || c === ",") return [TABULAR_SEPARATOR, true];
1060
1085
  }
1061
- return ADVANCE[c] ?? 1.02;
1086
+ const measured = ADVANCE[c];
1087
+ if (measured !== void 0) return [measured, true];
1088
+ const cp2 = c.codePointAt(0) ?? 0;
1089
+ for (const [lo, hi, units] of BLOCK_ADVANCE) if (cp2 >= lo && cp2 <= hi) return [units, false];
1090
+ return [UNMEASURED, true];
1062
1091
  }
1063
1092
  function weightFactor(weight) {
1064
1093
  return weight >= 700 ? 1.045 : weight >= 600 ? 1.03 : weight >= 500 ? 1.015 : 1;
1065
1094
  }
1066
1095
  function textWidth(text2, fontSize, weight = 400, tracking = 0, tabular = false) {
1067
- let units = 0;
1096
+ let weighted = 0;
1097
+ let emGrid = 0;
1068
1098
  let chars = 0;
1069
1099
  for (const c of text2) {
1070
- units += charUnits(c, tabular);
1100
+ const [units, scalesWithWeight] = charUnits(c, tabular);
1101
+ if (scalesWithWeight) weighted += units;
1102
+ else emGrid += units;
1071
1103
  chars++;
1072
1104
  }
1073
- return units * KERN_SLACK * fontSize * weightFactor(weight) + tracking * fontSize * chars;
1105
+ if (emGrid === 0) {
1106
+ return weighted * KERN_SLACK * fontSize * weightFactor(weight) + tracking * fontSize * chars;
1107
+ }
1108
+ return (weighted * weightFactor(weight) + emGrid) * KERN_SLACK * fontSize + tracking * fontSize * chars;
1074
1109
  }
1075
1110
  function wrap(text2, fontSize, maxWidth, weight = 400, tracking = 0) {
1076
1111
  if (maxWidth <= 0) return [text2];
@@ -5128,7 +5163,7 @@ var SENTENCES_PER_BEAT = 2;
5128
5163
  var FF_BEAT_SECONDS = 8;
5129
5164
  var MIN_BEAT_SECONDS = 4;
5130
5165
  var SHORT_FORM_CPS = 22;
5131
- var CUE_OVERHEAD = 1.28;
5166
+ var CUE_OVERHEAD = 1.3;
5132
5167
  var COMFORTABLE_CPS = 17;
5133
5168
  var MAX_PLAYBACK = 1.25;
5134
5169
  var SPEAKING_STOPS = {
@@ -5138,10 +5173,10 @@ var SPEAKING_STOPS = {
5138
5173
  };
5139
5174
  var RATE_STEPS = [
5140
5175
  ["+0%", 1],
5141
- ["+10%", 1.187],
5142
- ["+20%", 1.252],
5143
- ["+30%", 1.394],
5144
- ["+40%", 1.533]
5176
+ ["+10%", 1.086],
5177
+ ["+20%", 1.182],
5178
+ ["+30%", 1.278],
5179
+ ["+40%", 1.393]
5145
5180
  ];
5146
5181
  function durationPlan(prefs) {
5147
5182
  const speakingStops = SPEAKING_STOPS[prefs.narration.density];
@@ -6906,7 +6941,7 @@ async function deckRuntime() {
6906
6941
  }
6907
6942
  }
6908
6943
  function playerBundle() {
6909
- const require2 = createRequire(import.meta.url);
6944
+ const require2 = createRequire2(import.meta.url);
6910
6945
  try {
6911
6946
  return join7(dirname3(require2.resolve("hyperframes/package.json")), "dist", PLAYER_FILE);
6912
6947
  } catch {
@@ -6914,7 +6949,7 @@ function playerBundle() {
6914
6949
  }
6915
6950
  }
6916
6951
  async function vendorKatex(out) {
6917
- const require2 = createRequire(import.meta.url);
6952
+ const require2 = createRequire2(import.meta.url);
6918
6953
  const dist = join7(dirname3(require2.resolve("katex/package.json")), "dist");
6919
6954
  const css = await readFile8(join7(dist, "katex.min.css"), "utf8");
6920
6955
  const written = [];
@@ -8168,7 +8203,7 @@ var TOOLS = [
8168
8203
  inputSchema: schema(statusSchema)
8169
8204
  }
8170
8205
  ];
8171
- var server = new Server({ name: "decksmith", version: "0.1.0" }, { capabilities: { tools: {} } });
8206
+ var server = new Server({ name: "decksmith", version: VERSION }, { capabilities: { tools: {} } });
8172
8207
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
8173
8208
  server.setRequestHandler(CallToolRequestSchema, async (req) => {
8174
8209
  const args = req.params.arguments ?? {};
@@ -212,13 +212,49 @@ export declare const SHORT_FORM_CPS = 22;
212
212
  * takes `+10%` and lands at 21.9. Wrong in the OUTPUT, not in a gate — no gate
213
213
  * looks at this, which is why it survived.
214
214
  *
215
- * SCALE-INVARIANCE IS ASSUMED, and is the one thing here not measured: the ratio
216
- * is taken at `+0%` and applied at every step, on the reasoning that speeding the
217
- * voice up shrinks the cue windows and the breaths between them together.
218
- * Measuring it at `+10%` and `+20%` means synthesising the demo again at those
219
- * rates. `test/duration.test.ts` pins the `+0%` end against the artifact.
215
+ * SCALE-INVARIANCE IS MEASURED, and it holds. The ratio is taken at `+0%` and
216
+ * applied at every step, on the reasoning that speeding the voice up shrinks the
217
+ * cue windows and the breaths between them together. `scripts/measure-cue-rate.mjs`
218
+ * re-synthesised all 37 segments at all five steps `+0%` included, in one
219
+ * session, because edge-tts does not repeat itself and a fresh rate judged
220
+ * against a stored baseline measures the drift instead:
221
+ *
222
+ * ```
223
+ * rate meanCps p95 cue p95/mean median/mean
224
+ * +0% 14.509 18.089 1.2467 1.0601
225
+ * +10% 15.752 20.392 1.2945 1.0653
226
+ * +20% 17.148 21.321 1.2434 1.0567
227
+ * +30% 18.540 23.263 1.2548 1.0572
228
+ * +40% 20.205 25.515 1.2628 1.0663
229
+ * ```
230
+ *
231
+ * No trend in rate — so this stays a constant rather than becoming a function of
232
+ * the step. The p95 column wobbles because p95 over 39 cues IS THE SECOND-HIGHEST
233
+ * CUE, one window wide; `median/mean` is flat to within a percent, and it is the
234
+ * honest read on whether the distribution's shape moves. It does not.
235
+ *
236
+ * IT AND `RATE_STEPS` ARE ONE UNIT, and they moved together — 2026-08-02, from
237
+ * the run above. Read that table's `speedup` note before changing either.
238
+ *
239
+ * WHY 1.30 AND NOT 1.2945. It has to sit above EVERY ratio the run observed,
240
+ * because the number it feeds is a ceiling on caption readability and being
241
+ * under it means shipping captions faster than `SHORT_FORM_CPS`. The old 1.28
242
+ * was below the `+10%` reading and got away with it only because the speedups
243
+ * beside it were inflated by more — two errors cancelling, which is not a margin
244
+ * anyone can reason about. Correcting the speedups removed that cover, so this
245
+ * had to rise with them.
246
+ *
247
+ * IT COSTS A STEP, KNOWINGLY. The demo's real p95 cue at `+20%` is 21.321,
248
+ * inside the ceiling of 22 — but this predicts 22.13 for that step and refuses
249
+ * it, so the deck takes `+10%` and speaks slower than the artifact proves it
250
+ * could. A central estimate of ~1.26 would admit `+20%` and track the artifact
251
+ * to within 0.6%; it would also under-predict on about half of future runs. The
252
+ * trade was made deliberately in favour of never being under, on a statistic
253
+ * measured once over 39 cues.
254
+ *
255
+ * `test/duration.test.ts` pins the `+0%` end against the artifact.
220
256
  */
221
- export declare const CUE_OVERHEAD = 1.28;
257
+ export declare const CUE_OVERHEAD = 1.3;
222
258
  /** Broadcast subtitle practice. Past this the captions stop being readable. */
223
259
  export declare const COMFORTABLE_CPS = 17;
224
260
  /** How far playback may be sped up before the captions are the problem. */
@@ -261,6 +297,29 @@ export declare const SPEAKING_STOPS: Record<Prefs["narration"]["density"], numbe
261
297
  * `+60%` it is 28.5 and the caption is gone before it is read. `+50%` is
262
298
  * excluded for measuring slower than the step below it.
263
299
  *
300
+ * THE SPEEDUPS BELOW ARE NOT FROM THAT TABLE. They were, and they were too high
301
+ * at every step. The table above times ONE 72-character sentence, and a short
302
+ * sentence carries proportionally more silence at its ends, so dividing its
303
+ * total duration overstates what the prosody rate does to speech itself.
304
+ * Re-measured over the anchor deck's 37 segments and 196 seconds:
305
+ *
306
+ * ```
307
+ * step was is from
308
+ * +10% 1.187 1.086 meanCps 15.752 / 14.509
309
+ * +20% 1.252 1.182 meanCps 17.148 / 14.509
310
+ * +30% 1.394 1.278 meanCps 18.540 / 14.509
311
+ * +40% 1.533 1.393 meanCps 20.205 / 14.509
312
+ * ```
313
+ *
314
+ * `CUE_OVERHEAD` rose from 1.28 to 1.30 in the same commit and for this reason:
315
+ * it was below the cue ratio measured at `+10%` and only safe because these
316
+ * numbers were inflated by more. Neither is a safe edit alone — see the
317
+ * paragraph there. One run of `scripts/measure-cue-rate.mjs` produces both.
318
+ *
319
+ * THE TABLE ABOVE STILL EARNS ITS PLACE, because it is the only measurement of
320
+ * `+50%` and `+60%` anyone has taken, and what it says about them is why this
321
+ * list stops at `+40%`. The re-measurement covered these five steps only.
322
+ *
264
323
  * Latin-measured. A CJK deck gets the same steps, which is a guess of the same
265
324
  * kind `SPEECH_CPS.cjk` already is — replace it the first time one is narrated.
266
325
  */
@@ -0,0 +1 @@
1
+ export declare const VERSION: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jokerized/decksmith",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Turn a source document into an animated explanation deck.",
5
5
  "type": "module",
6
6
  "license": "MIT",