@projektemacher/storymapjs 0.10.8 → 0.11.0

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.
Files changed (195) hide show
  1. package/CHANGELOG +81 -0
  2. package/README.md +129 -12
  3. package/dist/assets/{demo-DBpeF31K.js → demo-bWnOyfUw.js} +1 -1
  4. package/dist/assets/harness-C3JUv5Ii.js +1 -0
  5. package/dist/assets/{harness-multi-CYHgI0a9.js → harness-multi-XZNex3tb.js} +1 -1
  6. package/dist/assets/{harness-support-Do7sIp2j.js → harness-support-CjfZIVeb.js} +1 -1
  7. package/dist/assets/main-DQ32hWBM.js +17 -0
  8. package/dist/context.json +13 -2
  9. package/dist/css/storymap.css +1 -1
  10. package/dist/demo.html +3 -2
  11. package/dist/docs/api/assets/navigation.js +1 -1
  12. package/dist/docs/api/assets/search.js +1 -1
  13. package/dist/docs/api/classes/StoryMap.html +777 -269
  14. package/dist/docs/api/functions/MediaType.html +1 -1
  15. package/dist/docs/api/functions/isPresentation3Collection.html +1 -1
  16. package/dist/docs/api/functions/isPresentation3Manifest.html +1 -1
  17. package/dist/docs/api/functions/isSlideshowCollection.html +51 -0
  18. package/dist/docs/api/functions/loadCSS.html +1 -1
  19. package/dist/docs/api/functions/manifestToStorymapData.html +1 -1
  20. package/dist/docs/api/functions/setLanguage.html +1 -1
  21. package/dist/docs/api/functions/slideshowToStorymapData.html +51 -0
  22. package/dist/docs/api/functions/slideshowVersion.html +48 -0
  23. package/dist/docs/api/functions/storymapToManifest.html +1 -1
  24. package/dist/docs/api/functions/validateStorymap.html +1 -1
  25. package/dist/docs/api/functions/validateStorymapAndReport.html +1 -1
  26. package/dist/docs/api/index.html +115 -12
  27. package/dist/docs/api/interfaces/AnimationHandle.html +2 -2
  28. package/dist/docs/api/interfaces/ImagereadyPayload.html +4 -4
  29. package/dist/docs/api/interfaces/LanguageEntry.html +6 -6
  30. package/dist/docs/api/interfaces/LatLngLiteral.html +4 -4
  31. package/dist/docs/api/interfaces/LoadOptions.html +2 -2
  32. package/dist/docs/api/interfaces/MapEvents.html +116 -0
  33. package/dist/docs/api/interfaces/MapMarkerEvents.html +66 -0
  34. package/dist/docs/api/interfaces/MarkerEventPayload.html +57 -0
  35. package/dist/docs/api/interfaces/MediaEvents.html +78 -0
  36. package/dist/docs/api/interfaces/MenuBarEvents.html +114 -0
  37. package/dist/docs/api/interfaces/MessageEvents.html +72 -0
  38. package/dist/docs/api/interfaces/OlLayer.html +1 -1
  39. package/dist/docs/api/interfaces/OlMap.html +1 -1
  40. package/dist/docs/api/interfaces/OlSource.html +1 -1
  41. package/dist/docs/api/interfaces/OlTileLayer.html +1 -1
  42. package/dist/docs/api/interfaces/OlVectorLayer.html +1 -1
  43. package/dist/docs/api/interfaces/OlView.html +1 -1
  44. package/dist/docs/api/interfaces/SlideBackgroundState.html +66 -0
  45. package/dist/docs/api/interfaces/SlideEvents.html +78 -0
  46. package/dist/docs/api/interfaces/SlideNavEvents.html +72 -0
  47. package/dist/docs/api/interfaces/SlideshowPlayerSettings.html +182 -0
  48. package/dist/docs/api/interfaces/SlideshowToStorymapResult.html +60 -0
  49. package/dist/docs/api/interfaces/SlideshowTranslatorOptions.html +65 -0
  50. package/dist/docs/api/interfaces/SlideshowWarning.html +72 -0
  51. package/dist/docs/api/interfaces/StoryMapEvents.html +146 -0
  52. package/dist/docs/api/interfaces/StoryMapMarker.html +763 -0
  53. package/dist/docs/api/interfaces/StorySliderEvents.html +102 -0
  54. package/dist/docs/api/interfaces/StorymapBasemap.html +69 -0
  55. package/dist/docs/api/interfaces/StorymapData.html +12 -6
  56. package/dist/docs/api/interfaces/StorymapDataWrapper.html +2 -2
  57. package/dist/docs/api/interfaces/StorymapDocument.html +2 -2
  58. package/dist/docs/api/interfaces/StorymapError.html +3 -3
  59. package/dist/docs/api/interfaces/StorymapGeoreference.html +5 -5
  60. package/dist/docs/api/interfaces/StorymapGeoreferenceBody.html +4 -4
  61. package/dist/docs/api/interfaces/StorymapGroundControlPoint.html +4 -4
  62. package/dist/docs/api/interfaces/StorymapLanguageMap.html +2 -2
  63. package/dist/docs/api/interfaces/StorymapManifest.html +12 -12
  64. package/dist/docs/api/interfaces/StorymapManifestAnnotation.html +43 -11
  65. package/dist/docs/api/interfaces/StorymapManifestBackground.html +6 -6
  66. package/dist/docs/api/interfaces/StorymapManifestCanvas.html +65 -17
  67. package/dist/docs/api/interfaces/StorymapManifestContentResource.html +8 -8
  68. package/dist/docs/api/interfaces/StorymapManifestFeatureCollection.html +4 -4
  69. package/dist/docs/api/interfaces/StorymapManifestGeoreferencing.html +7 -7
  70. package/dist/docs/api/interfaces/StorymapManifestImageService.html +4 -4
  71. package/dist/docs/api/interfaces/StorymapManifestRange.html +5 -5
  72. package/dist/docs/api/interfaces/StorymapManifestService.html +4 -4
  73. package/dist/docs/api/interfaces/StorymapManifestSpecificResource.html +4 -4
  74. package/dist/docs/api/interfaces/StorymapManifestStatement.html +3 -3
  75. package/dist/docs/api/interfaces/StorymapMapOptions.html +5 -5
  76. package/dist/docs/api/interfaces/StorymapOptions.html +277 -75
  77. package/dist/docs/api/interfaces/StorymapOverlayLayer.html +42 -11
  78. package/dist/docs/api/interfaces/StorymapSlide.html +70 -16
  79. package/dist/docs/api/interfaces/StorymapSlideBackground.html +4 -4
  80. package/dist/docs/api/interfaces/StorymapSlideLocation.html +58 -14
  81. package/dist/docs/api/interfaces/StorymapSlideMarker.html +8 -9
  82. package/dist/docs/api/interfaces/StorymapSlideMedia.html +49 -10
  83. package/dist/docs/api/interfaces/StorymapSlideNarration.html +61 -9
  84. package/dist/docs/api/interfaces/StorymapSlideText.html +4 -4
  85. package/dist/docs/api/interfaces/StorymapTilejson.html +8 -8
  86. package/dist/docs/api/interfaces/SwipableEvents.html +102 -0
  87. package/dist/docs/api/interfaces/TextEvents.html +66 -0
  88. package/dist/docs/api/media/events.md +66 -0
  89. package/dist/docs/api/media/migration-from-knightlab.md +89 -49
  90. package/dist/docs/api/media/slideshow.md +109 -0
  91. package/dist/docs/api/media/storymap-as-iiif-manifest.md +1007 -0
  92. package/dist/docs/api/modules.html +6 -6
  93. package/dist/docs/api/types/ContentState.html +3 -3
  94. package/dist/docs/api/types/FiredEvent.html +43 -0
  95. package/dist/docs/api/types/ImagereadyKind.html +1 -1
  96. package/dist/docs/api/types/MediaTypeMatch.html +5 -5
  97. package/dist/docs/api/types/SwipeDirection.html +36 -0
  98. package/dist/docs/api/types/TileSourceFactory.html +1 -1
  99. package/dist/docs/authoring.html +20 -7
  100. package/dist/docs/events.html +263 -0
  101. package/dist/docs/iiif.html +136 -22
  102. package/dist/docs/migration.html +66 -19
  103. package/dist/docs/readme.html +113 -12
  104. package/dist/embed/index.html +7 -0
  105. package/dist/examples/font-css-false.json +33 -0
  106. package/dist/examples/issue-image-region.json +1 -1
  107. package/dist/examples/layers-control.json +60 -0
  108. package/dist/examples/map-template-provider.json +36 -0
  109. package/dist/examples/multi-media.json +71 -0
  110. package/dist/examples-iiif/annotated-image.json +16 -0
  111. package/dist/examples-iiif/font-css-false.json +114 -0
  112. package/dist/examples-iiif/issue-image-region.json +1 -1
  113. package/dist/examples-iiif/layers-control.json +226 -0
  114. package/dist/examples-iiif/map-template-provider.json +133 -0
  115. package/dist/examples-iiif/multi-media.json +237 -0
  116. package/dist/examples-slideshow/single.json +79 -0
  117. package/dist/examples-slideshow/static/pixel.png +0 -0
  118. package/dist/examples-slideshow/static.json +44 -0
  119. package/dist/harness-multi.html +3 -3
  120. package/dist/harness.html +4 -3
  121. package/dist/index.html +3 -2
  122. package/dist/js/storymap.d.ts +1326 -289
  123. package/dist/js/storymap.js +6690 -4784
  124. package/dist/js/storymap.js.map +1 -1
  125. package/dist/navplace-properties.json +14 -0
  126. package/dist/site.css +54 -36
  127. package/docs/migration-from-knightlab.md +89 -49
  128. package/docs/storymap-as-iiif-manifest.md +199 -126
  129. package/package.json +4 -2
  130. package/schema/storymap.schema.json +334 -34
  131. package/src/core/Util.ts +3 -1
  132. package/src/core/mixins.ts +42 -28
  133. package/src/language/Language.ts +7 -0
  134. package/src/language/locale/.expected-gaps.json +287 -27
  135. package/src/language/locale/de.json +11 -1
  136. package/src/language/locale/en.json +11 -1
  137. package/src/main.ts +51 -0
  138. package/src/map/Map.ts +44 -6
  139. package/src/map/MapMarker.ts +16 -3
  140. package/src/map/openlayers/Map.OpenLayers.ts +787 -62
  141. package/src/map/openlayers/MapMarker.OpenLayers.ts +113 -13
  142. package/src/map/slideView.ts +149 -0
  143. package/src/map/types.ts +2 -0
  144. package/src/media/EmbedUtil.ts +27 -2
  145. package/src/media/Media.ts +27 -4
  146. package/src/media/embedId.ts +6 -0
  147. package/src/media/types/Flickr.ts +14 -3
  148. package/src/media/types/HtmlMedia.ts +66 -0
  149. package/src/media/types/Image.ts +15 -3
  150. package/src/media/types/SoundCloud.ts +1 -1
  151. package/src/media/types/Text.ts +27 -8
  152. package/src/media/types/Twitter.ts +9 -7
  153. package/src/media/types/Vimeo.ts +1 -1
  154. package/src/media/types/YouTube.ts +2 -2
  155. package/src/scss/Typography.scss +15 -15
  156. package/src/scss/VCO.StoryMap.scss +173 -8
  157. package/src/scss/core/Reset.scss +5 -18
  158. package/src/scss/map/VCO.Map.scss +1 -1
  159. package/src/scss/map/VCO.MapMarker.scss +20 -9
  160. package/src/scss/map/openlayers/VCO.Map.OpenLayers.scss +7 -4
  161. package/src/scss/media/VCO.Media.scss +7 -7
  162. package/src/scss/media/types/VCO.Media.Blockquote.scss +1 -1
  163. package/src/scss/media/types/VCO.Media.Text.scss +5 -5
  164. package/src/scss/media/types/VCO.Media.Twitter.scss +4 -4
  165. package/src/scss/media/types/VCO.Media.Wikipedia.scss +2 -19
  166. package/src/scss/site/site.scss +55 -36
  167. package/src/scss/slider/VCO.Slide.scss +49 -11
  168. package/src/scss/slider/VCO.SlideNav.scss +23 -7
  169. package/src/scss/slider/VCO.StorySlider.scss +50 -0
  170. package/src/scss/snapmap/VCO.SnapMap.scss +3 -3
  171. package/src/scss/ui/VCO.Consent.scss +20 -14
  172. package/src/scss/ui/VCO.Layers.scss +119 -0
  173. package/src/scss/ui/VCO.MenuBar.Button.scss +140 -19
  174. package/src/scss/ui/VCO.MenuBar.scss +9 -2
  175. package/src/scss/ui/VCO.Message.scss +14 -0
  176. package/src/slider/Slide.ts +232 -74
  177. package/src/slider/SlideNav.ts +15 -4
  178. package/src/slider/StorySlider.ts +203 -22
  179. package/src/storymap/Consent.ts +22 -0
  180. package/src/storymap/StoryMap.ts +944 -131
  181. package/src/storymap/content-state.ts +3 -8
  182. package/src/storymap/font-css.ts +72 -0
  183. package/src/storymap/from-slideshow.ts +785 -0
  184. package/src/storymap/iiif-shared.ts +228 -0
  185. package/src/storymap/iiif.ts +289 -100
  186. package/src/storymap/to-iiif.ts +131 -44
  187. package/src/types.ts +382 -17
  188. package/src/ui/LayersControl.ts +302 -0
  189. package/src/ui/MenuBar.ts +232 -21
  190. package/src/ui/Message.ts +36 -3
  191. package/src/ui/Swipable.ts +25 -7
  192. package/dist/assets/harness-Cr0rYpvt.js +0 -1
  193. package/dist/assets/main-DXalctuR.js +0 -17
  194. package/src/scss/VCO.StoryMap.Dark.scss +0 -150
  195. package/src/scss/Variables.Dark.scss +0 -57
