← ACE Carousel CreatorCONTENT HISTORY

Update to ACE Carousel Creator

Snapshot Nov 6, 2026 · 00:15 UTC · version 0.2.0

WHAT CHANGED

Package or technical metadata updated

Package or technical metadata updated

Observed in package metadata. These changes alone do not establish a new customer-facing feature.

Save ACE Carousel Creator and check future changes in Following.

Up to 3 plugins free · no card required.

All fields and original values.

These are saved file metadata. Open a changed file to read its text edits.

Package file

Before

Oct 24, 2026 · 13:48 UTC

Not present

After

Nov 6, 2026 · 00:15 UTC

{"sha256":"5f2025d9087cd8dc93ebe395791fda81379d9a438862e6e87a69b5faf4cc2b77","size":47}

Package file

Before

Oct 24, 2026 · 13:48 UTC

Not present

After

Nov 6, 2026 · 00:15 UTC

{"sha256":"fd48d4fdbb81718d2dfbffa6314dee7c56d042aa5dd96d34d45ee3b38ba91e49","size":315}

Package file

Before

Oct 24, 2026 · 13:48 UTC

Not present

After

Nov 6, 2026 · 00:15 UTC

{"sha256":"29942ea87db4340c9a272091ada1b037d8b8b02a2e76dce75509cb8a1e418059","size":2313}

Package file

Before

Oct 24, 2026 · 13:48 UTC

Not present

After

Nov 6, 2026 · 00:15 UTC

{"sha256":"2014b20842e56188734f68b1490b3cbb5a8dd5365993de5a9935fdc353ff30fc","size":1112}

Compare saved observations

Download comparison JSON

src/renderer.mjs

− removed · + added

