@bendyline/squisq 2.11.10 → 2.11.12

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/README.md CHANGED
@@ -20,7 +20,7 @@ npm install @bendyline/squisq
20
20
  | **schemas** | Type definitions — `Doc`, `BlockTemplate`, `Viewport`, `Theme`, `LayoutStrategy` |
21
21
  | **doc** | Template registry, 26 block templates, animation/theme utilities |
22
22
  | **markdown** | Markdown parsing, stringifying, AST types (`MarkdownDocument`), tree utilities |
23
- | **spatial** | Haversine distance, Geohash encode/decode |
23
+ | **spatial** | Haversine distance and bearing, great-circle paths, Geohash encode/decode |
24
24
  | **storage** | `StorageAdapter` interface, Memory + LocalStorage + LocalForage adapters |
25
25
 
26
26
  ## New in this release
@@ -92,10 +92,19 @@ the original fence byte-for-byte for markdown round-trips.
92
92
  ### Spatial Utilities
93
93
 
94
94
  ```ts
95
- import { encodeGeohash, haversineDistance } from '@bendyline/squisq/spatial';
95
+ import {
96
+ destinationPoint,
97
+ encodeGeohash,
98
+ haversineDistance,
99
+ sampleGreatCircle,
100
+ } from '@bendyline/squisq/spatial';
96
101
 
97
102
  const distanceKm = haversineDistance({ lat: 47.6, lng: -122.3 }, { lat: 37.7, lng: -122.4 });
98
103
  const hash = encodeGeohash(47.6, -122.3, 7);
104
+
105
+ // Points along the shortest route, and a position projected 5 km due east.
106
+ const route = sampleGreatCircle({ lat: 47.6, lng: -122.3 }, { lat: 51.5, lng: -0.1 }, 20);
107
+ const ahead = destinationPoint({ lat: 47.6, lng: -122.3 }, 90, 5_000);
99
108
  ```
100
109
 
101
110
  ### Materialize a Block
@@ -6152,6 +6152,13 @@ function treeBlock(input, context) {
6152
6152
  return layers;
6153
6153
  }
6154
6154
 
6155
+ // src/doc/utils/textMetrics.ts
6156
+ var AVERAGE_CHAR_WIDTH_EM = 0.62;
6157
+ var BOLD_CHAR_WIDTH_EM = 0.66;
6158
+ function estimateTextWidth(text, fontSize, charWidthEm = AVERAGE_CHAR_WIDTH_EM) {
6159
+ return text.length * fontSize * charWidthEm;
6160
+ }
6161
+
6155
6162
  // src/doc/templates/timelineBlock.ts
6156
6163
  var clamp012 = (value) => Math.max(0, Math.min(1, value));
6157
6164
  var clamp = (value, min, max) => Math.max(min, Math.min(max, value));
@@ -6298,7 +6305,14 @@ function timelineBlock(input, context) {
6298
6305
  }
6299
6306
  const hasTrackLabels = tracks.some((track) => !!track.label);
6300
6307
  const outerMargin = Math.max(48, viewport.width * 0.065);
6301
- const labelWidth = hasTrackLabels ? Math.min(280, viewport.width * 0.18) : 0;
6308
+ const labelGap = 32;
6309
+ const longestLabel = Math.max(
6310
+ 0,
6311
+ ...tracks.map(
6312
+ (track) => track.label ? estimateTextWidth(track.label, trackFontSize, BOLD_CHAR_WIDTH_EM) : 0
6313
+ )
6314
+ );
6315
+ const labelWidth = hasTrackLabels ? Math.min(Math.min(280, viewport.width * 0.18), Math.ceil(longestLabel) + labelGap) : 0;
6302
6316
  const axisStartX = outerMargin + labelWidth;
6303
6317
  const axisEndX = viewport.width - outerMargin;
6304
6318
  const axisWidth = Math.max(1, axisEndX - axisStartX);
@@ -6361,9 +6375,9 @@ function timelineBlock(input, context) {
6361
6375
  }
6362
6376
  },
6363
6377
  position: {
6364
- x: outerMargin + labelWidth / 2 - 16,
6378
+ x: outerMargin + (labelWidth - labelGap) / 2,
6365
6379
  y,
6366
- width: Math.max(1, labelWidth - 32),
6380
+ width: Math.max(1, labelWidth - labelGap),
6367
6381
  anchor: "center"
6368
6382
  },
6369
6383
  animation: motionEntrance(context, { type: "fadeIn", duration: 0.5, delay: trackDelay })
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  flattenRenderableBlocks,
3
3
  getBlockBodyText