@@ -37,6 +37,7 @@
37
37
  <li><a class="button" href="./migration.html">Migration guide</a></li>
38
38
  <li><a class="button" href="./iiif.html">IIIF docs</a></li>
39
39
  <li><a class="button" href="./authoring.html">Authoring</a></li>
40
+ <li><a class="button" href="./events.html">Events</a></li>
40
41
  <li><a class="button" href="./api/index.html">API docs</a></li>
41
42
  <li><a class="button" href="../index.html#help">Help</a></li>
42
43
  </ul>
@@ -53,7 +54,11 @@ the fixtures in <a href="../examples/"><code>public/examples/</code></a> are rea
53
54
  (<a href="../examples-iiif/"><code>public/examples-iiif/</code></a>), and
54
55
  <code>scripts/validate-iiif.mjs</code> checks every converted manifest against the
55
56
  <a href="https://presentation-validator.iiif.io/">official IIIF presentation validator</a>
56
- (<code>npm run validate:iiif</code>). All converted fixtures pass the official validator.</p>
57
+ (<code>npm run validate:iiif</code>). All converted fixtures pass the official validator,
58
+ except the two hand-authored georeferenced-layer fixtures, which the base
59
+ validator schema cannot accept by design (see &quot;Geo-referenced layers&quot; below);
60
+ <code>npm run validate:iiif</code> reports those two as <em>not covered</em> rather than as
61
+ failures.</p>
57
62
  <h2>Contexts</h2>