--- before
+++ after
@@ -0,0 +1,134 @@
+import { readFileSync, existsSync } from 'node:fs';
+import { mkdir, readFile, writeFile, rm, stat } from 'node:fs/promises';
+import { dirname, join } from 'node:path';
+import { randomUUID } from 'node:crypto';
+import { execFile } from 'node:child_process';
+import { promisify } from 'node:util';
+import { setTimeout as delay } from 'node:timers/promises';
+import sharp from 'sharp';
+import { DocumentError } from './errors.mjs';
+
+const exec = promisify(execFile);
+const simctl = async (args, timeout = 30_000) => (await exec('/usr/bin/xcrun', ['simctl', ...args], { timeout, maxBuffer: 2 * 1024 * 1024 })).stdout.trim();
+
+export async function contactSheet(slides) {
+  const columns = Math.min(4, slides.length), thumb = 300, gutter = 16, label = 28;
+  const height = Math.round(thumb * slides[0].height / slides[0].width);
+  const width = gutter + columns * (thumb + gutter);
+  const rows = Math.ceil(slides.length / columns);
+  const layers = [];
+  for (const [index, slide] of slides.entries()) {
+    const left = gutter + (index % columns) * (thumb + gutter);
+    const top = gutter + Math.floor(index / columns) * (height + label + gutter);
+    layers.push({ input: await sharp(slide.bytes).resize(thumb, height).png().toBuffer(), left, top });
+    layers.push({ input: Buffer.from(`<svg width="${thumb}" height="${label}"><text x="${thumb / 2}" y="20" text-anchor="middle" font-size="14" font-family="sans-serif" fill="#444">${index + 1} / ${slides.length}</text></svg>`), left, top: top + height });
+  }
+  return sharp({ create: { width, height: gutter + rows * (height + label + gutter), channels: 3, background: '#eeeeee' } }).composite(layers).png().toBuffer();
+}
+
+/** The renderer is a local macOS worker; its capability must never be advertised on Linux. */
+export function nativeRenderer(configPath = process.env.CAROUSEL_RENDERER_CONFIG) {
+  if (!configPath) return null;
+  if (process.platform !== 'darwin') throw new Error('Native ACE rendering requires macOS and Xcode Simulator');
+  const config = JSON.parse(readFileSync(configPath, 'utf8'));
+  if (config.protocol !== 1 || config.engine !== 'ACE SlideRasterizer' || !/^[a-f0-9-]{36}$/i.test(config.device)
+      || config.bundleId !== 'software.quokka.ace-plugin-renderer' || !existsSync(config.app)) throw new Error('Invalid native renderer configuration; run setup-native-renderer.mjs');
+  let pending = 0, tail = Promise.resolve();
+  const metadata = { engine: config.engine, protocol: config.protocol, rasterizer_sha256: config.rasterizer_sha256, built_at: config.built_at };
+  return {
+    metadata,
+    async render(archive, { width = 720, slideCount } = {}) {
+      if (!Number.isInteger(width) || width < 360 || width > 1080) throw new DocumentError('Preview width must be 360…1080 pixels');
+      if (pending >= 3) throw new DocumentError('Native renderer is busy. Retry after the current previews finish.');
+      pending++;
+      const work = tail.then(() => renderNative(configPath, config, archive, width, slideCount));
+      tail = work.catch(() => {});
+      try { return { ...await work, engine: metadata }; } finally { pending--; }
+    }
+  };
+}
+
+// A file lock also serializes CLI and MCP requests targeting the same worker.
+async function lockRenderer(path) {
+  const deadline = Date.now() + 45_000;
+  while (true) {
+    try {
+      await mkdir(path);
+      try { await writeFile(join(path, 'pid'), String(process.pid)); }
+      catch (error) { await rm(path, { recursive: true, force: true }); throw error; }
+      return () => rm(path, { recursive: true, force: true });
+    } catch (error) {
+      if (error.code !== 'EEXIST') throw error;
+      try {
+        const pid = Number(await readFile(join(path, 'pid'), 'utf8'));
+        if (Number.isInteger(pid) && pid > 0) {
+          try { process.kill(pid, 0); }
+          catch (error) { if (error.code === 'ESRCH') { await rm(path, { recursive: true, force: true }); continue; } }
+        }
+      } catch (error) {
+        if (error.code === 'ENOENT' && Date.now() - (await stat(path).catch(() => ({ mtimeMs: Date.now() }))).mtimeMs > 60_000) {
+          await rm(path, { recursive: true, force: true }); continue;
+        }
+      }
+      if (Date.now() > deadline) throw new DocumentError('Another native preview is still running; try again shortly');
+      await delay(200);
+    }
+  }
+}
+
+async function renderNative(configPath, config, archive, width, slideCount) {
+  const unlock = await lockRenderer(join(dirname(configPath), 'render.lock'));
+  let job;
+  try {
+    const devices = JSON.parse(await simctl(['list', 'devices', 'available', '-j'])).devices;
+    const device = Object.values(devices).flat().find(device => device.udid === config.device);
+    if (!device) throw new DocumentError('ACE preview simulator is unavailable; run setup-native-renderer.mjs');
+    if (device.state !== 'Booted') {
+      await simctl(['boot', config.device]);
+      await simctl(['bootstatus', config.device, '-b'], 120_000);
+    }
+    const container = await simctl(['get_app_container', config.device, config.bundleId, 'data']);
+    const id = randomUUID();
+    job = join(container, 'Documents', 'RenderJobs', id);
+    await mkdir(job, { recursive: true });
+    await writeFile(join(job, 'input.carousel'), archive);
+    await writeFile(join(job, 'request.json'), JSON.stringify({ width }));
+    const launch = await simctl(['launch', '--terminate-running-process', config.device, config.bundleId, '--render-job', id]);
+    const workerPID = Number(launch.match(/:\s*(\d+)$/)?.[1]);
+    const deadline = Date.now() + 90_000;
+    let result;
+    while (!result) {
+      try { result = JSON.parse(await readFile(join(job, 'result.json'), 'utf8')); }
+      catch (error) { if (error.code !== 'ENOENT') throw error; }
+      if (!result && Number.isInteger(workerPID) && workerPID > 0) {
+        try { process.kill(workerPID, 0); }
+        catch (error) {
+          if (error.code === 'ESRCH') {
+            result = await readFile(join(job, 'result.json'), 'utf8').then(JSON.parse).catch(() => null);
+            if (!result) throw new DocumentError('Native renderer exited without a preview. Rebuild the worker or inspect its crash report.');
+          }
+        }
+      }
+      if (!result && Date.now() > deadline) throw new DocumentError('Native preview timed out; the editable project is still available');
+      if (!result) await delay(100);
+    }
+    if (result.ok !== true) throw new DocumentError(`Native renderer: ${result.error ?? 'unknown failure'}`);
+    if (!Array.isArray(result.slides) || result.slides.length !== slideCount) throw new DocumentError('Native preview did not return every slide');
+    const slides = [];
+    for (const [index, item] of result.slides.entries()) {
+      if (item.file !== `slide-${String(index + 1).padStart(2, '0')}.png` || item.width !== width || !Number.isInteger(item.height) || item.height < 1 || item.height > 1920) throw new DocumentError('Invalid native preview output');
+      const bytes = await readFile(join(job, item.file));
+      if (bytes.length > 12 * 1024 * 1024) throw new DocumentError('Native preview exceeds its size limit');
+      const info = await sharp(bytes, { limitInputPixels: 2_100_000 }).metadata();
+      if (info.format !== 'png' || info.width !== width || info.height !== item.height) throw new DocumentError('Native preview image dimensions do not match');
+      slides.push({ ...item, bytes });
+    }
+    return { slides, sheet: await contactSheet(slides), warnings: result.warnings ?? [] };
+  } finally {
+    if (job) {
+      await simctl(['terminate', config.device, config.bundleId]).catch(() => {});
+      await rm(job, { recursive: true, force: true });
+    }
+    await unlock();
+  }
+}
Full technical diff · 55 changed fields

