@hraness/slopcamera 3.8.0 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/NOTICE.md +14 -0
  2. package/README.md +294 -298
  3. package/apps/desktop/application/html-overlay-integrity.ts +27 -4
  4. package/apps/desktop/application/operation.ts +1 -1
  5. package/apps/desktop/application/operations/spatial-render.ts +1 -1
  6. package/apps/desktop/cli/capability-manifest.ts +15 -2
  7. package/apps/desktop/cli/commands.ts +1 -1
  8. package/apps/desktop/cli/help.ts +23 -4
  9. package/apps/desktop/cli/portable-surface.ts +1 -0
  10. package/apps/desktop/cli/verbs.ts +4 -0
  11. package/apps/desktop/dist/cli/main.js +306 -284
  12. package/dist/cli.js +24 -4
  13. package/dist/{index-842t02pp.js → index-m6g0ca9b.js} +1 -1
  14. package/dist/{index-y8spxs77.js → index-mgychzh3.js} +6 -3
  15. package/dist/{index-k9bjw80z.js → index-rxx27q8b.js} +4 -4
  16. package/dist/index.js +1 -1
  17. package/dist/operations.js +1 -1
  18. package/dist/workflow.js +1 -1
  19. package/docs/README.md +4 -1
  20. package/package.json +5 -3
  21. package/skills/slopcamera/SKILL.md +2 -0
  22. package/skills/slopcamera/references/customization.md +8 -1
  23. package/skills/slopcamera/references/icon-place.md +76 -0
  24. package/skills/slopcamera/references/install.md +2 -2
  25. package/skills/slopcamera/references/music-video.md +10 -2
  26. package/skills/slopcamera/references/soundtracks.md +58 -0
  27. package/src/bounded-file.ts +135 -0
  28. package/src/cli.ts +191 -0
  29. package/src/icon-scene.ts +695 -0
  30. package/src/index.ts +2 -0
  31. package/src/mcp/tools.ts +311 -0
  32. package/src/mcp/types.ts +4 -0
  33. package/src/operations.ts +306 -0
  34. package/src/soundtrack.ts +489 -0
  35. package/src/version.ts +1 -1
@@ -24,6 +24,9 @@ import {
24
24
  } from "./html-overlay-browser-runtime";
25
25
 
26
26
  const Sha256Schema = z.string().regex(/^[a-f0-9]{64}$/u);
27
+ const ExecutionContractVersionSchema = z.union([z.literal(1), z.literal(2)]);
28
+ export type HtmlOverlayExecutionContractVersion = z.infer<typeof ExecutionContractVersionSchema>;
29
+
27
30
  const IntegrityLeafSchema = z.strictObject({
28
31
  key: z.string().min(1).max(512),
29
32
  sha256: Sha256Schema,
@@ -44,7 +47,7 @@ export const HtmlOverlayExecutionIntegritySchema = z.strictObject({
44
47
  }),
45
48
  rootSha256: Sha256Schema,
46
49
  runtimeSha256: Sha256Schema,
47
- schemaVersion: z.literal(1),
50
+ schemaVersion: ExecutionContractVersionSchema,
48
51
  });
49
52
  export type HtmlOverlayExecutionIntegrity = Readonly<
50
53
  z.infer<typeof HtmlOverlayExecutionIntegritySchema>
@@ -185,7 +188,7 @@ function legacyHtmlOverlayRendererContract(profileInput?: HtmlOverlayExecutionPr
185
188
  }
186
189
 
187
190
  /** Fetch opt-in grants only the exact declared private paths and changes execution identity. */
188
- export function htmlOverlayRendererContract(
191
+ function historicalHtmlOverlayRendererContract(
189
192
  profileInput?: HtmlOverlayExecutionProfile,
190
193
  resourcesInput: readonly HtmlOverlayDeclaredResource[] = [],
191
194
  ) {
@@ -204,6 +207,25 @@ export function htmlOverlayRendererContract(
204
207
  });
205
208
  }
206
209
 