4
- } from "./chunk-TYW5VMNP.js";
4
+ } from "./chunk-42IU2SJY.js";
5
5
  import {
6
6
  estimateSpokenWordCount
7
7
  } from "./chunk-GHOPHGOK.js";
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-SVN7T6BK.js";
6
6
  import {
7
7
  markdownToDoc
8
- } from "./chunk-TYW5VMNP.js";
8
+ } from "./chunk-42IU2SJY.js";
9
9
  import {
10
10
  cloneAndFreezeData,
11
11
  isTemplateBlock
@@ -329,20 +329,43 @@ function scopeContainer(parent, prefix) {
329
329
  // src/storage/MediaProviderFromContainer.ts
330
330
  function createMediaProviderFromContainer(container) {
331
331
  const blobUrlCache = /* @__PURE__ */ new Map();
332
- return {
333
- async resolveUrl(relativePath) {
334
- const cached = blobUrlCache.get(relativePath);
335
- if (cached) return cached;
332
+ const pending = /* @__PURE__ */ new Map();
333
+ const generations = /* @__PURE__ */ new Map();
334
+ let disposed = false;
335
+ function invalidate(path) {
336
+ generations.set(path, (generations.get(path) ?? 0) + 1);
337
+ pending.delete(path);
338
+ const cached = blobUrlCache.get(path);
339
+ if (cached) URL.revokeObjectURL(cached);
340
+ blobUrlCache.delete(path);
341
+ }
342
+ function resolveUrl(relativePath) {
343
+ if (disposed) return Promise.resolve(relativePath);
344
+ const cached = blobUrlCache.get(relativePath);
345
+ if (cached) return Promise.resolve(cached);
346
+ const existing = pending.get(relativePath);
347
+ if (existing) return existing;
348
+ const generation = generations.get(relativePath) ?? 0;
349
+ const work = (async () => {
336
350
  const data = await container.readFile(relativePath);
351
+ const entries = data ? await container.listFiles() : [];
352
+ if (disposed) return relativePath;
353
+ if ((generations.get(relativePath) ?? 0) !== generation) return resolveUrl(relativePath);
337
354
  if (!data) return relativePath;
338
- const entries = await container.listFiles();
339
- const entry = entries.find((e) => e.path === relativePath);
340
- const mimeType = entry?.mimeType ?? "application/octet-stream";
341
- const blob = new Blob([data], { type: mimeType });
342
- const url = URL.createObjectURL(blob);
355
+ const mimeType = entries.find((e) => e.path === relativePath)?.mimeType;
356
+ const url = URL.createObjectURL(
357
+ new Blob([data], { type: mimeType ?? "application/octet-stream" })
358
+ );
343
359
  blobUrlCache.set(relativePath, url);
344
360
  return url;
345
- },
361
+ })().finally(() => {
362
+ if (pending.get(relativePath) === work) pending.delete(relativePath);
363
+ });
364
+ pending.set(relativePath, work);
365
+ return work;
366
+ }
367
+ return {
368
+ resolveUrl,
346
369
  async listMedia() {
347
370
  const entries = await container.listFiles();
348
371
  return entries.filter((e) => !e.path.toLowerCase().endsWith(".md")).map((e) => ({
@@ -352,11 +375,7 @@ function createMediaProviderFromContainer(container) {
352
375
  }));
353
376
  },
354
377
  async addMedia(name, data, mimeType) {
355
- const cached = blobUrlCache.get(name);
356
- if (cached) {
357
- URL.revokeObjectURL(cached);
358
- blobUrlCache.delete(name);
359
- }
378
+ invalidate(name);
360
379
  let buffer;
361
380
  if (data instanceof Blob) {
362
381
  buffer = await data.arrayBuffer();
@@ -364,17 +383,17 @@ function createMediaProviderFromContainer(container) {
364
383
  buffer = data;
365
384
  }
366
385
  await container.writeFile(name, buffer, mimeType);
386
+ invalidate(name);
367
387
  return name;
368
388
  },
369
389
  async removeMedia(relativePath) {
370
- const cached = blobUrlCache.get(relativePath);
371
- if (cached) {
372
- URL.revokeObjectURL(cached);
373
- blobUrlCache.delete(relativePath);
374
- }
390
+ invalidate(relativePath);
375
391
  await container.removeFile(relativePath);
392
+ invalidate(relativePath);
376
393
  },
377
394
  dispose() {
395
+ disposed = true;
396
+ pending.clear();
378
397
  for (const url of blobUrlCache.values()) {
379
398
  URL.revokeObjectURL(url);
380
399
  }
@@ -109,6 +109,53 @@ function geohashOverlapsBounds(hash, bounds) {
109
109
  return !(hashNorth < bounds.south || hashSouth > bounds.north || hashEast < bounds.west || hashWest > bounds.east);
110
110
  }
111
111
 
112
+ // src/spatial/GreatCircle.ts
113
+ var DEG2RAD = Math.PI / 180;
114
+ var RAD2DEG = 180 / Math.PI;
115
+ var EARTH_RADIUS_METERS = 6371e3;
116
+ function interpolateGreatCircle(from, to, fraction) {
117
+ const lat1 = from.lat * DEG2RAD;
118
+ const lon1 = from.lng * DEG2RAD;
119
+ const lat2 = to.lat * DEG2RAD;
120
+ const lon2 = to.lng * DEG2RAD;
121
+ const dLat = lat2 - lat1;
122
+ const dLon = lon2 - lon1;
123
+ const a = Math.sin(dLat / 2) ** 2 + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon / 2) ** 2;
124
+ const delta = 2 * Math.asin(Math.min(1, Math.sqrt(a)));
125
+ if (delta === 0) return { lat: from.lat, lng: from.lng };
126
+ const A = Math.sin((1 - fraction) * delta) / Math.sin(delta);
127
+ const B = Math.sin(fraction * delta) / Math.sin(delta);
128
+ const x = A * Math.cos(lat1) * Math.cos(lon1) + B * Math.cos(lat2) * Math.cos(lon2);
129
+ const y = A * Math.cos(lat1) * Math.sin(lon1) + B * Math.cos(lat2) * Math.sin(lon2);
130
+ const z = A * Math.sin(lat1) + B * Math.sin(lat2);
131
+ const lat = Math.atan2(z, Math.sqrt(x * x + y * y));
132
+ const lon = Math.atan2(y, x);
133
+ return { lat: lat * RAD2DEG, lng: lon * RAD2DEG };
134
+ }
135
+ function sampleGreatCircle(from, to, samples) {
136
+ const n = Math.max(2, Math.floor(samples));
137
+ const points = [];
138
+ for (let i = 0; i < n; i++) {
139
+ points.push(interpolateGreatCircle(from, to, i / (n - 1)));
140
+ }
141
+ return points;
142
+ }
143
+ function destinationPoint(from, bearingDeg, distanceMeters) {
144
+ const delta = distanceMeters / EARTH_RADIUS_METERS;
145
+ const theta = bearingDeg * DEG2RAD;
146
+ const lat1 = from.lat * DEG2RAD;
147
+ const lon1 = from.lng * DEG2RAD;
148
+ const lat2 = Math.asin(
149
+ Math.sin(lat1) * Math.cos(delta) + Math.cos(lat1) * Math.sin(delta) * Math.cos(theta)
150
+ );
151
+ const lon2 = lon1 + Math.atan2(
152
+ Math.sin(theta) * Math.sin(delta) * Math.cos(lat1),
153
+ Math.cos(delta) - Math.sin(lat1) * Math.sin(lat2)
154
+ );
155
+ const lng = ((lon2 * RAD2DEG + 180) % 360 + 360) % 360 - 180;
156
+ return { lat: lat2 * RAD2DEG, lng };
157
+ }
158
+
112
159
  export {
113
160
  haversineDistance,
114
161
  calculateBearing,
@@ -119,5 +166,8 @@ export {
119
166
  getGeohashPrefix,
120
167
  geohashToHierarchicalPath,
121
168
  getGeohashPath,
122
- geohashOverlapsBounds
169
+ geohashOverlapsBounds,
170
+ interpolateGreatCircle,
171
+ sampleGreatCircle,
172
+ destinationPoint
123
173
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  buildNarrationScript,
3
3
  parseNarrationTimingJson
4
- } from "./chunk-PWCIJHZH.js";
4
+ } from "./chunk-BR7ZMDWW.js";
5
5
  import {
6
6
  SHAPE_NAMES,
7
7
  buildChartData,
@@ -32,7 +32,7 @@ import {
32
32
  templateRegistry,
33
33
  writeCustomTemplatesToFrontmatter,
34
34
  writeCustomThemesToFrontmatter
35
- } from "./chunk-TYW5VMNP.js";
35
+ } from "./chunk-42IU2SJY.js";
36
36
  import {
37
37
  ASCII_TREE_VOCAB,
38
38
  ASCII_VOCAB,
@@ -7,10 +7,10 @@ import {
7
7
  buildNarrationScript,
8
8
  expectedSyllablesAt,
9
9
  wordPosAtExpectedSyllables
10
- } from "./chunk-PWCIJHZH.js";
10
+ } from "./chunk-BR7ZMDWW.js";
11
11
  import {
12
12
  flattenRenderableBlocks
13
- } from "./chunk-TYW5VMNP.js";
13
+ } from "./chunk-42IU2SJY.js";
14
14
 
15
15
  // src/narration/types.ts
16
16
  var DEFAULT_FEATURE_CONFIG = Object.freeze({
package/dist/doc/index.js CHANGED
@@ -74,8 +74,8 @@ import {
74
74
  validateMarkdownSource,
75
75
  wordRevealDelay,
76
76
  writeDashboardLayoutsToFrontmatter
77
- } from "../chunk-CPQCZUBW.js";
78
- import "../chunk-PWCIJHZH.js";
77
+ } from "../chunk-S4427XKY.js";
78
+ import "../chunk-BR7ZMDWW.js";
79
79
  import {
80
80
  ASCII_CHAR_H,
81
81
  ASCII_CHAR_W,
@@ -206,7 +206,7 @@ import {
206
206
  wrapWithPersistentLayers,
207
207
  writeCustomTemplatesToFrontmatter,
208
208
  writeCustomThemesToFrontmatter
209
- } from "../chunk-TYW5VMNP.js";
209
+ } from "../chunk-42IU2SJY.js";
210
210
  import {
211
211
  ASCII_DIAGRAM_FENCE_LANGS,
212
212
  ASCII_TIMELINE_FENCE_LANGS,
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ export { M as MediaEntry, a as MediaProvider } from './MediaProvider-wpSe21B3.js
7
7
  export { E as EditorLayerMeta, I as ImageEditCanvas, a as ImageEditDoc, b as ImageEditLayer, c as ImageEditLayerKind, d as ImageEditMeta } from './ImageEditDoc-CYRQK8so.js';
8
8
  export { ASCII_CHAR_H, ASCII_CHAR_W, ASCII_DIAGRAM_FENCE_LANGS, ASCII_TIMELINE_FENCE_LANGS, AccentLayout, AsciiDiagram, AsciiDiagramDetection, AsciiDiagramEdge, AsciiDiagramNode, AsciiTimeline, AsciiTimelineDetection, AsciiTimelineEvent, AsciiTimelineLink, AsciiTimelineMarker, AsciiTimelineSide, AsciiTimelineStats, AsciiTimelineStyle, AsciiTimelineTrack, AudioSegmentTiming, BASE_INPUT_DESCRIPTORS, BLOCK_MEDIA_LAYOUT_POLICIES, BUILTIN_DASHBOARD_LAYOUTS, BlockLayerMaterialization, BlockMediaLayoutPolicy, BuildPreviewDocOptions, BuiltInTemplateName, CONTAINER_TEMPLATES, COVER_SLIDE_FRONTMATTER_KEYS, COVER_SLIDE_TEMPLATE_OPTIONS, ClipBox, ConnectorAnchor, ConnectorPort, ConnectorRouting, ConnectorSnapPoint, CoverBlockInput, CoverSlidePlayback, CoverSlideSettings, CoverSlideTemplate, CoverSlideTemplateOption, DASHBOARD_AUTO_LAYOUT_ID, DASHBOARD_FRONTMATTER_KEYS, DASHBOARD_STYLES, DASHBOARD_STYLE_IDS, DASHBOARD_ZOOM_LEVELS, DATA_FILE_EXTENSIONS, DEFAULT_COVER_SLIDE_SETTINGS, DEFAULT_DASHBOARD_SETTINGS, DEFAULT_DASHBOARD_STYLE, DEFAULT_LAYOUT, DEFAULT_WORD_STAGGER, DIAGRAM_LABEL_HORIZONTAL_PADDING, DIAGRAM_LABEL_LINE_HEIGHT, DIAGRAM_LABEL_MIN_FONT_SIZE, DIAGRAM_LABEL_VERTICAL_PADDING, DashboardCell, DashboardCellChrome, DashboardCellDefinition, DashboardCellFrame, DashboardDiagnostic, DashboardLayoutDefinition, DashboardLayoutSummary, DashboardLayoutValidationError, DashboardLayoutValidationResult, DashboardMaterialization, DashboardRectPct, DashboardSettings, DashboardSettingsOverrides, DashboardStyleId, DashboardStyleSummary, DashboardTitle, DashboardTitleSlotDefinition, DashboardZoomCandidate, DashboardZoomLevel, DashboardZoomMode, DataFenceParseResult, DataSourceReadOptions, DataSourceReader, DataSourceStats, DataSourceTable, DeriveTemplateInputsOptions, DetectAsciiTimelineOptions, DiagramEdge, DiagramLabelFit, DiagramLayout, DiagramLayoutOptions, DiagramNodePosition, DrawingConnector, DrawingLayout, DrawingLayoutOptions, DrawingShape, DrawingShapeKind, EmbeddedVideo, ExpandDocBlocksOptions, ExtractedTableData, FRONTMATTER_DASHBOARD_LAYOUTS_KEY, FirstImage, Flashcard, FlashcardChoice, FlashcardDeck, FlashcardDiagnostic, FlashcardDiagnosticCode, FlashcardFace, FlashcardKind, FlashcardSourceMode, GEOMETRY_BOUND_TEMPLATES, InputCoercion, LayerMaterializationDiagnostic, LayerMaterializationFailureMode, LayerMaterializationSource, LayoutLayerDefaults, LayoutLayersResult, MAX_COVER_SLIDE_DURATION_SECONDS, MarkdownToDocOptions, MarkdownValidationResult, MaterializeBlockLayersOptions, MaterializeDashboardOptions, MaterializeFlashcardsOptions, NarrationResolution, NativeMediaLayout, NoMediaLayout, PAGE_BASE_CSS, PATH_SHAPE_KINDS, PageSectionContext, PageSectionDraft, ParsedStat, RenderAsciiDiagramOptions, RenderAsciiTimelineOptions, RenderTreeOptions, RepairResult, ResolveDataReferencesOptions, ResolvedDashboardCell, ResolvedDataReferences, ResolvedPageBlock, RichListItem, RuntimeTemplateRegistry, SHAPE_NAMES, SectionExtractor, SupplementalMediaLayoutVariant, SupplementalMediaShape, SupplementalMediaVariantMatrix, TABLE_FED_TEMPLATES, TEMPLATE_AUTHORING_METADATA, TEMPLATE_INPUT_DESCRIPTORS, TEMPLATE_METADATA, TREE_FENCE_LANGS, TemplateAuthoringMetadata, TemplateAuthoringRole, TemplateBodyPolicy, TemplateInputDescriptor, TemplateMediaOwnership, TemplateMetadata, TemplateParamFinding, Tree, TreeDetection, TreeItem, TreeNode, UnconsumedMediaBehavior, ValidateOptions, adjustY, anchorPoint, applyNarrationTiming, applyRenderStyleToLayers, asciiCellToCanvas, asciiDiagramFromBlocks, asciiDiagramFromTemplateData, asciiDiagramToTemplateData, asciiTimelineToTemplateData, autoTemplatePreservesContent, bigText, buildDashboardCellChrome, buildPageCss, buildPageCssVars, buildPreviewDoc, buildRegistry, canvasToAsciiCell, chooseDashboardLayout, clipEndpoints, clipPoint, coerceTemplateParams, comparisonBar, composeDashboardLayers, computeDiagramLayout, computeDrawingLayout, computeLayoutLayers, connectorPath, contentBlock, countBlocks, countUpSpecFor, coverBlock, createAccentLayers, cssFilterForTreatment, dashboardCanvasFill, dashboardCellAccent, dataSidecarPrefix, dataTable, dateEvent, definitionCard, deriveTemplateInputs, desiredCellZoom, detectAsciiDiagram, detectAsciiTimeline, detectTree, diagramBlock, docToMarkdown, documentTitleFromFileName, drawingBlock, expandCoverBlock, expandDocBlocks, expandPersistentLayers, extractBlockquoteText, extractBodyPlainText, extractEmbeddedVideos, extractFirstEmbeddedVideo, extractFirstImage, extractImages, extractListItems, extractRichListItems, extractTableData, extractTableFromContents, factCard, fallbackBlockLayers, findFirstList, findFirstTable, fitBigTextSize, fitDiagramLabel, flattenBlocks, flattenRenderableBlocks, formatCountUp, formatCountValue, fullBleedQuote, getAccentLayout, getAnimationProgress, getAnimationStyle, getAvailableTemplates, getBlockBodyText, getBlockDepth, getBlockMediaLayoutPolicy, getDashboardLayoutSummaries, getDefaultAnimation, getDefaultAnimationDuration, getMotionProfile, getOverlayOpacity, getPersistentLayersFromTheme, getPinnedBlockMeta, getTemplateHint, getThemeFont, getTransitionClass, hasTemplate, imageWithCaption, isAsciiDiagramFence, isAsciiTimelineFence, isContainerTemplate, isDataFence, isDataFilePath, isEligibleAsciiFenceLang, isEligibleAsciiTimelineFenceLang, isEligibleTreeFenceLang, isExplicitDiagramLang, isExplicitTimelineLang, isExplicitTreeLang, isGeometryBoundTemplate, isRepairableDiagram, isShapeName, isTemplatedPageBlock, isTreeFence, isWrappedFlowTimelineSource, layoutBlock, layoutCapacity, leftFeature, lineStyleDasharray, lintTemplateParams, listBlock, listDashboardLayouts, mapBlock, markdownBlockSeparatorLines, markdownToDoc, markerPath, materializeBlockLayers, materializeDashboard, materializeFlashcards, motionDelay, motionEntrance, motionStateTransform, nearestSnapPoint, normalizeDashboardZoom, normalizeShapeKind, pageStyleDataAttributes, parseAsciiDiagram, parseAsciiTimeline, parseAsciiTimelineWithStats, parseDataFence, parseStatNumber, parseTree, parseWrappedFlowTimeline, parseYamlSubset, photoGrid, pullQuote, quoteBlock, readCustomTemplatesFromFrontmatter, readCustomThemesFromFrontmatter, readDashboardLayoutsFromFrontmatter, renderAsciiDiagram, renderAsciiTimeline, renderMarkdownBlocksHtml, renderTree, repairAsciiDiagram, replaceDataFence, resolveAudioMapping, resolveColorScheme, resolveCoverSlideSettings, resolveDashboardLayoutDefinition, resolveDashboardSettings, resolveDashboardStyleId, resolveDashboardZooms, resolveDataReferences, resolveFlashcardMarker, resolveLayoutCells, resolvePageBlock, resolvePersistentLayers, resolveTemplateName, resolveThemeForDoc, rightFeature, scaleAnimationDuration, scoreTextSimilarity, sectionExtractors, sectionHeader, shapePath, shouldUseShadow, snapEndpoints, snapPoints, statHighlight, stripBlockBackdropLayer, stripsBlockBackdrop, templateRegistry, themeWantsAmbientMotion, themedEntrance, themedFontSize, themedImageTreatment, themedScrim, themedSurfaceGradient, timelineBlock, titleBlock, transformOriginFor, transposeCells, treeBlock, treeFromMarkdownList, treeFromTemplateData, treeToTemplateData, twoColumn, validateDashboardLayoutDefinition, validateMarkdownDoc, validateMarkdownSource, videoPullQuote, videoWithCaption, wordRevealDelay, wrapWithPersistentLayers, writeCustomTemplatesToFrontmatter, writeCustomThemesToFrontmatter, writeDashboardLayoutsToFrontmatter } from './doc/index.js';
9
9
  export { M as MaterializePageSectionOptions, a as MaterializePageSectionsOptions, P as PageMedia, b as PageRichText, c as PageSection, d as PageSectionDiagnostic, e as PageSectionItem, f as PageSectionMaterialization, g as PageSectionSource, h as PageSpatialKind, i as PageTransformHints, m as materializePageSection, j as materializePageSections, r as resolvePageStyle } from './materializePageSection-Db7pABI0.js';
10
- export { calculateBearing, decodeGeohash, encodeGeohash, geohashOverlapsBounds, geohashToHierarchicalPath, getGeohash4Neighbors, getGeohashPath, getGeohashPrefix, getNeighbors, haversineDistance } from './spatial/index.js';
10
+ export { calculateBearing, decodeGeohash, destinationPoint, encodeGeohash, geohashOverlapsBounds, geohashToHierarchicalPath, getGeohash4Neighbors, getGeohashPath, getGeohashPrefix, getNeighbors, haversineDistance, interpolateGreatCircle, sampleGreatCircle } from './spatial/index.js';
11
11
  export { LocalForageAdapter, LocalForageAdapterOptions, LocalStorageAdapter, MemoryStorageAdapter, ScopedContentContainer, StorageAdapter, createMediaProviderFromContainer, scopeContainer } from './storage/index.js';
12
12
  export { C as ContentContainer, a as ContentEntry, M as MemoryContentContainer, f as findDocumentPath } from './ContentContainer-B2w9sUoL.js';
13
13
  export { DEFAULT_INTERACTIVE_RESOURCE_POLICY, DEFAULT_RESOURCE_MAX_BYTES, DEFAULT_RESOURCE_TIMEOUT_MS, DEFAULT_WRAP_WIDTH, FetchResourceBytesOptions, FetchedResource, HtmlPolicy, LOCAL_ONLY_RESOURCE_POLICY, MARKDOWN_SOURCE_TRANSFORMS, MarkdownSourceEdit, MarkdownSourceTransform, MarkdownSourceTransformId, MarkdownSourceTransformOptions, MarkdownSourceTransformResult, MarkdownWrapState, ResourcePolicy, ResourcePolicyError, SanitizeUrlOptions, TrailingAnnotationMatch, UrlKind, applyMarkdownSourceTransform, cleanupMarkdownSource, countNodes, createDocument, detectMarkdownWrapState, extractPlainText, fetchResourceBytes, findNodesByType, formatBlockScalar, formatFrontmatterValue, formatFrontmatterYaml, fromMdast, getChildren, inferDocumentTitle, isResourceUrlAllowed, matchTrailingPandocAttr, matchTrailingTemplateAnnotation, needsQuoting, parseFrontmatter, parseHtmlToNodes, parseMarkdown, parsePandocAttrTokens, plainTextFromInlineHtml, quoteAttrValue, readFrontmatterThemeId, sanitizeHtmlNodes, sanitizeUrl, serializePandocAttributes, setFrontmatterValues, splitFrontmatterBlock, splitKeyValueToken, stringifyHtmlNodes, stringifyMarkdown, toMdast, tokenizeAttrTokens, unquoteAttrValue, unwrapMarkdownSource, walkMarkdownTree, wrapMarkdownSource } from './markdown/index.js';
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  recordSlideShown,
28
28
  traceWordPosAt,
29
29
  vadStep
30
- } from "./chunk-BVQZCKXN.js";
30
+ } from "./chunk-X2TDC4E5.js";
31
31
  import {
32
32
  fenceRendererLangs
33
33
  } from "./chunk-PGI7HSWE.js";
@@ -65,7 +65,7 @@ import {
65
65
  getTransformStyleSummaries,
66
66
  resolveTransformStyle,
67
67
  transformNarratedSegment
68
- } from "./chunk-RV5OOBSV.js";
68
+ } from "./chunk-EWO2VLOS.js";
69
69
  import {
70
70
  extractContent,
71
71
  mapElementToBlock,
@@ -158,6 +158,7 @@ import {
158
158
  import {
159
159
  calculateBearing,
160
160
  decodeGeohash,
161
+ destinationPoint,
161
162
  encodeGeohash,
162
163
  geohashOverlapsBounds,
163
164
  geohashToHierarchicalPath,
@@ -165,8 +166,10 @@ import {
165
166
  getGeohashPath,
166
167
  getGeohashPrefix,
167
168
  getNeighbors,
168
- haversineDistance
169
- } from "./chunk-R3KTTOMS.js";
169
+ haversineDistance,
170
+ interpolateGreatCircle,
171
+ sampleGreatCircle
172
+ } from "./chunk-JQLUGVII.js";
170
173
  import {
171
174
  BUILTIN_DASHBOARD_LAYOUTS,
172
175
  COVER_SLIDE_FRONTMATTER_KEYS,
@@ -243,7 +246,7 @@ import {
243
246
  validateMarkdownSource,
244
247
  wordRevealDelay,
245
248
  writeDashboardLayoutsToFrontmatter
246
- } from "./chunk-CPQCZUBW.js";
249
+ } from "./chunk-S4427XKY.js";
247
250
  import {
248
251
  buildNarrationScript,
249
252
  buildNarrationTimingJson,
@@ -253,7 +256,7 @@ import {
253
256
  wordIndexAtChar,
254
257
  wordIndexAtTime,
255
258
  wordPosAtExpectedSyllables
256
- } from "./chunk-PWCIJHZH.js";
259
+ } from "./chunk-BR7ZMDWW.js";
257
260
  import {
258
261
  ASCII_CHAR_H,
259
262
  ASCII_CHAR_W,
@@ -384,7 +387,7 @@ import {
384
387
  wrapWithPersistentLayers,
385
388
  writeCustomTemplatesToFrontmatter,
386
389
  writeCustomThemesToFrontmatter
387
- } from "./chunk-TYW5VMNP.js";
390
+ } from "./chunk-42IU2SJY.js";
388
391
  import {
389
392
  ASCII_DIAGRAM_FENCE_LANGS,
390
393
  ASCII_TIMELINE_FENCE_LANGS,
@@ -525,7 +528,7 @@ import {
525
528
  createMediaProviderFromContainer,
526
529
  findDocumentPath,
527
530
  scopeContainer
528
- } from "./chunk-UNVHAK3A.js";
531
+ } from "./chunk-GIYWXYCK.js";
529
532
  import {
530
533
  DEFAULT_INTERACTIVE_RESOURCE_POLICY,
531
534
  DEFAULT_RESOURCE_MAX_BYTES,
@@ -844,6 +847,7 @@ export {
844
847
  deriveScale,
845
848
  deriveTemplateInputs,
846
849
  desiredCellZoom,
850
+ destinationPoint,
847
851
  detectAsciiDiagram,
848
852
  detectAsciiTimeline,
849
853
  detectMarkdownWrapState,
@@ -961,6 +965,7 @@ export {
961
965
  inferDocumentTitle,
962
966
  inferSchema,
963
967
  inspectAnimatedImage,
968
+ interpolateGreatCircle,
964
969
  isAsciiDiagramFence,
965
970
  isAsciiTimelineFence,
966
971
  isContainerTemplate,
@@ -1115,6 +1120,7 @@ export {
1115
1120
  revertToImageEditVersion,
1116
1121
  revertToVersion,
1117
1122
  rightFeature,
1123
+ sampleGreatCircle,
1118
1124
  sanitizeHtmlNodes,
1119
1125
  sanitizeUrl,
1120
1126
  saveImageEditVersion,
@@ -27,7 +27,7 @@ import {
27
27
  recordSlideShown,
28
28
  traceWordPosAt,
29
29
  vadStep
30
- } from "../chunk-BVQZCKXN.js";
30
+ } from "../chunk-X2TDC4E5.js";
31
31
  import "../chunk-NEWNNLWN.js";
32
32
  import {
33
33
  buildNarrationScript,
@@ -38,8 +38,8 @@ import {
38
38
  wordIndexAtChar,
39
39
  wordIndexAtTime,
40
40
  wordPosAtExpectedSyllables
41
- } from "../chunk-PWCIJHZH.js";
42
- import "../chunk-TYW5VMNP.js";
41
+ } from "../chunk-BR7ZMDWW.js";
42
+ import "../chunk-42IU2SJY.js";
43
43
  import "../chunk-C3NAY5YP.js";
44
44
  import "../chunk-PUS54YU6.js";
45
45
  import "../chunk-PFH3WV6J.js";
@@ -113,4 +113,32 @@ declare function geohashOverlapsBounds(hash: string, bounds: {
113
113
  west: number;
114
114
  }): boolean;
115
115
 
116
- export { calculateBearing, decodeGeohash, encodeGeohash, geohashOverlapsBounds, geohashToHierarchicalPath, getGeohash4Neighbors, getGeohashPath, getGeohashPrefix, getNeighbors, haversineDistance };
116
+ /**
117
+ * Great-circle paths on a spherical Earth.
118
+ *
119
+ * `interpolateGreatCircle` and `sampleGreatCircle` walk the shortest path between two
120
+ * coordinates (spherical linear interpolation), which stays true over long and high-latitude
121
+ * routes where a straight lat/lng line distorts badly: use them to sample points along a route,
122
+ * for example to find places near it. `destinationPoint` goes the other way: from a coordinate
123
+ * along a compass bearing for a distance, for example to project a moving position ahead of
124
+ * itself. The sphere is the same one `haversineDistance` uses (mean radius 6,371 km), so the
125
+ * two agree.
126
+ */
127
+
128
+ /**
129
+ * Interpolate a point a `fraction` (0..1) of the way along the great-circle path from `from`
130
+ * to `to`. At fraction 0 returns `from`; at 1 returns `to`.
131
+ */
132
+ declare function interpolateGreatCircle(from: Coordinates, to: Coordinates, fraction: number): Coordinates;
133
+ /**
134
+ * Sample `samples` evenly spaced points (both endpoints included) along the great-circle path.
135
+ * `samples` is clamped to at least 2.
136
+ */
137
+ declare function sampleGreatCircle(from: Coordinates, to: Coordinates, samples: number): Coordinates[];
138
+ /**
139
+ * The point `distanceMeters` from `from` along the great circle that starts at compass bearing
140
+ * `bearingDeg` (0 north, 90 east). Longitude is normalized to [-180, 180).
141
+ */
142
+ declare function destinationPoint(from: Coordinates, bearingDeg: number, distanceMeters: number): Coordinates;
143
+
144
+ export { calculateBearing, decodeGeohash, destinationPoint, encodeGeohash, geohashOverlapsBounds, geohashToHierarchicalPath, getGeohash4Neighbors, getGeohashPath, getGeohashPrefix, getNeighbors, haversineDistance, interpolateGreatCircle, sampleGreatCircle };
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  calculateBearing,
3
3
  decodeGeohash,
4
+ destinationPoint,
4
5
  encodeGeohash,
5
6
  geohashOverlapsBounds,
6
7
  geohashToHierarchicalPath,
@@ -8,11 +9,14 @@ import {
8
9
  getGeohashPath,
9
10
  getGeohashPrefix,
10
11
  getNeighbors,
11
- haversineDistance
12
- } from "../chunk-R3KTTOMS.js";
12
+ haversineDistance,
13
+ interpolateGreatCircle,
14
+ sampleGreatCircle
15
+ } from "../chunk-JQLUGVII.js";
13
16
  export {
14
17
  calculateBearing,
15
18
  decodeGeohash,
19
+ destinationPoint,
16
20
  encodeGeohash,
17
21
  geohashOverlapsBounds,
18
22
  geohashToHierarchicalPath,
@@ -20,5 +24,7 @@ export {
20
24
  getGeohashPath,
21
25
  getGeohashPrefix,
22
26
  getNeighbors,
23
- haversineDistance
27
+ haversineDistance,
28
+ interpolateGreatCircle,
29
+ sampleGreatCircle
24
30
  };
@@ -7,7 +7,7 @@ import {
7
7
  createMediaProviderFromContainer,
8
8
  findDocumentPath,
9
9
  scopeContainer
10
- } from "../chunk-UNVHAK3A.js";
10
+ } from "../chunk-GIYWXYCK.js";
11
11
  export {
12
12
  LocalForageAdapter,
13
13
  LocalStorageAdapter,
@@ -9,9 +9,9 @@ import {
9
9
  getTransformStyleSummaries,
10
10
  resolveTransformStyle,
11
11
  transformNarratedSegment
12
- } from "../chunk-RV5OOBSV.js";
12
+ } from "../chunk-EWO2VLOS.js";
13
13
  import "../chunk-SVN7T6BK.js";
14
- import "../chunk-TYW5VMNP.js";
14
+ import "../chunk-42IU2SJY.js";
15
15
  import "../chunk-C3NAY5YP.js";
16
16
  import "../chunk-PUS54YU6.js";
17
17
  import "../chunk-PFH3WV6J.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bendyline/squisq",
3
- "version": "2.11.10",
3
+ "version": "2.11.12",
4
4
  "description": "Headless utilities for doc/block rendering, spatial math, Markdown, and storage",
5
5
  "license": "MIT",
6
6
  "author": "Bendyline",