@osmo.inc/cli 0.1.18-preview.1 → 0.1.18

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
@@ -2,12 +2,10 @@
2
2
 
3
3
  Share videos. Collect feedback.
4
4
 
5
- This preview build requires the matching cloud API update for the new share and comment commands. It does not replace the stable npm release.
6
-
7
5
  Upload a video from any tool and get a review link with timestamped comments and version history.
8
6
 
9
7
  ```sh
10
- npm install -g @osmo.inc/cli@preview
8
+ npm install -g @osmo.inc/cli@latest
11
9
  osmo login
12
10
  osmo share ./video.mp4
13
11
  ```
package/SETUP.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Requires an Apple Silicon Mac, arm64 Node 22, and ffprobe (included with FFmpeg). The default service is https://studio.osmo.inc.
4
4
 
5
5
  ```sh
6
- npm install -g @osmo.inc/cli@preview
6
+ npm install -g @osmo.inc/cli@latest
7
7
  osmo login
8
8
  osmo share ./video.mp4
9
9
  ```
@@ -11,7 +11,7 @@ osmo share ./video.mp4
11
11
  ## Setup prompt for an AI agent
12
12
 
13
13
  ```text
14
- Install @osmo.inc/cli@preview from npm. Check for arm64 Node 22 and ffprobe.
14
+ Install @osmo.inc/cli@latest from npm. Check for arm64 Node 22 and ffprobe.
15
15
  Run osmo login --json and show me the approval link and code. After I approve,
16
16
  poll login status with the returned sessionId, respecting retryAfter.
17
17
  Run osmo whoami --json, then osmo share /path/to/video.mp4 --json.
package/dist/osmo.js CHANGED
@@ -404,6 +404,42 @@ var init_comments = __esm({
404
404
  }
405
405
  });
406
406
 
407
+ // ../studio/src/lib/export-settings.ts
408
+ function validateExportSettings(input, meta) {
409
+ const format2 = input.format ?? "h264";
410
+ const scale = input.scale ?? 1;
411
+ const quality = input.quality ?? "high";
412
+ const startFrame = input.startFrame ?? 0;
413
+ const endFrame = input.endFrame ?? meta.totalFrames - 1;
414
+ if (format2 !== "h264" && format2 !== "vp8" && format2 !== "prores")
415
+ throw new Error("Choose a supported export format");
416
+ if (typeof scale !== "number" || !exportScales.some((value) => value === scale))
417
+ throw new Error("Output scale must be 1, 1.5, 2 or 3");
418
+ if (quality !== "medium" && quality !== "high" && quality !== "max")
419
+ throw new Error("Choose a supported quality");
420
+ if (typeof startFrame !== "number" || typeof endFrame !== "number" || !Number.isInteger(startFrame) || !Number.isInteger(endFrame) || startFrame < 0 || endFrame < startFrame || endFrame >= meta.totalFrames)
421
+ throw new Error(
422
+ `Choose a frame range between 0 and ${meta.totalFrames - 1}`
423
+ );
424
+ return { format: format2, scale, quality, startFrame, endFrame };
425
+ }
426
+ var exportFormats, exportScales;
427
+ var init_export_settings = __esm({
428
+ "../studio/src/lib/export-settings.ts"() {
429
+ "use strict";
430
+ exportFormats = {
431
+ h264: { label: "MP4 (H.264)", extension: "mp4", mime: "video/mp4" },
432
+ vp8: { label: "WebM (VP8)", extension: "webm", mime: "video/webm" },
433
+ prores: {
434
+ label: "ProRes 4444 (MOV)",
435
+ extension: "mov",
436
+ mime: "video/quicktime"
437
+ }
438
+ };
439
+ exportScales = [1, 1.5, 2, 3];
440
+ }
441
+ });
442
+
407
443
  // src/worker.ts
408
444
  import { spawn as spawn2 } from "node:child_process";
409
445
  var Renderer;
@@ -1551,7 +1587,7 @@ async function listProjectResources(root) {
1551
1587
  throw new Error("Manifest exceeds 1 MB");
1552
1588
  const meta = JSON.parse(await fs4.readFile(manifestFile, "utf8"));
1553
1589
  const entry = `resources/${item.name}/${meta.entry}`, file = await resourceFile(root, entry);
1554
- const kind = meta.kind ?? meta.category ?? kinds[path15.extname(file).toLowerCase()];
1590
+ const kind = meta.kind ?? (meta.category === "3d" ? "model" : meta.category) ?? kinds[path15.extname(file).toLowerCase()];
1555
1591
  if (!["shader", "image", "video", "model", "scene"].includes(kind) || kinds[path15.extname(file).toLowerCase()] !== kind)
1556
1592
  throw new Error("Unsupported resource type");
1557
1593
  let effect;
@@ -2762,12 +2798,12 @@ function applyTimelineCommand(text2, command, {
2762
2798
  let tag = existing?.importClause.name.text;
2763
2799
  if (!tag) {
2764
2800
  let n = 1;
2765
- const names2 = new Set(
2801
+ const names = new Set(
2766
2802
  [...text2.matchAll(/\b[A-Za-z_$][\w$]*\b/g)].map((m) => m[0])
2767
2803
  );
2768
2804
  do {
2769
2805
  tag = `Animation${n++}`;
2770
- } while (names2.has(tag));
2806
+ } while (names.has(tag));
2771
2807
  }
2772
2808
  id = fresh();
2773
2809
  const element = `<${tag} id={${JSON.stringify(id)}} track={${track}} start={${start}} duration={${duration}} width={${card.width}} height={${card.height}}${Object.keys(card.values).length ? ` values={${JSON.stringify(card.values)}}` : ""} />`;
@@ -2874,8 +2910,8 @@ var init_timeline = __esm({
2874
2910
  }
2875
2911
  }
2876
2912
  };
2877
- pick = (names2, extras = {}) => Object.fromEntries(
2878
- names2.map((name) => [name, propertySpecs[name]]).concat(Object.entries(extras))
2913
+ pick = (names, extras = {}) => Object.fromEntries(
2914
+ names.map((name) => [name, propertySpecs[name]]).concat(Object.entries(extras))
2879
2915
  );
2880
2916
  transformNames = [
2881
2917
  "position",
@@ -2908,7 +2944,7 @@ var init_timeline = __esm({
2908
2944
 
2909
2945
  // ../editor/src/resource-source.ts
2910
2946
  import ts9 from "typescript";
2911
- function addImports(text2, names2, declaration = "") {
2947
+ function addImports(text2, names, declaration = "") {
2912
2948
  const ast = ts9.createSourceFile(
2913
2949
  "scene.tsx",
2914
2950
  text2,
@@ -2921,7 +2957,7 @@ function addImports(text2, names2, declaration = "") {
2921
2957
  );
2922
2958
  const bindings = existing?.importClause?.namedBindings;
2923
2959
  if (bindings && ts9.isNamedImports(bindings)) {
2924
- const missing = names2.filter(
2960
+ const missing = names.filter(
2925
2961
  (name) => !bindings.elements.some((e) => e.name.text === name)
2926
2962
  );
2927
2963
  if (missing.length)
@@ -2932,7 +2968,7 @@ function addImports(text2, names2, declaration = "") {
2932
2968
  text: `${bindings.elements.length ? ", " : ""}${missing.join(", ")} `
2933
2969
  }
2934
2970
  ]);
2935
- } else text2 = `import {${names2.join(", ")}} from '@osmo/scene';
2971
+ } else text2 = `import {${names.join(", ")}} from '@osmo/scene';
2936
2972
  ${text2}`;
