@neta-art/cohub-cli 10.7.0 → 10.8.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.
Files changed (37) hide show
  1. package/README.md +4 -4
  2. package/dist/board-kernel.js +276 -214
  3. package/dist/commands/boards/examples.js +16 -16
  4. package/dist/commands/boards.js +1 -1
  5. package/dist/commands/runtime.js +3 -14
  6. package/dist/runtime/connection.js +161 -54
  7. package/dist/runtime/harnesses/chained-transcript.d.ts +24 -0
  8. package/dist/runtime/harnesses/chained-transcript.js +62 -0
  9. package/dist/runtime/harnesses/claude-transcript.d.ts +8 -0
  10. package/dist/runtime/harnesses/claude-transcript.js +138 -0
  11. package/dist/runtime/harnesses/claude.js +20 -2
  12. package/dist/runtime/harnesses/codex.js +1 -1
  13. package/dist/runtime/harnesses/cursor-transcript.d.ts +37 -0
  14. package/dist/runtime/harnesses/cursor-transcript.js +183 -0
  15. package/dist/runtime/harnesses/cursor.d.ts +24 -0
  16. package/dist/runtime/harnesses/cursor.js +620 -0
  17. package/dist/runtime/harnesses/index.d.ts +1 -3
  18. package/dist/runtime/harnesses/index.js +4 -10
  19. package/dist/runtime/harnesses/pi.js +1 -1
  20. package/dist/runtime/harnesses/stream-json.d.ts +5 -1
  21. package/dist/runtime/harnesses/stream-json.js +31 -9
  22. package/dist/runtime/harnesses/types.d.ts +10 -5
  23. package/dist/runtime/harnesses/workbuddy-transcript.d.ts +8 -0
  24. package/dist/runtime/harnesses/workbuddy-transcript.js +127 -0
  25. package/dist/runtime/harnesses/workbuddy.d.ts +1 -1
  26. package/dist/runtime/harnesses/workbuddy.js +31 -7
  27. package/dist/runtime/json-rpc.d.ts +2 -0
  28. package/dist/runtime/json-rpc.js +9 -0
  29. package/dist/runtime/native/attach.d.ts +1 -1
  30. package/dist/runtime/native/attach.js +1 -4
  31. package/dist/runtime/native/execution.js +14 -3
  32. package/dist/runtime/native/ingest.d.ts +24 -2
  33. package/dist/runtime/native/ingest.js +76 -10
  34. package/dist/runtime/native/sessions.js +6 -1
  35. package/dist/runtime/native/transcript.d.ts +23 -0
  36. package/dist/runtime/native/transcript.js +40 -5
  37. package/package.json +3 -3
@@ -5650,6 +5650,51 @@ function json(params) {
5650
5650
  return jsonSchema;
5651
5651
  }
5652
5652
  const BOARD_ARROW_STROKE_SIZE = 2.5;
5653
+ const BOARD_DEFAULT_ITEM_SIZE$1 = {
5654
+ width: 240,
5655
+ height: 160
5656
+ };
5657
+ const BOARD_DEFAULT_SIZES$1 = {
5658
+ frame: {
5659
+ width: 480,
5660
+ height: 320
5661
+ },
5662
+ shape: {
5663
+ width: 200,
5664
+ height: 140
5665
+ },
5666
+ image: {
5667
+ width: 480,
5668
+ height: 270
5669
+ },
5670
+ video: {
5671
+ width: 480,
5672
+ height: 270
5673
+ },
5674
+ audio: {
5675
+ width: 320,
5676
+ height: 112
5677
+ },
5678
+ file: {
5679
+ width: 260,
5680
+ height: 132
5681
+ },
5682
+ task: {
5683
+ width: 480,
5684
+ height: 270
5685
+ },
5686
+ effect: {
5687
+ width: 240,
5688
+ height: 240
5689
+ },
5690
+ custom: {
5691
+ width: 480,
5692
+ height: 320
5693
+ }
5694
+ };
5695
+ function boardDefaultSize(type) {
5696
+ return { ...Object.hasOwn(BOARD_DEFAULT_SIZES$1, type) ? BOARD_DEFAULT_SIZES$1[type] : BOARD_DEFAULT_ITEM_SIZE$1 };
5697
+ }
5653
5698
  const BOARD_FONT_STACK = "\"Geist\", system-ui, -apple-system, \"Noto Sans CJK SC\", \"Noto Sans SC\", \"PingFang SC\", \"Microsoft YaHei\", \"Noto Sans Math\", \"Noto Sans Symbols 2\", \"DejaVu Sans\", \"FreeSans\", \"FreeSerif\", sans-serif";
5654
5699
  const BOARD_MONO_FONT_STACK = "\"Geist Mono\", \"Fira Code\", ui-monospace, \"Noto Sans Mono CJK SC\", \"Noto Sans Math\", \"DejaVu Sans\", \"FreeSans\", \"FreeSerif\", monospace";
5655
5700
  //#endregion
@@ -5827,12 +5872,9 @@ const itemEnvelope$1 = {
5827
5872
  locked: boolean().optional(),
5828
5873
  metadata: record(string(), unknown()).optional()
5829
5874
  };
