@neta-art/cohub 12.2.0 → 12.4.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 (93) hide show
  1. package/README.md +87 -3
  2. package/dist/board/editor/context.d.ts +2 -0
  3. package/dist/board/editor/document.d.ts +3 -1
  4. package/dist/board/editor/document.js +8 -6
  5. package/dist/board/editor/editor.d.ts +7 -3
  6. package/dist/board/editor/editor.js +8 -1
  7. package/dist/board/editor/index.d.ts +3 -3
  8. package/dist/board/editor/index.js +2 -2
  9. package/dist/board/editor/interaction.d.ts +23 -2
  10. package/dist/board/editor/interaction.js +99 -5
  11. package/dist/board/editor/query.d.ts +1 -1
  12. package/dist/board/editor/query.js +3 -7
  13. package/dist/board/editor/selection.js +13 -1
  14. package/dist/board/editor/tool.d.ts +4 -1
  15. package/dist/board/editor/tool.js +6 -1
  16. package/dist/board/model/asset-key.d.ts +9 -1
  17. package/dist/board/model/asset-key.js +27 -7
  18. package/dist/board/model/index.d.ts +5 -5
  19. package/dist/board/model/index.js +4 -4
  20. package/dist/board/model/items/create.js +1 -1
  21. package/dist/board/model/items/definition.d.ts +9 -1
  22. package/dist/board/model/items/index.d.ts +2 -2
  23. package/dist/board/model/items/registry.d.ts +2 -1
  24. package/dist/board/model/items/registry.js +1 -0
  25. package/dist/board/model/text-metrics.d.ts +21 -1
  26. package/dist/board/model/text-metrics.js +24 -1
  27. package/dist/board/model/themes.d.ts +49 -42
  28. package/dist/board/model/themes.js +49 -44
  29. package/dist/board/render/index.d.ts +8 -6
  30. package/dist/board/render/index.js +7 -5
  31. package/dist/board/render/labels.d.ts +15 -0
  32. package/dist/board/render/labels.js +14 -0
  33. package/dist/board/render/lod.d.ts +9 -1
  34. package/dist/board/render/lod.js +7 -1
  35. package/dist/board/render/media-interaction.d.ts +5 -2
  36. package/dist/board/render/media-interaction.js +14 -2
  37. package/dist/board/render/renderers/arrow-card-renderer.js +7 -5
  38. package/dist/board/render/renderers/board-renderer-registry.d.ts +12 -1
  39. package/dist/board/render/renderers/board-renderer-registry.js +9 -4
  40. package/dist/board/render/renderers/far-plate.d.ts +4 -1
  41. package/dist/board/render/renderers/far-plate.js +5 -1
  42. package/dist/board/render/renderers/file-card-renderer.js +44 -24
  43. package/dist/board/render/renderers/frame-card-renderer.js +9 -3
  44. package/dist/board/render/renderers/image-card-renderer.js +2 -2
  45. package/dist/board/render/renderers/model-card-renderer.js +2 -2
  46. package/dist/board/render/renderers/task-card-renderer.js +2 -2
  47. package/dist/board/render/renderers/video-card-renderer.js +2 -2
  48. package/dist/board/render/style.d.ts +1 -0
  49. package/dist/board/render/style.js +3 -1
  50. package/dist/board/render/text-edit.d.ts +32 -0
  51. package/dist/board/render/text-edit.js +134 -0
  52. package/dist/board/render/text-fit.d.ts +1 -3
  53. package/dist/board/render/text-fit.js +4 -43
  54. package/dist/board/render/text-measurement.d.ts +12 -2
  55. package/dist/board/render/text-measurement.js +55 -10
  56. package/dist/board/replica/index.d.ts +4 -2
  57. package/dist/board/replica/index.js +34 -21
  58. package/dist/board/replica/indexeddb.d.ts +16 -0
  59. package/dist/board/replica/indexeddb.js +155 -0
  60. package/dist/board/stage/assets.d.ts +16 -4
  61. package/dist/board/stage/assets.js +155 -30
  62. package/dist/board/stage/bench.d.ts +35 -0
  63. package/dist/board/stage/bench.js +153 -0
  64. package/dist/board/stage/device.d.ts +41 -0
  65. package/dist/board/stage/device.js +62 -0
  66. package/dist/board/stage/frame-budget.d.ts +19 -0
  67. package/dist/board/stage/frame-budget.js +69 -0
  68. package/dist/board/stage/idle.d.ts +4 -0
  69. package/dist/board/stage/idle.js +26 -0
  70. package/dist/board/stage/index.d.ts +9 -5
  71. package/dist/board/stage/index.js +5 -2
  72. package/dist/board/stage/presses.d.ts +21 -0
  73. package/dist/board/stage/presses.js +66 -0
  74. package/dist/board/stage/scene.d.ts +4 -0
  75. package/dist/board/stage/scene.js +45 -13
  76. package/dist/board/stage/stage.d.ts +21 -2
  77. package/dist/board/stage/stage.js +309 -89
  78. package/dist/board/stage/texture-pool.d.ts +6 -4
  79. package/dist/board/stage/texture-pool.js +42 -8
  80. package/dist/board/stage/views.d.ts +1 -1
  81. package/dist/board/stage/views.js +2 -2
  82. package/dist/chunks/environment.d.ts +6 -0
  83. package/dist/chunks/http.d.ts +9 -1
  84. package/dist/chunks/http.js +791 -4
  85. package/dist/index.d.ts +52 -1
  86. package/dist/index.js +65 -733
  87. package/dist/protocol/dist/board-model.d.ts +15 -1
  88. package/dist/protocol/dist/board-model.js +12 -2
  89. package/dist/protocol/dist/board-schema.d.ts +2 -1
  90. package/dist/protocol/dist/board-schema.js +4 -1
  91. package/dist/protocol/dist/core/media.js +4 -0
  92. package/dist/protocol/dist/index.d.ts +2 -2
  93. package/package.json +2 -1