2937
2973
  if (declaration) {
2938
2974
  const next = ts9.createSourceFile(
@@ -3059,11 +3095,11 @@ ${text2}`;
3059
3095
  text2 = addImports(text2, [plan.tag]);
3060
3096
  } else {
3061
3097
  const effect = plan.resource.effect;
3062
- const names2 = new Set(
3098
+ const names = new Set(
3063
3099
  [...text2.matchAll(/\b[A-Za-z_$][\w$]*\b/g)].map((m) => m[0])
3064
3100
  );
3065
3101
  let name = "resourceEffect", i = 1;
3066
- while (names2.has(name)) name = `resourceEffect${i++}`;
3102
+ while (names.has(name)) name = `resourceEffect${i++}`;
3067
3103
  const attrs = attributes2(node), attr = attrs.get("effects"), array = unwrap2(attr?.initializer);
3068
3104
  const call2 = `${name}(${JSON.stringify(effect.values ?? {})})`;
3069
3105
  if (attr) {
@@ -3700,7 +3736,7 @@ import http from "node:http";
3700
3736
  import fs6 from "node:fs";
3701
3737
  import { readFile as readFile11, stat as stat3, realpath as realpath2, readdir as readdir3 } from "node:fs/promises";
3702
3738
  import path19 from "node:path";
3703
- import { createHash as createHash8 } from "node:crypto";
3739
+ import { createHash as createHash8, randomUUID as randomUUID7 } from "node:crypto";
3704
3740
  import { spawn as spawn3 } from "node:child_process";
3705
3741
  async function revision(paths) {
3706
3742
  const hash3 = createHash8("sha256");
@@ -4383,9 +4419,12 @@ async function startStudio({
4383
4419
  { status: 409 }
4384
4420
  );
4385
4421
  const snapshot = project;
4386
- const filename2 = input.filename ?? `${path19.basename(scene, ".tsx")}-${Date.now()}.mp4`;
4387
- if (typeof filename2 !== "string" || !/^[\w .-]+\.mp4$/i.test(filename2) || filename2.startsWith("."))
4388
- throw new Error("Use a filename ending in .mp4");
4422
+ if (!state.meta) throw new Error("Load a scene before exporting");
4423
+ const settings2 = validateExportSettings(input, state.meta);
4424
+ const format2 = exportFormats[settings2.format];
4425
+ const filename2 = input.filename ?? `${path19.basename(scene, ".tsx")}-${Date.now()}.${format2.extension}`;
4426
+ if (typeof filename2 !== "string" || !/^[\w .-]+$/.test(filename2) || !filename2.toLowerCase().endsWith(`.${format2.extension}`) || filename2.startsWith("."))
4427
+ throw new Error(`Use a filename ending in .${format2.extension}`);
4389
4428
  const folder = path19.join(root, "exports");
4390
4429
  await fs6.promises.mkdir(folder, { recursive: true });
4391
4430
  const canonicalFolder = await realpath2(folder);
@@ -4398,6 +4437,7 @@ async function startStudio({
4398
4437
  { status: 409 }
4399
4438
  );
4400
4439
  const job = state.export = {
4440
+ id: randomUUID7(),
4401
4441
  status: "rendering",
4402
4442
  phase: "preparing",
4403
4443
  filename: filename2,
@@ -4422,7 +4462,7 @@ async function startStudio({
4422
4462
  job.phase = "rendering";
4423
4463
  await worker.request(
4424
4464
  "export",
4425
- { destination, supersample: 2 },
4465
+ { destination, supersample: 2, settings: settings2 },
4426
4466
  ({ done, total }) => {
4427
4467
  job.progress = done / total;
4428
4468
  }
@@ -4443,10 +4483,10 @@ async function startStudio({
4443
4483
  exportStarting = false;
4444
4484
  }
4445
4485
  }
4446
- if (req.method === "GET" && url2.pathname === "/api/export/download" && state.export?.status === "complete") {
4486
+ if (req.method === "GET" && url2.pathname === "/api/export/download" && state.export?.status === "complete" && (!url2.searchParams.has("id") || url2.searchParams.get("id") === state.export.id)) {
4447
4487
  const bytes3 = await readFile11(state.export.path);
4448
4488
  res.writeHead(200, {
4449
- "Content-Type": "video/mp4",
4489
+ "Content-Type": state.export.filename.toLowerCase().endsWith(".webm") ? "video/webm" : state.export.filename.toLowerCase().endsWith(".mov") ? "video/quicktime" : "video/mp4",
4450
4490
  "Content-Disposition": `attachment; filename="${state.export.filename}"`
4451
4491
  });
4452
4492
  return res.end(bytes3);
@@ -4645,6 +4685,7 @@ var studioStamp, studioDigest;
4645
4685
  var init_server = __esm({
4646
4686
  "src/server.ts"() {
4647
4687
  "use strict";
4688
+ init_export_settings();
4648
4689
  init_storyboard2();
4649
4690
  init_timeline_editor();
4650
4691
  init_project_resources();
@@ -5363,10 +5404,12 @@ var COST = {
5363
5404
  image: "is the same for each image",
5364
5405
  character: "grows with characters of text"
5365
5406
  };
5366
- var names = ["resource.json", "shader.d.ts", "shader.wgsl"];
5407
+ var packageFiles = (primitive) => primitive === "Model" ? ["model.glb", "resource.json"] : ["resource.json", "shader.d.ts", "shader.wgsl"];
5367
5408
  var LOCK = ".osmo-get.lock";
5368
5409
  var maxFile = 1024 * 1024;
5369
5410
  var maxResponse = 4 * maxFile;
5411
+ var maxModel = 64 * maxFile;
5412
+ var fileLimit = (name) => name.endsWith(".glb") ? maxModel : maxFile;
5370
5413
  var ownerPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
5371
5414
  var namePattern = /^[a-z0-9]+(?:[.-][a-z0-9]+)*$/;
5372
5415
  var versionPattern = /^\d+\.\d+\.\d+$/;
@@ -5418,7 +5461,7 @@ async function bytes(response, limit = maxResponse) {
5418
5461
  }
5419
5462
  return Buffer.concat(chunks);
5420
5463
  }
5421
- async function responseBody(response, json2 = true) {
5464
+ async function responseBody(response, json2 = true, limit) {
5422
5465
  if (!response.ok) {
5423
5466
  const body3 = await response.json().catch(() => ({}));
5424
5467
  if (response.status === 401)
@@ -5444,7 +5487,7 @@ async function responseBody(response, json2 = true) {
5444
5487
  `Osmo resource request failed (${response.status}). Retry later.`
5445
5488
  );
5446
5489
  }
5447
- const body2 = await bytes(response);
5490
+ const body2 = await bytes(response, limit);
5448
5491
  if (!json2) return body2;
5449
5492
  try {
5450
5493
  return JSON.parse(String(body2));
@@ -5472,12 +5515,12 @@ function validItem(item) {
5472
5515
  return !!item && text(item.id) && text(item.title) && typeof item.summary === "string" && (item.use === "run" || item.use === "get") && text(item.kind) && strings(item.tags) && (item.tasks === void 0 || strings(item.tasks));
5473
5516
  }
5474
5517
  function compatibility(pkg) {
5475
- const supported = pkg.primitive === "Shader" && pkg.compatibility?.scene === sceneVersion;
5518
+ const supported = (pkg.primitive === "Shader" || pkg.primitive === "Model") && pkg.compatibility?.scene === sceneVersion;
5476
5519
  return {
5477
5520
  supported,
5478
5521
  scene: pkg.compatibility?.scene,
5479
5522
  cliVersion: version,
5480
- note: supported ? "Supported by this CLI in Strict mode using Shader.src and explicit uniforms." : "This CLI cannot use this resource. Update the CLI before downloading it."
5523
+ note: !supported ? "This CLI cannot use this resource. Update the CLI before downloading it." : pkg.primitive === "Model" ? "Supported by this CLI: the Model primitive renders it, with scene content on its surfaces." : "Supported by this CLI in Strict mode using Shader.src and explicit uniforms."
5481
5524
  };
5482
5525
  }
5483
5526
  async function catalogDetail(ref) {
@@ -5496,7 +5539,9 @@ async function catalogDetail(ref) {
5496
5539
  const pkg = entry.package;
5497
5540
  if (!pkg || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(pkg.folder ?? "") || !versionPattern.test(pkg.version ?? "") || ref.version && pkg.version !== ref.version || !Array.isArray(pkg.presets) || !pkg.presets.length || !pkg.presets.every((p) => text(p.id) && text(p.title)) || !pkg.presets.some((p) => p.id === pkg.defaultPreset) || !Array.isArray(pkg.previews) || !pkg.previews.every(
5498
5541
  (p) => text(p.url) && ["image", "video"].includes(p.type)
5499
- ))
5542
+ ) || pkg.primitive === "Model" && !(Array.isArray(pkg.surfaces) && pkg.surfaces.every(
5543
+ (s) => text(s.id) && text(s.title) && strings(s.nodes) && Number.isInteger(s.width) && Number.isInteger(s.height)
5544
+ ) && Array.isArray(pkg.animations) && pkg.animations.every((a) => text(a.name))))
5500
5545
  invalid();
5501
5546
  return entry;
5502
5547
  }
@@ -5541,18 +5586,23 @@ async function show(ref) {
5541
5586
  next: `osmo resources get ${detail.id}${ref.version ? `@${ref.version}` : ""}`
5542
5587
  };
5543
5588
  }
5544
- function unpack(zip, pkg) {
5589
+ function checkFiles(pkg) {
5590
+ const names = packageFiles(pkg.primitive);
5545
5591
  if (!Array.isArray(pkg.files) || pkg.files.length !== names.length || [...pkg.files.map((f) => f.path)].sort().join(",") !== names.join(","))
5546
5592
  invalid();
5547
5593
  for (const file of pkg.files)
5548
- if (!Number.isInteger(file.bytes) || file.bytes < 1 || file.bytes > maxFile || !/^[a-f0-9]{64}$/.test(file.sha256 ?? ""))
5594
+ if (!Number.isInteger(file.bytes) || file.bytes < 1 || file.bytes > fileLimit(file.path) || !/^[a-f0-9]{64}$/.test(file.sha256 ?? ""))
5549
5595
  invalid();
5596
+ return names;
5597
+ }
5598
+ function unpack(zip, pkg) {
5599
+ const names = checkFiles(pkg);
5550
5600
  const prefix = `resources/${pkg.folder}/`, seen = /* @__PURE__ */ new Set();
5551
5601
  let extracted;
5552
5602
  try {
5553
5603
  extracted = unzipSync(zip, {
5554
5604
  filter: (file) => {
5555
- if (!names.some((name) => file.name === prefix + name) || seen.has(file.name) || file.originalSize > maxFile)
5605
+ if (!names.some((name) => file.name === prefix + name) || seen.has(file.name) || file.originalSize > fileLimit(file.name))
5556
5606
  invalid();
5557
5607
  seen.add(file.name);
5558
5608
  return true;
@@ -5578,9 +5628,9 @@ function unpack(zip, pkg) {
5578
5628
  } catch {
5579
5629
  invalid();
5580
5630
  }
5581
- if (manifest2.id !== pkg.folder || manifest2.version !== pkg.version || manifest2.entry !== "shader.wgsl" || manifest2.types !== "shader.d.ts" || manifest2.primitive !== "Shader" || !Array.isArray(manifest2.presets) || !manifest2.presets.some((p) => p.id === pkg.defaultPreset) || !manifest2.presets.every((p) => text(manifest2.usage?.[p.id])))
5631
+ if (manifest2.id !== pkg.folder || manifest2.version !== pkg.version || manifest2.primitive !== pkg.primitive || (pkg.primitive === "Model" ? manifest2.entry !== "model.glb" : manifest2.entry !== "shader.wgsl" || manifest2.types !== "shader.d.ts") || !Array.isArray(manifest2.presets) || !manifest2.presets.some((p) => p.id === pkg.defaultPreset) || !manifest2.presets.every((p) => text(manifest2.usage?.[p.id])))
5582
5632
  invalid();
5583
- return { files, manifest: manifest2 };
5633
+ return { files, manifest: manifest2, names };
5584
5634
  }
5585
5635
  async function stat(file) {
5586
5636
  try {
@@ -5590,7 +5640,7 @@ async function stat(file) {
5590
5640
  throw error;
5591
5641
  }
5592
5642
  }
5593
- async function save(destination, shown, files) {
5643
+ async function save(destination, shown, files, names) {
5594
5644
  const parent = path3.dirname(destination), base = path3.basename(destination);
5595
5645
  const inside2 = (await stat(destination))?.isDirectory() ?? false;
5596
5646
  if (!inside2) await mkdir2(parent, { recursive: true });
@@ -5676,14 +5726,17 @@ async function get(ref, flags) {
5676
5726
  const compat = compatibility(pkg);
5677
5727
  if (!compat.supported) fail("incompatible_resource", compat.note);
5678
5728
  const destination = path3.resolve(flags.out ?? pkg.folder);
5729
+ checkFiles(pkg);
5730
+ const declared = pkg.files.reduce((sum, file) => sum + file.bytes, 0);
5679
5731
  const zip = await responseBody(
5680
5732
  await authenticatedGet(
5681
5733
  `/api/resources/${ref.owner}/${ref.name}/versions/${pkg.version}/download`
5682
5734
  ),
5683
- false
5735
+ false,
5736
+ Math.max(maxResponse, declared + maxFile)
5684
5737
  );
5685
- const { files, manifest: manifest2 } = unpack(zip, pkg);
5686
- const status = await save(destination, flags.out ?? pkg.folder, files);
5738
+ const { files, manifest: manifest2, names } = unpack(zip, pkg);
5739
+ const status = await save(destination, flags.out ?? pkg.folder, files, names);
5687
5740
  const relative = path3.relative(await realpath(process.cwd()), await realpath(destination)).split(path3.sep).join("/");
5688
5741
  const folder = relative === "" ? "." : relative;
5689
5742
  const src = path3.isAbsolute(folder) || folder.startsWith("../") || folder === "." ? folder : `./${folder}`;
@@ -5705,9 +5758,10 @@ async function get(ref, flags) {
5705
5758
  )
5706
5759
  ])
5707
5760
  ),
5761
+ ...pkg.primitive === "Model" ? { surfaces: pkg.surfaces, animations: pkg.animations } : {},
5708
5762
  notes: manifest2.notes,
5709
5763
  compatibility: compat,
5710
- next: `Read ${folder}/shader.d.ts for what each uniform does, then use a usage snippet.`
5764
+ next: pkg.primitive === "Model" ? "Use a usage snippet, and put your scene content inside its Surface." : `Read ${folder}/shader.d.ts for what each uniform does, then use a usage snippet.`
5711
5765
  };
5712
5766
  }
5713
5767
  async function resourcesCommand(verb, args, flags = {}) {
@@ -5777,7 +5831,7 @@ function formatResources(result) {
5777
5831
  if ("usage" in r) {
5778
5832
  const usage = Object.entries(r.usage).map(
5779
5833
  ([preset, snippet]) => `${preset}:
5780
- ${snippet}`
5834
+ ${snippet.replaceAll("\n", "\n ")}`
5781
5835
  );
5782
5836
  return [
5783
5837
  `${r.id}@${r.version} ${r.status === "downloaded" ? "downloaded to" : "is already in"} ${r.folder}/`,
@@ -5816,10 +5870,28 @@ function formatResources(result) {
5816
5870
  return lines.join("\n");
5817
5871
  }
5818
5872
  const pkg = r.package;
5873
+ if (pkg.surfaces?.length)
5874
+ lines.push(
5875
+ "Surfaces (scene content goes here):",
5876
+ table(
5877
+ pkg.surfaces.map((s) => [
5878
+ ` ${s.id}`,
5879
+ `${s.width} x ${s.height}`,
5880
+ s.inset ? `${s.description} Keep text clear of ${s.inset.top} px at the top, ${s.inset.bottom} at the bottom, ${s.inset.left} at the left, ${s.inset.right} at the right.` : s.description
5881
+ ])
5882
+ ),
5883
+ ""
5884
+ );
5885
+ if (pkg.animations?.length)
5886
+ lines.push(
5887
+ "Animations (each takes 0 to 1):",
5888
+ table(pkg.animations.map((a) => [` ${a.name}`, a.description])),
5889
+ ""
5890
+ );
5819
5891
  lines.push(
5820
5892
  `Presets: ${pkg.presets.map((p) => p.id === pkg.defaultPreset ? `${p.id} (default)` : p.id).join(", ")}`,
5821
5893
  ...pkg.previews.map((p) => `${p.caption ?? p.type}: ${p.url}`),
5822
- pkg.pageUrl,
5894
+ ...pkg.pageUrl ? [pkg.pageUrl] : [],
5823
5895
  r.compatibility?.note ?? "",
5824
5896
  "",
5825
5897
  `Next: ${r.next}`
@@ -8476,7 +8548,7 @@ them like any other asset.
8476
8548
  | Vector curves, icons, cutouts or illustrations | Path with SVG d, fill and stroke; evenodd for holes |
8477
8549
  | Images, footage, soundtrack | Image, Video, Audio with local asset paths |
8478
8550
  | Parallax and solid cards | Camera, z and Group.depth |
8479
- | Content on a 3D model | Model with Surface children; inspect GLB selectors first |
8551
+ | Content on a 3D model | osmo resources list --type 3d; a usage snippet names its surfaces. Own GLBs: inspect selectors first |
8480
8552
  | Procedural backgrounds or liquid glass | Check resources; Shader with local src and explicit uniforms; glass samples backdrop |
8481
8553
  | Softness or texture | effects={[blur({ radius: 5 }), grain({ amount: 0.04 })]} |
8482
8554
 
@@ -9497,10 +9569,10 @@ function commandHelp(command) {
9497
9569
  const flags = Object.entries({ ...command.flags, ...GLOBAL_FLAGS }).filter(
9498
9570
  ([, flag]) => !flag.hidden
9499
9571
  );
9500
- const names2 = flags.map(
9572
+ const names = flags.map(
9501
9573
  ([name, flag]) => `--${name}${flag.value ? ` ${flag.value}` : ""}`
9502
9574
  );
9503
- const width = Math.max(...names2.map((name) => name.length));
9575
+ const width = Math.max(...names.map((name) => name.length));
9504
9576
  const aliases = (command.aliases ?? []).map(
9505
9577
  (path22) => `osmo ${path22.join(" ")}`
9506
9578
  );
@@ -9510,7 +9582,7 @@ function commandHelp(command) {
9510
9582
  typeof command.about === "function" ? command.about() : command.about,
9511
9583
  ...aliases.length ? ["", `Also: ${aliases.join(", ")}`] : [],
9512
9584
  "",
9513
- ...flags.map(([, flag], i) => ` ${names2[i].padEnd(width)} ${flag.help}`),
9585
+ ...flags.map(([, flag], i) => ` ${names[i].padEnd(width)} ${flag.help}`),
9514
9586
  ...command.example ? ["", "Example:", ` ${command.example}`] : []
9515
9587
  ].join("\n");
9516
9588
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@osmo.inc/cli",
3
- "version": "0.1.18-preview.1",
3
+ "version": "0.1.18",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public",
7
- "tag": "preview",
7
+ "tag": "latest",
8
8
  "registry": "https://registry.npmjs.org/"
9
9
  },
10
10
  "description": "Share videos. Collect feedback.",
package/release.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
- "version": "0.1.18-preview.1",
2
+ "version": "0.1.18",
3
3
  "platform": "darwin-arm64",
4
- "channel": "preview",
4
+ "channel": "stable",
5
5
  "defaultCloudOrigin": "https://studio.osmo.inc",
6
- "sourceCommit": "72b4469a3a5ce21e0a72052eadc2ba55ee1914dd",
6
+ "sourceCommit": "0ef9319689fadd084cc6c5c95fd820630be04ad6",
7
7
  "sourceDirty": false,
8
8
  "signing": "ad-hoc",
9
9
  "licenseFileIncluded": false,
@@ -16,30 +16,30 @@
16
16
  }
17
17
  },
18
18
  "contents": {
19
- "totalBytes": 59202875,
19
+ "totalBytes": 59229610,
20
20
  "fileCount": 947,
21
21
  "groups": {
22
- "vendor": 16998789,
23
- "studio": 15985162,
22
+ "vendor": 17015275,
23
+ "studio": 15991440,
24
24
  "node_modules/@esbuild/darwin-arm64": 10385745,
25
25
  "node_modules/typescript": 9913238,
26
26
  "third-party": 4800129,
27
27
  "src": 375601,
28
- "dist": 357974,
28
+ "dist": 362102,
29
29
  "node_modules/esbuild": 143795,
30
30
  "runtime": 137478,
31
31
  "node_modules/fflate": 96377,
32
32
  "DEPLOY.md": 3033,
33
- "README.md": 1652,
34
- "SETUP.md": 1370,
33
+ "README.md": 1508,
34
+ "SETUP.md": 1368,
35
35
  "THIRD_PARTY_NOTICES.md": 1088,
36
- "package.json": 900,
36
+ "package.json": 889,
37
37
  "bin": 544
38
38
  },
39
39
  "largestFiles": [
40
40
  {
41
41
  "path": "vendor/osmo-lite",
42
- "bytes": 16963024
42
+ "bytes": 16979520
43
43
  },
44
44
  {
45
45
  "path": "studio/src/engine_bg.wasm",
@@ -55,7 +55,7 @@
55
55
  },
56
56
  {
57
57
  "path": "studio/src/app.js",
58
- "bytes": 4689327
58
+ "bytes": 4694683
59
59
  },
60
60
  {
61
61
  "path": "node_modules/typescript/lib/lib.dom.d.ts",
@@ -71,7 +71,7 @@
71
71
  },
72
72
  {
73
73
  "path": "dist/osmo.js",
74
- "bytes": 357974
74
+ "bytes": 362102
75
75
  },
76
76
  {
77
77
  "path": "third-party/rust-standard-library/COPYRIGHT-library.html",
@@ -111,7 +111,7 @@
111
111
  },
112
112
  {
113
113
  "path": "studio/src/app.css",
114
- "bytes": 86419
114
+ "bytes": 87341
115
115
  },
116
116
  {
117
117
  "path": "third-party/npm/mediabunny@1.52.2/source/src/media-sink.ts",
@@ -120,15 +120,15 @@
120
120
  ]
121
121
  },
122
122
  "hashes": {
123
- "dist/osmo.js": "7231861a57f206d2647cb709268aee72ff417605831afe040d7c35a19c1490e8",
124
- "vendor/osmo-lite": "29664c2c287bd61de893ba16d510647d7f99b71958da9463c5a78fc8f0ab6982",
123
+ "dist/osmo.js": "0deba9fd346683e2e03a3c90060c91643fcda0a86ac6ef091489e05c88af2d89",
124
+ "vendor/osmo-lite": "d5ea0634df51a6ed0bfbb07ee1ae261eb1dce75745c31837f3ce810eb847f11d",
125
125
  "studio/src/engine_bg.wasm": "2077f7d96e556bfd35a34fc6ed2efaf0b1dddb98e2d48e9b373a8fe0a8e3d681",
126
- "studio/src/app.js": "f76c8a986ec553f395b5f5a4cee19d653331c8499daa25a95dbbb61ff31c2e5d",
127
- "studio/src/app.css": "fd1da526adfe593703ac0e3b62762c47de20258809e9b465262faf29677204df",
126
+ "studio/src/app.js": "6171912dcd36886bb75edd7eed412e7775bb727b8d09f62e2fe0104da5f64082",
127
+ "studio/src/app.css": "ac8d0d5c169da134d2ad7457aab63b10e0fcd4dbb3668406b33ed7dea05469d7",
128
128
  "third-party/inventory.json": "6ff4e90c6583a67ca8bfe95b3f4399cfcdc080d39585dce1314a8dd91ee6fecb"
129
129
  },
130
130
  "lockfiles": {
131
- "package-lock.json": "bc68eb025caa3fa805bdde374833a615395f1dfda09bf943f7ddac371ab01312",
131
+ "package-lock.json": "48c56210dd3c7eb15b751602ec4c1b8891d971abbf2301fec2da005571193317",
132
132
  "apps/native/Cargo.lock": "cf31d67cf167c5f32438abfeb42159eb50da61d36e4e482bae50ed3d71241373",
133
133
  "packages/render-engine/Cargo.lock": "a1a68051e1eea30ef0fa46bf17cd0685bb2c6a327defed0405e0d63dd61017a7"
134
134
  }