5830
- const boxed$1 = (width, height) => ({
5875
+ const boxed$1 = (size) => ({
5831
5876
  ...itemEnvelope$1,
5832
- size: BoardSizeSchema$1.default({
5833
- width,
5834
- height
5835
- })
5877
+ size: BoardSizeSchema$1.default({ ...size })
5836
5878
  });
5837
5879
  const unsized$1 = { ...itemEnvelope$1 };
5838
5880
  const fontSize$1 = finite$1.min(2).max(512);
@@ -5850,7 +5892,7 @@ const BOARD_SHAPE_GEOMETRIES$1 = [
5850
5892
  "path"
5851
5893
  ];
5852
5894
  const BoardFrameItemSchema$1 = object({
5853
- ...boxed$1(480, 320),
5895
+ ...boxed$1(BOARD_DEFAULT_SIZES$1.frame),
5854
5896
  type: literal("frame"),
5855
5897
  props: object({
5856
5898
  label: string().max(280).default(""),
@@ -5874,7 +5916,7 @@ const BoardTextItemSchema$1 = object({
5874
5916
  }).strict().prefault({})
5875
5917
  }).strict();
5876
5918
  const BoardShapeItemSchema$1 = object({
5877
- ...boxed$1(240, 160),
5919
+ ...boxed$1(BOARD_DEFAULT_SIZES$1.shape),
5878
5920
  type: literal("shape"),
5879
5921
  props: object({
5880
5922
  geometry: _enum(BOARD_SHAPE_GEOMETRIES$1).default("rectangle"),
@@ -5972,7 +6014,7 @@ const BoardCropSchema$1 = object({
5972
6014
  h: ratio$1
5973
6015
  }).strict().describe("Region shown, as fractions of the image. Without it the whole image fits inside size.");
5974
6016
  const BoardImageItemSchema$1 = object({
5975
- ...boxed$1(640, 360),
6017
+ ...boxed$1(BOARD_DEFAULT_SIZES$1.image),
5976
6018
  type: literal("image"),
5977
6019
  props: object({
5978
6020
  ...mediaProps$1,
@@ -5980,17 +6022,17 @@ const BoardImageItemSchema$1 = object({
5980
6022
  }).strict()
5981
6023
  }).strict();
5982
6024
  const BoardVideoItemSchema$1 = object({
5983
- ...boxed$1(640, 360),
6025
+ ...boxed$1(BOARD_DEFAULT_SIZES$1.video),
5984
6026
  type: literal("video"),
5985
6027
  props: object(timedFileProps$1).strict()
5986
6028
  }).strict();
5987
6029
  const BoardAudioItemSchema$1 = object({
5988
- ...boxed$1(480, 96),
6030
+ ...boxed$1(BOARD_DEFAULT_SIZES$1.audio),
5989
6031
  type: literal("audio"),
5990
6032
  props: object(timedFileProps$1).strict()
5991
6033
  }).strict();
5992
6034
  const BoardFileItemSchema$1 = object({
5993
- ...boxed$1(360, 220),
6035
+ ...boxed$1(BOARD_DEFAULT_SIZES$1.file),
5994
6036
  type: literal("file"),
5995
6037
  props: object(fileProps$1).strict()
5996
6038
  }).strict();
@@ -6047,7 +6089,7 @@ const BoardTaskSnapshotSchema$1 = object({
6047
6089
  updatedAt: string().optional()
6048
6090
  }).strict();
6049
6091
  const BoardTaskItemSchema$1 = object({
6050
- ...boxed$1(420, 240),
6092
+ ...boxed$1(BOARD_DEFAULT_SIZES$1.task),
6051
6093
  type: literal("task"),
6052
6094
  props: object({
6053
6095
  taskRunId: string().min(1).max(160).describe("The generation run shown; the server keeps the card's status and results up to date."),
@@ -6062,7 +6104,7 @@ const BOARD_EFFECT_KINDS$1 = [
6062
6104
  "glow"
6063
6105
  ];
6064
6106
  const BoardEffectItemSchema$1 = object({
6065
- ...boxed$1(240, 240),
6107
+ ...boxed$1(BOARD_DEFAULT_SIZES$1.effect),
6066
6108
  type: literal("effect"),
6067
6109
  props: object({
6068
6110
  kind: _enum(BOARD_EFFECT_KINDS$1),
@@ -6079,18 +6121,14 @@ const BoardEffectItemSchema$1 = object({
6079
6121
  }).strict()
6080
6122
  }).strict();
6081
6123
  const BoardCustomItemSchema$1 = object({
6082
- ...boxed$1(480, 320),
6124
+ ...boxed$1(BOARD_DEFAULT_SIZES$1.custom),
6083
6125
  type: literal("custom"),
6084
6126
  script: BoardScriptSchema$1,
6085
6127
  props: object({}).strict().default({})
6086
6128
  }).strict();
6087
6129
  const BOARD_EXTENSION_TYPE_PATTERN$1 = /^[a-z][a-z0-9]*(?:\.[a-z0-9-]+)+$/;
6088
6130
  const BoardExtensionItemSchema$1 = object({
6089
- ...itemEnvelope$1,
6090
- size: BoardSizeSchema$1.default({
6091
- width: 240,
6092
- height: 160
6093
- }),
6131
+ ...boxed$1(BOARD_DEFAULT_ITEM_SIZE$1),
6094
6132
  type: string().regex(BOARD_EXTENSION_TYPE_PATTERN$1),
6095
6133
  props: record(string(), unknown()).default({})
6096
6134
  }).strict();
@@ -6540,8 +6578,7 @@ function createBoardLayout(initialLookup, dependents) {
6540
6578
  } else box = {
6541
6579
  x: 0,
6542
6580
  y: 0,
6543
- width: 240,
6544
- height: 160
6581
+ ...boardDefaultSize(item.type)
6545
6582
  };
6546
6583
  boxes.set(id, box);
6547
6584
  return box;
@@ -27490,21 +27527,9 @@ function fitTextToWidth(text, value, width) {
27490
27527
  }
27491
27528
  //#endregion
27492
27529
  //#region ../sdk/src/board/render/text-resolution.ts
27493
- const MAX_BOARD_RESOLUTION = 3;
27494
- const MAX_BOARD_PIXELS = 8e6;
27495
- const MAX_TEXT_RESOLUTION = 6;
27496
- function getBoardResolution(size, devicePixelRatio = globalThis.devicePixelRatio) {
27497
- const density = Number.isFinite(devicePixelRatio) && devicePixelRatio > 0 ? devicePixelRatio : 1;
27498
- const pixels = size ? size.width * size.height : 0;
27499
- const budget = pixels > 0 ? Math.sqrt(MAX_BOARD_PIXELS / pixels) : MAX_BOARD_RESOLUTION;
27500
- return Math.min(density, MAX_BOARD_RESOLUTION, budget);
27501
- }
27502
- /**
27503
- * Zoom buckets for text re-rasterisation. Pixi Text is a bitmap: at high zoom it
27504
- * looks soft unless we raise its resolution. We quantise zoom into a few
27505
- * buckets so small zoom changes don't thrash texture regeneration.
27506
- */
27507
- const TEXT_ZOOM_BUCKETS = [
27530
+ const MIN_TEXT_RESOLUTION = .125;
27531
+ const MAX_TEXT_EDGE = 4096;
27532
+ const ZOOM_BUCKETS = [
27508
27533
  .5,
27509
27534
  1,
27510
27535
  1.5,
@@ -27514,23 +27539,17 @@ const TEXT_ZOOM_BUCKETS = [
27514
27539
  ];
27515
27540
  function textZoomBucket(zoom) {
27516
27541
  const clamped = Math.max(.1, Math.min(4, zoom));
27517
- for (const bucket of TEXT_ZOOM_BUCKETS) if (clamped <= bucket) return bucket;
27518
- return TEXT_ZOOM_BUCKETS[TEXT_ZOOM_BUCKETS.length - 1] ?? 4;
27542
+ for (const bucket of ZOOM_BUCKETS) if (clamped <= bucket) return bucket;
27543
+ return ZOOM_BUCKETS[ZOOM_BUCKETS.length - 1] ?? 4;
27519
27544
  }
27520
27545
  function boardCardDetailed(zoom) {
27521
27546
  return textZoomBucket(zoom) >= 1;
27522
27547
  }
27523
- /** Effective text resolution for a given camera zoom. */
27524
- function textResolutionForZoom(zoom) {
27525
- const bucket = textZoomBucket(zoom);
27526
- return Math.min(getBoardResolution() * Math.max(1, bucket), MAX_TEXT_RESOLUTION);
27527
- }
27528
- /** Update a Pixi text texture only when zoom crosses a resolution bucket. */
27529
- function syncTextResolution(text, state, zoom) {
27530
- const resolution = textResolutionForZoom(zoom);
27531
- if (resolution === state.resolution && resolution === text.resolution) return;
27532
- text.resolution = resolution;
27533
- state.resolution = resolution;
27548
+ function syncTextResolution(text, resolution) {
27549
+ const { width, height } = text.bounds;
27550
+ const limit = MAX_TEXT_EDGE / Math.max(1, Math.ceil(width + text.style.padding * 2), Math.ceil(height + text.style.padding * 2));
27551
+ const next = Math.min(limit, Math.max(MIN_TEXT_RESOLUTION, resolution));
27552
+ if (text.resolution !== next) text.resolution = next;
27534
27553
  }
27535
27554
  /** Defer expensive Pixi word-wrap rasterisation during a live resize. */
27536
27555
  function syncTextWrapWidth(text, state, width, defer) {
@@ -27712,13 +27731,15 @@ function createCardTag() {
27712
27731
  icon,
27713
27732
  text: null,
27714
27733
  sig: "",
27715
- resolution: 0,
27716
27734
  width: 0
27717
27735
  };
27718
27736
  }
27737
+ function tagScale(zoom) {
27738
+ return Math.min(MAX_GROWTH, Math.max(1, 1 / Math.max(zoom, .01)));
27739
+ }
27719
27740
  function zoomCardTag(tag, zoom) {
27720
27741
  if (!tag.text || !tag.sig) return;
27721
- const scale = Math.min(MAX_GROWTH, Math.max(1, 1 / Math.max(zoom, .01)));
27742
+ const scale = tagScale(zoom);
27722
27743
  const span = 17 + tag.text.width;
27723
27744
  tag.root.scale.set(scale);
27724
27745
  tag.root.position.set(0, -18 * scale);
@@ -27732,7 +27753,6 @@ function syncCardTag(tag, input, context) {
27732
27753
  return;
27733
27754
  }
27734
27755
  if (!tag.text) {
27735
- tag.resolution = textResolutionForZoom(context.zoom);
27736
27756
  tag.text = new Text({
27737
27757
  text: "",
27738
27758
  style: {
@@ -27740,30 +27760,27 @@ function syncCardTag(tag, input, context) {
27740
27760
  fontSize: 11,
27741
27761
  fontWeight: "500"
27742
27762
  },
27743
- resolution: tag.resolution,
27744
27763
  roundPixels: true
27745
27764
  });
27746
27765
  tag.root.addChild(tag.text);
27747
27766
  }
27748
- syncTextResolution(tag.text, tag, context.zoom);
27749
27767
  const sig = [
27750
27768
  input.glyph,
27751
27769
  input.text,
27752
27770
  input.width,
27753
27771
  context.themeKey
27754
27772
  ].join("|");
27755
- if (sig === tag.sig) {
27756
- zoomCardTag(tag, context.zoom);
27757
- return;
27758
- }
27759
- tag.sig = sig;
27760
- const color = context.palette.muted;
27761
- const pixel = context.style.icons === "pixel";
27762
- drawCardGlyph(tag.icon.clear(), input.glyph, color, pixel);
27763
- tag.text.style.fill = color;
27764
- tag.text.style.fontFamily = context.style.font;
27765
- fitTextToWidth(tag.text, input.text, Math.max(1, input.width - ICON - GAP$2));
27766
- tag.text.position.set(17, (ICON - tag.text.height) / 2);
27773
+ if (sig !== tag.sig) {
27774
+ tag.sig = sig;
27775
+ const color = context.palette.muted;
27776
+ const pixel = context.style.icons === "pixel";
27777
+ drawCardGlyph(tag.icon.clear(), input.glyph, color, pixel);
27778
+ tag.text.style.fill = color;
27779
+ tag.text.style.fontFamily = context.style.font;
27780
+ fitTextToWidth(tag.text, input.text, Math.max(1, input.width - ICON - GAP$2));
27781
+ tag.text.position.set(17, (ICON - tag.text.height) / 2);
27782
+ }
27783
+ syncTextResolution(tag.text, context.textResolution * tagScale(context.zoom));
27767
27784
  zoomCardTag(tag, context.zoom);
27768
27785
  }
27769
27786
  //#endregion
@@ -27968,6 +27985,19 @@ function traceCardOutline(graphics, rect, style, grow = 0) {
27968
27985
  const radius = Math.min(Math.max(0, style.radius + grow), width / 2, height / 2);
27969
27986
  return radius > 0 ? graphics.roundRect(x, y, width, height, radius) : graphics.rect(x, y, width, height);
27970
27987
  }
27988
+ function fillCardPicture(graphics, texture, picture, style, crop) {
27989
+ const sampling = texture.source.style;
27990
+ if (sampling.addressMode !== "mirror-repeat") {
27991
+ sampling.addressMode = "mirror-repeat";
27992
+ sampling.update();
27993
+ }
27994
+ const matrix = crop ? new Matrix(1 / crop.w, 0, 0, 1 / crop.h, -crop.x / crop.w, -crop.y / crop.h) : void 0;
27995
+ return traceCardOutline(graphics, picture, style).fill({
27996
+ texture,
27997
+ textureSpace: "local",
27998
+ ...matrix ? { matrix } : {}
27999
+ });
28000
+ }
27971
28001
  function tracePixelRect(graphics, x, y, width, height, step) {
27972
28002
  const s = Math.min(step, width / 4, height / 4);
27973
28003
  if (s <= 0) return graphics.rect(x, y, width, height);
@@ -28061,9 +28091,9 @@ function cardElevation(context, id) {
28061
28091
  }
28062
28092
  //#endregion
28063
28093
  //#region ../sdk/src/board/render/renderers/base-card-renderer.ts
28064
- function createLabel(text, style) {
28094
+ function createLabel(text, style, resolution) {
28065
28095
  return new Text({
28066
- resolution: getBoardResolution(),
28096
+ resolution,
28067
28097
  roundPixels: true,
28068
28098
  text,
28069
28099
  style: {
@@ -28220,12 +28250,15 @@ function audioKeyCenter(width, height) {
28220
28250
  function sync$13(container, item, context) {
28221
28251
  const parts = partsByContainer$13.get(container);
28222
28252
  if (!parts) return;
28253
+ syncContent$1(parts, item, context);
28254
+ syncTextResolution(parts.title, context.textResolution);
28255
+ }
28256
+ function syncContent$1(parts, item, context) {
28223
28257
  positionShell(parts.root, item);
28224
28258
  const { width, height } = item.frame;
28225
28259
  const title = item.props.snapshot?.title ?? getMediaResourceTitle(item.props.src);
28226
28260
  const durationMs = item.props.snapshot?.durationMs;
28227
28261
  const detailed = boardCardDetailed(context.zoom);
28228
- syncTextResolution(parts.title, parts, context.zoom);
28229
28262
  const elevation = cardElevation(context, item.id);
28230
28263
  const sig = [
28231
28264
  width,
@@ -28278,14 +28311,13 @@ const audioCardRenderer = {
28278
28311
  const root = new Container();
28279
28312
  const plate = new Graphics();
28280
28313
  const wave = new Graphics();
28281
- const resolution = textResolutionForZoom(context.zoom);
28282
28314
  const title = new Text({
28283
28315
  text: "",
28284
28316
  style: {
28285
28317
  fontSize: 13,
28286
28318
  fontWeight: "600"
28287
28319
  },
28288
- resolution,
28320
+ resolution: context.textResolution,
28289
28321
  roundPixels: true
28290
28322
  });
28291
28323
  root.addChild(plate, wave, title);
@@ -28294,8 +28326,7 @@ const audioCardRenderer = {
28294
28326
  plate,
28295
28327
  wave,
28296
28328
  title,
28297
- sig: "",
28298
- resolution
28329
+ sig: ""
28299
28330
  });
28300
28331
  if (item.type === "audio") sync$13(root, item, context);
28301
28332
  return root;
@@ -28303,6 +28334,9 @@ const audioCardRenderer = {
28303
28334
  update: (container, item, context) => {
28304
28335
  if (item.type === "audio") sync$13(container, item, context);
28305
28336
  },
28337
+ resolution: (container, item, context) => {
28338
+ if (item.type === "audio") sync$13(container, item, context);
28339
+ },
28306
28340
  renderFar: (graphics, item, context) => {
28307
28341
  drawFarPlate(graphics, item.frame, {
28308
28342
  fill: context.palette.surface,
@@ -28351,7 +28385,7 @@ function sync$12(container, item, context) {
28351
28385
  const elevation = cardElevation(context, item.id);
28352
28386
  const sig = [
28353
28387
  key ?? "",
28354
- texture ? `${texture.width}x${texture.height}` : "none",
28388
+ texture?.uid ?? "none",
28355
28389
  failed,
28356
28390
  width,
28357
28391
  height,
@@ -28420,6 +28454,9 @@ const modelCardRenderer = {
28420
28454
  update: (container, item, context) => {
28421
28455
  if (item.type === "file") sync$12(container, item, context);
28422
28456
  },
28457
+ resolution: (container, item, context) => {
28458
+ if (item.type === "file") sync$12(container, item, context);
28459
+ },
28423
28460
  zoom: (container, zoom) => {
28424
28461
  const tag = partsByContainer$12.get(container)?.tag;
28425
28462
  if (tag) zoomCardTag(tag, zoom);
@@ -28450,7 +28487,6 @@ function sync$11(container, item, context) {
28450
28487
  parts.line.alpha = itemAlpha(context, style.stroke);
28451
28488
  const color = itemColor(context, style.stroke, "brand");
28452
28489
  const size = style.strokeWidth ?? 2.5;
28453
- syncTextResolution(parts.label, parts, context.zoom);
28454
28490
  const resolved = resolveSceneArrow(item, context.scene);
28455
28491
  const path = trimPolyline(resolved.path, style.trim);
28456
28492
  const lineSig = [
@@ -28517,6 +28553,7 @@ function sync$11(container, item, context) {
28517
28553
  border: context.palette.border
28518
28554
  });
28519
28555
  }
28556
+ syncTextResolution(parts.label, context.textResolution);
28520
28557
  const visible = props.label.length > 0 && (style.trim === void 0 || style.trim >= .5);
28521
28558
  parts.label.visible = visible;
28522
28559
  parts.backdrop.visible = visible;
@@ -28530,7 +28567,6 @@ const arrowCardRenderer = {
28530
28567
  create: (item, context) => {
28531
28568
  const root = new Container();
28532
28569
  const line = new Graphics();
28533
- const resolution = textResolutionForZoom(context.zoom);
28534
28570
  const label = new Text({
28535
28571
  text: "",
28536
28572
  style: {
@@ -28539,7 +28575,7 @@ const arrowCardRenderer = {
28539
28575
  fontSize: 14,
28540
28576
  fontWeight: "500"
28541
28577
  },
28542
- resolution,
28578
+ resolution: context.textResolution,
28543
28579
  roundPixels: true
28544
28580
  });
28545
28581
  label.anchor.set(.5);
@@ -28551,8 +28587,7 @@ const arrowCardRenderer = {
28551
28587
  backdrop,
28552
28588
  label,
28553
28589
  lineSig: "",
28554
- labelSig: "",
28555
- resolution
28590
+ labelSig: ""
28556
28591
  });
28557
28592
  if (item.type === "arrow") sync$11(root, item, context);
28558
28593
  return root;
@@ -28560,6 +28595,10 @@ const arrowCardRenderer = {
28560
28595
  update: (container, item, context) => {
28561
28596
  if (item.type === "arrow") sync$11(container, item, context);
28562
28597
  },
28598
+ resolution: (container, _item, context) => {
28599
+ const parts = partsByContainer$11.get(container);
28600
+ if (parts) syncTextResolution(parts.label, context.textResolution);
28601
+ },
28563
28602
  renderFar: (graphics, item, context) => {
28564
28603
  if (item.type !== "arrow") return;
28565
28604
  const arrow = item;
@@ -28943,6 +28982,14 @@ function syncClip(parts, rect, style) {
28943
28982
  function sync$8(container, item, context) {
28944
28983
  const parts = partsByContainer$8.get(container);
28945
28984
  if (!parts) return;
28985
+ syncContent(parts, item, context);
28986
+ for (const text of [
28987
+ parts.title,
28988
+ parts.excerpt,
28989
+ parts.typeMark
28990
+ ]) syncTextResolution(text, context.textResolution);
28991
+ }
28992
+ function syncContent(parts, item, context) {
28946
28993
  positionShell(parts.root, item);
28947
28994
  const { width, height } = item.frame;
28948
28995
  const detail = detailFor(context.zoom);
@@ -28960,16 +29007,13 @@ function sync$8(container, item, context) {
28960
29007
  const kind = filePreviewKind(item.props.snapshot);
28961
29008
  const category = fileCategory(item.props.src, item.props.snapshot?.mimeType);
28962
29009
  const accent = fileCategoryAccent(category, context.palette);
28963
- syncTextResolution(parts.title, parts.titleRes, context.zoom);
28964
- syncTextResolution(parts.excerpt, parts.excerptRes, context.zoom);
28965
- syncTextResolution(parts.typeMark, parts.typeMarkRes, context.zoom);
28966
29010
  const visualSig = [
28967
29011
  key ?? "",
28968
29012
  width,
28969
29013
  height,
28970
29014
  detail,
28971
29015
  elevation,
28972
- texture ? `${texture.width}x${texture.height}` : "none",
29016
+ texture?.uid ?? "none",
28973
29017
  coverFailed,
28974
29018
  fileState,
28975
29019
  kind,
@@ -29086,7 +29130,7 @@ const fileCardRenderer = {
29086
29130
  const cover = new Sprite(Texture.EMPTY);
29087
29131
  const coverMask = new Graphics();
29088
29132
  cover.mask = coverMask;
29089
- const resolution = 1;
29133
+ const resolution = context.textResolution;
29090
29134
  const title = new Text({
29091
29135
  text: "",
29092
29136
  style: {
@@ -29143,10 +29187,7 @@ const fileCardRenderer = {
29143
29187
  title,
29144
29188
  excerpt,
29145
29189
  visualSig: "",
29146
- textSig: "",
29147
- titleRes: { resolution },
29148
- excerptRes: { resolution },
29149
- typeMarkRes: { resolution }
29190
+ textSig: ""
29150
29191
  });
29151
29192
  if (item.type === "file") sync$8(root, item, context);
29152
29193
  return root;
@@ -29154,6 +29195,9 @@ const fileCardRenderer = {
29154
29195
  update: (container, item, context) => {
29155
29196
  if (item.type === "file") sync$8(container, item, context);
29156
29197
  },
29198
+ resolution: (container, item, context) => {
29199
+ if (item.type === "file") sync$8(container, item, context);
29200
+ },
29157
29201
  zoom: (container, zoom) => {
29158
29202
  const tag = partsByContainer$8.get(container)?.tag;
29159
29203
  if (tag) zoomCardTag(tag, zoom);
@@ -29181,7 +29225,6 @@ function sync$7(container, item, context) {
29181
29225
  if (!parts) return;
29182
29226
  const { frame, style, props, locked } = item;
29183
29227
  positionShell(parts.root, item);
29184
- syncTextResolution(parts.label, parts, context.zoom);
29185
29228
  const fill = itemColor(context, style.fill ?? style.stroke, "neutral", "fill");
29186
29229
  const fillAlpha = (style.fillOpacity ?? (style.fill ? 1 : DEFAULT_WASH)) * itemAlpha(context, style.fill ?? style.stroke);
29187
29230
  const baseStroke = itemColor(context, style.stroke, "neutral");
@@ -29237,6 +29280,7 @@ function sync$7(container, item, context) {
29237
29280
  parts.label.style.fill = labelColor;
29238
29281
  parts.label.style.fontFamily = context.style.font;
29239
29282
  }
29283
+ syncTextResolution(parts.label, context.textResolution);
29240
29284
  parts.label.position.set(4, -18);
29241
29285
  }
29242
29286
  const frameCardRenderer = {
@@ -29250,15 +29294,14 @@ const frameCardRenderer = {
29250
29294
  fontFamily: BOARD_FONT_STACK,
29251
29295
  fontSize: 12,
29252
29296
  fontWeight: "600"
29253
- });
29297
+ }, context.textResolution);
29254
29298
  root.addChild(box, label);
29255
29299
  partsByContainer$7.set(root, {
29256
29300
  root,
29257
29301
  box,
29258
29302
  label,
29259
29303
  visualSig: "",
29260
- textSig: "",
29261
- resolution: label.resolution
29304
+ textSig: ""
29262
29305
  });
29263
29306
  if (item.type === "frame") sync$7(root, item, context);
29264
29307
  return root;
@@ -29266,6 +29309,10 @@ const frameCardRenderer = {
29266
29309
  update: (container, item, context) => {
29267
29310
  if (item.type === "frame") sync$7(container, item, context);
29268
29311
  },
29312
+ resolution: (container, _item, context) => {
29313
+ const parts = partsByContainer$7.get(container);
29314
+ if (parts) syncTextResolution(parts.label, context.textResolution);
29315
+ },
29269
29316
  renderFar: (graphics, item, context) => {
29270
29317
  if (item.type !== "frame" || item.props.decoration === "none") return;
29271
29318
  drawFarPlate(graphics, item.frame, {
@@ -29373,7 +29420,6 @@ function sync$6(container, item, context) {
29373
29420
  const fillOpacity = (style.fillOpacity ?? (style.fill ? 1 : 0)) * itemAlpha(context, style.fill ?? style.stroke);
29374
29421
  const strokeAlpha = itemAlpha(context, style.stroke ?? style.fill);
29375
29422
  const strokeWidth = style.strokeWidth ?? 1.75;
29376
- syncTextResolution(parts.label, parts, context.zoom);
29377
29423
  const visualSig = [
29378
29424
  width,
29379
29425
  height,
@@ -29432,6 +29478,7 @@ function sync$6(container, item, context) {
29432
29478
  parts.label.style.align = props.align;
29433
29479
  }
29434
29480
  syncTextWrapWidth(parts.label, parts, Math.max(1, width - 16), context.resizingIds.has(item.id));
29481
+ syncTextResolution(parts.label, context.textResolution);
29435
29482
  parts.label.position.set(width / 2, height / 2);
29436
29483
  }
29437
29484
  const shapeCardRenderer = {
@@ -29440,7 +29487,6 @@ const shapeCardRenderer = {
29440
29487
  create: (item, context) => {
29441
29488
  const root = new Container();
29442
29489
  const shape = new Graphics();
29443
- const resolution = textResolutionForZoom(context.zoom);
29444
29490
  const label = new Text({
29445
29491
  text: "",
29446
29492
  style: {
@@ -29452,7 +29498,7 @@ const shapeCardRenderer = {
29452
29498
  wordWrap: true,
29453
29499
  lineHeight: 28
29454
29500
  },
29455
- resolution,
29501
+ resolution: context.textResolution,
29456
29502
  roundPixels: true
29457
29503
  });
29458
29504
  label.anchor.set(.5);
@@ -29463,8 +29509,7 @@ const shapeCardRenderer = {
29463
29509
  label,
29464
29510
  visualSig: "",
29465
29511
  textSig: "",
29466
- wrapWidth: 0,
29467
- resolution
29512
+ wrapWidth: 0
29468
29513
  });
29469
29514
  if (item.type === "shape") sync$6(root, item, context);
29470
29515
  return root;
@@ -29472,6 +29517,10 @@ const shapeCardRenderer = {
29472
29517
  update: (container, item, context) => {
29473
29518
  if (item.type === "shape") sync$6(container, item, context);
29474
29519
  },
29520
+ resolution: (container, _item, context) => {
29521
+ const parts = partsByContainer$6.get(container);
29522
+ if (parts) syncTextResolution(parts.label, context.textResolution);
29523
+ },
29475
29524
  renderFar: (graphics, item, context) => {
29476
29525
  if (item.type !== "shape") return;
29477
29526
  drawFarPlate(graphics, item.frame, {
@@ -29497,10 +29546,8 @@ function sync$5(container, item, context) {
29497
29546
  parts.id = item.id;
29498
29547
  }
29499
29548
  positionShell(parts.root, item);
29500
- syncTextResolution(parts.label, parts.label, context.zoom);
29501
29549
  const { width, height } = item.frame;
29502
- const resolution = Math.min(4, Math.max(.25, context.zoom * getBoardResolution()));
29503
- const texture = context.scripts?.frame(item, context.time, resolution) ?? null;
29550
+ const texture = context.scripts?.frame(item, context.time) ?? null;
29504
29551
  const error = context.scripts?.error(item.id) ?? null;
29505
29552
  parts.sprite.visible = Boolean(texture);
29506
29553
  const display = texture ?? Texture.EMPTY;
@@ -29516,19 +29563,21 @@ function sync$5(container, item, context) {
29516
29563
  message,
29517
29564
  context.themeKey
29518
29565
  ].join("|");
29519
- if (sig === parts.sig) return;
29520
- parts.sig = sig;
29521
- parts.placeholder.clear();
29522
- if (!ready || error) parts.placeholder.rect(0, 0, width, height).stroke({
29523
- color: context.palette.border,
29524
- width: 1,
29525
- alpha: .8
29526
- });
29527
- parts.label.visible = !ready || Boolean(error);
29528
- parts.label.text = message;
29529
- parts.label.style.fill = error ? context.colors.rose.stroke : context.palette.muted;
29530
- parts.label.style.wordWrapWidth = Math.max(40, width - 16);
29531
- parts.label.position.set(width / 2, height / 2);
29566
+ if (sig !== parts.sig) {
29567
+ parts.sig = sig;
29568
+ parts.placeholder.clear();
29569
+ if (!ready || error) parts.placeholder.rect(0, 0, width, height).stroke({
29570
+ color: context.palette.border,
29571
+ width: 1,
29572
+ alpha: .8
29573
+ });
29574
+ parts.label.visible = !ready || Boolean(error);
29575
+ parts.label.text = message;
29576
+ parts.label.style.fill = error ? context.colors.rose.stroke : context.palette.muted;
29577
+ parts.label.style.wordWrapWidth = Math.max(40, width - 16);
29578
+ parts.label.position.set(width / 2, height / 2);
29579
+ }
29580
+ syncTextResolution(parts.label, context.textResolution);
29532
29581
  }
29533
29582
  const customCardRenderer = {
29534
29583
  id: "custom-card",
@@ -29547,7 +29596,8 @@ const customCardRenderer = {
29547
29596
  wordWrap: true,
29548
29597
  breakWords: true
29549
29598
  },
29550
- resolution: getBoardResolution()
29599
+ resolution: context.textResolution,
29600
+ roundPixels: true
29551
29601
  });
29552
29602
  label.anchor.set(.5);
29553
29603
  root.addChild(sprite, placeholder, label);
@@ -29565,6 +29615,10 @@ const customCardRenderer = {
29565
29615
  update: (container, item, context) => {
29566
29616
  if (item.type === "custom") sync$5(container, item, context);
29567
29617
  },
29618
+ resolution: (container, _item, context) => {
29619
+ const parts = partsByContainer$5.get(container);
29620
+ if (parts) syncTextResolution(parts.label, context.textResolution);
29621
+ },
29568
29622
  renderFar: (graphics, item, context) => {
29569
29623
  drawFarPlate(graphics, item.frame, {
29570
29624
  fill: context.palette.muted,
@@ -29592,28 +29646,6 @@ function cropRect(crop) {
29592
29646
  h
29593
29647
  } : null;
29594
29648
  }
29595
- function showTexture(parts, texture, crop) {
29596
- const rect = texture ? cropRect(crop) : null;
29597
- const key = rect ? `${rect.x}|${rect.y}|${rect.w}|${rect.h}` : "";
29598
- const previous = parts.cropped;
29599
- const reusable = previous && parts.cropSource === texture && parts.cropKey === key;
29600
- if (texture && rect && !reusable) {
29601
- const { frame } = texture;
29602
- const width = Math.max(1, frame.width * rect.w);
29603
- const height = Math.max(1, frame.height * rect.h);
29604
- const x = frame.x + Math.min(frame.width * rect.x, frame.width - width);
29605
- const y = frame.y + Math.min(frame.height * rect.y, frame.height - height);
29606
- parts.cropped = new Texture({
29607
- source: texture.source,
29608
- frame: new Rectangle(x, y, width, height)
29609
- });
29610
- } else if (!rect) parts.cropped = null;
29611
- parts.cropSource = rect ? texture : null;
29612
- parts.cropKey = key;
29613
- const display = parts.cropped ?? texture ?? Texture.EMPTY;
29614
- if (parts.sprite.texture !== display) parts.sprite.texture = display;
29615
- if (previous && previous !== parts.cropped) previous.destroy(false);
29616
- }
29617
29649
  const PRINT_MARGIN = 6;
29618
29650
  function sync$4(container, item, context) {
29619
29651
  const parts = partsByContainer$4.get(container);
@@ -29628,7 +29660,7 @@ function sync$4(container, item, context) {
29628
29660
  key ?? "",
29629
29661
  width,
29630
29662
  height,
29631
- texture ? `${texture.width}x${texture.height}` : "none",
29663
+ texture?.uid ?? "none",
29632
29664
  JSON.stringify(item.props.crop ?? null),
29633
29665
  failed,
29634
29666
  elevation,
@@ -29636,8 +29668,7 @@ function sync$4(container, item, context) {
29636
29668
  ].join("|");
29637
29669
  if (sig === parts.sig) return;
29638
29670
  parts.sig = sig;
29639
- showTexture(parts, texture, item.props.crop);
29640
- const display = parts.sprite.texture;
29671
+ const crop = cropRect(item.props.crop);
29641
29672
  const framed = context.style.media === "framed";
29642
29673
  const margin = framed ? Math.min(PRINT_MARGIN, width / 8, height / 8) : 0;
29643
29674
  const area = {
@@ -29646,7 +29677,7 @@ function sync$4(container, item, context) {
29646
29677
  width: width - margin * 2,
29647
29678
  height: height - margin * 2
29648
29679
  };
29649
- const fitted = texture ? containRect(area.width, area.height, display.width, display.height) : {
29680
+ const fitted = texture ? containRect(area.width, area.height, texture.width * (crop?.w ?? 1), texture.height * (crop?.h ?? 1)) : {
29650
29681
  ...area,
29651
29682
  x: 0,
29652
29683
  y: 0
@@ -29663,16 +29694,11 @@ function sync$4(container, item, context) {
29663
29694
  width: picture.width + margin * 2,
29664
29695
  height: picture.height + margin * 2
29665
29696
  } : picture;
29666
- parts.sprite.visible = Boolean(texture);
29667
- if (texture) {
29668
- parts.sprite.position.set(picture.x, picture.y);
29669
- parts.sprite.width = picture.width;
29670
- parts.sprite.height = picture.height;
29671
- }
29672
- traceCardOutline(parts.mask.clear(), picture, framed ? {
29697
+ parts.picture.clear();
29698
+ if (texture) fillCardPicture(parts.picture, texture, picture, framed ? {
29673
29699
  corner: "round",
29674
29700
  radius: 0
29675
- } : context.style).fill({ color: 16777215 });
29701
+ } : context.style, crop);
29676
29702
  parts.placeholder.clear();
29677
29703
  if (texture && !framed) return;
29678
29704
  drawCardSurface(parts.placeholder, card, context.style, {
@@ -29699,20 +29725,14 @@ const imageCardRenderer = {
29699
29725
  canRender: (item) => item.type === "image",
29700
29726
  create: (item, context) => {
29701
29727
  const root = new Container();
29702
- const sprite = new Sprite(Texture.EMPTY);
29703
29728
  const placeholder = new Graphics();
29704
- const mask = new Graphics();
29705
- root.addChild(placeholder, sprite, mask);
29706
- sprite.mask = mask;
29729
+ const picture = new Graphics();
29730
+ root.addChild(placeholder, picture);
29707
29731
  partsByContainer$4.set(root, {
29708
29732
  root,
29709
- sprite,
29710
29733
  placeholder,
29711
- mask,
29712
- sig: "",
29713
- cropped: null,
29714
- cropSource: null,
29715
- cropKey: ""
29734
+ picture,
29735
+ sig: ""
29716
29736
  });
29717
29737
  if (item.type === "image") sync$4(root, item, context);
29718
29738
  return root;
@@ -29727,9 +29747,7 @@ const imageCardRenderer = {
29727
29747
  });
29728
29748
  },
29729
29749
  destroy: (container) => {
29730
- const parts = partsByContainer$4.get(container);
29731
- parts?.root.destroy({ children: true });
29732
- parts?.cropped?.destroy(false);
29750
+ partsByContainer$4.get(container)?.root.destroy({ children: true });
29733
29751
  partsByContainer$4.delete(container);
29734
29752
  }
29735
29753
  };
@@ -29985,7 +30003,7 @@ function sync$3(container, item, context) {
29985
30003
  if (key !== parts.assetKey) {
29986
30004
  if (parts.assetKey) context.releaseTexture(parts.assetKey);
29987
30005
  parts.assetKey = key;
29988
- if (key) context.acquireTexture(key);
30006
+ if (key) context.acquireTexture(key, item);
29989
30007
  }
29990
30008
  const texture = key ? context.getTexture(key) : null;
29991
30009
  const previewFailed = Boolean(key && !texture && context.hasError(key));
@@ -30009,10 +30027,6 @@ function sync$3(container, item, context) {
30009
30027
  const detailText = !full || !surface ? "" : status === "failed" ? snapshot.errorExcerpt ?? "" : working ? snapshot.promptExcerpt ?? "" : "";
30010
30028
  const textArtifact = kind === "text" && artifact?.type === "text";
30011
30029
  const bodyText = textArtifact ? artifact.textExcerpt : counting ? `${label} · ${elapsed}` : label;
30012
- syncTextResolution(parts.body, parts, context.zoom);
30013
- syncTextResolution(parts.detail, parts, context.zoom);
30014
- syncTextResolution(parts.meta, parts, context.zoom);
30015
- syncTextResolution(parts.badge, parts, context.zoom);
30016
30030
  const textSig = [
30017
30031
  counting ? label : bodyText,
30018
30032
  detailText,
@@ -30043,6 +30057,12 @@ function sync$3(container, item, context) {
30043
30057
  parts.badge.style.fill = context.palette.text;
30044
30058
  if (parts.badge.text !== count) parts.badge.text = count;
30045
30059
  }
30060
+ for (const text of [
30061
+ parts.body,
30062
+ parts.detail,
30063
+ parts.meta,
30064
+ parts.badge
30065
+ ]) syncTextResolution(text, context.textResolution);
30046
30066
  const badgeWidth = Math.max(22, parts.badge.width + 12);
30047
30067
  const visualSig = [
30048
30068
  width,
@@ -30058,7 +30078,7 @@ function sync$3(container, item, context) {
30058
30078
  artifact?.type ?? "none",
30059
30079
  artifact?.id ?? "none",
30060
30080
  item.props.taskRunId,
30061
- texture ? `${texture.width}x${texture.height}` : "none",
30081
+ texture?.uid ?? "none",
30062
30082
  context.themeKey
30063
30083
  ].join("|");
30064
30084
  if (visualSig !== parts.visualSig) {
@@ -30160,7 +30180,6 @@ const taskCardRenderer = {
30160
30180
  const previewMask = new Graphics();
30161
30181
  const shimmer = new Graphics();
30162
30182
  const previewArt = new Graphics();
30163
- const resolution = textResolutionForZoom(context.zoom);
30164
30183
  const text = (fontFamily, fontSize, fontWeight) => new Text({
30165
30184
  text: "",
30166
30185
  style: {
@@ -30170,7 +30189,7 @@ const taskCardRenderer = {
30170
30189
  wordWrap: true,
30171
30190
  breakWords: true
30172
30191
  },
30173
- resolution,
30192
+ resolution: context.textResolution,
30174
30193
  roundPixels: true
30175
30194
  });
30176
30195
  const body = text(BOARD_FONT_STACK, 11.5, "500");
@@ -30204,7 +30223,6 @@ const taskCardRenderer = {
30204
30223
  assetKey: null,
30205
30224
  visualSig: "",
30206
30225
  textSig: "",
30207
- resolution,
30208
30226
  motion: {
30209
30227
  itemId: "",
30210
30228
  width: 0,
@@ -30227,6 +30245,9 @@ const taskCardRenderer = {
30227
30245
  const parts = partsByContainer$3.get(container);
30228
30246
  return parts ? advance(parts, clock) : null;
30229
30247
  },
30248
+ resolution: (container, item, context) => {
30249
+ if (item.type === "task") sync$3(container, item, context);
30250
+ },
30230
30251
  zoom: (container, zoom) => {
30231
30252
  const tag = partsByContainer$3.get(container)?.tag;
30232
30253
  if (tag) zoomCardTag(tag, zoom);
@@ -30278,7 +30299,6 @@ function sync$2(container, item, context) {
30278
30299
  const anchorX = props.align === "center" ? .5 : props.align === "right" ? 1 : 0;
30279
30300
  parts.body.anchor.set(anchorX, 0);
30280
30301
  parts.body.position.set(item.frame.width * anchorX, 0);
30281
- syncTextResolution(parts.body, parts, context.zoom * Math.max(1, previewScale));
30282
30302
  parts.body.alpha = itemAlpha(context, item.style.fill);
30283
30303
  parts.caret.alpha = parts.body.alpha;
30284
30304
  const ink = itemColor(context, item.style.fill, "neutral");
@@ -30308,6 +30328,7 @@ function sync$2(container, item, context) {
30308
30328
  breakWords: true
30309
30329
  });
30310
30330
  }
30331
+ syncTextResolution(parts.body, context.textResolution * previewScale);
30311
30332
  syncCaret(parts, item, context);
30312
30333
  }
30313
30334
  const textCardRenderer = {
@@ -30315,11 +30336,10 @@ const textCardRenderer = {
30315
30336
  canRender: (item) => item.type === "text",
30316
30337
  create: (item, context) => {
30317
30338
  const root = new Container();
30318
- const resolution = textResolutionForZoom(context.zoom);
30319
30339
  const body = new Text({
30320
30340
  text: "",
30321
30341
  style: { fontFamily: BOARD_FONT_STACKS.sans },
30322
- resolution,
30342
+ resolution: context.textResolution,
30323
30343
  roundPixels: true
30324
30344
  });
30325
30345
  const caret = new Graphics();
@@ -30328,7 +30348,6 @@ const textCardRenderer = {
30328
30348
  root,
30329
30349
  body,
30330
30350
  caret,
30331
- resolution,
30332
30351
  contentSig: ""
30333
30352
  });
30334
30353
  if (item.type === "text") sync$2(root, item, context);
@@ -30337,6 +30356,10 @@ const textCardRenderer = {
30337
30356
  update: (container, item, context) => {
30338
30357
  if (item.type === "text") sync$2(container, item, context);
30339
30358
  },
30359
+ resolution: (container, _item, context) => {
30360
+ const parts = partsByContainer$2.get(container);
30361
+ if (parts) syncTextResolution(parts.body, context.textResolution * parts.body.scale.x);
30362
+ },
30340
30363
  renderFar: (graphics, item, context) => {
30341
30364
  if (item.type !== "text") return;
30342
30365
  drawFarPlate(graphics, item.frame, {
@@ -30358,7 +30381,6 @@ function sync$1(container, item, context) {
30358
30381
  positionShell(parts.root, item);
30359
30382
  const { width, height } = item.frame;
30360
30383
  const realType = item.type;
30361
- syncTextResolution(parts.label, parts, context.zoom);
30362
30384
  const elevation = cardElevation(context, item.id);
30363
30385
  const visualSig = [
30364
30386
  width,
@@ -30393,6 +30415,7 @@ function sync$1(container, item, context) {
30393
30415
  parts.label.text = realType;
30394
30416
  parts.label.style.fill = context.palette.muted;
30395
30417
  }
30418
+ syncTextResolution(parts.label, context.textResolution);
30396
30419
  parts.label.position.set(width / 2, height / 2);
30397
30420
  }
30398
30421
  const unknownCardRenderer = {
@@ -30402,7 +30425,6 @@ const unknownCardRenderer = {
30402
30425
  const root = new Container();
30403
30426
  const box = new Graphics();
30404
30427
  box.context.batchMode = "batch";
30405
- const resolution = textResolutionForZoom(context.zoom);
30406
30428
  const label = new Text({
30407
30429
  text: "",
30408
30430
  style: {
@@ -30410,7 +30432,7 @@ const unknownCardRenderer = {
30410
30432
  fontSize: 11,
30411
30433
  fontWeight: "600"
30412
30434
  },
30413
- resolution,
30435
+ resolution: context.textResolution,
30414
30436
  roundPixels: true
30415
30437
  });
30416
30438
  label.anchor.set(.5);
@@ -30420,8 +30442,7 @@ const unknownCardRenderer = {
30420
30442
  box,
30421
30443
  label,
30422
30444
  visualSig: "",
30423
- textSig: "",
30424
- resolution
30445
+ textSig: ""
30425
30446
  });
30426
30447
  sync$1(root, item, context);
30427
30448
  return root;
@@ -30429,6 +30450,10 @@ const unknownCardRenderer = {
30429
30450
  update: (container, item, context) => {
30430
30451
  sync$1(container, item, context);
30431
30452
  },
30453
+ resolution: (container, _item, context) => {
30454
+ const parts = partsByContainer$1.get(container);
30455
+ if (parts) syncTextResolution(parts.label, context.textResolution);
30456
+ },
30432
30457
  renderFar: (graphics, item, context) => {
30433
30458
  drawFarPlate(graphics, item.frame, {
30434
30459
  fill: context.palette.muted,
@@ -30466,7 +30491,7 @@ function sync(container, item, context) {
30466
30491
  const elevation = cardElevation(context, item.id);
30467
30492
  const sig = [
30468
30493
  key ?? "",
30469
- texture ? `${texture.width}x${texture.height}` : "none",
30494
+ texture?.uid ?? "none",
30470
30495
  width,
30471
30496
  height,
30472
30497
  elevation,
@@ -30496,17 +30521,18 @@ function sync(container, item, context) {
30496
30521
  elevation
30497
30522
  });
30498
30523
  if (framed) drawFilmRails(parts.plate, width, height, rail, context.palette.bg);
30499
- traceCardOutline(parts.mask.clear(), framed ? screen : rect, framed ? {
30500
- corner: "round",
30501
- radius: 1
30502
- } : context.style).fill({ color: 16777215 });
30503
- if (texture && parts.sprite.texture !== texture) parts.sprite.texture = texture;
30504
- parts.sprite.visible = Boolean(texture);
30524
+ parts.picture.clear();
30505
30525
  if (texture) {
30506
30526
  const fitted = containRect(screen.width, screen.height, texture.width, texture.height);
30507
- parts.sprite.position.set(screen.x + fitted.x, screen.y + fitted.y);
30508
- parts.sprite.width = fitted.width;
30509
- parts.sprite.height = fitted.height;
30527
+ const picture = {
30528
+ ...fitted,
30529
+ x: screen.x + fitted.x,
30530
+ y: screen.y + fitted.y
30531
+ };
30532
+ fillCardPicture(parts.picture, texture, picture, framed ? {
30533
+ corner: "round",
30534
+ radius: 1
30535
+ } : context.style);
30510
30536
  }
30511
30537
  parts.chrome.clear();
30512
30538
  if (boardCardDetailed(context.zoom)) drawMediaPlayKey(parts.chrome, screen.x + screen.width / 2, screen.y + screen.height / 2, Math.min(18, Math.min(screen.width, screen.height) * .16), context);
@@ -30531,17 +30557,14 @@ const videoCardRenderer = {
30531
30557
  create: (item, context) => {
30532
30558
  const root = new Container();
30533
30559
  const plate = new Graphics();
30534
- const sprite = new Sprite(Texture.EMPTY);
30535
- const mask = new Graphics();
30560
+ const picture = new Graphics();
30536
30561
  const chrome = new Graphics();
30537
30562
  const tag = createCardTag();
30538
- root.addChild(plate, sprite, mask, chrome, tag.root);
30539
- sprite.mask = mask;
30563
+ root.addChild(plate, picture, chrome, tag.root);
30540
30564
  partsByContainer.set(root, {
30541
30565
  root,
30542
30566
  plate,
30543
- sprite,
30544
- mask,
30567
+ picture,
30545
30568
  chrome,
30546
30569
  tag,
30547
30570
  sig: ""
@@ -30552,6 +30575,9 @@ const videoCardRenderer = {
30552
30575
  update: (container, item, context) => {
30553
30576
  if (item.type === "video") sync(container, item, context);
30554
30577
  },
30578
+ resolution: (container, item, context) => {
30579
+ if (item.type === "video") sync(container, item, context);
30580
+ },
30555
30581
  zoom: (container, zoom) => {
30556
30582
  const tag = partsByContainer.get(container)?.tag;
30557
30583
  if (tag) zoomCardTag(tag, zoom);
@@ -30606,6 +30632,48 @@ function createBoardCardRendererResolver(renderers = []) {
30606
30632
  }
30607
30633
  /** The built-in renderers alone. */
30608
30634
  const getBoardCardRenderer = createBoardCardRendererResolver();
30635
+ const BOARD_DEFAULT_ITEM_SIZE = {
30636
+ width: 240,
30637
+ height: 160
30638
+ };
30639
+ const BOARD_DEFAULT_SIZES = {
30640
+ frame: {
30641
+ width: 480,
30642
+ height: 320
30643
+ },
30644
+ shape: {
30645
+ width: 200,
30646
+ height: 140
30647
+ },
30648
+ image: {
30649
+ width: 480,
30650
+ height: 270
30651
+ },
30652
+ video: {
30653
+ width: 480,
30654
+ height: 270
30655
+ },
30656
+ audio: {
30657
+ width: 320,
30658
+ height: 112
30659
+ },
30660
+ file: {
30661
+ width: 260,
30662
+ height: 132
30663
+ },
30664
+ task: {
30665
+ width: 480,
30666
+ height: 270
30667
+ },
30668
+ effect: {
30669
+ width: 240,
30670
+ height: 240
30671
+ },
30672
+ custom: {
30673
+ width: 480,
30674
+ height: 320
30675
+ }
30676
+ };
30609
30677
  //#endregion
30610
30678
  //#region ../protocol/dist/board-url.js
30611
30679
  const BOARD_REMOTE_URL_MAX_LENGTH = 4096;
@@ -30781,12 +30849,9 @@ const itemEnvelope = {
30781
30849
  locked: boolean().optional(),
30782
30850
  metadata: record(string(), unknown()).optional()
30783
30851
  };
30784
- const boxed = (width, height) => ({
30852
+ const boxed = (size) => ({
30785
30853
  ...itemEnvelope,
30786
- size: BoardSizeSchema.default({
30787
- width,
30788
- height
30789
- })
30854
+ size: BoardSizeSchema.default({ ...size })
30790
30855
  });
30791
30856
  const unsized = { ...itemEnvelope };
30792
30857
  const fontSize = finite.min(2).max(512);
@@ -30804,7 +30869,7 @@ const BOARD_SHAPE_GEOMETRIES = [
30804
30869
  "path"
30805
30870
  ];
30806
30871
  object({
30807
- ...boxed(480, 320),
30872
+ ...boxed(BOARD_DEFAULT_SIZES.frame),
30808
30873
  type: literal("frame"),
30809
30874
  props: object({
30810
30875
  label: string().max(280).default(""),
@@ -30828,7 +30893,7 @@ object({
30828
30893
  }).strict().prefault({})
30829
30894
  }).strict();
30830
30895
  object({
30831
- ...boxed(240, 160),
30896
+ ...boxed(BOARD_DEFAULT_SIZES.shape),
30832
30897
  type: literal("shape"),
30833
30898
  props: object({
30834
30899
  geometry: _enum(BOARD_SHAPE_GEOMETRIES).default("rectangle"),
@@ -30926,7 +30991,7 @@ const BoardCropSchema = object({
30926
30991
  h: ratio
30927
30992
  }).strict().describe("Region shown, as fractions of the image. Without it the whole image fits inside size.");
30928
30993
  object({
30929
- ...boxed(640, 360),
30994
+ ...boxed(BOARD_DEFAULT_SIZES.image),
30930
30995
  type: literal("image"),
30931
30996
  props: object({
30932
30997
  ...mediaProps,
@@ -30934,17 +30999,17 @@ object({
30934
30999
  }).strict()
30935
31000
  }).strict();
30936
31001
  object({
30937
- ...boxed(640, 360),
31002
+ ...boxed(BOARD_DEFAULT_SIZES.video),
30938
31003
  type: literal("video"),
30939
31004
  props: object(timedFileProps).strict()
30940
31005
  }).strict();
30941
31006
  object({
30942
- ...boxed(480, 96),
31007
+ ...boxed(BOARD_DEFAULT_SIZES.audio),
30943
31008
  type: literal("audio"),
30944
31009
  props: object(timedFileProps).strict()
30945
31010
  }).strict();
30946
31011
  object({
30947
- ...boxed(360, 220),
31012
+ ...boxed(BOARD_DEFAULT_SIZES.file),
30948
31013
  type: literal("file"),
30949
31014
  props: object(fileProps).strict()
30950
31015
  }).strict();
@@ -31001,7 +31066,7 @@ const BoardTaskSnapshotSchema = object({
31001
31066
  updatedAt: string().optional()
31002
31067
  }).strict();
31003
31068
  object({
31004
- ...boxed(420, 240),
31069
+ ...boxed(BOARD_DEFAULT_SIZES.task),
31005
31070
  type: literal("task"),
31006
31071
  props: object({
31007
31072
  taskRunId: string().min(1).max(160).describe("The generation run shown; the server keeps the card's status and results up to date."),
@@ -31016,7 +31081,7 @@ const BOARD_EFFECT_KINDS = [
31016
31081
  "glow"
31017
31082
  ];
31018
31083
  object({
31019
- ...boxed(240, 240),
31084
+ ...boxed(BOARD_DEFAULT_SIZES.effect),
31020
31085
  type: literal("effect"),
31021
31086
  props: object({
31022
31087
  kind: _enum(BOARD_EFFECT_KINDS),
@@ -31033,18 +31098,14 @@ object({
31033
31098
  }).strict()
31034
31099
  }).strict();
31035
31100
  object({
31036
- ...boxed(480, 320),
31101
+ ...boxed(BOARD_DEFAULT_SIZES.custom),
31037
31102
  type: literal("custom"),
31038
31103
  script: BoardScriptSchema,
31039
31104
  props: object({}).strict().default({})
31040
31105
  }).strict();
31041
31106
  const BOARD_EXTENSION_TYPE_PATTERN = /^[a-z][a-z0-9]*(?:\.[a-z0-9-]+)+$/;
31042
31107
  object({
31043
- ...itemEnvelope,
31044
- size: BoardSizeSchema.default({
31045
- width: 240,
31046
- height: 160
31047
- }),
31108
+ ...boxed(BOARD_DEFAULT_ITEM_SIZE),
31048
31109
  type: string().regex(BOARD_EXTENSION_TYPE_PATTERN),
31049
31110
  props: record(string(), unknown()).default({})
31050
31111
  }).strict();
@@ -31557,6 +31618,7 @@ function buildContext(input) {
31557
31618
  themeKey: "export",
31558
31619
  rendererType: "canvas",
31559
31620
  zoom: input.scale,
31621
+ textResolution: input.scale,
31560
31622
  reducedMotion: true,
31561
31623
  labels: DEFAULT_BOARD_RENDER_LABELS,
31562
31624
  taskRun: () => null,