added /files/.dockerignore

BEFORE
Field was absent
AFTER
{
  "sha256": "5f2025d9087cd8dc93ebe395791fda81379d9a438862e6e87a69b5faf4cc2b77",
  "size": 47
}

added /files/Dockerfile

BEFORE
Field was absent
AFTER
{
  "sha256": "fd48d4fdbb81718d2dfbffa6314dee7c56d042aa5dd96d34d45ee3b38ba91e49",
  "size": 315
}

added /files/LICENSE

BEFORE
Field was absent
AFTER
{
  "sha256": "29942ea87db4340c9a272091ada1b037d8b8b02a2e76dce75509cb8a1e418059",
  "size": 2313
}

added /files/README.md

BEFORE
Field was absent
AFTER
{
  "sha256": "2014b20842e56188734f68b1490b3cbb5a8dd5365993de5a9935fdc353ff30fc",
  "size": 1112
}

added /files/data~1catalog.json

BEFORE
Field was absent
AFTER
{
  "sha256": "93dcbf982d26c83ffef1134e7dd95115ce7337cd741ff963f27310becb4fff88",
  "size": 425901
}

added /files/data~1examples.json

BEFORE
Field was absent
AFTER
{
  "sha256": "9300369fb5b6ed73beb1db3352df1c6fb08e7c891589f6cb4e834beac9ecf124",
  "size": 3675
}

added /files/examples~1contact-gallery.yaml

BEFORE
Field was absent
AFTER
{
  "sha256": "31383e1bfa7f27aaf6b8d5fd6c450ec039e4be05390398b27341c2d82670733f",
  "size": 1626
}

added /files/examples~1effects-study.yaml

BEFORE
Field was absent
AFTER
{
  "sha256": "709a9449fa409ef272e58f07764eb2661961888a41329284a9b9aaf4fec1796c",
  "size": 1210
}