58
63
  <p>A manifest declares four context URLs, in this order: the official
59
64
  <a href="https://iiif.io/api/extension/navplace/">navPlace extension</a> context (which
@@ -67,7 +72,6 @@ reference; a manifest must reference it by URL, not paste it in (see the
67
72
  &quot;@version&quot;: 1.1,
68
73
  &quot;storymap&quot;: &quot;https://christianmahnke.de/iiif/storymap#&quot;,
69
74
  &quot;mapAsImage&quot;: &quot;storymap:mapAsImage&quot;,
70
- &quot;basemap&quot;: &quot;storymap:basemap&quot;,
71
75
  &quot;tilejson&quot;: &quot;storymap:tilejson&quot;,
72
76
  &quot;mapAccessToken&quot;: &quot;storymap:mapAccessToken&quot;,
73
77
  &quot;mapBackgroundColor&quot;: &quot;storymap:mapBackgroundColor&quot;,
@@ -97,7 +101,19 @@ reference; a manifest must reference it by URL, not paste it in (see the
97
101
  &quot;@type&quot;: &quot;@id&quot;
98
102
  },
99
103
  &quot;mediaSrcset&quot;: &quot;storymap:mediaSrcset&quot;,
100
- &quot;mediaSizes&quot;: &quot;storymap:mediaSizes&quot;
104
+ &quot;mediaSizes&quot;: &quot;storymap:mediaSizes&quot;,
105
+ &quot;rotation&quot;: &quot;storymap:rotation&quot;,
106
+ &quot;basemap&quot;: &quot;storymap:basemap&quot;,
107
+ &quot;filter&quot;: &quot;storymap:filter&quot;,
108
+ &quot;mask&quot;: &quot;storymap:mask&quot;,
109
+ &quot;slidetimeout&quot;: &quot;storymap:slidetimeout&quot;,
110
+ &quot;imgoverlay&quot;: &quot;storymap:imgoverlay&quot;,
111
+ &quot;loop&quot;: &quot;storymap:loop&quot;,
112
+ &quot;offset&quot;: &quot;storymap:offset&quot;,
113
+ &quot;play&quot;: &quot;storymap:play&quot;,
114
+ &quot;stopOnExit&quot;: &quot;storymap:stopOnExit&quot;,
115
+ &quot;stopAllPrevious&quot;: &quot;storymap:stopAllPrevious&quot;,
116
+ &quot;provenance&quot;: &quot;storymap:provenance&quot;
101
117
  }
102
118
  }
103
119
  </code></pre>
