@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.
- package/NOTICE.md +14 -0
- package/README.md +294 -298
- package/apps/desktop/application/html-overlay-integrity.ts +27 -4
- package/apps/desktop/application/operation.ts +1 -1
- package/apps/desktop/application/operations/spatial-render.ts +1 -1
- package/apps/desktop/cli/capability-manifest.ts +15 -2
- package/apps/desktop/cli/commands.ts +1 -1
- package/apps/desktop/cli/help.ts +23 -4
- package/apps/desktop/cli/portable-surface.ts +1 -0
- package/apps/desktop/cli/verbs.ts +4 -0
- package/apps/desktop/dist/cli/main.js +306 -284
- package/dist/cli.js +24 -4
- package/dist/{index-842t02pp.js → index-m6g0ca9b.js} +1 -1
- package/dist/{index-y8spxs77.js → index-mgychzh3.js} +6 -3
- package/dist/{index-k9bjw80z.js → index-rxx27q8b.js} +4 -4
- package/dist/index.js +1 -1
- package/dist/operations.js +1 -1
- package/dist/workflow.js +1 -1
- package/docs/README.md +4 -1
- package/package.json +5 -3
- package/skills/slopcamera/SKILL.md +2 -0
- package/skills/slopcamera/references/customization.md +8 -1
- package/skills/slopcamera/references/icon-place.md +76 -0
- package/skills/slopcamera/references/install.md +2 -2
- package/skills/slopcamera/references/music-video.md +10 -2
- package/skills/slopcamera/references/soundtracks.md +58 -0
- package/src/bounded-file.ts +135 -0
- package/src/cli.ts +191 -0
- package/src/icon-scene.ts +695 -0
- package/src/index.ts +2 -0
- package/src/mcp/tools.ts +311 -0
- package/src/mcp/types.ts +4 -0
- package/src/operations.ts +306 -0
- package/src/soundtrack.ts +489 -0
- package/src/version.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{DrawingValidationError,SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS,SLOPCAMERA_PORTABLE_CAPABILITY_VERSION,SLOPCAMERA_VERSION,STUDIO_LIMITS,SlopcameraCapabilityCommandSchema,SlopcameraCapabilityEffectSchema,SlopcameraCapabilityManifestSchema,SlopcameraCapabilityModuleDeclarationSchema,SlopcameraCapabilityModuleSchema,SlopcameraCapabilityOperationSchema,SlopcameraCapabilityPreparationSchema,SlopcameraCapabilityProfileSchema,SlopcameraCapabilityQualificationSchema,SlopcameraCapabilityResourceSchema,SlopcameraCapabilityResumeSchema,SlopcameraCapabilityToolSchema,SlopcameraCapabilityWorkflowSchema,SlopcameraMcpToolRuntime,SlopcameraSceneVariantsSchema,StudioCapabilityNameSchema,StudioDigestSchema,StudioEngineOptionsSchema,StudioEngineSchema,StudioExecutionProfileSchema,StudioJobSchema,StudioOutputArtifactSchema,StudioOutputFormatSchema,StudioOutputInterpretationSchema,StudioOutputRoleSchema,StudioOutputSpecSchema,StudioPathSchema,StudioPlanSchema,StudioReceiptSchema,StudioRenderSchema,StudioRuntimeIdentitySchema,StudioSourceBundleSchema,StudioSourceSpaceSchema,VISUAL_STYLE_IDS,VISUAL_STYLE_PROFILES,VISUAL_STYLE_VARIATION_ALGORITHM,VisualStyleIdSchema,VisualStyleProfileSchema,WorkspaceBoundary,WorkspaceBoundaryError,artifactSummary,checkDiagramFile,checkDrawingFile,compileSlopcameraCapabilityManifest,createPortableSlopcameraCapabilityManifest,createVisualStyleDirection,critiqueSlopcameraIconSet,defineSlopcameraCapabilityModule,diagramApi,drawingMinimumGlyphHeightPt,drawingPageGeometry,drawingProfile,drawingSourceByteLimit,generateSlopcameraIconSet,getVisualStyleProfile,inspectStudioBundle,inspectStudioPlan,mcpMaximumRenderedPixels,mcpMaximumScale,mcpSourceByteLimit,parseDrawingSource,parseSlopcameraCapabilityManifest,parseSlopcameraIconSetSpec,parseSlopcameraSceneVariants,parseStudioJob,parseStudioPlan,parseStudioReceipt,parseStudioRuntimeIdentity,parseStudioSourceBundle,planSlopcameraSceneGallery,planStudioJob,readDiagramFile,readDrawingFile,renderDiagramFile,renderDrawing,renderDrawingFile,runMcpServer,sampleVisualStyleExposure,slopcameraApi,slopcameraIconSetDefaultPool,slopcameraIconSetDefaultSetRounds,slopcameraIconSetMaximumMembers,slopcameraIconSetMaximumNameBytes,slopcameraIconSetMaximumSetRounds,slopcameraIconSetSlugPattern,slopcameraMcpProtocolVersion,slopcameraMcpServerName,slopcameraMcpTools,slopcameraPortableCapabilityManifest,slopcameraSceneGalleryLimits,starterDrawingSource,studioJobSha256,studioOutputPath,studioRuntimeSha256,studioSourceBundleSha256,summarizeSceneVariantPatch,validateStudioReceipt,visualStyleFrameVariation}from"./index-k9bjw80z.js";import{bundledSkillPath,installSkill}from"./index-grk47tgs.js";import"./index-z1kd1x8j.js";import"./index-3cxf2c58.js";import{SlopcameraWorkflowError,defineSlopcameraWorkflow,runSlopcameraWorkflow}from"./index-842t02pp.js";import{DiagramValidationError,SlopcameraOperationError,StackLayoutError,builtInIcons,collectSlopcameraIconCandidates,composeSlopcameraImageGallery,critiqueIconRaster,estimateIconStrokePixels,executeSlopcameraOperation,executeSlopcameraOperationWithLease,extractIconLineArt,galleryCandidateId,galleryPromptFor,generateSlopcameraIcon,generateSlopcameraImageGallery,iconPromptFor,iconVisualGateProblems,isSlopcameraOperationCode,lintDiagram,loadIconLanguageRuntime,measureIconCandidateMetrics,parseDiagramSource,parseDiagramSpec,parseSlopcameraGalleryVary,parseSlopcameraOperationInput,planSlopcameraGallery,renderIconPreview,renderPng,renderSvg,resolveDiagramSource,resolveEdge,resolveStackLayout,searchSlopcameraOperations,serializeTldr,slopcameraGalleryAxes,slopcameraGalleryKinds,slopcameraGalleryLimits,slopcameraIconContextProfiles,slopcameraIconContexts,slopcameraIconCritiqueDefaultModel,slopcameraIconCritiqueTimeoutMs,slopcameraIconDefaultInk,slopcameraIconDefaultRounds,slopcameraIconMaximumRounds,slopcameraIconPanel,slopcameraIconSubjectMaximumBytes,slopcameraOperationCodes,slopcameraOperationHostResourceClaims,slopcameraOperationRegistry,stackLayoutDefaults,withSlopcameraOperationHostAdmission,writeAtomically}from"./index-y8spxs77.js";import{VTRACER_VERSION,VectorizeError,vectorizeDefaultLimits,vectorizeHardLimits,vectorizeImage,vectorizeProfileNames,vtracerReleases}from"./index-mnp0bftq.js";import{SlopcameraCloudError,createFixedGatewayFetch,generateSlopcameraImage,generateSlopcameraImageFile,resolveSlopcameraGatewayCredential,slopcameraGatewayApiBaseUrl,slopcameraGatewayCredentialStatus,slopcameraImageModels,slopcameraMaximumPromptBytes,slopcameraMaximumRawImageBytes,slopcameraResponseMediaTypes}from"./index-p74xy76d.js";import{HOST_RESOURCE_MAX_WAIT_MILLISECONDS,HostResourceError,createDefaultHostResourceCoordinator,createHostResourceCoordinator,createProcessLocalHostResourceCoordinator,defaultSlopcameraHostResourceProfile,defaultSlopcameraHostResourceStateRoot,normalizeHostResourceClaims,normalizeHostResourceProfile,slopcameraHostResourceNames}from"./index-b3geqczn.js";import"./index-80a36bc0.js";export{writeAtomically,withSlopcameraOperationHostAdmission,vtracerReleases,visualStyleFrameVariation,vectorizeProfileNames,vectorizeImage,vectorizeHardLimits,vectorizeDefaultLimits,validateStudioReceipt,summarizeSceneVariantPatch,studioSourceBundleSha256,studioRuntimeSha256,studioOutputPath,studioJobSha256,starterDrawingSource,stackLayoutDefaults,slopcameraSceneGalleryLimits,slopcameraResponseMediaTypes,slopcameraPortableCapabilityManifest,slopcameraOperationRegistry,slopcameraOperationHostResourceClaims,slopcameraOperationCodes,slopcameraMcpTools,slopcameraMcpServerName,slopcameraMcpProtocolVersion,slopcameraMaximumRawImageBytes,slopcameraMaximumPromptBytes,slopcameraImageModels,slopcameraIconSubjectMaximumBytes,slopcameraIconSetSlugPattern,slopcameraIconSetMaximumSetRounds,slopcameraIconSetMaximumNameBytes,slopcameraIconSetMaximumMembers,slopcameraIconSetDefaultSetRounds,slopcameraIconSetDefaultPool,slopcameraIconPanel,slopcameraIconMaximumRounds,slopcameraIconDefaultRounds,slopcameraIconDefaultInk,slopcameraIconCritiqueTimeoutMs,slopcameraIconCritiqueDefaultModel,slopcameraIconContexts,slopcameraIconContextProfiles,slopcameraHostResourceNames,slopcameraGatewayCredentialStatus,slopcameraGatewayApiBaseUrl,slopcameraGalleryLimits,slopcameraGalleryKinds,slopcameraGalleryAxes,slopcameraApi,serializeTldr,searchSlopcameraOperations,sampleVisualStyleExposure,runSlopcameraWorkflow,runMcpServer,resolveStackLayout,resolveSlopcameraGatewayCredential,resolveEdge,resolveDiagramSource,renderSvg,renderPng,renderIconPreview,renderDrawingFile,renderDrawing,renderDiagramFile,readDrawingFile,readDiagramFile,planStudioJob,planSlopcameraSceneGallery,planSlopcameraGallery,parseStudioSourceBundle,parseStudioRuntimeIdentity,parseStudioReceipt,parseStudioPlan,parseStudioJob,parseSlopcameraSceneVariants,parseSlopcameraOperationInput,parseSlopcameraIconSetSpec,parseSlopcameraGalleryVary,parseSlopcameraCapabilityManifest,parseDrawingSource,parseDiagramSpec,parseDiagramSource,normalizeHostResourceProfile,normalizeHostResourceClaims,measureIconCandidateMetrics,mcpSourceByteLimit,mcpMaximumScale,mcpMaximumRenderedPixels,loadIconLanguageRuntime,lintDiagram,isSlopcameraOperationCode,installSkill,inspectStudioPlan,inspectStudioBundle,iconVisualGateProblems,iconPromptFor,getVisualStyleProfile,generateSlopcameraImageGallery,generateSlopcameraImageFile,generateSlopcameraImage,generateSlopcameraIconSet,generateSlopcameraIcon,galleryPromptFor,galleryCandidateId,extractIconLineArt,executeSlopcameraOperationWithLease,executeSlopcameraOperation,estimateIconStrokePixels,drawingSourceByteLimit,drawingProfile,drawingPageGeometry,drawingMinimumGlyphHeightPt,diagramApi,defineSlopcameraWorkflow,defineSlopcameraCapabilityModule,defaultSlopcameraHostResourceStateRoot,defaultSlopcameraHostResourceProfile,critiqueSlopcameraIconSet,critiqueIconRaster,createVisualStyleDirection,createProcessLocalHostResourceCoordinator,createPortableSlopcameraCapabilityManifest,createHostResourceCoordinator,createFixedGatewayFetch,createDefaultHostResourceCoordinator,composeSlopcameraImageGallery,compileSlopcameraCapabilityManifest,collectSlopcameraIconCandidates,checkDrawingFile,checkDiagramFile,bundledSkillPath,builtInIcons,artifactSummary,WorkspaceBoundaryError,WorkspaceBoundary,VisualStyleProfileSchema,VisualStyleIdSchema,VectorizeError,VTRACER_VERSION,VISUAL_STYLE_VARIATION_ALGORITHM,VISUAL_STYLE_PROFILES,VISUAL_STYLE_IDS,StudioSourceSpaceSchema,StudioSourceBundleSchema,StudioRuntimeIdentitySchema,StudioRenderSchema,StudioReceiptSchema,StudioPlanSchema,StudioPathSchema,StudioOutputSpecSchema,StudioOutputRoleSchema,StudioOutputInterpretationSchema,StudioOutputFormatSchema,StudioOutputArtifactSchema,StudioJobSchema,StudioExecutionProfileSchema,StudioEngineSchema,StudioEngineOptionsSchema,StudioDigestSchema,StudioCapabilityNameSchema,StackLayoutError,SlopcameraWorkflowError,SlopcameraSceneVariantsSchema,SlopcameraOperationError,SlopcameraMcpToolRuntime,SlopcameraCloudError,SlopcameraCapabilityWorkflowSchema,SlopcameraCapabilityToolSchema,SlopcameraCapabilityResumeSchema,SlopcameraCapabilityResourceSchema,SlopcameraCapabilityQualificationSchema,SlopcameraCapabilityProfileSchema,SlopcameraCapabilityPreparationSchema,SlopcameraCapabilityOperationSchema,SlopcameraCapabilityModuleSchema,SlopcameraCapabilityModuleDeclarationSchema,SlopcameraCapabilityManifestSchema,SlopcameraCapabilityEffectSchema,SlopcameraCapabilityCommandSchema,STUDIO_LIMITS,SLOPCAMERA_VERSION,SLOPCAMERA_PORTABLE_CAPABILITY_VERSION,SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS,HostResourceError,HOST_RESOURCE_MAX_WAIT_MILLISECONDS,DrawingValidationError,DiagramValidationError};
|
|
2
|
+
import{DrawingValidationError,SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS,SLOPCAMERA_PORTABLE_CAPABILITY_VERSION,SLOPCAMERA_VERSION,STUDIO_LIMITS,SlopcameraCapabilityCommandSchema,SlopcameraCapabilityEffectSchema,SlopcameraCapabilityManifestSchema,SlopcameraCapabilityModuleDeclarationSchema,SlopcameraCapabilityModuleSchema,SlopcameraCapabilityOperationSchema,SlopcameraCapabilityPreparationSchema,SlopcameraCapabilityProfileSchema,SlopcameraCapabilityQualificationSchema,SlopcameraCapabilityResourceSchema,SlopcameraCapabilityResumeSchema,SlopcameraCapabilityToolSchema,SlopcameraCapabilityWorkflowSchema,SlopcameraMcpToolRuntime,SlopcameraSceneVariantsSchema,StudioCapabilityNameSchema,StudioDigestSchema,StudioEngineOptionsSchema,StudioEngineSchema,StudioExecutionProfileSchema,StudioJobSchema,StudioOutputArtifactSchema,StudioOutputFormatSchema,StudioOutputInterpretationSchema,StudioOutputRoleSchema,StudioOutputSpecSchema,StudioPathSchema,StudioPlanSchema,StudioReceiptSchema,StudioRenderSchema,StudioRuntimeIdentitySchema,StudioSourceBundleSchema,StudioSourceSpaceSchema,VISUAL_STYLE_IDS,VISUAL_STYLE_PROFILES,VISUAL_STYLE_VARIATION_ALGORITHM,VisualStyleIdSchema,VisualStyleProfileSchema,WorkspaceBoundary,WorkspaceBoundaryError,artifactSummary,checkDiagramFile,checkDrawingFile,compileSlopcameraCapabilityManifest,createPortableSlopcameraCapabilityManifest,createVisualStyleDirection,critiqueSlopcameraIconSet,defineSlopcameraCapabilityModule,diagramApi,drawingMinimumGlyphHeightPt,drawingPageGeometry,drawingProfile,drawingSourceByteLimit,generateSlopcameraIconSet,getVisualStyleProfile,inspectStudioBundle,inspectStudioPlan,mcpMaximumRenderedPixels,mcpMaximumScale,mcpSourceByteLimit,parseDrawingSource,parseSlopcameraCapabilityManifest,parseSlopcameraIconSetSpec,parseSlopcameraSceneVariants,parseStudioJob,parseStudioPlan,parseStudioReceipt,parseStudioRuntimeIdentity,parseStudioSourceBundle,planSlopcameraSceneGallery,planStudioJob,readDiagramFile,readDrawingFile,renderDiagramFile,renderDrawing,renderDrawingFile,runMcpServer,sampleVisualStyleExposure,slopcameraApi,slopcameraIconSetDefaultPool,slopcameraIconSetDefaultSetRounds,slopcameraIconSetMaximumMembers,slopcameraIconSetMaximumNameBytes,slopcameraIconSetMaximumSetRounds,slopcameraIconSetSlugPattern,slopcameraMcpProtocolVersion,slopcameraMcpServerName,slopcameraMcpTools,slopcameraPortableCapabilityManifest,slopcameraSceneGalleryLimits,starterDrawingSource,studioJobSha256,studioOutputPath,studioRuntimeSha256,studioSourceBundleSha256,summarizeSceneVariantPatch,validateStudioReceipt,visualStyleFrameVariation}from"./index-rxx27q8b.js";import{bundledSkillPath,installSkill}from"./index-grk47tgs.js";import"./index-z1kd1x8j.js";import"./index-3cxf2c58.js";import{SlopcameraWorkflowError,defineSlopcameraWorkflow,runSlopcameraWorkflow}from"./index-m6g0ca9b.js";import{DiagramValidationError,SlopcameraIconError,SlopcameraOperationError,SlopcameraSoundtrackError,StackLayoutError,assertInertIconSvg,builtInIcons,collectSlopcameraIconCandidates,composeSlopcameraIcon,composeSlopcameraImageGallery,composeSlopcameraSoundtrack,critiqueIconRaster,deriveSlopcameraSoundtrackGrid,detectSlopcameraSoundtrackFormat,estimateIconStrokePixels,executeSlopcameraOperation,executeSlopcameraOperationWithLease,extractIconLineArt,galleryCandidateId,galleryPromptFor,generateSlopcameraIcon,generateSlopcameraImageGallery,iconPromptFor,iconVisualGateProblems,isSlopcameraOperationCode,lintDiagram,loadIconLanguageRuntime,measureIconCandidateMetrics,parseDiagramSource,parseDiagramSpec,parseSlopcameraGalleryVary,parseSlopcameraOperationInput,planSlopcameraGallery,projectSlopcameraSoundtrackGrid,renderIconPreview,renderPng,renderSlopcameraIcon,renderSvg,resolveDiagramSource,resolveEdge,resolveStackLayout,searchSlopcameraOperations,serializeTldr,slopcameraGalleryAxes,slopcameraGalleryKinds,slopcameraGalleryLimits,slopcameraIconContextProfiles,slopcameraIconContexts,slopcameraIconCritiqueDefaultModel,slopcameraIconCritiqueTimeoutMs,slopcameraIconDefaultInk,slopcameraIconDefaultLanguage,slopcameraIconDefaultRounds,slopcameraIconEngine,slopcameraIconLanguages,slopcameraIconMaximumRounds,slopcameraIconPalettes,slopcameraIconPanel,slopcameraIconSceneLimits,slopcameraIconSubjectMaximumBytes,slopcameraOperationCodes,slopcameraOperationHostResourceClaims,slopcameraOperationRegistry,slopcameraSoundtrackEngine,slopcameraSoundtrackFormats,slopcameraSoundtrackLimits,soundtrackBeatTimeUs,stackLayoutDefaults,withSlopcameraOperationHostAdmission,writeAtomically}from"./index-mgychzh3.js";import{VTRACER_VERSION,VectorizeError,vectorizeDefaultLimits,vectorizeHardLimits,vectorizeImage,vectorizeProfileNames,vtracerReleases}from"./index-mnp0bftq.js";import{SlopcameraCloudError,createFixedGatewayFetch,generateSlopcameraImage,generateSlopcameraImageFile,resolveSlopcameraGatewayCredential,slopcameraGatewayApiBaseUrl,slopcameraGatewayCredentialStatus,slopcameraImageModels,slopcameraMaximumPromptBytes,slopcameraMaximumRawImageBytes,slopcameraResponseMediaTypes}from"./index-p74xy76d.js";import{HOST_RESOURCE_MAX_WAIT_MILLISECONDS,HostResourceError,createDefaultHostResourceCoordinator,createHostResourceCoordinator,createProcessLocalHostResourceCoordinator,defaultSlopcameraHostResourceProfile,defaultSlopcameraHostResourceStateRoot,normalizeHostResourceClaims,normalizeHostResourceProfile,slopcameraHostResourceNames}from"./index-b3geqczn.js";import"./index-80a36bc0.js";export{writeAtomically,withSlopcameraOperationHostAdmission,vtracerReleases,visualStyleFrameVariation,vectorizeProfileNames,vectorizeImage,vectorizeHardLimits,vectorizeDefaultLimits,validateStudioReceipt,summarizeSceneVariantPatch,studioSourceBundleSha256,studioRuntimeSha256,studioOutputPath,studioJobSha256,starterDrawingSource,stackLayoutDefaults,soundtrackBeatTimeUs,slopcameraSoundtrackLimits,slopcameraSoundtrackFormats,slopcameraSoundtrackEngine,slopcameraSceneGalleryLimits,slopcameraResponseMediaTypes,slopcameraPortableCapabilityManifest,slopcameraOperationRegistry,slopcameraOperationHostResourceClaims,slopcameraOperationCodes,slopcameraMcpTools,slopcameraMcpServerName,slopcameraMcpProtocolVersion,slopcameraMaximumRawImageBytes,slopcameraMaximumPromptBytes,slopcameraImageModels,slopcameraIconSubjectMaximumBytes,slopcameraIconSetSlugPattern,slopcameraIconSetMaximumSetRounds,slopcameraIconSetMaximumNameBytes,slopcameraIconSetMaximumMembers,slopcameraIconSetDefaultSetRounds,slopcameraIconSetDefaultPool,slopcameraIconSceneLimits,slopcameraIconPanel,slopcameraIconPalettes,slopcameraIconMaximumRounds,slopcameraIconLanguages,slopcameraIconEngine,slopcameraIconDefaultRounds,slopcameraIconDefaultLanguage,slopcameraIconDefaultInk,slopcameraIconCritiqueTimeoutMs,slopcameraIconCritiqueDefaultModel,slopcameraIconContexts,slopcameraIconContextProfiles,slopcameraHostResourceNames,slopcameraGatewayCredentialStatus,slopcameraGatewayApiBaseUrl,slopcameraGalleryLimits,slopcameraGalleryKinds,slopcameraGalleryAxes,slopcameraApi,serializeTldr,searchSlopcameraOperations,sampleVisualStyleExposure,runSlopcameraWorkflow,runMcpServer,resolveStackLayout,resolveSlopcameraGatewayCredential,resolveEdge,resolveDiagramSource,renderSvg,renderSlopcameraIcon,renderPng,renderIconPreview,renderDrawingFile,renderDrawing,renderDiagramFile,readDrawingFile,readDiagramFile,projectSlopcameraSoundtrackGrid,planStudioJob,planSlopcameraSceneGallery,planSlopcameraGallery,parseStudioSourceBundle,parseStudioRuntimeIdentity,parseStudioReceipt,parseStudioPlan,parseStudioJob,parseSlopcameraSceneVariants,parseSlopcameraOperationInput,parseSlopcameraIconSetSpec,parseSlopcameraGalleryVary,parseSlopcameraCapabilityManifest,parseDrawingSource,parseDiagramSpec,parseDiagramSource,normalizeHostResourceProfile,normalizeHostResourceClaims,measureIconCandidateMetrics,mcpSourceByteLimit,mcpMaximumScale,mcpMaximumRenderedPixels,loadIconLanguageRuntime,lintDiagram,isSlopcameraOperationCode,installSkill,inspectStudioPlan,inspectStudioBundle,iconVisualGateProblems,iconPromptFor,getVisualStyleProfile,generateSlopcameraImageGallery,generateSlopcameraImageFile,generateSlopcameraImage,generateSlopcameraIconSet,generateSlopcameraIcon,galleryPromptFor,galleryCandidateId,extractIconLineArt,executeSlopcameraOperationWithLease,executeSlopcameraOperation,estimateIconStrokePixels,drawingSourceByteLimit,drawingProfile,drawingPageGeometry,drawingMinimumGlyphHeightPt,diagramApi,detectSlopcameraSoundtrackFormat,deriveSlopcameraSoundtrackGrid,defineSlopcameraWorkflow,defineSlopcameraCapabilityModule,defaultSlopcameraHostResourceStateRoot,defaultSlopcameraHostResourceProfile,critiqueSlopcameraIconSet,critiqueIconRaster,createVisualStyleDirection,createProcessLocalHostResourceCoordinator,createPortableSlopcameraCapabilityManifest,createHostResourceCoordinator,createFixedGatewayFetch,createDefaultHostResourceCoordinator,composeSlopcameraSoundtrack,composeSlopcameraImageGallery,composeSlopcameraIcon,compileSlopcameraCapabilityManifest,collectSlopcameraIconCandidates,checkDrawingFile,checkDiagramFile,bundledSkillPath,builtInIcons,assertInertIconSvg,artifactSummary,WorkspaceBoundaryError,WorkspaceBoundary,VisualStyleProfileSchema,VisualStyleIdSchema,VectorizeError,VTRACER_VERSION,VISUAL_STYLE_VARIATION_ALGORITHM,VISUAL_STYLE_PROFILES,VISUAL_STYLE_IDS,StudioSourceSpaceSchema,StudioSourceBundleSchema,StudioRuntimeIdentitySchema,StudioRenderSchema,StudioReceiptSchema,StudioPlanSchema,StudioPathSchema,StudioOutputSpecSchema,StudioOutputRoleSchema,StudioOutputInterpretationSchema,StudioOutputFormatSchema,StudioOutputArtifactSchema,StudioJobSchema,StudioExecutionProfileSchema,StudioEngineSchema,StudioEngineOptionsSchema,StudioDigestSchema,StudioCapabilityNameSchema,StackLayoutError,SlopcameraWorkflowError,SlopcameraSoundtrackError,SlopcameraSceneVariantsSchema,SlopcameraOperationError,SlopcameraMcpToolRuntime,SlopcameraIconError,SlopcameraCloudError,SlopcameraCapabilityWorkflowSchema,SlopcameraCapabilityToolSchema,SlopcameraCapabilityResumeSchema,SlopcameraCapabilityResourceSchema,SlopcameraCapabilityQualificationSchema,SlopcameraCapabilityProfileSchema,SlopcameraCapabilityPreparationSchema,SlopcameraCapabilityOperationSchema,SlopcameraCapabilityModuleSchema,SlopcameraCapabilityModuleDeclarationSchema,SlopcameraCapabilityManifestSchema,SlopcameraCapabilityEffectSchema,SlopcameraCapabilityCommandSchema,STUDIO_LIMITS,SLOPCAMERA_VERSION,SLOPCAMERA_PORTABLE_CAPABILITY_VERSION,SLOPCAMERA_CAPABILITY_MANIFEST_LIMITS,HostResourceError,HOST_RESOURCE_MAX_WAIT_MILLISECONDS,DrawingValidationError,DiagramValidationError};
|
package/dist/operations.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{SlopcameraOperationError,executeSlopcameraOperation,executeSlopcameraOperationWithLease,isSlopcameraOperationCode,parseSlopcameraOperationInput,searchSlopcameraOperations,slopcameraOperationCodes,slopcameraOperationHostResourceClaims,slopcameraOperationRegistry,withSlopcameraOperationHostAdmission}from"./index-
|
|
2
|
+
import{SlopcameraOperationError,executeSlopcameraOperation,executeSlopcameraOperationWithLease,isSlopcameraOperationCode,parseSlopcameraOperationInput,searchSlopcameraOperations,slopcameraOperationCodes,slopcameraOperationHostResourceClaims,slopcameraOperationRegistry,withSlopcameraOperationHostAdmission}from"./index-mgychzh3.js";import"./index-mnp0bftq.js";import"./index-p74xy76d.js";import"./index-b3geqczn.js";import"./index-80a36bc0.js";export{withSlopcameraOperationHostAdmission,slopcameraOperationRegistry,slopcameraOperationHostResourceClaims,slopcameraOperationCodes,searchSlopcameraOperations,parseSlopcameraOperationInput,isSlopcameraOperationCode,executeSlopcameraOperationWithLease,executeSlopcameraOperation,SlopcameraOperationError};
|
package/dist/workflow.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{SlopcameraWorkflowError,defineSlopcameraWorkflow,runSlopcameraWorkflow}from"./index-
|
|
2
|
+
import{SlopcameraWorkflowError,defineSlopcameraWorkflow,runSlopcameraWorkflow}from"./index-m6g0ca9b.js";import"./index-mgychzh3.js";import"./index-mnp0bftq.js";import"./index-p74xy76d.js";import"./index-b3geqczn.js";import"./index-80a36bc0.js";export{runSlopcameraWorkflow,defineSlopcameraWorkflow,SlopcameraWorkflowError};
|
package/docs/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SlopCamera documentation
|
|
2
2
|
|
|
3
|
-
Slopcamera is a media studio for coding agents.
|
|
3
|
+
Slopcamera is a media studio for coding agents. Your agent writes a short source file, the CLI checks and renders it, and a revision is an edit to that file and a new render. Choose a guide for the work you want to do.
|
|
4
4
|
|
|
5
5
|
Install the [current Slopcamera release](../README.md#install-slopcamera) for the CLI, SDK, and matching Agent Skill. Each guide names its local runtimes and any correction that needs [current source](how-to/use-current-source.md). Some examples import TypeScript from the repository and need a checkout to run. Historical Atet archives retain their original package and commands. The [CLI parity table](cli-parity.md) maps every action of the retired menu-bar companion to a command. The [capability reference](reference/capabilities.md) distinguishes them and lists local runtime requirements.
|
|
6
6
|
|
|
@@ -35,12 +35,15 @@ Install the [current Slopcamera release](../README.md#install-slopcamera) for th
|
|
|
35
35
|
|
|
36
36
|
- [Capabilities, versions, and platforms](reference/capabilities.md): current Slopcamera capabilities, historical Atet versions, and supported runtime boundaries.
|
|
37
37
|
- [SDK surfaces](reference/sdk.md): portable and local imports, operation projections, and execution contracts.
|
|
38
|
+
- [Techniques catalog](https://slopcamera.com/docs/reference/techniques): every packaged technique by job, with its first command, guide, and a rendered example where one exists.
|
|
38
39
|
- [CLI help](reference/capabilities.md#discover-the-installed-contract): exact grammar and JSON schemas from the installed host.
|
|
39
40
|
|
|
40
41
|
## Understand the design
|
|
41
42
|
|
|
42
43
|
- [Source, representations, and projects](architecture.md): what stays editable, what a receipt proves, and how local and cloud work fit together.
|
|
43
44
|
- [Extension architecture](extension-architecture.md): the closed registry, inert recipe packs, trusted workflows, and where authored code can and cannot go.
|
|
45
|
+
- [Why Slopcamera](https://slopcamera.com/docs/explanation/why-slopcamera): why the agent keeps a source file and reuses installed techniques, with comparisons to [Remotion](https://slopcamera.com/docs/explanation/slopcamera-vs-remotion), [HyperFrames](https://slopcamera.com/docs/explanation/slopcamera-vs-hyperframes), and [other tools](https://slopcamera.com/docs/explanation/remotion-alternatives-for-coding-agents).
|
|
46
|
+
- [Token benchmark](https://slopcamera.com/docs/explanation/token-benchmark): agent token use and cost on four media tasks with and without Slopcamera installed, with the harness and raw results in [`bench/token-savings`](../bench/token-savings/README.md).
|
|
44
47
|
- [Choose an HTML authoring surface](html-overlay-creative-toolkit.md): why DOM, vector, Three.js, and explicit GPU profiles serve different jobs. Its ecosystem research is dated separately from its supported locks.
|
|
45
48
|
|
|
46
49
|
## Work with an agent
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hraness/slopcamera",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"description": "SlopCamera lets your coding agent make images, diagrams, animation, 3D scenes, and video from source files it can keep revising.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -220,7 +220,7 @@
|
|
|
220
220
|
"typecheck:sdk": "tsc --noEmit -p tsconfig.json",
|
|
221
221
|
"typecheck:desktop": "tsc --noEmit -p apps/desktop/tsconfig.json",
|
|
222
222
|
"lint": "bun run lint:sdk && bun run lint:desktop && bun run lint:api",
|
|
223
|
-
"lint:sdk": "eslint src packages/scene scripts",
|
|
223
|
+
"lint:sdk": "eslint src packages/scene scripts bench",
|
|
224
224
|
"lint:desktop": "eslint apps/desktop/contracts apps/desktop/core apps/desktop/application apps/desktop/code apps/desktop/workflows apps/desktop/html-overlay apps/desktop/cli apps/desktop/qualification apps/desktop/analysis apps/desktop/studio",
|
|
225
225
|
"test": "bun run test:sdk && bun run test:desktop && bun run test:api && bun run --cwd apps/web test",
|
|
226
226
|
"test:sdk": "bun test ./src ./packages/scene",
|
|
@@ -242,7 +242,7 @@
|
|
|
242
242
|
"test:html-overlay:operation:macos": "SLOPCAMERA_RUN_HTML_OVERLAY_OPERATION_SMOKE=1 bun test ./apps/desktop/application/operations/media/html-overlay.test.ts",
|
|
243
243
|
"verify:html-overlay:macos": "bun run test:html-overlay:browser:macos && bun run test:html-overlay:libraries:macos && bun run test:html-overlay:operation:macos",
|
|
244
244
|
"benchmark:code-concurrency": "bun run ./apps/desktop/code/concurrency-benchmark.ts",
|
|
245
|
-
"check:release-workflows": "bun test ./scripts/release-workflow.test.ts ./scripts/github-release.test.ts",
|
|
245
|
+
"check:release-workflows": "bun test ./scripts/release-workflow.test.ts ./scripts/github-release.test.ts ./scripts/dependency-admissions.test.ts",
|
|
246
246
|
"check:schema": "bun run ./scripts/validate-schema.ts",
|
|
247
247
|
"check:skill": "bun run ./scripts/validate-skill.ts && bun test ./scripts/social-collage-compositor.test.ts && bun examples/style-portfolio/verify-animation-source.mjs",
|
|
248
248
|
"check:standalone": "bun test ./scripts/standalone-support-fixture.test.ts && bun run ./scripts/check-standalone.ts",
|
|
@@ -273,6 +273,8 @@
|
|
|
273
273
|
"@ai-sdk/gateway-v4": "npm:@ai-sdk/gateway@^4.0.27",
|
|
274
274
|
"@hraness/algal": "github:hraness/algal#c46264a",
|
|
275
275
|
"@hraness/desktop-foundation": "https://github.com/hraness/desktop-foundation/releases/download/v0.9.0/hraness-desktop-foundation-0.9.0.tgz",
|
|
276
|
+
"@hraness/iconplace": "0.1.0",
|
|
277
|
+
"@hraness/soundfish": "0.7.0",
|
|
276
278
|
"@hraness/support-foundation": "github:hraness/support-foundation#8bb514d24b79dc3f305390700ae312cab88e7ad2",
|
|
277
279
|
"@noble/hashes": "2.2.0",
|
|
278
280
|
"@paper-design/shaders": "0.0.77",
|
|
@@ -30,6 +30,8 @@ Slopcamera installs from its verified release archive or from source. Historical
|
|
|
30
30
|
| Patent-style drawing sheets, physical margins, monochrome SVGs or a drawing PDF | [Drawing sheets](references/patent-drawings.md) |
|
|
31
31
|
| Custom diagram themes, fonts or icon packages | [Customization](references/customization.md) |
|
|
32
32
|
| Raster artwork converted to SVG | [Vectorization](references/vectorization.md) |
|
|
33
|
+
| Deterministic vector icon, icon scene or construction program, no model | [Icon scenes](references/icon-place.md) |
|
|
34
|
+
| Tempo, meter and section cues from a Soundfish score or MIDI file | [Soundtracks](references/soundtracks.md) |
|
|
33
35
|
| Clean up, caption, frame, or deliver existing recordings and footage | [Video projects](references/video-projects.md) |
|
|
34
36
|
| Music video, dancing mascot or timed HTML scene with a local soundtrack | [Music videos](references/music-video.md) |
|
|
35
37
|
| Product launch film, UI mockup motion, kinetic type, or coming from HyperFrames or Remotion | [Launch films](references/launch-films.md); for a whole Hraness product launch, the `product-launch` agent skill |
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Fonts and icon adapters
|
|
2
2
|
|
|
3
|
-
`slopcamera` deliberately ships no commercial font and no large icon set.
|
|
3
|
+
`slopcamera` deliberately ships no commercial font and no large icon set. Its
|
|
4
|
+
one built-in icon library, icon.place, is described below.
|
|
4
5
|
|
|
5
6
|
## Custom font
|
|
6
7
|
|
|
@@ -72,6 +73,12 @@ package's data into `{ viewBox, body }`. Keep that package in the consuming
|
|
|
72
73
|
repository rather than adding it to `slopcamera`. Preserve the icon package's
|
|
73
74
|
license and attribution requirements.
|
|
74
75
|
|
|
76
|
+
icon.place is the one icon library built into `slopcamera`. It draws its own
|
|
77
|
+
icon scenes and construction programs to standalone SVG through
|
|
78
|
+
`slopcamera image icon compose|render`; see [icon scenes](icon-place.md). It
|
|
79
|
+
does not add icons to the diagram `icons` table, so diagram icons from any
|
|
80
|
+
other package still go through a local adapter.
|
|
81
|
+
|
|
75
82
|
Icon bodies may contain ordinary SVG geometry such as `path`, `circle`, `rect`,
|
|
76
83
|
`line`, `polyline`, and `polygon`. Scripts, event handlers, `foreignObject`, and
|
|
77
84
|
embedded web content are rejected.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Compose and render vector icon scenes
|
|
2
|
+
|
|
3
|
+
Use this workflow when the user wants a deterministic vector icon, a small
|
|
4
|
+
composed scene of icons, or a drawn construction program, without a model or a
|
|
5
|
+
network request. Slopcamera bundles the icon.place library at one exact version
|
|
6
|
+
for this. For a generated product mark or topic icon from a text brief, use
|
|
7
|
+
[brand illustrations](brand-illustrations.md) instead.
|
|
8
|
+
|
|
9
|
+
## Pick a source
|
|
10
|
+
|
|
11
|
+
Both commands read one local JSON file of at most 1 MiB. The kind is detected
|
|
12
|
+
from its content:
|
|
13
|
+
|
|
14
|
+
- A **scene**: up to eight placed icons with a canvas and a background.
|
|
15
|
+
- A **collection**: up to six layered icons that compose into one scene.
|
|
16
|
+
- A **construction program**: parts, operations and a drawing recipe that
|
|
17
|
+
compile to one drawing.
|
|
18
|
+
- A **recipe** that an earlier render wrote. A recipe records the source, the
|
|
19
|
+
render settings and the output digests.
|
|
20
|
+
|
|
21
|
+
Keep the source in the workspace as the authoritative file. The SVG is a
|
|
22
|
+
replaceable derivative.
|
|
23
|
+
|
|
24
|
+
## Compose
|
|
25
|
+
|
|
26
|
+
`compose` parses and solves the source and reports its digests, element count
|
|
27
|
+
and diagnostics. It writes nothing unless `--output` names a `.json` file for the
|
|
28
|
+
canonical solved document:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
slopcamera image icon compose icons/window.json --json
|
|
32
|
+
slopcamera image icon compose icons/window.json --output icons/window.solved.json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Composing a solved document again gives the same digests. Report any
|
|
36
|
+
diagnostics; they are the library's own layout findings.
|
|
37
|
+
|
|
38
|
+
## Render
|
|
39
|
+
|
|
40
|
+
`render` draws the source to an inert SVG. `--recipe` also writes a replayable
|
|
41
|
+
recipe:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
slopcamera image icon render icons/window.json --output icons/window.svg \
|
|
45
|
+
--recipe icons/window.recipe.json --size 256 --palette ink
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- `--size` sets the output edge from 16 to 1024 pixels.
|
|
49
|
+
- `--palette` (`original`, `ink`, `earth` or `night`) applies to scenes and
|
|
50
|
+
collections. `--background` paints the paper behind any source.
|
|
51
|
+
- `--language` selects one of the drawing languages for a construction program,
|
|
52
|
+
such as `outline`, `woodcut` or `stipple`. `slopcamera help image` lists them.
|
|
53
|
+
|
|
54
|
+
To reproduce an icon, render its recipe. A recipe fixes its own settings, so do
|
|
55
|
+
not pass `--size`, `--palette`, `--background` or `--language` with it. Replay
|
|
56
|
+
fails if the recipe was edited after it was written or if the drawing no longer
|
|
57
|
+
matches the recorded digests; report that instead of re-rendering from scratch.
|
|
58
|
+
|
|
59
|
+
The same renders are available as the `compose_icon` and `render_icon` MCP
|
|
60
|
+
tools with root-relative paths, and as the `slopcamera.icon.compose` and
|
|
61
|
+
`slopcamera.icon.render` operations.
|
|
62
|
+
|
|
63
|
+
## Checks
|
|
64
|
+
|
|
65
|
+
- The output is a path-only SVG. Scripts, styles, images, event handlers,
|
|
66
|
+
external references and foreign content are rejected before anything is
|
|
67
|
+
written.
|
|
68
|
+
- Source, output and recipe must be three different files. Existing outputs are
|
|
69
|
+
replaced atomically.
|
|
70
|
+
- Receipts record the source digest, the solved and SVG digests, and the
|
|
71
|
+
library version. Keep the receipt when provenance matters.
|
|
72
|
+
- Inspect the SVG at its intended size. A clean render is not evidence that
|
|
73
|
+
the icon communicates the intended idea.
|
|
74
|
+
|
|
75
|
+
For diagram icons from a third-party icon package, keep using a local adapter as
|
|
76
|
+
described in [customization](customization.md).
|
|
@@ -14,14 +14,14 @@ command -v slopcamera
|
|
|
14
14
|
|
|
15
15
|
A restricted shell can omit package-manager paths. Check known host installation paths before declaring a tool unavailable. If Bun is genuinely absent, follow its official [installation guide](https://bun.sh/docs/installation) within the user’s authorized setup scope. Do not switch package managers or pipe an unreviewed installer into a shell.
|
|
16
16
|
|
|
17
|
-
Slopcamera installs from its verified release archive: `bun add --global https://github.com/hraness/slopcamera/releases/download/v3.
|
|
17
|
+
Slopcamera installs from its verified release archive: `bun add --global https://github.com/hraness/slopcamera/releases/download/v3.8.1/hraness-slopcamera-3.8.1.tgz`, then `slopcamera doctor --json`. Building from source is the contributor path. Historical Atet archives do not install the renamed CLI; never substitute `slopcamera` into an old archive URL.
|
|
18
18
|
|
|
19
19
|
If an update from a previous local archive reports `DependencyLoop`, use Bun's
|
|
20
20
|
[named tarball syntax](https://bun.com/docs/pm/cli/add#tarball-dependencies) with
|
|
21
21
|
the same verified archive:
|
|
22
22
|
|
|
23
23
|
```sh
|
|
24
|
-
bun add --global @hraness/slopcamera@https://github.com/hraness/slopcamera/releases/download/v3.
|
|
24
|
+
bun add --global @hraness/slopcamera@https://github.com/hraness/slopcamera/releases/download/v3.8.1/hraness-slopcamera-3.8.1.tgz
|
|
25
25
|
slopcamera --version
|
|
26
26
|
```
|
|
27
27
|
|
|
@@ -18,8 +18,16 @@ delivery. Keep the scene's deliberate style and original media intact.
|
|
|
18
18
|
|
|
19
19
|
Use the user's selected track and supplied tempo. Establish an explicit duration,
|
|
20
20
|
beat-zero offset, and beats per bar from the task or relevant audio inspection.
|
|
21
|
-
The first version does not detect tempo, downbeats, or track duration
|
|
22
|
-
replace explicit musical timing with an unsupported
|
|
21
|
+
The first version does not detect tempo, downbeats, or track duration from
|
|
22
|
+
audio. Do not replace explicit musical timing with an unsupported
|
|
23
|
+
automatic-analysis claim.
|
|
24
|
+
|
|
25
|
+
When the track was made from a Soundfish score or a MIDI file, derive the timing
|
|
26
|
+
from that source instead with
|
|
27
|
+
`slopcamera media soundtrack grid <score> --start-us <n> --json`. Its `music`
|
|
28
|
+
object drops straight into `parameters.music` below, and its section cue times
|
|
29
|
+
mark shot changes. See [soundtracks](soundtracks.md). Take `timing.durationUs`
|
|
30
|
+
from the audio file itself.
|
|
23
31
|
|
|
24
32
|
Check the installed command and host before preparing exact source:
|
|
25
33
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Derive a soundtrack beat grid
|
|
2
|
+
|
|
3
|
+
Use this workflow when a music video or timed HTML scene has a Soundfish score
|
|
4
|
+
or a Standard MIDI file, and the scene needs the track's tempo, meter and
|
|
5
|
+
section cue times. Slopcamera bundles the Soundfish library at one exact version
|
|
6
|
+
to read scores. It renders no audio: pair the grid with the audio file the user
|
|
7
|
+
mixes or supplies.
|
|
8
|
+
|
|
9
|
+
## Supported sources
|
|
10
|
+
|
|
11
|
+
One local file of at most 1 MiB, detected from its content or set with
|
|
12
|
+
`--format`:
|
|
13
|
+
|
|
14
|
+
- `compose`: Soundfish compose text for one loop.
|
|
15
|
+
- `song`: Soundfish song text with named sections.
|
|
16
|
+
- `json`: a Soundfish loop or song document.
|
|
17
|
+
- `midi`: a Standard MIDI file with one constant tempo and meter.
|
|
18
|
+
|
|
19
|
+
To write or edit scores, install the `@hraness/soundfish` package and use its
|
|
20
|
+
own agent skill. Slopcamera does not bundle that skill.
|
|
21
|
+
|
|
22
|
+
## Verify a score
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
slopcamera media soundtrack compose music/hook.song --json
|
|
26
|
+
slopcamera media soundtrack compose music/hook.song --output music/hook.json
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`compose` parses and verifies the score and reports its canonical digest, kind
|
|
30
|
+
(loop or song), tempo, beats per bar, bars and duration. `--output` writes the
|
|
31
|
+
verified score document as `.json`. Report any warnings the receipt carries.
|
|
32
|
+
|
|
33
|
+
## Derive the grid
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
slopcamera media soundtrack grid music/hook.song --start-us 500000 \
|
|
37
|
+
--output music/hook.grid.json --json
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The receipt's `music` object is exactly the `{ "bpm", "beatOffsetUs",
|
|
41
|
+
"beatsPerBar" }` shape an HTML scene request accepts under
|
|
42
|
+
`parameters.music`. `--start-us` is the timeline microsecond where the first
|
|
43
|
+
beat lands; it defaults to `0`. Each section carries its label, repeat, bars,
|
|
44
|
+
beats and `startUs`/`endUs` cue times on the same timeline.
|
|
45
|
+
|
|
46
|
+
- Cue times are whole microseconds and never drift more than half a microsecond
|
|
47
|
+
from the beat they name.
|
|
48
|
+
- Sections tile the score from `beatOffsetUs` to `endUs` with no gaps.
|
|
49
|
+
- The same score always yields the same digest and grid.
|
|
50
|
+
|
|
51
|
+
Use the grid in [music videos](music-video.md): copy `music` into the scene
|
|
52
|
+
request and use the section cues for shot changes. Set `timing.durationUs` from
|
|
53
|
+
the audio file, not only from the grid, because a mixed track can have a
|
|
54
|
+
different tail.
|
|
55
|
+
|
|
56
|
+
The same reads are available as the `compose_soundtrack` and
|
|
57
|
+
`derive_soundtrack_grid` MCP tools with root-relative paths, and as the
|
|
58
|
+
`slopcamera.soundtrack.compose` and `slopcamera.soundtrack.grid` operations.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto"
|
|
2
|
+
import { constants } from "node:fs"
|
|
3
|
+
import { mkdir, open, rename, rm, stat } from "node:fs/promises"
|
|
4
|
+
import { dirname, join, resolve } from "node:path"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Bounded local file reads and atomic replaceable writes shared by the
|
|
8
|
+
* icon-scene and soundtrack operations. Reads check the size before and
|
|
9
|
+
* after reading so a growing file cannot exceed the declared bound.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export class BoundedFileError extends Error {
|
|
13
|
+
readonly code: "SOURCE_NOT_FOUND" | "SOURCE_NOT_FILE" | "SOURCE_TOO_LARGE" | "SOURCE_UNREADABLE"
|
|
14
|
+
|
|
15
|
+
constructor(code: BoundedFileError["code"], message: string) {
|
|
16
|
+
super(message)
|
|
17
|
+
this.name = "BoundedFileError"
|
|
18
|
+
this.code = code
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function errorCode(error: unknown): string | undefined {
|
|
23
|
+
return typeof error === "object" && error !== null && "code" in error
|
|
24
|
+
? String((error as { readonly code: unknown }).code)
|
|
25
|
+
: undefined
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function readBoundedFile(
|
|
29
|
+
path: string,
|
|
30
|
+
maximumBytes: number,
|
|
31
|
+
label: string,
|
|
32
|
+
): Promise<Uint8Array> {
|
|
33
|
+
let handle
|
|
34
|
+
try {
|
|
35
|
+
// Non-blocking so a FIFO or device fails the regular-file check instead of hanging.
|
|
36
|
+
handle = await open(path, constants.O_RDONLY | constants.O_NONBLOCK)
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (errorCode(error) === "ENOENT") {
|
|
39
|
+
throw new BoundedFileError("SOURCE_NOT_FOUND", `${label} does not exist.`)
|
|
40
|
+
}
|
|
41
|
+
throw new BoundedFileError("SOURCE_UNREADABLE", `${label} could not be opened.`)
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const metadata = await handle.stat()
|
|
45
|
+
if (!metadata.isFile()) {
|
|
46
|
+
throw new BoundedFileError("SOURCE_NOT_FILE", `${label} must be a regular file.`)
|
|
47
|
+
}
|
|
48
|
+
if (metadata.size > maximumBytes) {
|
|
49
|
+
throw new BoundedFileError(
|
|
50
|
+
"SOURCE_TOO_LARGE",
|
|
51
|
+
`${label} exceeds the ${String(maximumBytes)}-byte limit.`,
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
// Read one byte past the bound so a file that grew after stat fails closed.
|
|
55
|
+
const buffer = new Uint8Array(maximumBytes + 1)
|
|
56
|
+
let length = 0
|
|
57
|
+
for (;;) {
|
|
58
|
+
const { bytesRead } = await handle.read(buffer, length, buffer.length - length, length)
|
|
59
|
+
if (bytesRead === 0) break
|
|
60
|
+
length += bytesRead
|
|
61
|
+
if (length > maximumBytes) {
|
|
62
|
+
throw new BoundedFileError(
|
|
63
|
+
"SOURCE_TOO_LARGE",
|
|
64
|
+
`${label} exceeds the ${String(maximumBytes)}-byte limit.`,
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return buffer.slice(0, length)
|
|
69
|
+
} finally {
|
|
70
|
+
await handle.close()
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function decodeUtf8Source(bytes: Uint8Array, label: string): string {
|
|
75
|
+
try {
|
|
76
|
+
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: false }).decode(bytes)
|
|
77
|
+
} catch {
|
|
78
|
+
throw new BoundedFileError("SOURCE_UNREADABLE", `${label} must be UTF-8 text.`)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function sha256Hex(value: string | Uint8Array): string {
|
|
83
|
+
return createHash("sha256").update(value).digest("hex")
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Replace `path` atomically with `value`, creating its parent directory. */
|
|
87
|
+
export async function publishReplaceableFile(
|
|
88
|
+
path: string,
|
|
89
|
+
value: string | Uint8Array,
|
|
90
|
+
): Promise<void> {
|
|
91
|
+
const directory = dirname(path)
|
|
92
|
+
await mkdir(directory, { recursive: true })
|
|
93
|
+
// A fixed-length name stays under NAME_MAX whatever the target's basename.
|
|
94
|
+
const temporaryPath = join(directory, `.slopcamera-${randomUUID()}.tmp`)
|
|
95
|
+
try {
|
|
96
|
+
const handle = await open(temporaryPath, "wx")
|
|
97
|
+
try {
|
|
98
|
+
await handle.writeFile(value)
|
|
99
|
+
await handle.sync()
|
|
100
|
+
} finally {
|
|
101
|
+
await handle.close()
|
|
102
|
+
}
|
|
103
|
+
await rename(temporaryPath, path)
|
|
104
|
+
} finally {
|
|
105
|
+
await rm(temporaryPath, { force: true }).catch(() => undefined)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* True when two declared paths name the same file, such as an output that
|
|
111
|
+
* would replace its source. Equal resolved spellings collide; existing files
|
|
112
|
+
* also collide by device and inode, which catches links and case-insensitive
|
|
113
|
+
* spellings of one file.
|
|
114
|
+
*/
|
|
115
|
+
export async function hasPathCollision(paths: readonly (string | undefined)[]): Promise<boolean> {
|
|
116
|
+
const spellings = new Set<string>()
|
|
117
|
+
const identities = new Set<string>()
|
|
118
|
+
for (const path of paths) {
|
|
119
|
+
if (path === undefined) continue
|
|
120
|
+
const absolute = resolve(path)
|
|
121
|
+
if (spellings.has(absolute)) return true
|
|
122
|
+
spellings.add(absolute)
|
|
123
|
+
let identity: string
|
|
124
|
+
try {
|
|
125
|
+
const metadata = await stat(absolute, { bigint: true })
|
|
126
|
+
identity = `${String(metadata.dev)}:${String(metadata.ino)}`
|
|
127
|
+
} catch (error) {
|
|
128
|
+
if (errorCode(error) === "ENOENT" || errorCode(error) === "ENOTDIR") continue
|
|
129
|
+
throw new BoundedFileError("SOURCE_UNREADABLE", "A declared path could not be inspected.")
|
|
130
|
+
}
|
|
131
|
+
if (identities.has(identity)) return true
|
|
132
|
+
identities.add(identity)
|
|
133
|
+
}
|
|
134
|
+
return false
|
|
135
|
+
}
|