added /files/examples~1free-collage.yaml

BEFORE
Field was absent
AFTER
{
  "sha256": "82e9ea3801309187184a41c6a0490d4af1fa792abca303f462ae9d1a0a9b48a0",
  "size": 1139
}

added /files/examples~1photo-story.yaml

BEFORE
Field was absent
AFTER
{
  "sha256": "10b1f45fe3eab32b55740bfb3526831a23374ae41120ff05fead7a8761fd9d47",
  "size": 1060
}

added /files/examples~1smart-stamp.yaml

BEFORE
Field was absent
AFTER
{
  "sha256": "b039ec2ed3e17f9c1757f4380f7abe5ce366bb71d06153e087053cf0f21ae019",
  "size": 914
}

added /files/examples~1type-led.yaml

BEFORE
Field was absent
AFTER
{
  "sha256": "4220649308cf1b1b3418409b1d880b516df55e3e81dd87a9a44b3226b63d55da",
  "size": 1200
}

added /files/native~1RendererApp.swift

BEFORE
Field was absent
AFTER
{
  "sha256": "90f7699ffa9b44cb1263dbfebab1f0c1062ebf934cb97a4e718cc577fc66539c",
  "size": 4434
}

changed /files/package-lock.json/sha256

BEFORE
"ad8658df058ed6e12856e442e18591e49ee0dae7af722e8482940b43fa6d0432"
AFTER
"1ff211f79a56954cb9b076c2eeedd85b56a361584f8205f11b84764f4f4fdf75"

changed /files/package.json/sha256

BEFORE
"2d43a17f4b9852e8cea13f32c903536b8fc8132607045a72d1f3c710c8de3efc"
AFTER
"ea3ade412901851f814ecda42c8a32e00e72052bba153bc76f5ff515a30be224"

changed /files/package.json/size

BEFORE
503
AFTER
908

changed /files/plugin.json/sha256

BEFORE
"9171fcb956c5e86ca839303912e290b0db31660efcd7017698fb540d21bd9ba5"
AFTER
"8cdbe9970f20ed8120bd20a37b5e1c0604b48aa49e099bd00920e372734e2566"

changed /files/plugin.json/size

BEFORE
11337
AFTER
10022

changed /files/scripts~1build-carousel.mjs/sha256

BEFORE
"0ec532932ce99c8e02f0f2b57730efd590f17b5c822c18ccb35aaaf43f0dab3f"
AFTER
"8496a1368be3dbf2ef9245f449ac7a5158dec37184fa30c638ed127e663e65b2"

changed /files/scripts~1build-carousel.mjs/size

BEFORE
1161
AFTER
1184

added /files/scripts~1check-server.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "42674a0f1e3797f36247f0093dae0cba1d4b8c407690bd929902d881605767ff",
  "size": 4394
}

added /files/scripts~1get-spec.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "771b4044e7bb24fa563b169e8c1880b41709c76c35c5778279004b47f85861d9",
  "size": 311
}

changed /files/scripts~1package-plugin.mjs/sha256

BEFORE
"698df0d5de5c1a076b100f47f0e00705467a85b77d31b9fae15e5bc36ebb7fa8"
AFTER
"7df454a476fa80d28753c85541082b193a6b0aa1156bbadc3b80e7a3783ce7a3"

changed /files/scripts~1package-plugin.mjs/size

BEFORE
5594
AFTER
6810

added /files/scripts~1render-carousel.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "ae7b739231767f5e17dd7957c179bbdc617fe9d4718437967733df67ad031537",
  "size": 1450
}

added /files/scripts~1setup-native-renderer.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "f18984ec4a2fa0587d737db082e4cfa33ea09adda828b4cce915bc61b812d8a6",
  "size": 4180
}

added /files/scripts~1sync-catalog.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "315dccd2343306cef52dedbd87798d495f5b0c5ad9e66bdeb9e56bc4e692fae8",
  "size": 626
}

