@hraness/slopcamera 3.2.8 → 3.3.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.
- package/README.md +29 -9
- package/apps/desktop/application/context.ts +6 -0
- package/apps/desktop/application/default-registry.ts +26 -0
- package/apps/desktop/application/operation.ts +14 -1
- package/apps/desktop/application/operations/index.ts +4 -0
- package/apps/desktop/application/operations/spatial-behavior.ts +151 -0
- package/apps/desktop/application/operations/spatial-direction.ts +222 -0
- package/apps/desktop/application/operations/spatial-rendered-audit.ts +174 -0
- package/apps/desktop/application/operations/spatial-review.ts +194 -0
- package/apps/desktop/application/operations/spatial-scene.ts +25 -1
- package/apps/desktop/application/registry.ts +2 -2
- package/apps/desktop/application/spatial-asset-admission.ts +201 -0
- package/apps/desktop/application/spatial-assets.ts +160 -31
- package/apps/desktop/application/spatial-render.ts +217 -20
- package/apps/desktop/application/spatial-rendered-audit.ts +273 -0
- package/apps/desktop/application/spatial-review.ts +361 -0
- package/apps/desktop/application/spatial-spz.ts +48 -3
- package/apps/desktop/application/spatial-world-import.ts +26 -5
- package/apps/desktop/application/spatial-world-metadata.ts +105 -0
- package/apps/desktop/cli/args.ts +514 -11
- package/apps/desktop/cli/capability-manifest.ts +374 -0
- package/apps/desktop/cli/cinema-renderer.ts +608 -0
- package/apps/desktop/cli/command-host-resources.ts +29 -1
- package/apps/desktop/cli/commands.ts +1188 -4
- package/apps/desktop/cli/gateway-review-provider.ts +334 -0
- package/apps/desktop/cli/help.ts +172 -6
- package/apps/desktop/cli/main.ts +3 -3
- package/apps/desktop/cli/portable-surface.ts +6 -1
- package/apps/desktop/cli/spatial-asset-service.ts +124 -0
- package/apps/desktop/cli/spatial-design-service.ts +237 -0
- package/apps/desktop/cli/spatial-generate-service.ts +370 -0
- package/apps/desktop/cli/spatial-scene-service.ts +268 -4
- package/apps/desktop/cli/workflow-code.ts +1 -1
- package/apps/desktop/code/semantic-builder.ts +24 -0
- package/apps/desktop/contracts/cinema.ts +736 -0
- package/apps/desktop/contracts/index.ts +1 -0
- package/apps/desktop/contracts/spatial-asset.ts +16 -0
- package/apps/desktop/contracts/spatial-world.ts +26 -3
- package/apps/desktop/core/cinema-plan.ts +1320 -0
- package/apps/desktop/core/index.ts +1 -0
- package/apps/desktop/core/storage.ts +75 -0
- package/apps/desktop/dist/cli/main.js +725 -273
- package/apps/desktop/html-overlay/spatial.ts +619 -57
- package/apps/desktop/workflows/cinematic-world.ts +127 -0
- package/apps/desktop/workflows/index.ts +6 -0
- package/dist/cli.js +25 -429
- package/dist/code/advanced.js +1 -269
- package/dist/code/index.js +16 -2239
- package/dist/generate.js +1 -23
- package/dist/host-resources.js +1 -25
- package/dist/index-0bbesn4m.js +35 -0
- package/dist/index-296qhpf2.js +3 -0
- package/dist/index-3cxf2c58.js +3 -0
- package/dist/index-77fjfg9f.js +3 -0
- package/dist/index-80a36bc0.js +3 -0
- package/dist/index-a3vvs3rf.js +3 -0
- package/dist/index-b3geqczn.js +5 -0
- package/dist/index-cgpkyjqa.js +3 -0
- package/dist/index-f0ptv8dm.js +7 -0
- package/dist/index-grk47tgs.js +3 -0
- package/dist/index-qry58nj2.js +10 -0
- package/dist/index.js +1 -226
- package/dist/operations.js +1 -28
- package/dist/skill-install-gx7afxsd.js +2 -0
- package/dist/vectorize/worker.js +1 -141
- package/dist/workflow.js +1 -15
- package/docs/README.md +5 -1
- package/package.json +7 -5
- package/skills/slopcamera/SKILL.md +6 -1
- package/skills/slopcamera/references/directed-scenes.md +22 -2
- package/skills/slopcamera/references/gateway-media.md +15 -1
- package/skills/slopcamera/references/image-galleries.md +166 -0
- package/skills/slopcamera/references/install.md +1 -1
- package/skills/slopcamera/references/parametric-design.md +14 -0
- package/skills/slopcamera/references/scene-building.md +32 -0
- package/skills/slopcamera/references/social-collage-banners.md +204 -0
- package/skills/slopcamera/references/workflows-sdk.md +3 -3
- package/skills/slopcamera/scripts/compose-social-collage-banner.ts +728 -0
- package/src/capability-manifest.ts +361 -0
- package/src/cli.ts +222 -4
- package/src/code/canonical-json.ts +9 -0
- package/src/generate.ts +2 -2
- package/src/icon.ts +1111 -0
- package/src/image-gallery.ts +1049 -0
- package/src/index.ts +11 -0
- package/src/mcp/boundary.ts +11 -11
- package/src/mcp/index.ts +3 -0
- package/src/mcp/server.ts +2 -1
- package/src/mcp/tools.ts +1642 -130
- package/src/mcp/types.ts +19 -0
- package/src/operations.ts +412 -0
- package/src/portable-capability-manifest.ts +67 -0
- package/src/scene-gallery.ts +184 -0
- package/src/spatial-scene/asset-admission.ts +183 -0
- package/src/spatial-scene/audit-rendered.ts +692 -0
- package/src/spatial-scene/audit.ts +617 -0
- package/src/spatial-scene/behavior-audit.ts +252 -0
- package/src/spatial-scene/behavior-bake.ts +233 -0
- package/src/spatial-scene/behavior-fns.ts +585 -0
- package/src/spatial-scene/behavior-gallery.ts +109 -0
- package/src/spatial-scene/behavior-stdlib.ts +323 -0
- package/src/spatial-scene/behavior-trace.ts +325 -0
- package/src/spatial-scene/behavior.ts +618 -0
- package/src/spatial-scene/build.ts +632 -0
- package/src/spatial-scene/camera-rig.ts +125 -0
- package/src/spatial-scene/camera-track.ts +4 -2
- package/src/spatial-scene/character.ts +124 -0
- package/src/spatial-scene/contracts.ts +75 -7
- package/src/spatial-scene/design-templates.ts +351 -0
- package/src/spatial-scene/design.ts +327 -0
- package/src/spatial-scene/direction-compile.ts +584 -0
- package/src/spatial-scene/direction.ts +122 -0
- package/src/spatial-scene/effects.ts +149 -0
- package/src/spatial-scene/evaluate.ts +109 -29
- package/src/spatial-scene/gallery.ts +277 -0
- package/src/spatial-scene/generate.ts +239 -0
- package/src/spatial-scene/geometry-native.ts +165 -0
- package/src/spatial-scene/geometry.ts +1216 -0
- package/src/spatial-scene/gltf.ts +600 -77
- package/src/spatial-scene/identity.ts +55 -2
- package/src/spatial-scene/index.ts +36 -0
- package/src/spatial-scene/inspect.ts +35 -6
- package/src/spatial-scene/material-lighting.ts +609 -0
- package/src/spatial-scene/math.ts +21 -4
- package/src/spatial-scene/motion-evidence.ts +88 -0
- package/src/spatial-scene/parametric.ts +765 -0
- package/src/spatial-scene/particle-preparation.ts +183 -0
- package/src/spatial-scene/particle.ts +195 -0
- package/src/spatial-scene/patch.ts +109 -15
- package/src/spatial-scene/performance.ts +1613 -0
- package/src/spatial-scene/probe.ts +137 -0
- package/src/spatial-scene/recipe-pack.ts +86 -0
- package/src/spatial-scene/render-effects.ts +240 -0
- package/src/spatial-scene/review.ts +639 -0
- package/src/spatial-scene/simulation-bake.ts +206 -0
- package/src/spatial-scene/simulation.ts +187 -0
- package/src/spatial-scene/solve.ts +366 -0
- package/src/spatial-scene/temporal-audit.ts +354 -0
- package/src/version.ts +1 -1
- package/dist/index-42zsesc1.js +0 -2257
- package/dist/index-7131pg1c.js +0 -1820
- package/dist/index-7308egqr.js +0 -48
- package/dist/index-8txs6fkn.js +0 -712
- package/dist/index-fava6pge.js +0 -192
- package/dist/index-h1k0fnjq.js +0 -2363
- package/dist/index-r7gdhmsp.js +0 -424
- package/dist/index-sh6xbav6.js +0 -1219
- package/dist/index-z1w83f81.js +0 -4
- package/dist/index-zfnddgay.js +0 -2029
- package/dist/skill-install-dh0ntqba.js +0 -10
package/apps/desktop/cli/args.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { CliError } from "./errors";
|
|
2
2
|
import { MAX_EVENT_QUERY_LIMIT } from "./query-limits";
|
|
3
3
|
import { STUDIO_TEMPLATES, type StudioTemplate } from "./studio-template-names";
|
|
4
|
+
import {
|
|
5
|
+
slopcameraGalleryKinds,
|
|
6
|
+
slopcameraGalleryLimits,
|
|
7
|
+
} from "../../../src/image-gallery";
|
|
4
8
|
|
|
5
9
|
export type OverlayKind = "image" | "svg" | "gif" | "video" | "emoji";
|
|
6
10
|
export type ZoomTargetKind = "rect" | "point" | "cursor" | "window" | "focused-input";
|
|
@@ -58,6 +62,12 @@ export type SpatialWorldCommand = JsonOption & {
|
|
|
58
62
|
readonly kind: "spatial-world"; readonly action: "import";
|
|
59
63
|
readonly input: string; readonly sourceRoot: string; readonly outputRoot: string;
|
|
60
64
|
};
|
|
65
|
+
export type SpatialAssetCommand = JsonOption & {
|
|
66
|
+
readonly kind: "spatial-asset"; readonly action: "admit";
|
|
67
|
+
readonly file: string; readonly output: string;
|
|
68
|
+
readonly sourceRoot?: string; readonly assetId?: string;
|
|
69
|
+
readonly metersPerUnit: number; readonly sourceUp: "x" | "y" | "z";
|
|
70
|
+
};
|
|
61
71
|
export type DirectingCommand = JsonOption & { readonly kind: "directing" } & (
|
|
62
72
|
| { readonly action: "init"; readonly path: string }
|
|
63
73
|
| { readonly action: "anchor"; readonly input: string }
|
|
@@ -69,12 +79,37 @@ export type DirectingCommand = JsonOption & { readonly kind: "directing" } & (
|
|
|
69
79
|
| { readonly action: "resume" | "cleanup"; readonly id: string; readonly attempt: string }
|
|
70
80
|
| { readonly action: "review"; readonly id: string; readonly attempt: string; readonly decision: "accepted" | "rejected"; readonly note: string }
|
|
71
81
|
);
|
|
72
|
-
export type SpatialSceneCommand = JsonOption & { readonly kind: "spatial-scene"
|
|
73
|
-
| { readonly action: "init" | "inspect" }
|
|
74
|
-
| { readonly action: "
|
|
75
|
-
| { readonly action: "
|
|
76
|
-
| { readonly action: "
|
|
77
|
-
| { readonly action: "
|
|
82
|
+
export type SpatialSceneCommand = JsonOption & { readonly kind: "spatial-scene" } & (
|
|
83
|
+
| { readonly action: "init" | "inspect"; readonly path: string }
|
|
84
|
+
| { readonly action: "diff"; readonly path: string; readonly other: string }
|
|
85
|
+
| { readonly action: "patch"; readonly path: string; readonly patch: string; readonly output: string }
|
|
86
|
+
| { readonly action: "evaluate"; readonly path: string; readonly camera: string; readonly timeUs: number }
|
|
87
|
+
| { readonly action: "audit"; readonly path: string; readonly camera: string; readonly timesUs?: readonly number[]; readonly assetBounds?: string }
|
|
88
|
+
| { readonly action: "render-audit"; readonly path: string; readonly camera: string; readonly timesUs?: readonly number[] }
|
|
89
|
+
| { readonly action: "solve"; readonly path: string; readonly goals: string; readonly output?: string; readonly assetBounds?: string }
|
|
90
|
+
| { readonly action: "review"; readonly path: string; readonly camera: string; readonly timesUs?: readonly number[]; readonly allowCloudUpload: boolean }
|
|
91
|
+
| { readonly action: "camera-track"; readonly path: string; readonly request: string; readonly output: string }
|
|
92
|
+
| { readonly action: "plan" | "render"; readonly path: string; readonly request: string; readonly assets?: string; readonly executionProfile?: SpatialCliExecutionProfile }
|
|
93
|
+
| { readonly action: "generate"; readonly module: string; readonly generatorId: string; readonly parameters?: string; readonly seed?: number; readonly into?: string; readonly output: string }
|
|
94
|
+
| { readonly action: "direction-check"; readonly direction: string; readonly scene: string }
|
|
95
|
+
| { readonly action: "direction-plan"; readonly direction: string; readonly scene: string; readonly camera?: string; readonly output?: string }
|
|
96
|
+
| { readonly action: "direction-gallery"; readonly direction: string; readonly scene: string; readonly axis: string; readonly camera?: string; readonly output?: string }
|
|
97
|
+
| { readonly action: "effects-check"; readonly effects: string; readonly scene: string }
|
|
98
|
+
| { readonly action: "effects-plan"; readonly draft: string; readonly scene: string; readonly output?: string }
|
|
99
|
+
| { readonly action: "effects-bake"; readonly simulation: string; readonly scene: string; readonly output: string }
|
|
100
|
+
| { readonly action: "behavior-check"; readonly behavior: string; readonly scene: string }
|
|
101
|
+
| { readonly action: "behavior-bake"; readonly behavior: string; readonly scene: string; readonly channelMap?: string; readonly output: string }
|
|
102
|
+
| { readonly action: "behavior-gallery"; readonly behavior: string; readonly scene: string; readonly channelMap?: string; readonly output?: string }
|
|
103
|
+
| { readonly action: "behavior-audit"; readonly bake: string; readonly output?: string }
|
|
104
|
+
| { readonly action: "temporal-audit"; readonly path: string; readonly camera: string; readonly timesUs?: readonly number[]; readonly contacts?: string; readonly cutBeforeUs?: readonly number[] }
|
|
105
|
+
);
|
|
106
|
+
export type SpatialDesignCommand = JsonOption & { readonly kind: "spatial-design" } & (
|
|
107
|
+
| { readonly action: "catalog" }
|
|
108
|
+
| { readonly action: "init"; readonly directory: string; readonly template: string }
|
|
109
|
+
| { readonly action: "inspect"; readonly path: string }
|
|
110
|
+
| { readonly action: "set"; readonly path: string; readonly parameters: string; readonly output: string }
|
|
111
|
+
| { readonly action: "compile"; readonly path: string; readonly scene?: string; readonly outputDir: string }
|
|
112
|
+
| { readonly action: "gallery"; readonly path: string; readonly scene?: string; readonly variants: string; readonly outputDir: string }
|
|
78
113
|
);
|
|
79
114
|
export type SpatialProjectCommand = JsonOption & {
|
|
80
115
|
readonly kind: "spatial-project"; readonly project: string;
|
|
@@ -89,10 +124,13 @@ export type CliCommand =
|
|
|
89
124
|
| StudioCommand
|
|
90
125
|
| DirectingCommand
|
|
91
126
|
| SpatialWorldCommand
|
|
127
|
+
| SpatialAssetCommand
|
|
92
128
|
| SpatialSceneCommand
|
|
129
|
+
| SpatialDesignCommand
|
|
93
130
|
| SpatialProjectCommand
|
|
94
131
|
| { readonly kind: "help"; readonly topic: readonly string[] }
|
|
95
132
|
| { readonly kind: "version" }
|
|
133
|
+
| ({ readonly kind: "capabilities" } & JsonOption)
|
|
96
134
|
| ({ readonly kind: "operations-list" } & JsonOption)
|
|
97
135
|
| ({ readonly kind: "operations-show"; readonly operation: string } & JsonOption)
|
|
98
136
|
| ({ readonly kind: "diagram-check"; readonly path: string } & JsonOption)
|
|
@@ -194,6 +232,29 @@ export type CliCommand =
|
|
|
194
232
|
readonly temperature: number | undefined;
|
|
195
233
|
readonly timeout: string;
|
|
196
234
|
} & JsonOption)
|
|
235
|
+
| ({
|
|
236
|
+
readonly candidatesFile: string | undefined;
|
|
237
|
+
readonly cell: number | undefined;
|
|
238
|
+
readonly count: number | undefined;
|
|
239
|
+
readonly galleryKind: string | undefined;
|
|
240
|
+
readonly kind: "ai-image-gallery";
|
|
241
|
+
readonly model: string;
|
|
242
|
+
readonly outputDir: string;
|
|
243
|
+
readonly preview: "probe" | undefined;
|
|
244
|
+
readonly subject: string;
|
|
245
|
+
readonly tiled: boolean | undefined;
|
|
246
|
+
readonly timeout: string;
|
|
247
|
+
readonly vary: string | undefined;
|
|
248
|
+
} & JsonOption)
|
|
249
|
+
| ({
|
|
250
|
+
readonly camera: string | undefined;
|
|
251
|
+
readonly cell: number | undefined;
|
|
252
|
+
readonly kind: "ai-scene-gallery";
|
|
253
|
+
readonly outputDir: string;
|
|
254
|
+
readonly scene: string;
|
|
255
|
+
readonly timeUs: number | undefined;
|
|
256
|
+
readonly variants: string;
|
|
257
|
+
} & JsonOption)
|
|
197
258
|
| ({
|
|
198
259
|
readonly allowCloudUpload: boolean;
|
|
199
260
|
readonly aspectRatio: string | undefined;
|
|
@@ -387,6 +448,16 @@ export type CliCommand =
|
|
|
387
448
|
readonly project: string;
|
|
388
449
|
readonly width: number;
|
|
389
450
|
} & JsonOption)
|
|
451
|
+
| ({
|
|
452
|
+
readonly action: "init" | "check" | "plan" | "animatic" | "run" | "audit" | "gallery";
|
|
453
|
+
readonly allowPlaceholders: boolean;
|
|
454
|
+
readonly axis: string | undefined;
|
|
455
|
+
readonly dryRun: boolean;
|
|
456
|
+
readonly force: boolean;
|
|
457
|
+
readonly kind: "project-cinema";
|
|
458
|
+
readonly output: string | undefined;
|
|
459
|
+
readonly project: string;
|
|
460
|
+
} & JsonOption)
|
|
390
461
|
| ({
|
|
391
462
|
readonly apply: boolean;
|
|
392
463
|
readonly candidate: string | undefined;
|
|
@@ -809,6 +880,12 @@ function exactPositionals(parsed: ParsedOptions, count: number, usage: string):
|
|
|
809
880
|
|
|
810
881
|
const JSON_SPEC = { "--json": "flag" } as const;
|
|
811
882
|
|
|
883
|
+
function parseCapabilities(argv: readonly string[]): CliCommand {
|
|
884
|
+
const parsed = parseOptions(argv, JSON_SPEC);
|
|
885
|
+
exactPositionals(parsed, 0, "slopcamera capabilities [--json]");
|
|
886
|
+
return { json: optionFlag(parsed, "--json"), kind: "capabilities" };
|
|
887
|
+
}
|
|
888
|
+
|
|
812
889
|
function parseDoctor(argv: readonly string[]): CliCommand {
|
|
813
890
|
const parsed = parseOptions(argv, JSON_SPEC);
|
|
814
891
|
exactPositionals(parsed, 0, "slopcamera doctor [--json]");
|
|
@@ -911,7 +988,10 @@ function parseAiProviderOptions(argv: readonly string[]): CliCommand {
|
|
|
911
988
|
}
|
|
912
989
|
|
|
913
990
|
function parseAiImage(argv: readonly string[]): CliCommand {
|
|
914
|
-
if (argv[0]
|
|
991
|
+
if (argv[0] === "gallery") return parseAiImageGallery(argv.slice(1));
|
|
992
|
+
if (argv[0] !== "generate") {
|
|
993
|
+
fail("Usage: slopcamera ai image <generate|gallery> --model <id> [options]");
|
|
994
|
+
}
|
|
915
995
|
const parsed = parseOptions(argv.slice(1), {
|
|
916
996
|
...JSON_SPEC,
|
|
917
997
|
"--allow-cloud-upload": "flag",
|
|
@@ -969,6 +1049,145 @@ function parseAiImage(argv: readonly string[]): CliCommand {
|
|
|
969
1049
|
};
|
|
970
1050
|
}
|
|
971
1051
|
|
|
1052
|
+
function parseAiImageGallery(argv: readonly string[]): CliCommand {
|
|
1053
|
+
const parsed = parseOptions(argv, {
|
|
1054
|
+
...JSON_SPEC,
|
|
1055
|
+
"--candidates": "value",
|
|
1056
|
+
"--cell": "value",
|
|
1057
|
+
"--count": "value",
|
|
1058
|
+
"--kind": "value",
|
|
1059
|
+
"--model": "value",
|
|
1060
|
+
"--no-tile": "flag",
|
|
1061
|
+
"--output-dir": "value",
|
|
1062
|
+
"--preview": "value",
|
|
1063
|
+
"--tile": "flag",
|
|
1064
|
+
"--timeout": "value",
|
|
1065
|
+
"--vary": "value",
|
|
1066
|
+
});
|
|
1067
|
+
const [subject] = exactPositionals(
|
|
1068
|
+
parsed,
|
|
1069
|
+
1,
|
|
1070
|
+
"slopcamera ai image gallery <subject> --model <id> --output-dir <directory> [options]",
|
|
1071
|
+
);
|
|
1072
|
+
const model = optionString(parsed, "--model");
|
|
1073
|
+
if (model === undefined) fail("--model is required.");
|
|
1074
|
+
const outputDir = optionString(parsed, "--output-dir");
|
|
1075
|
+
if (outputDir === undefined || outputDir.trim() === "") {
|
|
1076
|
+
fail("--output-dir is required.");
|
|
1077
|
+
}
|
|
1078
|
+
const galleryKind = optionString(parsed, "--kind");
|
|
1079
|
+
if (
|
|
1080
|
+
galleryKind !== undefined
|
|
1081
|
+
&& !(slopcameraGalleryKinds as readonly string[]).includes(galleryKind)
|
|
1082
|
+
) {
|
|
1083
|
+
fail(`--kind must be one of: ${slopcameraGalleryKinds.join(", ")}.`);
|
|
1084
|
+
}
|
|
1085
|
+
const count = optionalStrictInteger(optionString(parsed, "--count"), "--count");
|
|
1086
|
+
if (count !== undefined && count > slopcameraGalleryLimits.candidates) {
|
|
1087
|
+
fail(`--count must be at most ${slopcameraGalleryLimits.candidates}.`);
|
|
1088
|
+
}
|
|
1089
|
+
const cell = optionalStrictInteger(optionString(parsed, "--cell"), "--cell");
|
|
1090
|
+
if (
|
|
1091
|
+
cell !== undefined
|
|
1092
|
+
&& (
|
|
1093
|
+
cell < slopcameraGalleryLimits.cellEdgeMin
|
|
1094
|
+
|| cell > slopcameraGalleryLimits.cellEdgeMax
|
|
1095
|
+
)
|
|
1096
|
+
) {
|
|
1097
|
+
fail(
|
|
1098
|
+
`--cell must be between ${slopcameraGalleryLimits.cellEdgeMin} and ${slopcameraGalleryLimits.cellEdgeMax}.`,
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1101
|
+
const candidatesFile = optionString(parsed, "--candidates");
|
|
1102
|
+
const vary = optionString(parsed, "--vary");
|
|
1103
|
+
if (candidatesFile !== undefined && (vary !== undefined || count !== undefined)) {
|
|
1104
|
+
fail("--candidates is mutually exclusive with --vary and --count.");
|
|
1105
|
+
}
|
|
1106
|
+
const tile = optionFlag(parsed, "--tile");
|
|
1107
|
+
const noTile = optionFlag(parsed, "--no-tile");
|
|
1108
|
+
if (tile && noTile) fail("--tile and --no-tile are mutually exclusive.");
|
|
1109
|
+
const preview = optionString(parsed, "--preview");
|
|
1110
|
+
if (preview !== undefined && preview !== "probe") {
|
|
1111
|
+
fail("--preview must be probe.");
|
|
1112
|
+
}
|
|
1113
|
+
if (
|
|
1114
|
+
preview === "probe"
|
|
1115
|
+
&& !["texture", "skybox", "backdrop"].includes(galleryKind ?? "image")
|
|
1116
|
+
) {
|
|
1117
|
+
fail("--preview probe requires --kind texture, skybox, or backdrop.");
|
|
1118
|
+
}
|
|
1119
|
+
return {
|
|
1120
|
+
candidatesFile,
|
|
1121
|
+
cell,
|
|
1122
|
+
count,
|
|
1123
|
+
galleryKind,
|
|
1124
|
+
json: optionFlag(parsed, "--json"),
|
|
1125
|
+
kind: "ai-image-gallery",
|
|
1126
|
+
model,
|
|
1127
|
+
outputDir,
|
|
1128
|
+
preview: preview as "probe" | undefined,
|
|
1129
|
+
subject: subject!,
|
|
1130
|
+
tiled: tile ? true : noTile ? false : undefined,
|
|
1131
|
+
timeout: optionString(parsed, "--timeout") ?? "10m",
|
|
1132
|
+
vary,
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
function parseAiScene(argv: readonly string[]): CliCommand {
|
|
1137
|
+
if (argv[0] !== "gallery") {
|
|
1138
|
+
fail("Usage: slopcamera ai scene gallery <scene.json> --variants <file.json> --output-dir <directory> [options]");
|
|
1139
|
+
}
|
|
1140
|
+
const parsed = parseOptions(argv.slice(1), {
|
|
1141
|
+
...JSON_SPEC,
|
|
1142
|
+
"--camera": "value",
|
|
1143
|
+
"--cell": "value",
|
|
1144
|
+
"--output-dir": "value",
|
|
1145
|
+
"--time-us": "value",
|
|
1146
|
+
"--variants": "value",
|
|
1147
|
+
});
|
|
1148
|
+
const [scene] = exactPositionals(
|
|
1149
|
+
parsed,
|
|
1150
|
+
1,
|
|
1151
|
+
"slopcamera ai scene gallery <scene.json> --variants <file.json> --output-dir <directory> [options]",
|
|
1152
|
+
);
|
|
1153
|
+
const variants = optionString(parsed, "--variants");
|
|
1154
|
+
if (variants === undefined) fail("--variants is required.");
|
|
1155
|
+
const outputDir = optionString(parsed, "--output-dir");
|
|
1156
|
+
if (outputDir === undefined || outputDir.trim() === "") {
|
|
1157
|
+
fail("--output-dir is required.");
|
|
1158
|
+
}
|
|
1159
|
+
const timeUsText = optionString(parsed, "--time-us");
|
|
1160
|
+
let timeUs: number | undefined;
|
|
1161
|
+
if (timeUsText !== undefined) {
|
|
1162
|
+
if (!/^\d+$/u.test(timeUsText) || !Number.isSafeInteger(Number(timeUsText))) {
|
|
1163
|
+
fail("--time-us must be a nonnegative integer microsecond time.");
|
|
1164
|
+
}
|
|
1165
|
+
timeUs = Number(timeUsText);
|
|
1166
|
+
}
|
|
1167
|
+
const cell = optionalStrictInteger(optionString(parsed, "--cell"), "--cell");
|
|
1168
|
+
if (
|
|
1169
|
+
cell !== undefined
|
|
1170
|
+
&& (
|
|
1171
|
+
cell < slopcameraGalleryLimits.cellEdgeMin
|
|
1172
|
+
|| cell > slopcameraGalleryLimits.cellEdgeMax
|
|
1173
|
+
)
|
|
1174
|
+
) {
|
|
1175
|
+
fail(
|
|
1176
|
+
`--cell must be between ${slopcameraGalleryLimits.cellEdgeMin} and ${slopcameraGalleryLimits.cellEdgeMax}.`,
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
return {
|
|
1180
|
+
camera: optionString(parsed, "--camera"),
|
|
1181
|
+
cell,
|
|
1182
|
+
json: optionFlag(parsed, "--json"),
|
|
1183
|
+
kind: "ai-scene-gallery",
|
|
1184
|
+
outputDir,
|
|
1185
|
+
scene: scene!,
|
|
1186
|
+
timeUs,
|
|
1187
|
+
variants,
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
|
|
972
1191
|
function parseAiVideo(argv: readonly string[]): CliCommand {
|
|
973
1192
|
if (argv[0] !== "generate") fail("Usage: slopcamera ai video generate --model <id> [options]");
|
|
974
1193
|
const parsed = parseOptions(argv.slice(1), {
|
|
@@ -1131,11 +1350,12 @@ function parseAi(argv: readonly string[]): CliCommand {
|
|
|
1131
1350
|
case "models": return parseAiModels(argv.slice(1));
|
|
1132
1351
|
case "provider-options": return parseAiProviderOptions(argv.slice(1));
|
|
1133
1352
|
case "image": return parseAiImage(argv.slice(1));
|
|
1353
|
+
case "scene": return parseAiScene(argv.slice(1));
|
|
1134
1354
|
case "video": return parseAiVideo(argv.slice(1));
|
|
1135
1355
|
case "speech": return parseAiSpeech(argv.slice(1));
|
|
1136
1356
|
case "transcribe": return parseAiTranscribe(argv.slice(1));
|
|
1137
1357
|
case undefined:
|
|
1138
|
-
default: fail("Usage: slopcamera ai <models|provider-options|image|video|speech|transcribe> [options]");
|
|
1358
|
+
default: fail("Usage: slopcamera ai <models|provider-options|image|scene|video|speech|transcribe> [options]");
|
|
1139
1359
|
}
|
|
1140
1360
|
}
|
|
1141
1361
|
|
|
@@ -1742,7 +1962,65 @@ function parseProject(argv: readonly string[]): CliCommand {
|
|
|
1742
1962
|
width: strictEvenPositiveInteger(optionString(parsed, "--width"), "--width", 1_920),
|
|
1743
1963
|
};
|
|
1744
1964
|
}
|
|
1745
|
-
|
|
1965
|
+
if (action === "cinema") {
|
|
1966
|
+
const cinemaAction = argv[1];
|
|
1967
|
+
if (
|
|
1968
|
+
cinemaAction !== "init"
|
|
1969
|
+
&& cinemaAction !== "check"
|
|
1970
|
+
&& cinemaAction !== "plan"
|
|
1971
|
+
&& cinemaAction !== "animatic"
|
|
1972
|
+
&& cinemaAction !== "run"
|
|
1973
|
+
&& cinemaAction !== "audit"
|
|
1974
|
+
&& cinemaAction !== "gallery"
|
|
1975
|
+
) {
|
|
1976
|
+
fail("Usage: slopcamera project cinema <init|check|plan|animatic|run|audit|gallery> <project> [options]");
|
|
1977
|
+
}
|
|
1978
|
+
const parsed = parseOptions(argv.slice(2), {
|
|
1979
|
+
...JSON_SPEC,
|
|
1980
|
+
"--allow-placeholders": "flag",
|
|
1981
|
+
"--axis": "value",
|
|
1982
|
+
"--dry-run": "flag",
|
|
1983
|
+
"--force": "flag",
|
|
1984
|
+
"--output": "value",
|
|
1985
|
+
});
|
|
1986
|
+
const [project] = exactPositionals(
|
|
1987
|
+
parsed,
|
|
1988
|
+
1,
|
|
1989
|
+
`slopcamera project cinema ${cinemaAction} <project> [options]`,
|
|
1990
|
+
);
|
|
1991
|
+
if (optionFlag(parsed, "--dry-run") && cinemaAction !== "animatic" && cinemaAction !== "run") {
|
|
1992
|
+
fail("--dry-run is valid only for project cinema animatic or run.");
|
|
1993
|
+
}
|
|
1994
|
+
if (optionFlag(parsed, "--force") && cinemaAction !== "init") {
|
|
1995
|
+
fail("--force is valid only for project cinema init.");
|
|
1996
|
+
}
|
|
1997
|
+
const output = optionString(parsed, "--output");
|
|
1998
|
+
if (output !== undefined && (cinemaAction === "init" || cinemaAction === "check" || cinemaAction === "audit")) {
|
|
1999
|
+
fail("--output is valid only for project cinema plan, animatic, run, or gallery.");
|
|
2000
|
+
}
|
|
2001
|
+
const axis = optionString(parsed, "--axis");
|
|
2002
|
+
if (cinemaAction === "gallery" && axis === undefined) {
|
|
2003
|
+
fail("project cinema gallery requires --axis <pacing|transitions|looks|audio|structure|mixed>.");
|
|
2004
|
+
}
|
|
2005
|
+
if (axis !== undefined && cinemaAction !== "gallery") {
|
|
2006
|
+
fail("--axis is valid only for project cinema gallery.");
|
|
2007
|
+
}
|
|
2008
|
+
if (optionFlag(parsed, "--allow-placeholders") && (cinemaAction === "init" || cinemaAction === "check" || cinemaAction === "audit" || cinemaAction === "gallery")) {
|
|
2009
|
+
fail("--allow-placeholders is valid only for project cinema plan, animatic, or run.");
|
|
2010
|
+
}
|
|
2011
|
+
return {
|
|
2012
|
+
action: cinemaAction,
|
|
2013
|
+
allowPlaceholders: optionFlag(parsed, "--allow-placeholders"),
|
|
2014
|
+
axis,
|
|
2015
|
+
dryRun: optionFlag(parsed, "--dry-run"),
|
|
2016
|
+
force: optionFlag(parsed, "--force"),
|
|
2017
|
+
json: optionFlag(parsed, "--json"),
|
|
2018
|
+
kind: "project-cinema",
|
|
2019
|
+
output,
|
|
2020
|
+
project: project!,
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
fail("Usage: slopcamera project <inspect|add|edit|render|cinema> ...");
|
|
1746
2024
|
}
|
|
1747
2025
|
|
|
1748
2026
|
function parseInspect(argv: readonly string[]): CliCommand {
|
|
@@ -2990,9 +3268,77 @@ function parseSpatialWorldArgs(argv: readonly string[]): SpatialWorldCommand {
|
|
|
2990
3268
|
return fail("Usage: slopcamera scene world import --input <request.json> --source-root <directory> --output-root <artifact-directory>");
|
|
2991
3269
|
}
|
|
2992
3270
|
|
|
2993
|
-
|
|
3271
|
+
const SPATIAL_ASSET_ADMIT_USAGE = "slopcamera scene asset admit <model.glb> --output <manifest.json> [--source-root <directory>] [--asset-id <id>] [--meters-per-unit <n>] [--source-up x|y|z] [--json]";
|
|
3272
|
+
|
|
3273
|
+
function parseSpatialAssetArgs(argv: readonly string[]): SpatialAssetCommand {
|
|
2994
3274
|
const action = argv[0];
|
|
3275
|
+
if (action !== "admit") return fail(`Usage: ${SPATIAL_ASSET_ADMIT_USAGE}`);
|
|
3276
|
+
const parsed = parseOptions(argv.slice(1), {
|
|
3277
|
+
...JSON_SPEC, "--source-root": "value", "--asset-id": "value",
|
|
3278
|
+
"--meters-per-unit": "value", "--source-up": "value", "--output": "value",
|
|
3279
|
+
});
|
|
3280
|
+
const [file] = exactPositionals(parsed, 1, SPATIAL_ASSET_ADMIT_USAGE);
|
|
3281
|
+
const output = optionString(parsed, "--output");
|
|
3282
|
+
if (output === undefined) fail("scene asset admit requires --output.");
|
|
3283
|
+
const assetId = optionString(parsed, "--asset-id");
|
|
3284
|
+
if (assetId !== undefined && (assetId.length > 128 || !/^asset_[a-zA-Z0-9][a-zA-Z0-9_-]*$/u.test(assetId))) {
|
|
3285
|
+
fail("--asset-id must be an asset_-prefixed identifier of at most 128 characters.");
|
|
3286
|
+
}
|
|
3287
|
+
return {
|
|
3288
|
+
kind: "spatial-asset", action, file: file!, output,
|
|
3289
|
+
...(optionString(parsed, "--source-root") === undefined ? {} : { sourceRoot: optionString(parsed, "--source-root")! }),
|
|
3290
|
+
...(assetId === undefined ? {} : { assetId }),
|
|
3291
|
+
metersPerUnit: boundedNumber(optionString(parsed, "--meters-per-unit"), "--meters-per-unit", 0.000001, 1_000_000, 1),
|
|
3292
|
+
sourceUp: oneOf(optionString(parsed, "--source-up"), "--source-up", ["x", "y", "z"], "y"),
|
|
3293
|
+
json: optionFlag(parsed, "--json"),
|
|
3294
|
+
};
|
|
3295
|
+
}
|
|
3296
|
+
|
|
3297
|
+
function parseSpatialDesignArgs(argv: readonly string[]): SpatialDesignCommand {
|
|
3298
|
+
const action = argv[0];
|
|
3299
|
+
if (action === "catalog") {
|
|
3300
|
+
const parsed = parseOptions(argv.slice(1), JSON_SPEC);
|
|
3301
|
+
exactPositionals(parsed, 0, "slopcamera scene design catalog [--json]");
|
|
3302
|
+
return { kind: "spatial-design", action, json: optionFlag(parsed, "--json") };
|
|
3303
|
+
}
|
|
3304
|
+
if (action === "init") {
|
|
3305
|
+
const parsed = parseOptions(argv.slice(1), { ...JSON_SPEC, "--template": "value" });
|
|
3306
|
+
const [directory] = exactPositionals(parsed, 1, "slopcamera scene design init <directory> --template <id> [--json]");
|
|
3307
|
+
const template = optionString(parsed, "--template");
|
|
3308
|
+
if (template === undefined) return fail("scene design init requires --template; use scene design catalog.");
|
|
3309
|
+
return { kind: "spatial-design", action, directory: directory!, template, json: optionFlag(parsed, "--json") };
|
|
3310
|
+
}
|
|
3311
|
+
if (action === "inspect" || action === "check") {
|
|
3312
|
+
const parsed = parseOptions(argv.slice(1), JSON_SPEC);
|
|
3313
|
+
const [path] = exactPositionals(parsed, 1, "slopcamera scene design inspect <design.json> [--json]");
|
|
3314
|
+
return { kind: "spatial-design", action: "inspect", path: path!, json: optionFlag(parsed, "--json") };
|
|
3315
|
+
}
|
|
3316
|
+
if (action === "set") {
|
|
3317
|
+
const parsed = parseOptions(argv.slice(1), { ...JSON_SPEC, "--parameters": "value", "--output": "value" });
|
|
3318
|
+
const [path] = exactPositionals(parsed, 1, "slopcamera scene design set <design.json> --parameters <values.json> --output <new-design.json> [--json]");
|
|
3319
|
+
const parameters = optionString(parsed, "--parameters"), output = optionString(parsed, "--output");
|
|
3320
|
+
if (parameters === undefined || output === undefined) return fail("scene design set requires --parameters and --output.");
|
|
3321
|
+
return { kind: "spatial-design", action, path: path!, parameters, output, json: optionFlag(parsed, "--json") };
|
|
3322
|
+
}
|
|
3323
|
+
if (action === "compile" || action === "gallery") {
|
|
3324
|
+
const parsed = parseOptions(argv.slice(1), { ...JSON_SPEC, "--scene": "value", "--output-dir": "value", ...(action === "gallery" ? { "--variants": "value" as const } : {}) });
|
|
3325
|
+
const [path] = exactPositionals(parsed, 1, `slopcamera scene design ${action} <design.json> [--scene <scene.json>] --output-dir <new-directory> [--json]`);
|
|
3326
|
+
const scene = optionString(parsed, "--scene"), outputDir = optionString(parsed, "--output-dir");
|
|
3327
|
+
if (outputDir === undefined) return fail(`scene design ${action} requires --output-dir.`);
|
|
3328
|
+
const shared = { kind: "spatial-design" as const, path: path!, ...(scene === undefined ? {} : { scene }), outputDir, json: optionFlag(parsed, "--json") };
|
|
3329
|
+
if (action === "compile") return { ...shared, action };
|
|
3330
|
+
const variants = optionString(parsed, "--variants");
|
|
3331
|
+
if (variants === undefined) return fail("scene design gallery requires --variants.");
|
|
3332
|
+
return { ...shared, action, variants };
|
|
3333
|
+
}
|
|
3334
|
+
return fail("Usage: slopcamera scene design <catalog|init|inspect|set|compile|gallery> ...");
|
|
3335
|
+
}
|
|
3336
|
+
|
|
3337
|
+
function parseSpatialSceneArgs(argv: readonly string[]): SpatialSceneCommand | SpatialDesignCommand | SpatialProjectCommand | SpatialWorldCommand | SpatialAssetCommand {
|
|
3338
|
+
const action = argv[0];
|
|
3339
|
+
if (action === "design") return parseSpatialDesignArgs(argv.slice(1));
|
|
2995
3340
|
if (action === "world") return parseSpatialWorldArgs(argv.slice(1));
|
|
3341
|
+
if (action === "asset") return parseSpatialAssetArgs(argv.slice(1));
|
|
2996
3342
|
if (action === "project") {
|
|
2997
3343
|
const projectAction = argv[1];
|
|
2998
3344
|
if (projectAction === "snapshot") {
|
|
@@ -3022,6 +3368,11 @@ function parseSpatialSceneArgs(argv: readonly string[]): SpatialSceneCommand | S
|
|
|
3022
3368
|
const [path] = exactPositionals(parsed, 1, `slopcamera scene ${action} <scene.json> [--json]`);
|
|
3023
3369
|
return { kind: "spatial-scene", action: action === "check" ? "inspect" : action, path: path!, json: optionFlag(parsed, "--json") };
|
|
3024
3370
|
}
|
|
3371
|
+
if (action === "diff") {
|
|
3372
|
+
const parsed = parseOptions(argv.slice(1), JSON_SPEC);
|
|
3373
|
+
const [path, other] = exactPositionals(parsed, 2, "slopcamera scene diff <scene-a.json> <scene-b.json> [--json]");
|
|
3374
|
+
return { kind: "spatial-scene", action, path: path!, other: other!, json: optionFlag(parsed, "--json") };
|
|
3375
|
+
}
|
|
3025
3376
|
if (action === "patch") {
|
|
3026
3377
|
const parsed = parseOptions(argv.slice(1), { ...JSON_SPEC, "--patch": "value", "--output": "value" });
|
|
3027
3378
|
const [path] = exactPositionals(parsed, 1, "slopcamera scene patch <scene.json> --patch <patch.json> --output <new-scene.json>");
|
|
@@ -3043,6 +3394,54 @@ function parseSpatialSceneArgs(argv: readonly string[]): SpatialSceneCommand | S
|
|
|
3043
3394
|
if (camera === undefined || time === undefined || !/^\d+$/u.test(time) || !Number.isSafeInteger(Number(time))) fail("scene evaluate requires --camera and integer --time-us.");
|
|
3044
3395
|
return { kind: "spatial-scene", action, path: path!, camera, timeUs: Number(time), json: optionFlag(parsed, "--json") };
|
|
3045
3396
|
}
|
|
3397
|
+
if (action === "audit") {
|
|
3398
|
+
const parsed = parseOptions(argv.slice(1), { ...JSON_SPEC, "--camera": "value", "--times-us": "value", "--asset-bounds": "value" });
|
|
3399
|
+
const [path] = exactPositionals(parsed, 1, "slopcamera scene audit <scene.json> --camera <camera-id> [--times-us <csv>] [--asset-bounds <bounds-or-admission.json>] [--json]");
|
|
3400
|
+
const camera = optionString(parsed, "--camera"), times = optionString(parsed, "--times-us"), assetBounds = optionString(parsed, "--asset-bounds");
|
|
3401
|
+
if (camera === undefined) fail("scene audit requires --camera.");
|
|
3402
|
+
let timesUs: number[] | undefined;
|
|
3403
|
+
if (times !== undefined) {
|
|
3404
|
+
if (!/^\d+(,\d+)*$/u.test(times)) return fail("scene audit --times-us must be a comma-separated list of nonnegative integers.");
|
|
3405
|
+
timesUs = times.split(",").map(Number);
|
|
3406
|
+
if (timesUs.length > 64) return fail("scene audit --times-us is bounded to 64 samples.");
|
|
3407
|
+
}
|
|
3408
|
+
return { kind: "spatial-scene", action, path: path!, camera, ...(timesUs === undefined ? {} : { timesUs }), ...(assetBounds === undefined ? {} : { assetBounds }), json: optionFlag(parsed, "--json") };
|
|
3409
|
+
}
|
|
3410
|
+
if (action === "render-audit") {
|
|
3411
|
+
const parsed = parseOptions(argv.slice(1), { ...JSON_SPEC, "--camera": "value", "--times-us": "value" });
|
|
3412
|
+
const [path] = exactPositionals(parsed, 1, "slopcamera scene render-audit <scene.json> --camera <camera-id> [--times-us <csv>] [--json]");
|
|
3413
|
+
const camera = optionString(parsed, "--camera"), times = optionString(parsed, "--times-us");
|
|
3414
|
+
if (camera === undefined) fail("scene render-audit requires --camera.");
|
|
3415
|
+
let timesUs: number[] | undefined;
|
|
3416
|
+
if (times !== undefined) {
|
|
3417
|
+
if (!/^\d+(,\d+)*$/u.test(times)) return fail("scene render-audit --times-us must be a comma-separated list of nonnegative integers.");
|
|
3418
|
+
timesUs = times.split(",").map(Number);
|
|
3419
|
+
if (timesUs.length > 64) return fail("scene render-audit --times-us is bounded to 64 samples.");
|
|
3420
|
+
}
|
|
3421
|
+
return { kind: "spatial-scene", action, path: path!, camera, ...(timesUs === undefined ? {} : { timesUs }), json: optionFlag(parsed, "--json") };
|
|
3422
|
+
}
|
|
3423
|
+
if (action === "solve") {
|
|
3424
|
+
const parsed = parseOptions(argv.slice(1), { ...JSON_SPEC, "--goals": "value", "--output": "value", "--asset-bounds": "value" });
|
|
3425
|
+
const [path] = exactPositionals(parsed, 1, "slopcamera scene solve <scene.json> --goals <goals.json> [--output <patch.json>] [--asset-bounds <bounds-or-admission.json>] [--json]");
|
|
3426
|
+
const goals = optionString(parsed, "--goals"), output = optionString(parsed, "--output"), assetBounds = optionString(parsed, "--asset-bounds");
|
|
3427
|
+
if (goals === undefined) fail("scene solve requires --goals.");
|
|
3428
|
+
return { kind: "spatial-scene", action, path: path!, goals, ...(output === undefined ? {} : { output }), ...(assetBounds === undefined ? {} : { assetBounds }), json: optionFlag(parsed, "--json") };
|
|
3429
|
+
}
|
|
3430
|
+
if (action === "review") {
|
|
3431
|
+
const parsed = parseOptions(argv.slice(1), { ...JSON_SPEC, "--camera": "value", "--times-us": "value", "--allow-cloud-upload": "flag" });
|
|
3432
|
+
const [path] = exactPositionals(parsed, 1, "slopcamera scene review <scene.json> --camera <camera-id> [--times-us <csv>] --allow-cloud-upload [--json]");
|
|
3433
|
+
const camera = optionString(parsed, "--camera"), times = optionString(parsed, "--times-us");
|
|
3434
|
+
if (camera === undefined) fail("scene review requires --camera.");
|
|
3435
|
+
let timesUs: number[] | undefined;
|
|
3436
|
+
if (times !== undefined) {
|
|
3437
|
+
if (!/^\d+(,\d+)*$/u.test(times)) return fail("scene review --times-us must be a comma-separated list of nonnegative integers.");
|
|
3438
|
+
timesUs = times.split(",").map(Number);
|
|
3439
|
+
if (timesUs.length > 4) return fail("scene review --times-us is bounded to 4 samples.");
|
|
3440
|
+
if (timesUs.some(value => !Number.isSafeInteger(value))) return fail("scene review --times-us values must be safe integers.");
|
|
3441
|
+
if (new Set(timesUs).size !== timesUs.length) return fail("scene review --times-us values must be unique.");
|
|
3442
|
+
}
|
|
3443
|
+
return { kind: "spatial-scene", action, path: path!, camera, ...(timesUs === undefined ? {} : { timesUs }), allowCloudUpload: optionFlag(parsed, "--allow-cloud-upload"), json: optionFlag(parsed, "--json") };
|
|
3444
|
+
}
|
|
3046
3445
|
if (action === "plan" || action === "render") {
|
|
3047
3446
|
const parsed = parseOptions(argv.slice(1), { ...JSON_SPEC, "--request": "value", "--assets": "value", "--profile": "value" });
|
|
3048
3447
|
const [path] = exactPositionals(parsed, 1, `slopcamera scene ${action} <scene.json> --request <request.json> [--assets <bindings.json>]`);
|
|
@@ -3051,7 +3450,110 @@ function parseSpatialSceneArgs(argv: readonly string[]): SpatialSceneCommand | S
|
|
|
3051
3450
|
const executionProfile = spatialCliExecutionProfile(optionString(parsed, "--profile"));
|
|
3052
3451
|
return { kind: "spatial-scene", action, path: path!, request, ...(assets === undefined ? {} : { assets }), ...(executionProfile === undefined ? {} : { executionProfile }), json: optionFlag(parsed, "--json") };
|
|
3053
3452
|
}
|
|
3054
|
-
|
|
3453
|
+
if (action === "generate") {
|
|
3454
|
+
const parsed = parseOptions(argv.slice(1), { ...JSON_SPEC, "--module": "value", "--generator-id": "value", "--parameters": "value", "--seed": "value", "--into": "value", "--output": "value" });
|
|
3455
|
+
exactPositionals(parsed, 0, "slopcamera scene generate --module <generator.ts> --generator-id <id> [--parameters <params.json>] [--seed <n>] [--into <scene.json>] --output <new-scene.json> [--json]");
|
|
3456
|
+
const modulePath = optionString(parsed, "--module"), generatorId = optionString(parsed, "--generator-id"), output = optionString(parsed, "--output");
|
|
3457
|
+
if (modulePath === undefined || generatorId === undefined || output === undefined) fail("scene generate requires --module, --generator-id, and --output.");
|
|
3458
|
+
const seed = optionalNonNegativeInteger(optionString(parsed, "--seed"), "--seed");
|
|
3459
|
+
if (seed !== undefined && seed > 0xffff_ffff) fail("--seed must be between 0 and 4294967295.");
|
|
3460
|
+
const parameters = optionString(parsed, "--parameters"), into = optionString(parsed, "--into");
|
|
3461
|
+
return { kind: "spatial-scene", action, module: modulePath, generatorId, output, ...(parameters === undefined ? {} : { parameters }), ...(seed === undefined ? {} : { seed }), ...(into === undefined ? {} : { into }), json: optionFlag(parsed, "--json") };
|
|
3462
|
+
}
|
|
3463
|
+
if (action === "direction") {
|
|
3464
|
+
const directionAction = argv[1];
|
|
3465
|
+
if (directionAction === "check") {
|
|
3466
|
+
const parsed = parseOptions(argv.slice(2), { ...JSON_SPEC, "--scene": "value" });
|
|
3467
|
+
const [direction] = exactPositionals(parsed, 1, "slopcamera scene direction check <direction.json> --scene <scene.json> [--json]");
|
|
3468
|
+
const scene = optionString(parsed, "--scene");
|
|
3469
|
+
if (scene === undefined) fail("scene direction check requires --scene.");
|
|
3470
|
+
return { kind: "spatial-scene", action: "direction-check", direction: direction!, scene, json: optionFlag(parsed, "--json") };
|
|
3471
|
+
}
|
|
3472
|
+
if (directionAction === "plan" || directionAction === "gallery") {
|
|
3473
|
+
const parsed = parseOptions(argv.slice(2), { ...JSON_SPEC, "--axis": "value", "--camera": "value", "--output": "value", "--scene": "value" });
|
|
3474
|
+
const [direction] = exactPositionals(parsed, 1, `slopcamera scene direction ${directionAction} <direction.json> --scene <scene.json>${directionAction === "gallery" ? " --axis <axis>" : ""} [--camera <camera-id>] [--output <out.json>] [--json]`);
|
|
3475
|
+
const scene = optionString(parsed, "--scene"), camera = optionString(parsed, "--camera"), output = optionString(parsed, "--output"), axis = optionString(parsed, "--axis");
|
|
3476
|
+
if (scene === undefined) fail(`scene direction ${directionAction} requires --scene.`);
|
|
3477
|
+
if (directionAction === "gallery" && axis === undefined) fail("scene direction gallery requires --axis.");
|
|
3478
|
+
return directionAction === "gallery"
|
|
3479
|
+
? { kind: "spatial-scene", action: "direction-gallery", direction: direction!, scene, axis: axis!, ...(camera === undefined ? {} : { camera }), ...(output === undefined ? {} : { output }), json: optionFlag(parsed, "--json") }
|
|
3480
|
+
: { kind: "spatial-scene", action: "direction-plan", direction: direction!, scene, ...(camera === undefined ? {} : { camera }), ...(output === undefined ? {} : { output }), json: optionFlag(parsed, "--json") };
|
|
3481
|
+
}
|
|
3482
|
+
fail("Usage: slopcamera scene direction <check|plan|gallery> ...");
|
|
3483
|
+
}
|
|
3484
|
+
if (action === "effects") {
|
|
3485
|
+
const effectsAction = argv[1];
|
|
3486
|
+
if (effectsAction === "check") {
|
|
3487
|
+
const parsed = parseOptions(argv.slice(2), { ...JSON_SPEC, "--scene": "value" });
|
|
3488
|
+
const [effects] = exactPositionals(parsed, 1, "slopcamera scene effects check <effects.json> --scene <scene.json> [--json]");
|
|
3489
|
+
const scene = optionString(parsed, "--scene");
|
|
3490
|
+
if (scene === undefined) fail("scene effects check requires --scene.");
|
|
3491
|
+
return { kind: "spatial-scene", action: "effects-check", effects: effects!, scene, json: optionFlag(parsed, "--json") };
|
|
3492
|
+
}
|
|
3493
|
+
if (effectsAction === "plan") {
|
|
3494
|
+
const parsed = parseOptions(argv.slice(2), { ...JSON_SPEC, "--output": "value", "--scene": "value" });
|
|
3495
|
+
const [draft] = exactPositionals(parsed, 1, "slopcamera scene effects plan <draft.json> --scene <scene.json> [--output <effects.json>] [--json]");
|
|
3496
|
+
const scene = optionString(parsed, "--scene"), output = optionString(parsed, "--output");
|
|
3497
|
+
if (scene === undefined) fail("scene effects plan requires --scene.");
|
|
3498
|
+
return { kind: "spatial-scene", action: "effects-plan", draft: draft!, scene, ...(output === undefined ? {} : { output }), json: optionFlag(parsed, "--json") };
|
|
3499
|
+
}
|
|
3500
|
+
if (effectsAction === "bake") {
|
|
3501
|
+
const parsed = parseOptions(argv.slice(2), { ...JSON_SPEC, "--output": "value", "--scene": "value" });
|
|
3502
|
+
const [simulation] = exactPositionals(parsed, 1, "slopcamera scene effects bake <simulation.json> --scene <scene.json> --output <receipt.json> [--json]");
|
|
3503
|
+
const scene = optionString(parsed, "--scene"), output = optionString(parsed, "--output");
|
|
3504
|
+
if (scene === undefined || output === undefined) fail("scene effects bake requires --scene and --output.");
|
|
3505
|
+
return { kind: "spatial-scene", action: "effects-bake", simulation: simulation!, scene, output, json: optionFlag(parsed, "--json") };
|
|
3506
|
+
}
|
|
3507
|
+
fail("Usage: slopcamera scene effects <check|plan|bake> ...");
|
|
3508
|
+
}
|
|
3509
|
+
if (action === "behavior") {
|
|
3510
|
+
const behaviorAction = argv[1];
|
|
3511
|
+
if (behaviorAction === "check") {
|
|
3512
|
+
const parsed = parseOptions(argv.slice(2), { ...JSON_SPEC, "--scene": "value" });
|
|
3513
|
+
const [behavior] = exactPositionals(parsed, 1, "slopcamera scene behavior check <behavior.json> --scene <scene.json> [--json]");
|
|
3514
|
+
const scene = optionString(parsed, "--scene");
|
|
3515
|
+
if (scene === undefined) fail("scene behavior check requires --scene.");
|
|
3516
|
+
return { kind: "spatial-scene", action: "behavior-check", behavior: behavior!, scene, json: optionFlag(parsed, "--json") };
|
|
3517
|
+
}
|
|
3518
|
+
if (behaviorAction === "bake" || behaviorAction === "gallery") {
|
|
3519
|
+
const parsed = parseOptions(argv.slice(2), { ...JSON_SPEC, "--channel-map": "value", "--output": "value", "--scene": "value" });
|
|
3520
|
+
const [behavior] = exactPositionals(parsed, 1, `slopcamera scene behavior ${behaviorAction} <behavior.json> --scene <scene.json> [--channel-map <map.json>]${behaviorAction === "bake" ? " --output <bake.json>" : " [--output <gallery.json>]"} [--json]`);
|
|
3521
|
+
const scene = optionString(parsed, "--scene"), channelMap = optionString(parsed, "--channel-map"), output = optionString(parsed, "--output");
|
|
3522
|
+
if (scene === undefined) fail(`scene behavior ${behaviorAction} requires --scene.`);
|
|
3523
|
+
if (behaviorAction === "bake" && output === undefined) fail("scene behavior bake requires --output.");
|
|
3524
|
+
const shared = { kind: "spatial-scene" as const, behavior: behavior!, scene, ...(channelMap === undefined ? {} : { channelMap }), json: optionFlag(parsed, "--json") };
|
|
3525
|
+
return behaviorAction === "bake"
|
|
3526
|
+
? { ...shared, action: "behavior-bake", output: output! }
|
|
3527
|
+
: { ...shared, action: "behavior-gallery", ...(output === undefined ? {} : { output }) };
|
|
3528
|
+
}
|
|
3529
|
+
if (behaviorAction === "audit") {
|
|
3530
|
+
const parsed = parseOptions(argv.slice(2), { ...JSON_SPEC, "--output": "value" });
|
|
3531
|
+
const [bake] = exactPositionals(parsed, 1, "slopcamera scene behavior audit <bake.json> [--output <audit.json>] [--json]");
|
|
3532
|
+
const output = optionString(parsed, "--output");
|
|
3533
|
+
return { kind: "spatial-scene", action: "behavior-audit", bake: bake!, ...(output === undefined ? {} : { output }), json: optionFlag(parsed, "--json") };
|
|
3534
|
+
}
|
|
3535
|
+
fail("Usage: slopcamera scene behavior <check|bake|gallery|audit> ...");
|
|
3536
|
+
}
|
|
3537
|
+
if (action === "temporal-audit") {
|
|
3538
|
+
const parsed = parseOptions(argv.slice(1), { ...JSON_SPEC, "--camera": "value", "--contacts": "value", "--cut-before-us": "value", "--times-us": "value" });
|
|
3539
|
+
const [path] = exactPositionals(parsed, 1, "slopcamera scene temporal-audit <scene.json> --camera <camera-id> [--times-us <csv>] [--contacts <contacts.json>] [--cut-before-us <csv>] [--json]");
|
|
3540
|
+
const camera = optionString(parsed, "--camera"), times = optionString(parsed, "--times-us"), contacts = optionString(parsed, "--contacts"), cutBefore = optionString(parsed, "--cut-before-us");
|
|
3541
|
+
if (camera === undefined) fail("scene temporal-audit requires --camera.");
|
|
3542
|
+
let timesUs: number[] | undefined;
|
|
3543
|
+
if (times !== undefined) {
|
|
3544
|
+
if (!/^\d+(,\d+)*$/u.test(times)) return fail("scene temporal-audit --times-us must be a comma-separated list of nonnegative integers.");
|
|
3545
|
+
timesUs = times.split(",").map(Number);
|
|
3546
|
+
if (timesUs.length > 64) return fail("scene temporal-audit --times-us is bounded to 64 samples.");
|
|
3547
|
+
}
|
|
3548
|
+
let cutBeforeUs: number[] | undefined;
|
|
3549
|
+
if (cutBefore !== undefined) {
|
|
3550
|
+
if (!/^\d+(,\d+)*$/u.test(cutBefore)) return fail("scene temporal-audit --cut-before-us must be a comma-separated list of nonnegative integers.");
|
|
3551
|
+
cutBeforeUs = cutBefore.split(",").map(Number);
|
|
3552
|
+
if (cutBeforeUs.length > 64) return fail("scene temporal-audit --cut-before-us is bounded to 64 values.");
|
|
3553
|
+
}
|
|
3554
|
+
return { kind: "spatial-scene", action, path: path!, camera, ...(timesUs === undefined ? {} : { timesUs }), ...(contacts === undefined ? {} : { contacts }), ...(cutBeforeUs === undefined ? {} : { cutBeforeUs }), json: optionFlag(parsed, "--json") };
|
|
3555
|
+
}
|
|
3556
|
+
fail("Usage: slopcamera scene <init|check|inspect|diff|patch|evaluate|audit|render-audit|solve|review|camera-track|generate|plan|render|direction|effects|behavior|temporal-audit|asset|project|world> ...");
|
|
3055
3557
|
}
|
|
3056
3558
|
|
|
3057
3559
|
export function parseCliArgs(argv: readonly string[]): CliCommand {
|
|
@@ -3079,6 +3581,7 @@ export function parseCliArgs(argv: readonly string[]): CliCommand {
|
|
|
3079
3581
|
case "direct": return parseDirectingArgs(argv.slice(1));
|
|
3080
3582
|
case "scene": return parseSpatialSceneArgs(argv.slice(1));
|
|
3081
3583
|
case "operations": return parseOperations(argv.slice(1));
|
|
3584
|
+
case "capabilities": return parseCapabilities(argv.slice(1));
|
|
3082
3585
|
case "diagram": return parseDiagram(argv.slice(1));
|
|
3083
3586
|
case "image": return parseImage(argv.slice(1));
|
|
3084
3587
|
case "workflows": return parseWorkflows(argv.slice(1));
|