210
+ /** Historical receipts select v1 explicitly; all new execution binds clone prevention. */
211
+ export function htmlOverlayRendererContract(
212
+ profileInput?: HtmlOverlayExecutionProfile,
213
+ resourcesInput: readonly HtmlOverlayDeclaredResource[] = [],
214
+ version: HtmlOverlayExecutionContractVersion = 2,
215
+ ) {
216
+ const contract = historicalHtmlOverlayRendererContract(profileInput, resourcesInput);
217
+ if (ExecutionContractVersionSchema.parse(version) === 1) return contract;
218
+ return Object.freeze({
219
+ ...contract,
220
+ launch: Object.freeze({
221
+ ...contract.launch,
222
+ args: Object.freeze(contract.launch.args.map(argument => argument.startsWith("--disable-features=")
223
+ ? `${argument},PaintHolding,MacAppCodeSignClone` : argument)),
224
+ }),
225
+ schemaVersion: 4,
226
+ });
227
+ }
228
+
207
229
  export function assertHtmlOverlayExecutionProfileLibraries(
208
230
  libraries: readonly string[], profile?: HtmlOverlayExecutionProfile,
209
231
  ): void {
@@ -258,6 +280,7 @@ export function createHtmlOverlayExecutionBundle(
258
280
  authoringInput: HtmlOverlayAuthoringInput,
259
281
  browserRuntimeInput: HtmlOverlayBrowserRuntimeBinding,
260
282
  executionProfile?: HtmlOverlayExecutionProfile,
283
+ contractVersion: HtmlOverlayExecutionContractVersion = 2,
261
284
  ): HtmlOverlayExecutionBundle {
262
285
  const authoring = HtmlOverlayAuthoringInputSchema.parse(authoringInput);
263
286
  assertHtmlOverlayExecutionProfileLibraries(authoring.libraries, executionProfile);
@@ -290,7 +313,7 @@ export function createHtmlOverlayExecutionBundle(
290
313
  },
291
314
  },
292
315
  { key: "browser-runtime", value: browserRuntime },
293
- { key: "renderer-contract", value: htmlOverlayRendererContract(executionProfile, authoring.resources) },
316
+ { key: "renderer-contract", value: htmlOverlayRendererContract(executionProfile, authoring.resources, contractVersion) },
294
317
  {
295
318
  key: "document",
296
319
  value: {
@@ -326,7 +349,7 @@ export function createHtmlOverlayExecutionBundle(
326
349
  leaves,
327
350
  rootSha256: merkleRoot(leaves),
328
351
  runtimeSha256,
329
- schemaVersion: 1,
352
+ schemaVersion: contractVersion,
330
353
  });
331
354
  return Object.freeze({
332
355
  importMap,
@@ -4,7 +4,7 @@ import type { z } from "zod";
4
4
 
5
5
  import type { ApplicationContext } from "./context";
6
6
 
7
- export const SLOPCAMERA_APPLICATION_TOOL_VERSION = "slopcamera-3.8.0" as const;
7
+ export const SLOPCAMERA_APPLICATION_TOOL_VERSION = "slopcamera-3.9.0" as const;
8
8
 
9
9
  export const OPERATION_KINDS = [
10
10
  "scene.audit",
@@ -381,7 +381,7 @@ export async function recoverSpatialRenderOutput(application: ApplicationContext
381
381
  mode: plan.request.mode, frameRate: plan.request.selection.kind === "video" ? plan.request.selection.frameRate : { numerator: 1, denominator: 1 }, preparedAssets: batch.preparedAssets });
382
382
  equal(batch.metadata, expectedBatch.metadata, "Spatial batch metadata differs from the exact scene samples.");
383
383
  equal(batch.metadataSha256, expectedBatch.metadataSha256, "Spatial batch metadata digest is invalid.");
384
- const execution = createHtmlOverlayExecutionBundle(expectedBatch.authoring, input.browserRuntime, plan.request.executionProfile);
384
+ const execution = createHtmlOverlayExecutionBundle(expectedBatch.authoring, input.browserRuntime, plan.request.executionProfile, batch.executionIntegrity.schemaVersion);
385
385
  assertHtmlOverlayGpuEvidenceProfile(plan.request.executionProfile, batch.gpuEvidence);
386
386
  equal(batch.gpuEvidence, receipt.runtime.gpuEvidence, "Spatial batch hardware identity differs from its completion receipt.");
387
387
  equal(batch.executionIntegrity, execution.integrity, "Spatial batch execution integrity differs from its exact authored runtime.");
@@ -127,8 +127,12 @@ const capabilityModules = Object.freeze([
127
127
  { effect: "local-read", name: "diagram sheets check" },
128
128
  { effect: "local-derived-write", name: "diagram sheets render" },
129
129
  { effect: "local-derived-write", name: "image vectorize" },
130
+ { effect: "local-derived-write", name: "image icon compose" },
131
+ { effect: "local-derived-write", name: "image icon render" },
132
+ { effect: "local-derived-write", name: "media soundtrack compose" },
133
+ { effect: "local-derived-write", name: "media soundtrack grid" },
130
134
  ],
131
- description: "Portable diagrams, CLI/SDK drawing sheets, local vectorization, and the bounded semantic operation projection.",
135
+ description: "Portable diagrams, CLI/SDK drawing sheets, local vectorization, deterministic icon scenes and soundtrack beat grids, and the bounded semantic operation projection.",
132
136
  moduleId: "slopcamera.capability.diagram-image",
133
137
  operationKeys: diagramImageOperations,
134
138
  profiles: [{
@@ -139,7 +143,16 @@ const capabilityModules = Object.freeze([
139
143
  }],
140
144
  stability: "stable",
141
145
  title: "Diagrams and images",
142
- toolNames: ["check_diagram", "execute_slopcamera", "render_diagram", "search_slopcamera"],
146
+ toolNames: [
147
+ "check_diagram",
148
+ "compose_icon",
149
+ "compose_soundtrack",
150
+ "derive_soundtrack_grid",
151
+ "execute_slopcamera",
152
+ "render_diagram",
153
+ "render_icon",
154
+ "search_slopcamera",
155
+ ],
143
156
  trust: "portable",
144
157
  version: 1,
145
158
  workflowKeys: [],
@@ -365,7 +365,7 @@ import {
365
365
  workflowRunStore,
366
366
  } from "./workflow-runs";
367
367
 
368
- export const SLOPCAMERA_VERSION = "3.8.0";
368
+ export const SLOPCAMERA_VERSION = "3.9.0";
369
369
 
370
370
  // Legacy direct renders predate per-target output contracts. Keep them
371
371
  // bounded generously enough for long-form production while preventing one
@@ -37,7 +37,7 @@ Commands:
37
37
  Discover and run Vercel AI Gateway media models
38
38
  credits status|topup|wait|forget
39
39
  Buy and inspect hosted generation credits
40
- media audio|color Apply local non-destructive audio and video effects
40
+ media audio|color|soundtrack Apply local audio and video effects; derive soundtrack beat grids
41
41
  outputs Print the agent outputs directory
42
42
  outputs list|open|reveal List the newest outputs or open one on this Mac
43
43
  status What Slopcamera is doing, credits and newest outputs
@@ -293,6 +293,10 @@ compliance. Drawing sheets are exposed through this CLI and the root SDK, not co
293
293
  slopcamera image icon --set <file.json> --output-dir <directory>
294
294
  [--context <card|hero|inline>] [--candidates <1-4>]
295
295
  [--set-rounds <1-4>] [--keep-raster] [--json]
296
+ slopcamera image icon compose <source.json> [--output <file.json>] [--json]
297
+ slopcamera image icon render <source.json> --output <file.svg> [--recipe <file.json>]
298
+ [--size <16-1024>] [--background] [--palette <original|ink|earth|night>]
299
+ [--language <language>] [--json]
296
300
 
297
301
  Explicit --output file commands delegate to @hraness/slopcamera. Vectorization is local,
298
302
  bounded, checksum-pinned, and emits inert SVG. File generation uses Vercel AI Gateway with the
@@ -308,7 +312,13 @@ variation axes or an explicit candidate list — keeps every candidate with its
308
312
  composes a labelled contact sheet plus receipt for agent review. Texture cells repeat the
309
313
  candidate 2×2 so seams are inspectable (--tile/--no-tile overrides). It never replaces existing
310
314
  outputs and never promotes a candidate into authored source; review the sheet and select
311
- explicitly.`,
315
+ explicitly.
316
+
317
+ Icon compose and render are local and deterministic, with no model or network. They solve and
318
+ draw icon.place scenes, collections, construction programs, and recipes into inert SVG; a recipe
319
+ replays only when its recorded digests match. Construction-program languages: outline, sketch,
320
+ pen, crosshatch, engraving, stipple, halftone, glyph, flat, shaded, figure, cutpaper, woodcut,
321
+ offset.`,
312
322
  style: `Usage:
313
323
  slopcamera style list [--json]
314
324
  slopcamera style show <id> [--json]
@@ -616,6 +626,15 @@ argv, receipts, or logs. When a configured wallet runs out, paid calls fail with
616
626
  [--output <relative-path>] [--json]
617
627
  slopcamera media color <video-path> [grade] [--video-stream <index>]
618
628
  [--output <relative-path>] [--json]
629
+ slopcamera media soundtrack compose <score> [--output <file.json>]
630
+ [--format <compose|song|json|midi>] [--json]
631
+ slopcamera media soundtrack grid <score> [--output <file.json>] [--start-us <n>]
632
+ [--format <compose|song|json|midi>] [--json]
633
+
634
+ Soundtrack verbs delegate to @hraness/slopcamera. They verify a Soundfish loop or song (compose
635
+ text, song text, score JSON, or a Standard MIDI file) and derive the {bpm, beatOffsetUs,
636
+ beatsPerBar} music timing that HTML scene requests accept, plus section cue times. They render
637
+ no audio; pair the grid with the track you mix.
619
638
 
620
639
  Audio effects may be combined in one deterministic chain:
621
640
  --volume-db <-60..24>
@@ -725,7 +744,7 @@ export function completions(words: readonly string[]): readonly string[] {
725
744
  if (command === "diagram") return words[1] === "sheets"
726
745
  ? ["init", "check", "render"]
727
746
  : ["init", "check", "render", "sheets"];
728
- if (command === "image") return ["vectorize", "generate", "gallery", "icon"];
747
+ if (command === "image") return words[1] === "icon" ? ["compose", "render"] : ["vectorize", "generate", "gallery", "icon"];
729
748
  if (command === "workflows") return ["list", "show", "plan", "run"];
730
749
  if (command === "code") return ["init", "check", "plan", "run"];
731
750
  if (command === "runs") return ["list", "show", "resume", "approve", "cancel"];
@@ -748,7 +767,7 @@ export function completions(words: readonly string[]): readonly string[] {
748
767
  if (command === "fillers") return ["list", "apply"];
749
768
  if (command === "ai") return ["models", "provider-options", "image", "video", "speech", "transcribe"];
750
769
  if (command === "credits") return ["status", "topup", "wait", "forget"];
751
- if (command === "media") return ["audio", "color"];
770
+ if (command === "media") return words[1] === "soundtrack" ? ["compose", "grid"] : ["audio", "color", "soundtrack"];
752
771
  if (command === "render") return ["plan", "run"];
753
772
  if (command === "assets") return ["emoji"];
754
773
  if (command === "outputs") return ["list", "open", "reveal"];
@@ -289,6 +289,7 @@ export async function runPortableSurface(
289
289
  argv[0] === "code"
290
290
  && (argv[1] === "search" || argv[1] === "execute")
291
291
  )
292
+ || (argv[0] === "media" && argv[1] === "soundtrack")
292
293
  || (
293
294
  argv[0] === "image"
294
295
  && (
@@ -96,6 +96,8 @@ export const CLI_VERBS: readonly VerbRow[] = [
96
96
  row("image generate", "operate", "Generate an image with Vercel AI Gateway"),
97
97
  row("image gallery", "operate", "Generate a review gallery of image candidates"),
98
98
  row("image icon", "operate", "Generate a line-art SVG icon"),
99
+ row("image icon compose", "operate", "Solve a vector icon scene and report its digests"),
100
+ row("image icon render", "operate", "Draw a vector icon scene or recipe to inert SVG"),
99
101
 
100
102
  row("html catalog", "read", "List HTML scene profiles"),
101
103
  row("html scaffold", "operate", "Write a new HTML scene"),
@@ -138,6 +140,8 @@ export const CLI_VERBS: readonly VerbRow[] = [
138
140
 
139
141
  row("media audio", "operate", "Apply audio effects into a new file"),
140
142
  row("media color", "operate", "Apply a color grade into a new file"),
143
+ row("media soundtrack compose", "operate", "Verify a loop or song score"),
144
+ row("media soundtrack grid", "operate", "Derive music timing and section cues from a score"),
141
145
 
142
146
  row("outputs", "read", "Print the outputs folder"),
143
147
  row("outputs list", "read", "List the files in the outputs folder, newest first"),