changed /files/skills~1create-carousel~1SKILL.md/sha256

BEFORE
"9151fb427fee5e69f407c0f1e2ee2f33d77d2b0cc99f4f6409730ad62cd6de25"
AFTER
"0d4c5ec38abdeeae533cdd8985685be4c0f532a0637f95767d2b999e605fa9e7"

changed /files/skills~1create-carousel~1SKILL.md/size

BEFORE
3939
AFTER
10609

added /files/skills~1create-carousel~1references~1DESIGN_GUIDE.md

BEFORE
Field was absent
AFTER
{
  "sha256": "2ffd410e74f7028499999a3373315b076c5b1cea0930664fe14726810fc1b618",
  "size": 4266
}

changed /files/skills~1create-carousel~1references~1DSL_LAYOUT_SPEC.md/sha256

BEFORE
"1278b5f6f81afe42e29433479c5c102e3f75ae16eb93e23dd0eb2a70a15125d1"
AFTER
"3394ff0ae25f338c282c55fe53dc580ae2c596b62f09da77f24452a5724e6cb0"

changed /files/skills~1create-carousel~1references~1DSL_LAYOUT_SPEC.md/size

BEFORE
212874
AFTER
218069

added /files/skills~1create-carousel~1references~1WRITING_GUIDE.md

BEFORE
Field was absent
AFTER
{
  "sha256": "fcf68ef35f4e3a858d3d6236e4f3dd182fd52b018c24cd663d257ed1b4a2f477",
  "size": 5902
}

changed /files/src~1archive.mjs/sha256

BEFORE
"a7c8b4ed23371010e755a3898f926f6bed4d2dd5d257d4a7c98a3041a048b46d"
AFTER
"f082bea90b8ff5e2655cccd7044bff2248d551e8989c734ee24ce4a8b14b64e9"

changed /files/src~1archive.mjs/size

BEFORE
2908
AFTER
3498

added /files/src~1catalog.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "41e0108752aff449b825d15a46808ccdbc43649ba4998143118dca4b3e6ca962",
  "size": 6068
}

added /files/src~1diagnostics.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "a620e5631de644ab4a5586127c4612a94695152202b26145336f1d8cf70cacd5",
  "size": 7803
}

changed /files/src~1document.mjs/sha256

BEFORE
"a38e271507e7b55fb606ad619d907a6836ecdce8dafd502b8f042d155d3a6f7c"
AFTER
"97a4868aafefe954717d9058d5d910639076613b8e157f80f2f47c42db8c46ec"

changed /files/src~1document.mjs/size

BEFORE
13586
AFTER
12413

added /files/src~1errors.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "d1f236c2bff72432b73e3aa27ad675ee1038c80ccf8b457fbb4f717898061660",
  "size": 44
}

added /files/src~1recipes.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "660b575c97fc2ee70c0668c482d8f949185cf748acc7caee62b739fc44bbdcd1",
  "size": 4103
}

added /files/src~1renderer.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "44b8f9cad2feabe0b99cce1e8a6a6e830b8788ad8112b58c0444eedf720720da",
  "size": 7706
}

changed /files/src~1server.mjs/sha256

BEFORE
"711db8dfd4f596dcf673d6edd728f96ebc6177fb05284310b40748ffb3777679"
AFTER
"67a96be7fcf04f603c900ce5151b73943c671f7cdbe65e82ef1be6d494008ca4"

changed /files/src~1server.mjs/size

BEFORE
10916
AFTER
23198

added /files/src~1spec.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "2564a2e59d6abbc363d6622741e0c47e0958013bde2472295b8b4586d2858fcf",
  "size": 4491
}

changed /files/tests~1carousel.test.mjs/sha256

