sketchmark 1.0.0 → 1.0.1

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.

Potentially problematic release.


This version of sketchmark might be problematic. Click here for more details.

@@ -7181,6 +7181,7 @@ var AIDiagram = (function (exports) {
7181
7181
  this._pointerType = 'none';
7182
7182
  // ── TTS ──
7183
7183
  this._tts = false;
7184
+ this._speechDone = null;
7184
7185
  this.drawTargetEdges = getDrawTargetEdgeIds(steps);
7185
7186
  this.drawTargetNodes = getDrawTargetNodeIds(steps);
7186
7187
  // Groups: non-edge draw steps whose target has a #group-{id} element in the SVG.
@@ -7311,7 +7312,11 @@ var AIDiagram = (function (exports) {
7311
7312
  while (this.canNext) {
7312
7313
  const nextStep = this.steps[this._step + 1];
7313
7314
  this.next();
7314
- await new Promise((r) => setTimeout(r, this._playbackWaitMs(nextStep, msPerStep)));
7315
+ // Wait for timer AND speech to finish (whichever is longer)
7316
+ await Promise.all([
7317
+ new Promise((r) => setTimeout(r, this._playbackWaitMs(nextStep, msPerStep))),
7318
+ this._speechDone ?? Promise.resolve(),
7319
+ ]);
7315
7320
  }
7316
7321
  }
7317
7322
  goTo(index) {
@@ -7349,8 +7354,13 @@ var AIDiagram = (function (exports) {
7349
7354
  // Compute minimum time the step actually needs to finish
7350
7355
  let minNeeded = 0;
7351
7356
  if (step.action === "narrate") {
7357
+ const text = step.value ?? "";
7352
7358
  // Typing effect: chars × typeMs + fade buffer
7353
- minNeeded = (step.value?.length ?? 0) * ANIMATION.narrationTypeMs + ANIMATION.narrationFadeMs;
7359
+ const typingMs = text.length * ANIMATION.narrationTypeMs + ANIMATION.narrationFadeMs;
7360
+ // TTS estimate: ~150ms per word + 500ms buffer for engine latency
7361
+ const wordCount = text.split(/\s+/).filter(Boolean).length;
7362
+ const ttsMs = this._tts ? wordCount * 150 + 500 : 0;
7363
+ minNeeded = Math.max(typingMs, ttsMs);
7354
7364
  }
7355
7365
  else if (step.action === "circle" || step.action === "underline" ||
7356
7366
  step.action === "crossout" || step.action === "bracket") {
@@ -7895,8 +7905,8 @@ var AIDiagram = (function (exports) {
7895
7905
  }
7896
7906
  // ── narration ───────────────────────────────────────────
7897
7907
  _initCaption() {
7898
- if (!this._container)
7899
- return;
7908
+ // Remove any leftover caption from a previous instance
7909
+ document.querySelector('.skm-caption')?.remove();
7900
7910
  const cap = document.createElement("div");
7901
7911
  cap.className = "skm-caption";
7902
7912
  cap.style.cssText = `
@@ -7926,7 +7936,7 @@ var AIDiagram = (function (exports) {
7926
7936
  this._captionTextEl.textContent = text;
7927
7937
  return;
7928
7938
  }
7929
- // Fire TTS first it has internal startup latency, so give it a head start
7939
+ // Fire TTS as full sentence play() waits for _speechDone
7930
7940
  if (this._tts && text)
7931
7941
  this._speak(text);
7932
7942
  // Typing effect
@@ -7949,11 +7959,17 @@ var AIDiagram = (function (exports) {
7949
7959
  utter.rate = 0.95;
7950
7960
  utter.pitch = 1;
7951
7961
  utter.lang = "en-US";
7962
+ // Track when speech actually finishes
7963
+ this._speechDone = new Promise((resolve) => {
7964
+ utter.onend = () => resolve();
7965
+ utter.onerror = () => resolve();
7966
+ });
7952
7967
  speechSynthesis.speak(utter);
7953
7968
  }
7954
7969
  _cancelSpeech() {
7955
7970
  if (typeof speechSynthesis !== "undefined")
7956
7971
  speechSynthesis.cancel();
7972
+ this._speechDone = null;
7957
7973
  }
7958
7974
  /** Pre-warm the speech engine with a silent utterance to eliminate cold-start delay */
7959
7975
  _warmUpSpeech() {
@@ -8460,12 +8476,10 @@ var AIDiagram = (function (exports) {
8460
8476
  interactive: true,
8461
8477
  onNodeClick,
8462
8478
  });
8463
- // Create rough.js instance for annotations
8479
+ // Create rough.js instance for annotations (same import as SVG renderer)
8464
8480
  let rc = null;
8465
8481
  try {
8466
- const roughMod = window.rough ?? (typeof require !== 'undefined' ? require('roughjs/bin/rough') : null);
8467
- if (roughMod?.svg)
8468
- rc = roughMod.svg(svg);
8482
+ rc = rough.svg(svg);
8469
8483
  }
8470
8484
  catch { /* rough.js not available — annotations disabled */ }
8471
8485
  const containerEl = el instanceof SVGSVGElement ? undefined : el;
@@ -8474,7 +8488,7 @@ var AIDiagram = (function (exports) {
8474
8488
  onReady?.(anim, svg);
8475
8489
  const instance = {
8476
8490
  scene, anim, svg, canvas,
8477
- update: (newDsl) => render({ ...options, dsl: newDsl }),
8491
+ update: (newDsl) => { anim?.destroy(); return render({ ...options, dsl: newDsl }); },
8478
8492
  exportSVG: (filename = 'diagram.svg') => {
8479
8493
  if (svg) {
8480
8494
  Promise.resolve().then(function () { return index; }).then(m => m.exportSVG(svg, { filename }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sketchmark",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "A plain-text DSL for hand-drawn diagrams. Write boxes, edges, and groups as code — renders sketchy SVG/Canvas via rough.js with a built-in step-by-step animation system.",
5
5
  "keywords": [
6
6
  "diagram",