@@ -125,7 +141,6 @@ what the fixtures reference. Content:</p>
125
141
  &quot;@context&quot;: {
126
142
  &quot;@version&quot;: 1.1,
127
143
  &quot;storymap&quot;: &quot;https://christianmahnke.de/iiif/storymap#&quot;,
128
- &quot;basemap&quot;: &quot;storymap:basemap&quot;,
129
144
  &quot;tilejson&quot;: &quot;storymap:tilejson&quot;,
130
145
  &quot;mapAsImage&quot;: &quot;storymap:mapAsImage&quot;,
131
146
  &quot;mapAccessToken&quot;: &quot;storymap:mapAccessToken&quot;,
@@ -153,7 +168,19 @@ what the fixtures reference. Content:</p>
153
168
  &quot;overlays&quot;: &quot;storymap:overlays&quot;,
154
169
  &quot;type&quot;: { &quot;@id&quot;: &quot;storymap:type&quot;, &quot;@type&quot;: &quot;@id&quot; },
155
170
  &quot;mediaSrcset&quot;: &quot;storymap:mediaSrcset&quot;,
156
- &quot;mediaSizes&quot;: &quot;storymap:mediaSizes&quot;
171
+ &quot;mediaSizes&quot;: &quot;storymap:mediaSizes&quot;,
172
+ &quot;rotation&quot;: &quot;storymap:rotation&quot;,
173
+ &quot;basemap&quot;: &quot;storymap:basemap&quot;,
174
+ &quot;filter&quot;: &quot;storymap:filter&quot;,
175
+ &quot;mask&quot;: &quot;storymap:mask&quot;,
176
+ &quot;slidetimeout&quot;: &quot;storymap:slidetimeout&quot;,
177
+ &quot;imgoverlay&quot;: &quot;storymap:imgoverlay&quot;,
178
+ &quot;loop&quot;: &quot;storymap:loop&quot;,
179
+ &quot;offset&quot;: &quot;storymap:offset&quot;,
180
+ &quot;play&quot;: &quot;storymap:play&quot;,
181
+ &quot;stopOnExit&quot;: &quot;storymap:stopOnExit&quot;,
182
+ &quot;stopAllPrevious&quot;: &quot;storymap:stopAllPrevious&quot;,
183
+ &quot;provenance&quot;: &quot;storymap:provenance&quot;
157
184
  }
158
185
  }
159
186
  </code></pre>
@@ -301,9 +328,16 @@ with one GeoJSON Feature:</p>
301
328
  verbatim. For image-map storymaps (<code>storymap:mapAsImage: true</code>) the values are
302
329
  image coordinates rather than WGS84 degrees; consumers can detect this via
303
330
  <code>storymap:mapAsImage</code>.</li>
304
- <li><code>properties</code>: marker data — <code>name</code>, <code>zoom</code>, <code>line</code>, <code>icon</code>, <code>iconSize</code>,
305
- <code>image</code>, <code>use_custom_marker</code>, plus the presentation-only <code>popup</code> and
306
- <code>audioBadge</code> (only present keys).</li>
331
+ <li><code>properties</code>: marker data — <code>name</code>, <code>zoom</code>, <code>rotation</code> (view rotation in
332
+ degrees clockwise), <code>basemap</code> (a per-slide basemap override: any <code>map_type</code>
333
+ value or IIIF <code>info.json</code> URL), <code>filter</code> (per-slide image grading:
334
+ <code>brightness</code>/<code>contrast</code>/<code>saturate</code> in percent, <code>hueRotate</code> in degrees,
335
+ <code>sepia</code> in percent, <code>blur</code> in CSS pixels), <code>mask</code> (a spotlight mask:
336
+ normalized <code>{x, y, w, h}</code> viewport fractions plus <code>color</code>/<code>invert</code>), <code>line</code>,
337
+ <code>icon</code>, <code>iconSize</code>, <code>image</code>, <code>use_custom_marker</code>, plus the
338
+ presentation-only <code>popup</code> and <code>audioBadge</code> (only present keys). Slides
339
+ without <code>lat</code>/<code>lon</code> carry <code>rotation</code>/<code>basemap</code>/<code>filter</code>/<code>mask</code> as the
340
+ canvas <code>storymap:</code> terms below instead.</li>
307
341
  <li><code>location.use_custom_marker</code> / <code>use_custom_markers</code> (manifest) opt into
308
342
  custom marker rendering; see the storymap terms below.</li>
309
343
  </ul>
@@ -315,8 +349,7 @@ context, and a client that meets a property it does not understand must ignore
315
349
  it. There is no IIIF extension for marker presentation — navPlace defines
316
350
  exactly one term, <code>navPlace</code> itself — so the local context is the only option.
317
351
  It is why <code>popup</code> and <code>audioBadge</code> need no <code>storymap:</code> term of their own, and
318
- the same mechanism is what <code>docs/plans/iiif-media-tours.md</code> §2 wants for its
319
- marker config. The nine local names hang off this project&#39;s existing namespace
352
+ the same mechanism serves marker config. The thirteen local names hang off this project&#39;s existing namespace
320
353
  (<code>https://christianmahnke.de/iiif/storymap#</code>), not a new one.</p>
321
354
  <h3>Context order matters</h3>
322
355
  <p>The navPlace extension&#39;s context <strong>must be listed before</strong> the Presentation 3
@@ -408,7 +441,9 @@ properties):</p>
408
441
  <p>A keyword basemap and a tile URL template are different kinds of thing, and
409
442
  <code>mapType</code> used to be both. They are now separate: <code>storymap:basemap</code> names a
410
443
  source the viewer knows how to configure, and an <strong>unprefixed</strong> <code>tilejson</code>
411
- object describes any other tile service in the standard&#39;s own terms. Only
444
+ object describes any other tile service in the standard&#39;s own terms (the
445
+ <code>tilejson</code> context entry stays prefixed by JSON-LD convention; only the
446
+ unprefixed wire form is read). Only
412
447
  <code>tiles</code> is required:</p>