BEFORE
"d006e3346166652fa2104ebe75ec621f545255cd58924f86f4f922065dcac398"
AFTER
"3d2bef07c979ebb12149442ecc81704d5ead4822ec58bea2d43a64c8b15db026"

changed /files/tests~1carousel.test.mjs/size

BEFORE
8150
AFTER
8364

added /files/tests~1diagnostics.test.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "b3baa3352b4a57b38e13e674ec4a96f6a7d8547b251f2a1f6474327773a46cd8",
  "size": 5280
}

added /files/tests~1discovery.test.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "d6b7f4e6447e9d398b1b88feead7644d6f29be721a9175d8a29fcdb40e9cec75",
  "size": 8147
}

changed /files/tests~1http.integration.mjs/sha256

BEFORE
"f77721afd3db1659dda0874702326c703b627185729fb2f462c1ec3dd94aa166"
AFTER
"d2f14621194cf28139f2e04dd77df988d7423f6c0b2b070e9e231796c383d7ae"

changed /files/tests~1http.integration.mjs/size

BEFORE
2053
AFTER
2995

added /files/tests~1native.integration.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "37bc67dd03fa1931a1a52c9ee0860a3b9e056619d0f8a735ee029ac3ae33412d",
  "size": 7909
}

added /files/tests~1package.test.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "c7d100facf765bd64763a2825e65a2a2f662f94fc5ded114f524aabf039b11c9",
  "size": 2933
}

added /files/tests~1preview.test.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "a3b1c7317dc71d4d065156a89014b131b997e7c0c06203b8b4deac0d24fe9c89",
  "size": 5386
}

added /files/tests~1uploads.test.mjs