@@ -1,6 +1,6 @@
1
1
  import { variantSource } from "../../media.js";
2
2
  import { loadVideoThumbnailTexture } from "../render/video-thumbnail.js";
3
- import { Assets, Texture } from "pixi.js";
3
+ import { Assets, DOMAdapter, Texture } from "pixi.js";
4
4
  //#region src/board/stage/texture-pool.ts
5
5
  /** Load an image in the page's CORS context when Pixi's worker path fails. */
6
6
  function loadImageElementTexture(url) {
@@ -62,22 +62,23 @@ async function unloadBoardImageTexture(url, texture) {
62
62
  await Assets.unload(url).catch(() => {});
63
63
  if (!texture?.destroyed) texture?.destroy(true);
64
64
  }
65
- function fit(width, height, edge) {
66
- const scale = edge / Math.max(width, height);
65
+ function fit(width, height, edge, cover = false) {
66
+ const scale = edge / (cover ? Math.min(width, height) : Math.max(width, height));
67
67
  return scale < 1 ? {
68
68
  resizeWidth: Math.max(1, Math.round(width * scale)),
69
69
  resizeHeight: Math.max(1, Math.round(height * scale))
70
70
  } : null;
71
71
  }
72
72
  /**
73
- * Decode an image no larger than `edge` along its long side, for sources
74
- * without CDN variants. The texture is unshared; destroy it to release it.
73
+ * Decode an image no larger than `edge` along its long side (short side with
74
+ * `cover`), for sources without CDN variants. The texture is unshared; destroy
75
+ * it to release it.
75
76
  */
76
- async function loadFittedImageTexture(url, edge) {
77
+ async function loadFittedImageTexture(url, edge, cover = false) {
77
78
  const response = await fetch(url);
78
79
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
79
80
  const image = await createImageBitmap(await response.blob());
80
- const size = fit(image.width, image.height, edge);
81
+ const size = fit(image.width, image.height, edge, cover);
81
82
  if (!size) return Texture.from(image, true);
82
83
  try {
83
84
  return Texture.from(await createImageBitmap(image, {
@@ -98,6 +99,39 @@ async function shrinkBoardTexture(texture, edge) {
98
99
  resizeQuality: "medium"
99
100
  }), true);
100
101
  }
102
+ const TONE_SAMPLE = 8;
103
+ let toneContext;
104
+ async function readTextureTone(texture) {
105
+ const resource = texture.source.resource;
106
+ if (!resource || texture.destroyed) return null;
107
+ const bitmap = await createImageBitmap(resource, {
108
+ resizeWidth: TONE_SAMPLE,
109
+ resizeHeight: TONE_SAMPLE,
110
+ resizeQuality: "medium"
111
+ });
112
+ try {
113
+ toneContext ??= DOMAdapter.get().createCanvas(TONE_SAMPLE, TONE_SAMPLE).getContext("2d", { willReadFrequently: true });
114
+ if (!toneContext) return null;
115
+ toneContext.clearRect(0, 0, TONE_SAMPLE, TONE_SAMPLE);
116
+ toneContext.drawImage(bitmap, 0, 0);
117
+ const { data } = toneContext.getImageData(0, 0, TONE_SAMPLE, TONE_SAMPLE);
118
+ let red = 0;
119
+ let green = 0;
120
+ let blue = 0;
121
+ let weight = 0;
122
+ for (let index = 0; index < data.length; index += 4) {
123
+ const alpha = data[index + 3];
124
+ red += data[index] * alpha;
125
+ green += data[index + 1] * alpha;
126
+ blue += data[index + 2] * alpha;
127
+ weight += alpha;
128
+ }
129
+ if (weight === 0) return null;
130
+ return Math.round(red / weight) << 16 | Math.round(green / weight) << 8 | Math.round(blue / weight);
131
+ } finally {
132
+ bitmap.close();
133
+ }
134
+ }
101
135
  /**
102
136
  * Share image textures by resolved URL without sharing Board ownership.
103
137
  *
@@ -186,4 +220,4 @@ function createBoardImageTexturePool(options) {
186
220
  }
187
221
  const boardImageTexturePool = createBoardImageTexturePool();
188
222
  //#endregion
189
- export { boardImageTexturePool, createBoardImageTexturePool, loadBoardImageTexture, loadFittedImageTexture, shrinkBoardTexture, unloadBoardImageTexture };
223
+ export { boardImageTexturePool, createBoardImageTexturePool, loadBoardImageTexture, loadFittedImageTexture, readTextureTone, shrinkBoardTexture, unloadBoardImageTexture };
@@ -38,6 +38,6 @@ type BoardItemViewLayer = {
38
38
  }): void;
39
39
  destroy(): void;
40
40
  };
41
- declare function createBoardItemViewLayer(host: HTMLElement, editor: BoardEditor, views: readonly BoardItemView[], camera: () => BoardViewport, onInvalidate?: () => void): BoardItemViewLayer;
41
+ declare function createBoardItemViewLayer(host: HTMLElement, editor: BoardEditor, views: readonly BoardItemView[], camera: () => BoardViewport, onInvalidate?: () => void, layer?: "above" | "below"): BoardItemViewLayer;
42
42
  //#endregion
43
43
  export { BoardItemView, BoardItemViewContext, BoardItemViewInstance, BoardItemViewLayer, createBoardItemViewLayer };
@@ -18,10 +18,10 @@ function onScreen(frame, camera, surface) {
18
18
  const top = bounds.y * camera.zoom + camera.y;
19
19
  return left + bounds.width * camera.zoom >= -240 && top + bounds.height * camera.zoom >= -240 && left <= surface.width + VISIBLE_MARGIN && top <= surface.height + VISIBLE_MARGIN;
20
20
  }
21
- function createBoardItemViewLayer(host, editor, views, camera, onInvalidate = () => {}) {
21
+ function createBoardItemViewLayer(host, editor, views, camera, onInvalidate = () => {}, layer = "above") {
22
22
  const element = host.ownerDocument.createElement("div");
23
23
  element.dataset.boardViews = "";
24
- element.style.cssText = "position:absolute;inset:0;z-index:2;overflow:hidden;pointer-events:none";
24
+ element.style.cssText = `position:absolute;inset:0;z-index:${layer === "below" ? 0 : 2};overflow:hidden;pointer-events:none`;
25
25
  host.appendChild(element);
26
26
  const world = host.ownerDocument.createElement("div");
27
27
  world.style.cssText = "position:absolute;inset:0;transform-origin:0 0;pointer-events:none";
@@ -1358,6 +1358,12 @@ declare const BoardExtensionItemSchema: z.ZodObject<{
1358
1358
  }, z.core.$strict>>;
1359
1359
  type: z.ZodString;
1360
1360
  props: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
1361
+ preview: z.ZodOptional<z.ZodObject<{
1362
+ title: z.ZodOptional<z.ZodString>;
1363
+ excerpt: z.ZodOptional<z.ZodString>;
1364
+ cover: z.ZodOptional<z.ZodString>;
1365
+ src: z.ZodOptional<z.ZodString>;
1366
+ }, z.core.$strict>>;
1361
1367
  }, z.core.$strict>;
1362
1368
  declare const BOARD_ITEM_SCHEMAS: {
1363
1369
  readonly frame: z.ZodObject<{
@@ -1251,6 +1251,7 @@ type BoardRemote = {
1251
1251
  playback: BoardPlaybackSnapshot | null;
1252
1252
  };
1253
1253
  }) => void;
1254
+ resync?: () => void;
1254
1255
  }): () => void;
1255
1256
  };
1256
1257
  //#endregion
@@ -1264,6 +1265,7 @@ type BoardSubscriptionHandlers = {
1264
1265
  awareness?: (event: BoardAwarenessUpdatedEvent) => void;
1265
1266
  playback?: (event: BoardPlaybackChangedEvent) => void;
1266
1267
  event?: (event: BoardChangedEvent | BoardAwarenessUpdatedEvent | BoardPlaybackChangedEvent) => void;
1268
+ resync?: () => void;
1267
1269
  };
1268
1270
  type BoardClientOptions = {
1269
1271
  http: HttpTransport;
@@ -1316,12 +1318,18 @@ declare class BoardClient implements BoardRemote {
1316
1318
  on(type: "awareness", handler: (event: BoardAwarenessUpdatedEvent) => void): () => void;
1317
1319
  on(type: "playback", handler: (event: BoardPlaybackChangedEvent) => void): () => void;
1318
1320
  }
1321
+ type BoardFileReader = {
1322
+ read(path: string, customFetch?: Fetch): Promise<SpaceFsFileResponse | SpaceFsPreparingFile>;
1323
+ };
1319
1324
  declare class SpaceBoardsApi {
1320
1325
  private readonly http;
1321
1326
  private readonly spaceId;
1322
1327
  private readonly websocket;
1323
- constructor(http: HttpTransport, spaceId: string, websocket: WebsocketClient | null);
1328
+ private readonly files;
1329
+ constructor(http: HttpTransport, spaceId: string, websocket: WebsocketClient | null, files: BoardFileReader);
1324
1330
  byId(boardId: string): BoardClient;
1331
+ open(target: string, customFetch?: Fetch): Promise<BoardClient>;
1332
+ resolveId(path: string, customFetch?: Fetch): Promise<string>;
1325
1333
  /** Create a `.board` file and its Board, optionally with an initial document. */
1326
1334
  create(input: BoardCreateInput): Promise<BoardReadResult>;
1327
1335
  }