413
448
  <pre><code class="language-json">{
414
449
  &quot;service&quot;: [
@@ -432,7 +467,9 @@ object describes any other tile service in the standard&#39;s own terms. Only
432
467
  </code></pre>
433
468
  <p><code>tiles</code> becomes <code>map_type</code>, so everything that dispatches on a template (the
434
469
  <code>tile_source_factory</code> option, attribution, the minimap) works unchanged. The
435
- rest is honoured where the map can act on it:</p>
470
+ rest is honoured where the map can act on it when <em>reading</em> a manifest; note
471
+ the converter only writes <code>{tiles}</code> back out, so a manifest → storymap →
472
+ manifest cycle drops <code>minzoom</code>/<code>maxzoom</code>/<code>bounds</code>/<code>scheme</code>/<code>center</code>:</p>
436
473
  <table>
437
474
  <thead>
438
475
  <tr>
@@ -507,9 +544,9 @@ offset, the same reason <code>map_bbox</code> works the way it does.</p>
507
544
  <td><code>{left, top}</code></td>
508
545
  </tr>
509
546
  <tr>
510
- <td><code>mapSubdomains</code></td>
547
+ <td><em>(none — removed)</em></td>
511
548
  <td><code>map_subdomains</code></td>
512
- <td>Tile URL subdomains</td>
549
+ <td><em>dropped</em> (inert, no reader; see the full mapping table)</td>
513
550
  </tr>
514
551
  <tr>
515
552
  <td><em>(none)</em></td>
@@ -519,7 +556,7 @@ offset, the same reason <code>map_bbox</code> works the way it does.</p>
519
556
  <tr>
520
557
  <td><code>fontCss</code></td>
521
558
  <td><code>font_css</code></td>
522
- <td>e.g. <code>stock:dancing-ledger</code></td>
559
+ <td>e.g. <code>stock:dancing-ledger</code>, or <code>false</code> for no injected theme</td>
523
560
  </tr>
524
561
  <tr>
525
562
  <td><code>callToAction</code></td>
@@ -547,9 +584,9 @@ offset, the same reason <code>map_bbox</code> works the way it does.</p>
547
584
  <td>boolean</td>
548
585
  </tr>
549
586
  <tr>
550
- <td><code>lessBounce</code></td>
587
+ <td><em>(none — removed)</em></td>
551
588
  <td><code>less_bounce</code></td>
552
- <td>boolean</td>
589
+ <td><em>dropped</em> (inert, no reader; see the full mapping table)</td>
553
590
  </tr>
554
591
  <tr>
555
592
  <td><code>lineFollowsPath</code></td>
@@ -626,12 +663,24 @@ offset, the same reason <code>map_bbox</code> works the way it does.</p>
626
663
  <td><code>overlays[]</code> (georeference entries)</td>
627
664
  <td>IIIF images placed from ground control points — see &quot;Geo-referenced layers&quot;</td>
628
665
  </tr>
666
+ <tr>
667
+ <td><em>(viewer option)</em></td>
668
+ <td><code>show_layers_control</code>, <code>basemaps</code></td>
669
+ <td>the layer switcher and its basemap list: viewer-side only, never read from a manifest; <code>label</code> functions likewise never cross the JSON boundary</td>
670
+ </tr>
629
671
  </tbody></table>
630
672
  <h3>Canvas level — direct properties</h3>
631
673
  <p>Canvas objects are open for extension terms, so slide-specific StoryMap data is
632
674
  carried directly on the Canvas: <code>storymap:type</code>, plus the two terms with no
633
675
  standard home, <code>storymap:mediaSrcset</code> and <code>storymap:mediaSizes</code> (see the
634
- Canvas table above). A slide&#39;s date is the standard <code>navDate</code> and its
676
+ Canvas table above), plus the view directives <code>storymap:rotation</code>,
677
+ <code>storymap:basemap</code>, <code>storymap:filter</code> and <code>storymap:mask</code> (the fallback for
678
+ slides without <code>lat</code>/<code>lon</code>, which have no <code>navPlace</code> to carry them — the
679
+ reader prefers <code>navPlace</code> when both spell a key), the per-slide autoplay
680
+ dwell <code>storymap:slidetimeout</code> (milliseconds, <code>0</code> holds), the per-slide
681
+ image overlay <code>storymap:imgoverlay</code> (<code>{url, size?, opacity?, extent?}</code>) and
682
+ the provenance identifiers <code>storymap:provenance</code>
683
+ (<code>{manifest?, canvas?, image?}</code>, data-only). A slide&#39;s date is the standard <code>navDate</code> and its
635
684
  background is the standard <code>background</code> annotation. The media caption, credit and alt
636
685
  text are <strong>not</strong> terms any more: they are the painting annotation&#39;s own <code>label</code>,
637
686
  <code>requiredStatement</code> and <code>accessibilitySummary</code>, which is where Presentation 3
@@ -640,6 +689,19 @@ are simply no longer read.</p>
640
689
  <p>Readers must use the prefixed term for the slide type (<code>storymap:type</code>): the
641
690
  bare <code>type</code> key of a Canvas is the IIIF class type (<code>&quot;Canvas&quot;</code>) and can never
642
691
  carry the StoryMap slide type.</p>
692
+ <p><strong>Gating.</strong> The slideshow-motivated fields above (<code>rotation</code>, <code>basemap</code>,
693
+ <code>filter</code>, <code>mask</code>, <code>slidetimeout</code>, <code>imgoverlay</code>, <code>provenance</code>) are read
694
+ data-preservingly from any manifest, but they render <strong>only for slideshow
695
+ tours</strong> (the viewer&#39;s internal <code>slideshow_source</code> marker, set when a
696
+ document arrives through the slideshow translator). Hand-written manifests
697
+ and storymap JSON keep the long-standing rendering; see the README&#39;s
698
+ slideshow section. The playback flags (<code>storymap:loop/offset/play/ stopOnExit/stopAllPrevious</code>) are gated the same way.</p>
699
+ <p><strong>Placement.</strong> The view directives live on the <strong>Canvas</strong> (direct
700
+ properties); the playback flags live as <strong>Annotation</strong> foreign members —
701
+ <code>storymap:loop/offset/play/stopOnExit</code> on the painting annotation (for
702
+ audio/video media) and the full set including <code>storymap:stopAllPrevious</code>
703
+ on the <code>supplementing</code> narration annotation. When a key is spelled both on
704
+ the Canvas and in <code>navPlace</code> properties, <code>navPlace</code> wins.</p>
643
705
  <h2>Annotation-driven tour stops</h2>
644
706
  <p>A Canvas annotation whose <code>motivation</code> is <code>commenting</code>, <code>tagging</code>,
645
707
  <code>classifying</code> or <code>describing</code> and whose target resolves to a region becomes
@@ -698,8 +760,8 @@ and the standard properties are the only source:</p>
698
760
  <td>time-anchored stops</td>
699
761
  </tr>
700
762
  <tr>
701
- <td>a sibling <code>TextualBody</code> with <code>format: text/vtt</code></td>
702
- <td><code>subtitles</code></td>
763
+ <td>a sibling <code>TextualBody</code> with <code>format: text/vtt</code> <strong>and an <code>id</code></strong></td>
764
+ <td><code>subtitles</code> (both required — the <code>id</code> is the subtitle file URL)</td>
703
765
  </tr>
704
766
  </tbody></table>
705
767
  <h2>Native IIIF vs. the StoryMap extension</h2>
@@ -1245,7 +1307,7 @@ photo, and a slide with a YouTube video — full manifest:</p>
1245
1307
  </tr>
1246
1308
  <tr>
1247
1309
  <td><code>iiif.url</code></td>
1248
- <td>Canvas Image annotation <code>service[0].id</code> + <code>/info.json</code></td>
1310
+ <td>Canvas Image annotation <code>service[0].id</code> + <code>/info.json</code> (only when the story uses <code>map_type: &quot;iiif&quot;</code>)</td>
1249
1311
  </tr>
1250
1312
  <tr>
1251
1313
  <td><code>iiif.attribution</code></td>
@@ -1257,7 +1319,7 @@ photo, and a slide with a YouTube video — full manifest:</p>
1257
1319
  </tr>
1258
1320
  <tr>
1259
1321
  <td><code>font_css</code></td>
1260
- <td><code>service[0].storymap:fontCss</code></td>
1322
+ <td><code>service[0].storymap:fontCss</code> (<code>false</code> disables the injected theme)</td>
1261
1323
  </tr>
1262
1324
  <tr>
1263
1325
  <td><code>call_to_action</code></td>
@@ -1279,6 +1341,18 @@ photo, and a slide with a YouTube video — full manifest:</p>
1279
1341
  <td><em>(root) <code>width</code>, <code>height</code></em></td>
1280
1342
  <td><em>dropped</em> (viewer embed size)</td>
1281
1343
  </tr>
1344
+ <tr>
1345
+ <td><em>(slideshow tours) player chrome (<code>textmode</code>, <code>textsize</code>, <code>progressbar</code>, <code>fxmode</code>, <code>mode</code>, <code>hud*</code>, <code>shownav</code>, <code>show_*</code>, <code>viewerheight</code>, <code>autoplay</code>)</em></td>
1346
+ <td><em>dropped</em> (no IIIF vocabulary; translator-only, see docs/slideshow.md)</td>
1347
+ </tr>
1348
+ <tr>
1349
+ <td><code>credit.creator</code> / <code>credit.rights</code></td>
1350
+ <td>Manifest <code>metadata</code> entries (&quot;Creator&quot; / &quot;Rights&quot;) — one way: the reader keeps all metadata in <code>data.metadata[]</code> and never reconstructs <code>credit</code>, and <code>credit.licenseUrl</code> is not written at all</td>
1351
+ </tr>
1352
+ <tr>
1353
+ <td><code>iiif.fallbackUrl</code></td>
1354
+ <td><em>dropped</em> (runtime fallback; tour documents carry <code>image_static</code> per stop)</td>
1355
+ </tr>
1282
1356
  </tbody></table>
1283
1357
  <table>
1284
1358
  <thead>
@@ -1336,6 +1410,46 @@ photo, and a slide with a YouTube video — full manifest:</p>
1336
1410
  <td>Canvas <code>navPlace</code> Feature <code>properties.use_custom_marker</code></td>
1337
1411
  </tr>
1338
1412
  <tr>
1413
+ <td><code>location.rotation</code></td>
1414
+ <td>Canvas <code>navPlace</code> Feature <code>properties.rotation</code>, else Canvas <code>storymap:rotation</code></td>
1415
+ </tr>
1416
+ <tr>
1417
+ <td><code>location.basemap</code></td>
1418
+ <td>Canvas <code>navPlace</code> Feature <code>properties.basemap</code>, else Canvas <code>storymap:basemap</code></td>
1419
+ </tr>
1420
+ <tr>
1421
+ <td><code>location.filter</code></td>
1422
+ <td>Canvas <code>navPlace</code> Feature <code>properties.filter</code>, else Canvas <code>storymap:filter</code></td>
1423
+ </tr>
1424
+ <tr>
1425
+ <td><code>location.mask</code></td>
1426
+ <td>Canvas <code>navPlace</code> Feature <code>properties.mask</code>, else Canvas <code>storymap:mask</code></td>
1427
+ </tr>
1428
+ <tr>
1429
+ <td><code>slidetimeout</code></td>
1430
+ <td>Canvas <code>storymap:slidetimeout</code> (milliseconds, <code>0</code> holds)</td>
1431
+ </tr>
1432
+ <tr>
1433
+ <td><code>imgoverlay</code></td>
1434
+ <td>Canvas <code>storymap:imgoverlay</code></td>
1435
+ </tr>
1436
+ <tr>
1437
+ <td><code>provenance</code></td>
1438
+ <td>Canvas <code>storymap:provenance</code> (data-only identifiers)</td>
1439
+ </tr>
1440
+ <tr>
1441
+ <td><code>narration.url</code></td>
1442
+ <td>Supplementing annotation body <code>{type: &quot;Sound&quot;}</code></td>
1443
+ </tr>
1444
+ <tr>
1445
+ <td><code>narration.loop/offset/play/stopOnExit/stopAllPrevious</code></td>
1446
+ <td>Supplementing annotation <code>storymap:</code> members (foreign members, only when set)</td>
1447
+ </tr>
1448
+ <tr>
1449
+ <td><code>media.offset/loop/play/stopOnExit</code></td>
1450
+ <td>Painting annotation <code>storymap:</code> members (foreign members, only when set)</td>
1451
+ </tr>
1452
+ <tr>
1339
1453
  <td><code>media.url</code> (image)</td>
1340
1454
  <td>Annotation body <code>{type: &quot;Image&quot;, format: ...}</code></td>
1341
1455
  </tr>
@@ -37,6 +37,7 @@
37
37
  <li><a class="button" href="./migration.html">Migration guide</a></li>
38
38
  <li><a class="button" href="./iiif.html">IIIF docs</a></li>
39
39
  <li><a class="button" href="./authoring.html">Authoring</a></li>
40
+ <li><a class="button" href="./events.html">Events</a></li>
40
41
  <li><a class="button" href="./api/index.html">API docs</a></li>
41
42
  <li><a class="button" href="../index.html#help">Help</a></li>
42
43
  </ul>
@@ -154,6 +155,10 @@ are rendered wider with a visible track for contrast.</li>
154
155
  <td><code>font_css: &quot;stock:&lt;name&gt;&quot;</code> (or a path)</td>
155
156
  <td>paths now resolve against the page URL (not the library location), plus the font files ship via <code>@fontsource-utils/scss</code>; no separate font CSS link needed</td>
156
157
  </tr>
158
+ <tr>
159
+ <td><code>font_css: false</code> (bundler consumers)</td>
160
+ <td><code>stock:&lt;name&gt;</code> resolves via <code>import.meta.url</code>, which only survives when this package is <em>not</em> processed by a bundler — bundling inlines <code>dist/js/storymap.js</code> into a chunk and the theme URL breaks. Instead <code>import &quot;@projektemacher/storymapjs/css/fonts/font.default.css&quot;</code> (fingerprinted, <code>files/</code> rebased by the bundler) and pass <code>font_css: false</code> for no injected <code>&lt;link&gt;</code>. <code>&quot;none&quot;</code> works too for JSON. A failing theme only warns</td>
161
+ </tr>
157
162
  </tbody></table>
158
163
  <h2>A story with no map</h2>
159
164
  <p><code>map_type: &quot;none&quot;</code> runs the storymap as text and media only. Nothing is
@@ -241,11 +246,12 @@ their neutral values, and the map setters are no-ops.</p>
241
246
  <td>service no longer available (won&#39;t fix) — paste the provider&#39;s <code>&lt;iframe&gt;</code> snippet into the slide text if the service returns</td>
242
247
  </tr>
243
248
  </tbody></table>
244
- <p>Extra media per slide (#358, partial): each slide still has one primary
245
- <code>media</code> item, but an <code>&lt;iframe&gt;</code> embed snippet pasted into the slide <code>text</code>
246
- field now renders sanitized (scripts, event handlers and non-https sources
247
- dropped) — use this for a second video/map/embed or as the migration path
248
- for removed media types:</p>
249
+ <p>Extra media per slide (#358, partial): a slide takes <code>media_extra</code> (a list of
250
+ further media items, rendered after the primary one) plus <code>media_layout</code>
251
+ (<code>stack</code>, the default, or <code>row</code> for two side-by-side items). An <code>&lt;iframe&gt;</code>
252
+ embed snippet pasted into the slide <code>text</code> field still renders sanitized
253
+ (scripts, event handlers and non-https sources dropped) — keep that as the
254
+ migration path for removed media types:</p>
249
255
  <pre><code class="language-html">&lt;p&gt;Extra footage:&lt;/p&gt;
250
256
  &lt;iframe
251
257
  src=&quot;https://example.com/embed/123&quot;
@@ -272,9 +278,10 @@ below). It is <code>null</code> until the map has been built.</li>
272
278
  before; the mini map is an OpenLayers <code>OverviewMap</code> control.</li>
273
279
  <li>New basemap options: vector styles via <code>map_type: &quot;osm:&lt;style&gt;&quot;</code> (OpenFreeMap)
274
280
  or a Mapbox style JSON URL.</li>
275
- <li>All OL types (<code>Map</code>, <code>View</code>, <code>Layer</code>, <code>Source</code>, <code>Feature</code>, ...) are
276
- re-exported, so a consumer can type its own overlays without depending on
277
- <code>ol</code> directly.</li>
281
+ <li>The <code>Ol*</code> aliases re-exported from <code>src/main.ts</code> (<code>OlMap</code>, <code>OlView</code>,
282
+ <code>OlLayer</code>, <code>OlTileLayer</code>, <code>OlVectorLayer</code>, <code>OlSource</code>, <code>OlProjection</code>) let
283
+ a consumer type the map and layers without depending on <code>ol</code> directly;
284
+ anything beyond those (features, geometries, coordinates) still needs <code>ol</code>.</li>
278
285
  </ul>
279
286
  <h3>Direct Leaflet calls → OpenLayers</h3>
280
287
  <p>Both maps are reachable from the same place (<code>storymap.map</code>), so only the
@@ -384,12 +391,20 @@ deprecated no-ops and one is gone:</p>
384
391
  </tr>
385
392
  <tr>
386
393
  <td><code>marker.createPopup()</code></td>
387
- <td><strong>deprecated no-op</strong> — it never did anything upstream either (empty base body, commented-out Leaflet body), so the <code>map_popup</code> option that called it had no effect. Still accepted, still inert</td>
394
+ <td><strong>deprecated no-op</strong> — it never did anything upstream either (empty base body, commented-out Leaflet body), so the <code>map_popup</code> option that called it had no effect. Still accepted, still inert. Use <code>marker.openPopup()</code> / <code>storymap.openMarkerPopup(n)</code> instead</td>
388
395
  </tr>
389
396
  <tr>
390
397
  <td><code>marker.addTo()</code>, <code>marker.removeFrom()</code>, <code>marker.updateDisplay()</code>, <code>marker.active()</code>, <code>marker.location()</code></td>
391
398
  <td>unchanged</td>
392
399
  </tr>
400
+ <tr>
401
+ <td><code>marker.openPopup()</code> / <code>closePopup()</code> / <code>togglePopup()</code> / <code>isPopupEnabled()</code> / <code>popupOpen</code></td>
402
+ <td><strong>new</strong> — programmatic control of the popup card (<code>marker: { popup: true }</code>); <code>openPopup()</code> returns false when disabled or not a real marker, <code>popupOpen</code> reports the state</td>
403
+ </tr>
404
+ <tr>
405
+ <td><code>storymap.openMarkerPopup(n)</code> / <code>closeMarkerPopup(n?)</code> / <code>isPopupOpen(n)</code></td>
406
+ <td><strong>new</strong> — open/close/query a stop&#39;s card from the viewer; <code>openMarkerPopup</code> navigates to <code>n</code> first and returns false (changing nothing) when disabled, out of range, disposed or mapless</td>
407
+ </tr>
393
408
  </tbody></table>
394
409
  <p>Marker helpers that Leaflet provided on the marker object (<code>getLatLng</code>,
395
410
  <code>setIcon</code>, <code>bindPopup</code>) are gone; use <code>marker.latLon()</code>, the
@@ -424,7 +439,7 @@ viewer keeps internally is available through accessors on <code>storymap</code>
424
439
  </tr>
425
440
  <tr>
426
441
  <td><code>getMinimap()</code></td>
427
- <td>the <code>OverviewMap</code> control, or its inner map via <code>getOverviewMap()</code></td>
442
+ <td>the inner overview <code>ol/Map</code> (<code>OlMap | null</code>), not the <code>OverviewMap</code> control itself — there is no accessor for the control object</td>
428
443
  </tr>
429
444
  <tr>
430
445
  <td><code>getLine()</code> / <code>getLineActive()</code></td>
@@ -454,6 +469,20 @@ entries in order, and <strong>10/11</strong> for the full and travelled route li
454
469
  custom layer with no explicit z-index lands wherever OpenLayers puts it,
455
470
  which is above the lines — set one explicitly if the layer must sit inside
456
471
  the stack.</p>
472
+ <h3>Layer switcher</h3>
473
+ <p><code>show_layers_control: true</code> adds a disclosure button to the menubar with
474
+ basemap radios and overlay checkboxes. Basemap candidates come from
475
+ <code>basemaps[]</code> (entry 0 is the initial basemap unless <code>map_type</code> says
476
+ otherwise; omit for an overlays-only control); overlay rows come from the
477
+ built <code>overlays[]</code> entries, so a malformed entry never gets a row and row
478
+ <em>i</em> is always layer <em>i</em>. <code>label</code> may be a function for host i18n (re-invoked
479
+ on <code>refreshLabels()</code>), <code>locked: true</code> renders a row checked and disabled,
480
+ <code>control: false</code> hides a row without removing the overlay — but function
481
+ labels survive only in constructor options, because <code>mergeData()</code> lets
482
+ storymap JSON overwrite same-named option keys. A runtime basemap swap
483
+ rebuilds layers but never the view, so candidates needing another
484
+ projection are refused with a warning; switching fires <code>basemapchange</code> /
485
+ <code>overlaychange</code>, and the visitor&#39;s choice is never persisted.</p>
457
486
  <h3>Image space vs. georeferenced</h3>
458
487
  <p><code>map_type: &quot;iiif&quot;</code> is a mercator map by default. With <code>map_as_image: true</code> the
459
488
  image <em>is</em> the map: the view projection becomes <code>EPSG:4326</code>, the view is
@@ -490,14 +519,15 @@ viewer&#39;s own pan/zoom set, <code>view</code> merges over the computed defaul
490
519
  <p>For source classes the templates cannot express (WMS, authenticated or
491
520
  gridded sources), use the <code>tile_source_factory</code> option. It is consulted
492
521
  for every base, overlay and minimap layer before the built-in
493
- <code>map_type</code> handling — return a <code>TileLayer</code> (or a bare <code>Source</code>, which
494
- is wrapped in one), or <code>null</code>/<code>undefined</code> to fall through:</p>
522
+ <code>map_type</code> handling — return any <code>ol/layer/Layer</code> (used as-is) or a bare
523
+ <code>Source</code> (which is wrapped in a <code>TileLayer</code>), or <code>null</code>/<code>undefined</code> to fall
524
+ through:</p>
495
525
  <pre><code class="language-js">import TileLayer from &quot;ol/layer/Tile&quot;;
496
526
  import TileWMS from &quot;ol/source/TileWMS&quot;;
497
527
 
498
528
  new StoryMap(&quot;embed&quot;, data, {
499
529
  map_type: &quot;wms:flood&quot;,
500
- tile_source_factory: (map_type, { createDefault }) =&gt;
530
+ tile_source_factory: (map_type, { options, createDefault }) =&gt;
501
531
  map_type.startsWith(&quot;wms:&quot;)
502
532
  ? new TileLayer({
503
533
  source: new TileWMS({
@@ -509,6 +539,11 @@ new StoryMap(&quot;embed&quot;, data, {
509
539
  : createDefault(),
510
540
  });
511
541
  </code></pre>
542
+ <p>The second factory argument also carries the resolved <code>options</code>
543
+ (<code>{ options, createDefault }</code>). A factory may return any <code>ol/layer/Layer</code>
544
+ (used as-is — including sourceless layers such as Allmaps&#39;
545
+ <code>WarpedMapLayer</code>), a bare <code>Source</code> (wrapped in a <code>TileLayer</code>), or
546
+ <code>null</code>/<code>undefined</code> to fall through to the default <code>map_type</code> handling.</p>
512
547
  <p>Custom sources must carry their own attributions (via the returned
513
548
  source or the <code>attribution</code> option) — only the built-in <code>osm*</code> types
514
549
  are credited automatically. <code>tile_source_factory</code> is constructor- and
@@ -531,13 +566,25 @@ manifest-only (the legacy format cannot express ground control points); see
531
566
  <a href="./iiif.html#geo-referenced-layers">docs/storymap-as-iiif-manifest.md</a>.</li>
532
567
  <li>The editor, staging/backend infrastructure, AWS/GitHub hosting scripts and the
533
568
  Python authoring server are gone — this is a viewer-only library.</li>
569
+ <li><strong>Slideshow tours</strong> are a third input format: W3C <code>AnnotationCollection</code>
570
+ documents (the format of slideshow-style guided image tours) load
571
+ directly by object, file or URL, auto-detected after the IIIF branch
572
+ (<code>slideshow: false</code> opts out). A pure translator converts them to
573
+ storymap data — per-slide image regions, rotation, filter grading,
574
+ spotlight masks, per-slide basemaps, narration with playback flags and
575
+ player chrome — which renders only for slideshow tours (the internal
576
+ <code>slideshow_source</code> marker; other documents are unaffected). Convert
577
+ offline with <code>npm run convert:slideshow</code>; the full mapping is in
578
+ <a href="slideshow.md">docs/slideshow.md</a>.</li>
534
579
  </ul>
535
- <h2>Events (unchanged, plus two new ones)</h2>
536
- <p><code>change</code> (with <code>current_slide</code>, and now also <code>current_id</code> — the slide&#39;s
537
- <code>uniqueid</code>, for deep-linking), <code>loaded</code>, <code>title</code>, <code>dataloaded</code>,
538
- <code>fontLoaded</code>, plus the listener map in the constructor — all work as before.
539
- <code>markerAdded</code>/<code>markerRemoved</code> still fire on the map object, and <code>imageready</code>
540
- is new (see above).</p>
580
+ <h2>Events (unchanged, plus new ones)</h2>
581
+ <p>The canonical reference is <a href="./events.html">docs/events.md</a> — one table per
582
+ emitter, with payloads. What changed in migration terms: <code>change</code> gains
583
+ <code>current_id</code>, <code>loaded</code>, <code>title</code>, <code>dataloaded</code>, <code>fontLoaded</code>,
584
+ <code>transitionstart</code>/<code>transitionend</code>, <code>error</code> and the constructor listener map
585
+ all work as before; <code>markerAdded</code>/<code>markerRemoved</code> still fire on the map
586
+ object; <code>imageready</code>, <code>markerclick</code> and <code>popupopen</code>/<code>popupclose</code> are new
587
+ (see above).</p>
541
588
  <p>Two additions for IIIF tours: <code>await storymap.loadAnnotations()</code> fetches a
542
589
  manifest&#39;s externally referenced annotation pages and appends them as stops,
543
590
  then fires <code>annotationsloaded</code> with <code>{ stops, searchService, failed }</code>. A