BEFORE
Field was absent
AFTER
{
  "sha256": "3e7dc647b2c2268e0c4cd71e119af9531079aced921011a081d1d5a7448d323b",
  "size": 6352
}
Full snapshot data
{
  "files": {
    ".app.json": {
      "sha256": "5e21add253e73f295f8dd9638efdad6133db89cea1afc6eb8bef86fcd9dc9d29",
      "size": 108
    },
    ".dockerignore": {
      "sha256": "5f2025d9087cd8dc93ebe395791fda81379d9a438862e6e87a69b5faf4cc2b77",
      "size": 47
    },
    "Dockerfile": {
      "sha256": "fd48d4fdbb81718d2dfbffa6314dee7c56d042aa5dd96d34d45ee3b38ba91e49",
      "size": 315
    },
    "LICENSE": {
      "sha256": "29942ea87db4340c9a272091ada1b037d8b8b02a2e76dce75509cb8a1e418059",
      "size": 2313
    },
    "README.md": {
      "sha256": "2014b20842e56188734f68b1490b3cbb5a8dd5365993de5a9935fdc353ff30fc",
      "size": 1112
    },
    "assets/icon.png": {
      "sha256": "6dfad6349d9c99ac11613f4abbe19fe6e608f89357e0c2ff87abf7079072cb83",
      "size": 31011
    },
    "data/catalog.json": {
      "sha256": "93dcbf982d26c83ffef1134e7dd95115ce7337cd741ff963f27310becb4fff88",
      "size": 425901
    },
    "data/examples.json": {
      "sha256": "9300369fb5b6ed73beb1db3352df1c6fb08e7c891589f6cb4e834beac9ecf124",
      "size": 3675
    },
    "examples/contact-gallery.yaml": {
      "sha256": "31383e1bfa7f27aaf6b8d5fd6c450ec039e4be05390398b27341c2d82670733f",
      "size": 1626
    },
    "examples/creator-demo-preview.png": {
      "sha256": "72f9bdd64e2f4bbbeee007d645a75ea38e90713f99079c5fbafe74f8c3ea306c",
      "size": 69512
    },
    "examples/creator-demo.carousel": {
      "sha256": "4a16b05ee1c671d4e57d58136058838c15b542456f55d0e25df92941f9a64465",
      "size": 5679
    },
    "examples/creator-demo.yaml": {
      "sha256": "ac375143bd9958012deed3c38cb84c212a585c40a96c051f5503df17b74f642a",
      "size": 3908
    },
    "examples/effects-study.yaml": {
      "sha256": "709a9449fa409ef272e58f07764eb2661961888a41329284a9b9aaf4fec1796c",
      "size": 1210
    },
    "examples/free-collage.yaml": {
      "sha256": "82e9ea3801309187184a41c6a0490d4af1fa792abca303f462ae9d1a0a9b48a0",
      "size": 1139
    },
    "examples/photo-story.yaml": {
      "sha256": "10b1f45fe3eab32b55740bfb3526831a23374ae41120ff05fead7a8761fd9d47",
      "size": 1060
    },
    "examples/smart-stamp.yaml": {
      "sha256": "b039ec2ed3e17f9c1757f4380f7abe5ce366bb71d06153e087053cf0f21ae019",
      "size": 914
    },
    "examples/type-led.yaml": {
      "sha256": "4220649308cf1b1b3418409b1d880b516df55e3e81dd87a9a44b3226b63d55da",
      "size": 1200
    },
    "mcp.json": {
      "sha256": "828f2d5c8663ded2b9b701aa0fd0f0848bd1fbd865c1e8a170bb1b13148e7ccb",
      "size": 210
    },
    "native/RendererApp.swift": {
      "sha256": "90f7699ffa9b44cb1263dbfebab1f0c1062ebf934cb97a4e718cc577fc66539c",
      "size": 4434
    },
    "package-lock.json": {
      "sha256": "1ff211f79a56954cb9b076c2eeedd85b56a361584f8205f11b84764f4f4fdf75",
      "size": 61504
    },
    "package.json": {
      "sha256": "ea3ade412901851f814ecda42c8a32e00e72052bba153bc76f5ff515a30be224",
      "size": 908
    },
    "plugin.json": {
      "sha256": "8cdbe9970f20ed8120bd20a37b5e1c0604b48aa49e099bd00920e372734e2566",
      "size": 10022
    },
    "scripts/build-carousel.mjs": {
      "sha256": "8496a1368be3dbf2ef9245f449ac7a5158dec37184fa30c638ed127e663e65b2",
      "size": 1184
    },
    "scripts/check-server.mjs": {
      "sha256": "42674a0f1e3797f36247f0093dae0cba1d4b8c407690bd929902d881605767ff",
      "size": 4394
    },
    "scripts/get-spec.mjs": {
      "sha256": "771b4044e7bb24fa563b169e8c1880b41709c76c35c5778279004b47f85861d9",
      "size": 311
    },
    "scripts/package-plugin.mjs": {
      "sha256": "7df454a476fa80d28753c85541082b193a6b0aa1156bbadc3b80e7a3783ce7a3",
      "size": 6810
    },
    "scripts/render-carousel.mjs": {
      "sha256": "ae7b739231767f5e17dd7957c179bbdc617fe9d4718437967733df67ad031537",
      "size": 1450
    },
    "scripts/setup-native-renderer.mjs": {
      "sha256": "f18984ec4a2fa0587d737db082e4cfa33ea09adda828b4cce915bc61b812d8a6",
      "size": 4180
    },
    "scripts/sync-catalog.mjs": {
      "sha256": "315dccd2343306cef52dedbd87798d495f5b0c5ad9e66bdeb9e56bc4e692fae8",
      "size": 626
    },
    "skills/create-carousel/SKILL.md": {
      "sha256": "0d4c5ec38abdeeae533cdd8985685be4c0f532a0637f95767d2b999e605fa9e7",
      "size": 10609
    },
    "skills/create-carousel/references/DESIGN_GUIDE.md": {
      "sha256": "2ffd410e74f7028499999a3373315b076c5b1cea0930664fe14726810fc1b618",
      "size": 4266
    },
    "skills/create-carousel/references/DSL_LAYOUT_SPEC.md": {
      "sha256": "3394ff0ae25f338c282c55fe53dc580ae2c596b62f09da77f24452a5724e6cb0",
      "size": 218069
    },
    "skills/create-carousel/references/WRITING_GUIDE.md": {
      "sha256": "fcf68ef35f4e3a858d3d6236e4f3dd182fd52b018c24cd663d257ed1b4a2f477",
      "size": 5902
    },
    "src/archive.mjs": {
      "sha256": "f082bea90b8ff5e2655cccd7044bff2248d551e8989c734ee24ce4a8b14b64e9",
      "size": 3498
    },
    "src/catalog.mjs": {
      "sha256": "41e0108752aff449b825d15a46808ccdbc43649ba4998143118dca4b3e6ca962",
      "size": 6068
    },
    "src/diagnostics.mjs": {
      "sha256": "a620e5631de644ab4a5586127c4612a94695152202b26145336f1d8cf70cacd5",
      "size": 7803
    },
    "src/document.mjs": {
      "sha256": "97a4868aafefe954717d9058d5d910639076613b8e157f80f2f47c42db8c46ec",
      "size": 12413
    },
    "src/errors.mjs": {
      "sha256": "d1f236c2bff72432b73e3aa27ad675ee1038c80ccf8b457fbb4f717898061660",
      "size": 44
    },
    "src/recipes.mjs": {
      "sha256": "660b575c97fc2ee70c0668c482d8f949185cf748acc7caee62b739fc44bbdcd1",
      "size": 4103
    },
    "src/renderer.mjs": {
      "sha256": "44b8f9cad2feabe0b99cce1e8a6a6e830b8788ad8112b58c0444eedf720720da",
      "size": 7706
    },
    "src/server.mjs": {
      "sha256": "67a96be7fcf04f603c900ce5151b73943c671f7cdbe65e82ef1be6d494008ca4",
      "size": 23198
    },
    "src/spec.mjs": {
      "sha256": "2564a2e59d6abbc363d6622741e0c47e0958013bde2472295b8b4586d2858fcf",
      "size": 4491
    },
    "tests/carousel.test.mjs": {
      "sha256": "3d2bef07c979ebb12149442ecc81704d5ead4822ec58bea2d43a64c8b15db026",
      "size": 8364
    },
    "tests/diagnostics.test.mjs": {
      "sha256": "b3baa3352b4a57b38e13e674ec4a96f6a7d8547b251f2a1f6474327773a46cd8",
      "size": 5280
    },
    "tests/discovery.test.mjs": {
      "sha256": "d6b7f4e6447e9d398b1b88feead7644d6f29be721a9175d8a29fcdb40e9cec75",
      "size": 8147
    },
    "tests/http.integration.mjs": {
      "sha256": "d2f14621194cf28139f2e04dd77df988d7423f6c0b2b070e9e231796c383d7ae",
      "size": 2995
    },
    "tests/native.integration.mjs": {
      "sha256": "37bc67dd03fa1931a1a52c9ee0860a3b9e056619d0f8a735ee029ac3ae33412d",
      "size": 7909
    },
    "tests/package.test.mjs": {
      "sha256": "c7d100facf765bd64763a2825e65a2a2f662f94fc5ded114f524aabf039b11c9",
      "size": 2933
    },
    "tests/preview.test.mjs": {
      "sha256": "a3b1c7317dc71d4d065156a89014b131b997e7c0c06203b8b4deac0d24fe9c89",
      "size": 5386
    },
    "tests/uploads.test.mjs": {
      "sha256": "3e7dc647b2c2268e0c4cd71e119af9531079aced921011a081d1d5a7448d323b",
      "size": 6352
    }
  }
}

SHA-256 of public snapshot: 64959cf6937ca474b78ee128969c5afdcb3064e41f5dc2d8e4ef072e2c240fab