m0saic 0.2.2 → 0.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/LICENSE +22 -7
- package/README.md +23 -5
- package/dist/browseE2e.js +1 -1
- package/dist/connectionsFromEnv.js +1 -1
- package/dist/e2eTemplateVariants.js +1 -1
- package/dist/frontDoor.js +1 -1
- package/dist/index.js +1 -1
- package/dist/inlineDsl.js +1 -1
- package/dist/mcp/bridgeClient.js +1 -0
- package/dist/mcp/server.js +1 -0
- package/dist/mcp/tools.js +1 -0
- package/dist/mosaicxRunner.js +1 -1
- package/dist/outputPattern.js +1 -1
- package/dist/showcaseFeed.js +1 -1
- package/dist/templateDoctor.js +1 -1
- package/dist/utils/checkFeasibility.js +1 -1
- package/dist/utils/collectRenderErrors.js +1 -1
- package/dist/utils/enrichImageAlphaFromDoc.js +1 -1
- package/dist/utils/ensureFfmpeg.js +1 -1
- package/dist/utils/extractLayoutMeta.js +1 -1
- package/dist/utils/failureHints.js +1 -1
- package/dist/utils/ffmpegProbe.js +1 -1
- package/dist/utils/formatM0saicForCli.js +1 -1
- package/dist/utils/hashFile.js +1 -1
- package/dist/utils/helpGroups.js +1 -1
- package/dist/utils/installContext.js +1 -0
- package/dist/utils/invocation.js +1 -1
- package/dist/utils/licenseActivation.js +1 -0
- package/dist/utils/licenseActivationWorker.js +1 -0
- package/dist/utils/mosaicSpinner.js +1 -1
- package/dist/utils/parseDimensions.js +1 -1
- package/dist/utils/pathInfo.js +1 -1
- package/dist/utils/readJsonArg.js +1 -1
- package/dist/utils/renderOutcome.js +1 -1
- package/dist/utils/renderReport.js +1 -1
- package/dist/utils/renderSignals.js +1 -1
- package/dist/utils/renderWorkspace.js +1 -1
- package/dist/utils/reportOutputFormat.js +1 -0
- package/dist/utils/setupFfmpeg.js +1 -1
- package/dist/utils/telemetry.js +1 -1
- package/dist/utils/telemetryFlushWorker.js +1 -1
- package/dist/utils/telemetryUpstream.js +1 -1
- package/dist/utils/telemetryUsage.js +1 -1
- package/dist/utils/toolchainConfig.js +1 -1
- package/dist/utils/tutorialDuration.js +1 -1
- package/dist/utils/updateCheck.js +1 -1
- package/dist/utils/updateCheckWorker.js +1 -1
- package/dist/utils/validateSourceCounts.js +1 -1
- package/dist/utils/versions.js +1 -1
- package/dist/webCustomizeLink.js +1 -1
- package/node_modules/@m0saic/community-m/NOTICE +9 -0
- package/node_modules/@m0saic/community-m/release.json +2 -2
- package/node_modules/@m0saic/core/dist/core/buildChildMosaicSource.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildChunkCommands.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildEncodeCommands.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildLavfiSource.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildMediaSource.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildMosaicNode.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildMosaicPlanFromFile.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildSvgTextSource.js +1 -1
- package/node_modules/@m0saic/core/dist/core/buildTextRenderCommand.js +1 -1
- package/node_modules/@m0saic/core/dist/core/collectRefTargets.js +1 -1
- package/node_modules/@m0saic/core/dist/core/index.js +1 -1
- package/node_modules/@m0saic/core/dist/core/maskCacheDir.js +1 -1
- package/node_modules/@m0saic/core/dist/core/maskWorkerBridge.js +1 -1
- package/node_modules/@m0saic/core/dist/core/playbackPlaySpeed.js +1 -1
- package/node_modules/@m0saic/core/dist/core/prepareProps.js +1 -1
- package/node_modules/@m0saic/core/dist/core/primaryOutput.js +1 -1
- package/node_modules/@m0saic/core/dist/core/rasterizeMaskPng.js +1 -1
- package/node_modules/@m0saic/core/dist/core/rasterizeSvgMediaPng.js +1 -1
- package/node_modules/@m0saic/core/dist/core/refTargetTap.js +1 -1
- package/node_modules/@m0saic/core/dist/core/resolveMasks.js +1 -1
- package/node_modules/@m0saic/core/dist/core/resolveMasksSync.js +1 -1
- package/node_modules/@m0saic/core/dist/core/resolveStrokeRingsSync.js +1 -1
- package/node_modules/@m0saic/core/dist/core/roundedRectMask.js +1 -1
- package/node_modules/@m0saic/core/dist/core/strokeRing.js +1 -1
- package/node_modules/@m0saic/core/dist/core/svgRaster.js +1 -1
- package/node_modules/@m0saic/core/dist/defaults.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/backgroundImageInput.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/bufferGuard.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/ffmpegCommands.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyBackdropBlur.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyBlur.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyBorderRadius.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyCamera.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyChromaKey.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyFade.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyGrade.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyMask.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyNoise.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyPixelize.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyRotate.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyStroke.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/applyTileEffects.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/coverCrop.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/index.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/filters/sourceRectCrop.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/gridLowering.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/index.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/splitAvMux.js +1 -1
- package/node_modules/@m0saic/core/dist/ffmpeg/threadGuard.js +1 -1
- package/node_modules/@m0saic/core/dist/flatten/index.js +1 -1
- package/node_modules/@m0saic/core/dist/fs/index.js +1 -1
- package/node_modules/@m0saic/core/dist/fs/tempWorkspace.js +1 -1
- package/node_modules/@m0saic/core/dist/index.js +1 -1
- package/node_modules/@m0saic/core/dist/media/buildAssetManifestFromInputs.js +1 -1
- package/node_modules/@m0saic/core/dist/media/buildMediaRegistryFromInput.js +1 -1
- package/node_modules/@m0saic/core/dist/media/collectMediaInputsFromInvocationProps.js +1 -1
- package/node_modules/@m0saic/core/dist/media/collectMediaInputsFromMosaicRenderableFile.js +1 -1
- package/node_modules/@m0saic/core/dist/media/collectMediaInputsFromProps.js +1 -1
- package/node_modules/@m0saic/core/dist/media/index.js +1 -1
- package/node_modules/@m0saic/core/dist/media/internalMintAsset.js +1 -1
- package/node_modules/@m0saic/core/dist/media/remoteUrl.js +1 -1
- package/node_modules/@m0saic/core/dist/media/stageUnsafeFilenames.js +1 -1
- package/node_modules/@m0saic/core/dist/media/types.js +1 -1
- package/node_modules/@m0saic/core/dist/output/index.js +1 -1
- package/node_modules/@m0saic/core/dist/output/resolveOutputFormat.js +1 -1
- package/node_modules/@m0saic/core/dist/output/types.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/cellLuminanceProbe.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/extractSubtitleCues.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/helpers.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/index.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/luminanceProbe.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/probeMedia.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/runFFprobe.js +1 -1
- package/node_modules/@m0saic/core/dist/probe/types.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/engineRedaction.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/ffmpegFailure.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/filterPreflight.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/hashFile.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/index.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/pathInfo.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/perfHeatmap.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/perfReport.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/pipelineM0p.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/renderCostModel.constants.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/renderCostModel.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/renderReport.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/renderSidecars.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/resolveMosaicx.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/runPlan.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/types.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/upstream.js +1 -1
- package/node_modules/@m0saic/core/dist/runtime/writeSidecars.js +1 -1
- package/node_modules/@m0saic/core/dist/types/chunk.js +1 -1
- package/node_modules/@m0saic/core/dist/types/index.js +1 -1
- package/node_modules/@m0saic/core/dist/types/mosaic-plan.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/assertTiming.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/command.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/createEngineContext.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/createTemplateRenderCache.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/ffmpegColor.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/formatDuration.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/fsSafeId.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/index.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/lowerRenderableToMosaicDocument.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/movSafeCodec.js +1 -1
- package/node_modules/@m0saic/core/dist/utils/resolveBoxFrac.js +1 -1
- package/node_modules/@m0saic/core/dist/validate/index.js +1 -1
- package/node_modules/@m0saic/core/scripts/mask-rasterize-core.js +1 -1
- package/node_modules/@m0saic/core/scripts/mask-rasterize-worker.js +1 -1
- package/node_modules/@m0saic/core/scripts/mask-worker-thread.js +1 -1
- package/node_modules/@m0saic/dictionary/NOTICE +9 -0
- package/node_modules/@m0saic/dictionary/README.md +315 -0
- package/node_modules/@m0saic/dictionary/package.json +1 -1
- package/node_modules/@m0saic/dsl/package.json +1 -1
- package/node_modules/@m0saic/dsl-file-formats/dist/cjs/agent.js +6 -0
- package/node_modules/@m0saic/dsl-file-formats/dist/cjs/m0/parseM0File.js +1 -1
- package/node_modules/@m0saic/dsl-file-formats/dist/cjs/m0/serializeM0File.js +2 -2
- package/node_modules/@m0saic/dsl-file-formats/dist/cjs/m0c/m0cFile.js +3 -3
- package/node_modules/@m0saic/dsl-file-formats/dist/cjs/types.js +1 -1
- package/node_modules/@m0saic/dsl-file-formats/package.json +1 -1
- package/node_modules/@m0saic/dsl-stdlib/dist/cjs/builders/bakeM0cInsets.js +1 -0
- package/node_modules/@m0saic/dsl-stdlib/dist/cjs/builders/index.js +1 -1
- package/node_modules/@m0saic/dsl-stdlib/package.json +1 -1
- package/node_modules/@m0saic/knowledge/LICENSE +21 -0
- package/node_modules/@m0saic/knowledge/README.md +71 -0
- package/node_modules/@m0saic/knowledge/dist/index.js +1 -0
- package/node_modules/@m0saic/knowledge/docs/README.md +60 -0
- package/node_modules/@m0saic/knowledge/docs/file-formats/m0-iteration-protocol.md +120 -0
- package/node_modules/@m0saic/knowledge/docs/file-formats/m0p-and-custom-field.md +195 -0
- package/node_modules/@m0saic/knowledge/docs/handbook/README.md +27 -0
- package/node_modules/@m0saic/knowledge/docs/handbook/composition-arithmetic.md +278 -0
- package/node_modules/@m0saic/knowledge/docs/handbook/dsl-complexity.md +75 -0
- package/node_modules/@m0saic/knowledge/docs/handbook/dsl-rules.md +367 -0
- package/node_modules/@m0saic/knowledge/docs/handbook/feasibility-precision-quantization.md +591 -0
- package/node_modules/@m0saic/knowledge/docs/handbook/m0-construction-methods.md +201 -0
- package/node_modules/@m0saic/knowledge/docs/handbook/precision-tiers.md +84 -0
- package/node_modules/@m0saic/knowledge/docs/m0saic-thesis.md +95 -0
- package/node_modules/@m0saic/knowledge/docs/runtime/README.md +24 -0
- package/node_modules/@m0saic/knowledge/docs/runtime/agent-at-the-canvas.md +108 -0
- package/node_modules/@m0saic/knowledge/docs/runtime/cli-usage.md +475 -0
- package/node_modules/@m0saic/knowledge/docs/runtime/ffmpeg-expression-limits.md +117 -0
- package/node_modules/@m0saic/knowledge/docs/runtime/reduce-to-one.md +96 -0
- package/node_modules/@m0saic/knowledge/docs/skills/README.md +40 -0
- package/node_modules/@m0saic/knowledge/docs/skills/axis-and-geometry.md +103 -0
- package/node_modules/@m0saic/knowledge/docs/skills/dsl-stdlib-method-catalog.md +7 -0
- package/node_modules/@m0saic/knowledge/docs/skills/identity.md +123 -0
- package/node_modules/@m0saic/knowledge/docs/skills/labels-and-masks.md +170 -0
- package/node_modules/@m0saic/knowledge/docs/skills/m0saic-string-generation.md +251 -0
- package/node_modules/@m0saic/knowledge/docs/skills/more-atoms-not-bigger-atoms.md +77 -0
- package/node_modules/@m0saic/knowledge/docs/skills/overlay-semantics.md +194 -0
- package/node_modules/@m0saic/knowledge/docs/skills/parse-apis.md +79 -0
- package/node_modules/@m0saic/knowledge/docs/skills/passthrough-semantics.md +136 -0
- package/node_modules/@m0saic/knowledge/docs/skills/structural-construction.md +86 -0
- package/node_modules/@m0saic/knowledge/docs/skills/text-in-templates.md +126 -0
- package/node_modules/@m0saic/knowledge/docs/skills/zero-overlay-analysis.md +87 -0
- package/node_modules/@m0saic/knowledge/docs/templates/README.md +65 -0
- package/node_modules/@m0saic/knowledge/docs/templates/capability-templates.md +72 -0
- package/node_modules/@m0saic/knowledge/docs/templates/construction-strategy.md +329 -0
- package/node_modules/@m0saic/knowledge/docs/templates/data-pipeline.md +324 -0
- package/node_modules/@m0saic/knowledge/docs/templates/emission-patterns.md +130 -0
- package/node_modules/@m0saic/knowledge/docs/templates/geometry-recipes.md +248 -0
- package/node_modules/@m0saic/knowledge/docs/templates/layout-contract.md +168 -0
- package/node_modules/@m0saic/knowledge/docs/templates/output-resolution-tree.md +210 -0
- package/node_modules/@m0saic/knowledge/docs/templates/patterns/case-study-lessons.md +69 -0
- package/node_modules/@m0saic/knowledge/docs/templates/patterns/perf-authoring-rules.md +100 -0
- package/node_modules/@m0saic/knowledge/docs/templates/patterns/primitive-extraction-pattern.md +103 -0
- package/node_modules/@m0saic/knowledge/docs/templates/philosophy-and-contract.md +310 -0
- package/node_modules/@m0saic/knowledge/docs/templates/recursion-nested-rendering.md +154 -0
- package/node_modules/@m0saic/knowledge/docs/templates/reference/grid.md +104 -0
- package/node_modules/@m0saic/knowledge/docs/templates/reference/json-prop-type.md +169 -0
- package/node_modules/@m0saic/knowledge/docs/templates/reference/mosaic-color.md +81 -0
- package/node_modules/@m0saic/knowledge/docs/templates/reference/mosaic-placement-props.md +103 -0
- package/node_modules/@m0saic/knowledge/docs/templates/reference/prop-bindings.md +338 -0
- package/node_modules/@m0saic/knowledge/docs/templates/reference/template-flags.md +236 -0
- package/node_modules/@m0saic/knowledge/docs/templates/render-lifecycle.md +117 -0
- package/node_modules/@m0saic/knowledge/docs/templates/rendering-model-contract.md +392 -0
- package/node_modules/@m0saic/knowledge/docs/templates/standalone-pack-authoring.md +309 -0
- package/node_modules/@m0saic/knowledge/docs/templates/theming.md +81 -0
- package/node_modules/@m0saic/knowledge/docs/templates/ui-controls.md +150 -0
- package/node_modules/@m0saic/knowledge/package.json +6 -0
- package/node_modules/@m0saic/momo-types/README.md +109 -0
- package/node_modules/@m0saic/momo-types/dist/agent.js +1 -6
- package/node_modules/@m0saic/momo-types/dist/context.js +1 -1
- package/node_modules/@m0saic/momo-types/package.json +1 -1
- package/node_modules/@m0saic/platform/README.md +3 -0
- package/node_modules/@m0saic/platform/dist/cjs/index.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/mosaic/outputKind/outputKind.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/mosaic/propBindings/index.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/mosaic/propBindings/propBindings.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/mosaic/validate/validateSources.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/packages/mosaicPackages.js +1 -0
- package/node_modules/@m0saic/platform/dist/cjs/paths/m0saicRoot.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/telemetry/lifecycle.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/telemetry/preview.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/telemetry/sender.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/telemetry/usageRecorder.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/telemetry/usageStore.js +3 -3
- package/node_modules/@m0saic/platform/dist/cjs/template-repos/index.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/template-repos/loadTemplateRepoFromPath.js +4 -4
- package/node_modules/@m0saic/platform/dist/cjs/template-repos/templateCatalogSidecars.js +2 -0
- package/node_modules/@m0saic/platform/dist/cjs/templateCatalog/index.js +1 -0
- package/node_modules/@m0saic/platform/dist/cjs/templateCatalog/templateCatalog.js +1 -0
- package/node_modules/@m0saic/platform/dist/cjs/toolchain/ffmpeg/baseline.json +25 -97
- package/node_modules/@m0saic/platform/dist/cjs/toolchain/ffmpeg/index.js +1 -1
- package/node_modules/@m0saic/platform/dist/cjs/toolchain/ffmpeg/install.js +2 -2
- package/node_modules/@m0saic/platform/dist/cjs/toolchain/goldenFfmpeg.js +6 -6
- package/node_modules/@m0saic/platform/package.json +1 -1
- package/node_modules/@m0saic/product/dist/communityRelease.js +1 -1
- package/node_modules/@m0saic/product/dist/freeTierLicense.js +1 -1
- package/node_modules/@m0saic/product/dist/index.js +1 -1
- package/node_modules/@m0saic/product/dist/licenseActivationNotice.js +1 -0
- package/node_modules/@m0saic/product/dist/licenseFile.js +1 -0
- package/node_modules/@m0saic/product/dist/licenseToken.js +1 -1
- package/node_modules/@m0saic/product/dist/makeScratchPath.js +1 -0
- package/node_modules/@m0saic/product/dist/postRenderWrapper.js +1 -1
- package/node_modules/@m0saic/product/dist/publicKeys.js +1 -1
- package/node_modules/@m0saic/product/dist/revokedKeys.js +1 -1
- package/node_modules/@m0saic/product/dist/upstreamDefaults.js +1 -1
- package/node_modules/@m0saic/product/dist/workspaceScaffold.js +1 -0
- package/node_modules/@m0saic/template-utils/dist/brand/hello-world/helloWorld.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/geometry-contract/frameResolution.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/geometry-contract/index.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/geometry-contract/layoutConstraint.js +2 -2
- package/node_modules/@m0saic/template-utils/dist/m0saic/loadSession.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/render/createDesignContext.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/sources/makeErrorMosaic.js +2 -2
- package/node_modules/@m0saic/template-utils/dist/sources/svgTextSource.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/template/auditRenderedTemplate.js +5 -5
- package/node_modules/@m0saic/template-utils/dist/template/auditSchemaConventions.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/template/defineMosaicTemplate.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/template/resolveTemplateOutputHints.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/template/templateCatalogStore.js +1 -0
- package/node_modules/@m0saic/template-utils/dist/template/templateConventions.js +4 -4
- package/node_modules/@m0saic/template-utils/dist/template/templateRegistry.js +3 -3
- package/node_modules/@m0saic/template-utils/dist/template/validateTemplateProps.js +1 -1
- package/node_modules/@m0saic/template-utils/dist/text/fitText.js +6 -6
- package/node_modules/@m0saic/template-utils/package.json +1 -1
- package/node_modules/@m0saic/templates/NOTICE +9 -0
- package/node_modules/@m0saic/templates/dist/catalog.js +1 -0
- package/node_modules/@m0saic/templates/dist/freeze.js +8 -8
- package/node_modules/@m0saic/templates/dist/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/_shared/canvas-handles.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/_shared/stand-in.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/agents/commit-feed/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/agents/commit-feed/v2/commit-feed.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/agents/commit-feed/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/agents/trace-timeline/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/agents/trace-timeline/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/agents/trace-timeline/v2/trace-timeline.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/_shared/alpine-conventions.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/bar-graph/v2/bar-graph.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/bar-graph/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/commit-feed/v3/commit-feed.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/commit-feed/v3/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/contributor-table/v2/contributor-table.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/contributor-table/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/donut/v4/donut.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/donut/v4/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/heatmap/v3/heatmap.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/heatmap/v3/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/kpi-card/v3/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/kpi-card/v3/kpi-card.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/leaderboard/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/leaderboard/v2/leaderboard.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/line-chart/v3/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/line-chart/v3/line-chart.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/progress-card/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/progress-card/v2/progress-card.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/stat-card/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/stat-card/v2/stat-card.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/timeline/v3/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/timeline/v3/timeline.js +4 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/treemap/v3/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/alpine/treemap/v3/treemap.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/benchmark/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/benchmark/report/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/benchmark/report/v2/report.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/brand/business-card/v2/business-card.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/brand/business-card/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/brand/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/brand/logo/v4/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/brand/logo/v4/logo_runner.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/charts/bar-graph/v3/bar-graph.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/charts/bar-graph/v3/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/charts/donut/v5/donut.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/charts/donut/v5/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/charts/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/charts/line-chart/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/charts/line-chart/v2/line-chart.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/charts/stat-card/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/charts/stat-card/v2/stat-card.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/code/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/code/snippet-morph/v2/snippet-morph.js +3 -0
- package/node_modules/@m0saic/templates/dist/m0saic/collage/image-collage/v2/image-collage.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/collage/image-collage/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/collage/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/dsl-tutorial/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/dsl-tutorial/v2/dsl-tutorial.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/dsl-tutorial/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/github/year-card/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/github/year-card/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/github/year-card/v2/year-card.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/hero/ffmpeg-pulse/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/hero/ffmpeg-pulse/runner/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/hero/ffmpeg-pulse/runner/v2/runner.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/barcode/v2/barcode.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/barcode/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/blur-regions/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/media/blur-regions/v1/tutorial.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/media/blur-regions/v2/blur-regions.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/blur-regions/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/highlights/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/media/highlights/v2/highlights.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/highlights/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/media/logo-animate/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/media/logo-animate/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/logo-animate/v2/logo-animate.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/metadata-stamp/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/media/metadata-stamp/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/metadata-stamp/v2/metadata-stamp.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/qr/code/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/qr/code/v2/qr-code.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/qr/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/media/qr/stamp/v2/qr-stamp-custom.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/screencap_grid/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/media/screencap_grid/v3/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/screencap_grid/v3/screencap-grid.js +4 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/screencap_grid_aspect_safe/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/media/screencap_grid_aspect_safe/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/screencap_grid_aspect_safe/v2/screencap-grid-aspect-safe.js +3 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/scroll_wall/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/media/scroll_wall/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/scroll_wall/v2/scroll-wall.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/subtitle-burn/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/media/subtitle-burn/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/subtitle-burn/v2/subtitle-burn.js +4 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/trickplay/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/media/trickplay/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/trickplay/v2/trickplay.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/video_to_png_sequence/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/media/video_to_png_sequence/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/video_to_png_sequence/v2/video-to-png-sequence.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/watermark/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/media/watermark/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/media/watermark/v2/watermark.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/primitives/grid/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/primitives/grid/v3/grid.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/social/quote-card/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/social/quote-card/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/social/quote-card/v2/quote-card.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/story/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/story/narrated-chapters/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/story/narrated-chapters/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/story/narrated-chapters/v2/narrated-chapters.js +4 -0
- package/node_modules/@m0saic/templates/dist/m0saic/story/scrapbook/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/story/scrapbook/v2/props.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/story/scrapbook/v2/scrapbook.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/theming/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/theming/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/theming/v2/theming.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/web/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/m0saic/web/page-skeleton/v2/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/web/page-skeleton/v2/page-skeleton.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/wireframe/base/v3/index.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/wireframe/base/v3/wireframe.js +1 -0
- package/node_modules/@m0saic/templates/dist/m0saic/wireframe/index.js +1 -1
- package/node_modules/@m0saic/templates/dist/repo.js +1 -1
- package/node_modules/@m0saic/templates/dist/template-catalog.json +5429 -0
- package/node_modules/@m0saic/templates/dist/template-registry.js +1 -1
- package/node_modules/@m0saic/templates/dist/web.js +1 -1
- package/node_modules/@m0saic/templates/package.json +1 -1
- package/node_modules/@m0saic/templates/template-catalog.json +5429 -0
- package/node_modules/@m0saic/templates/template-manifest.json +1030 -286
- package/node_modules/@m0saic/templates/web-template-ids.json +38 -0
- package/node_modules/@m0saic/templates-advanced/NOTICE +9 -0
- package/node_modules/@m0saic/text/package.json +1 -1
- package/node_modules/@m0saic/types/dist/analytics/consent.js +1 -1
- package/node_modules/@m0saic/types/dist/analytics/event.js +1 -1
- package/node_modules/@m0saic/types/dist/analytics/usageMetrics.js +1 -1
- package/node_modules/@m0saic/types/dist/identifiers/identifiers.js +1 -1
- package/node_modules/@m0saic/types/dist/telemetry/ffmpegFailure.js +1 -1
- package/node_modules/@m0saic/types/dist/template/template.js +1 -1
- package/node_modules/@m0saic/types/package.json +1 -1
- package/node_modules/@m0saic/types-internal/dist/analytics/featureKeys.js +1 -1
- package/package.json +13 -11
- package/resources/starter-base/starter-base.json +10 -0
- package/resources/starter-base/starter-base.tgz +0 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# Prop bindings — the rect that SHOWS a prop is its handle in Make
|
|
2
|
+
|
|
3
|
+
A template marks the source that DISPLAYS a prop with `source.editor.binding`
|
|
4
|
+
(or `bindings`, several leaves on one rect). Make resolves them per render and
|
|
5
|
+
turns the rect into the prop's canvas handle: double-click / a badge to edit,
|
|
6
|
+
a file dropped on it to fill a media slot. Bindings are re-resolved on every
|
|
7
|
+
render and keyed by the PROP — never by a stableKey, which changes whenever the
|
|
8
|
+
geometry does.
|
|
9
|
+
|
|
10
|
+
One predicate decides what is bindable: `classifyBindableProp` in
|
|
11
|
+
`@m0saic/platform` (`mosaic/propBindings`). Template tests
|
|
12
|
+
(`resolvePropBindings` in `@m0saic/template-utils`) and the Make page both use
|
|
13
|
+
it, so a template can never offer an edit the page refuses, or vice versa.
|
|
14
|
+
`bindProps` / `bindPropPath` THROW at author time for what the platform would
|
|
15
|
+
silently drop — a template test should never reach the silent path.
|
|
16
|
+
|
|
17
|
+
## The wire shape
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
binding: {
|
|
21
|
+
propKey: string; // dotted path as propsSchema nests it: "label", "titles.title"
|
|
22
|
+
index?: number; // ONE element of string[] / number[] / media[]
|
|
23
|
+
path?: Array<string | number>; // route into a json / list / array value: [2, "title"]
|
|
24
|
+
kind?: "string" | "number" | "color" | "rect" | "media"; // required on structured leaves
|
|
25
|
+
layer?: number; // which text layer shows the leaf (multi-layer text)
|
|
26
|
+
onClear?: "remove-element" | "unset-leaf";
|
|
27
|
+
seedDraft?: string;
|
|
28
|
+
companion?: boolean;
|
|
29
|
+
range?: { start: number; end: number }; // one line of a multi-line string leaf
|
|
30
|
+
focus?: { start: number; end: number }; // the token the rect shows, inside range
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Rules:
|
|
35
|
+
|
|
36
|
+
- `propKey` is exactly as `propsSchema` nests it; every segment past the
|
|
37
|
+
first walks a `type: "group"` prop's `fields`.
|
|
38
|
+
- Basic lists (`string[]`, `number[]`, `media[]`) bind ONE element — a
|
|
39
|
+
non-negative integer `index`. The list itself is never bindable.
|
|
40
|
+
- Structured props (`json` / `list` / `array`) bind a LEAF: `path` from the
|
|
41
|
+
prop's value plus an explicit `kind` (the schema has no per-leaf type, and an
|
|
42
|
+
empty leaf must still be an "add" handle). `index` is shorthand for a leading
|
|
43
|
+
numeric segment.
|
|
44
|
+
- `meta.ui.hidden` props, booleans, connection-driven option strings
|
|
45
|
+
(`optionsFromConnection` — the host has no list without the connection) and
|
|
46
|
+
whole lists are never bindable. A stray `index` on a scalar is ignored.
|
|
47
|
+
- A **closed set** — `constraints.oneOf` or a static `control.options` list — binds
|
|
48
|
+
as kind **`choice`** (2026-10-01): Make shows the set (a segmented row up to four
|
|
49
|
+
choices, a select beyond) on the inline editor and on the tile card, and one click
|
|
50
|
+
writes the value; nothing is typed, `seedDraft` is dropped. Basic props only — a
|
|
51
|
+
structured leaf has no set to offer, so `kind: "choice"` there is refused. The case it exists for:
|
|
52
|
+
a full-canvas card bound to its theme `preset` (the alpine cards, the GitHub year
|
|
53
|
+
card) — the click on the card is where the theme gets changed, and the `canvasFill`
|
|
54
|
+
rule accepts a full-canvas rect that carries such a handle.
|
|
55
|
+
- Bind even when the value is empty — the rect is then a handle to ADD.
|
|
56
|
+
|
|
57
|
+
## Kinds
|
|
58
|
+
|
|
59
|
+
| prop / leaf | binding | kind | Make handle |
|
|
60
|
+
|---|---|---|---|
|
|
61
|
+
| free-text `string` (or one `string[]` element, or a structured leaf) | `bindProp(src, key[, i])` / `bindPropPath(src, key, path, "string")` | `"string"` | T — the inline text form |
|
|
62
|
+
| colour-valued string (`isColor` / `colorPicker`) | same | `"color"` | swatch — a picker |
|
|
63
|
+
| `number` (or one `number[]` element, or a leaf) | same, `"number"` | `"number"` | 123 — the inline form |
|
|
64
|
+
| `json` with `picker: "regions"`, `regions.max: 1` | `bindPropRect(src, key)` — no path | `"rect"` | move glyph — the regions draw session on the cell |
|
|
65
|
+
| `media`, one `media[]` element, or a leaf holding a path | `bindProp(src, key[, i])` / `bindPropPath(…, "media")` | `"media"` | picture glyph — a DROP target + the media chip |
|
|
66
|
+
|
|
67
|
+
Order the entries the way a double-click should read them: `fields[0]` is the
|
|
68
|
+
primary action (a plain double-click); the badge row offers every kind.
|
|
69
|
+
|
|
70
|
+
## The roll call — `bindingsDeclared` (THROW, 2026-09-25)
|
|
71
|
+
|
|
72
|
+
**Every prop that CAN carry a canvas handle is either bound, or declared.** A new template that does
|
|
73
|
+
neither fails the build. Founder ruling: "if it makes sense to bind, we do — or warn if it's not."
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
bindings: { unbound: { fps: "timing", gap: "geometry", seed: "determinism" } }
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
One honest word is the point — the reason is for a reviewer. Keys are dotted exactly as `propsSchema`
|
|
80
|
+
nests them (`titles.title`).
|
|
81
|
+
|
|
82
|
+
### The complete surface — one ruling per control
|
|
83
|
+
|
|
84
|
+
`MUST ACCOUNT` = bind it, or name it in `bindings.unbound`. `NEVER` = not a canvas thing; the
|
|
85
|
+
right-hand panel is its surface, and the rule stays silent.
|
|
86
|
+
|
|
87
|
+
| Prop / flavour | Handle | Convention |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `string`, free text | `string` | **MUST ACCOUNT** |
|
|
90
|
+
| `string` + `isColor` / `colorPicker` | `color` | **MUST ACCOUNT** |
|
|
91
|
+
| `number` | `number` | **MUST ACCOUNT** |
|
|
92
|
+
| `media` | `media` (also a drop target) | **MUST ACCOUNT** |
|
|
93
|
+
| `string[]` · `number[]` · `media[]` | per element, by index | **MUST ACCOUNT** (bound anywhere on the prop counts) |
|
|
94
|
+
| `json` · `list` · `array` | per leaf, `path` + `kind` | **MUST ACCOUNT** (any leaf counts) |
|
|
95
|
+
| `json` + `picker: "regions"` | `rect` | **MUST ACCOUNT** |
|
|
96
|
+
| `string` + closed set (`oneOf`, a static `options` list) | `choice` (a pick, never typed) | **NEVER DEMANDED** — a mode has no rect of its own; bind it when a rect IS the mode (the card → `preset`) |
|
|
97
|
+
| `string` / `number` + `optionsFromConnection` | — | **NEVER** — the host has no list without the connection |
|
|
98
|
+
| `number` + closed set | — | **NEVER** |
|
|
99
|
+
| `boolean` | — | **NEVER** — a one-way door: `false` renders no rect to click |
|
|
100
|
+
| `group` | — | **NEVER** — a container; its fields are walked individually |
|
|
101
|
+
| `m0` · `m0c` · `m0p` | — | **NEVER** — the value IS the composition of every rect, not one of them |
|
|
102
|
+
| `code` | — | **NEVER** — read-only by contract; a handle implies editing |
|
|
103
|
+
| anything `ui.hidden` or `consumer: "human"` | — | **NEVER** |
|
|
104
|
+
|
|
105
|
+
Why the `m0` family is excluded, since it is the tempting one: a layout prop has no clickable element.
|
|
106
|
+
All 10 shipped layout props (wireframe, dsl-tutorial, screencap-grid v1/v2, watermark, qr-animate,
|
|
107
|
+
camera-debug) drive the ROOT composition — you would have to select the whole grid, which the canvas
|
|
108
|
+
cannot express. If a template ever nests a layout prop into ONE cell, that cell is a real handle and a
|
|
109
|
+
sixth kind (`"layout"`) becomes worth having. None does today.
|
|
110
|
+
|
|
111
|
+
**Bindable ≠ has a rect.** The predicate says a `number` is always inline-editable; whether any rect
|
|
112
|
+
*shows* it is the template's business. `durationMs`, `fps`, `gap`, `seed`, `padding` are all
|
|
113
|
+
accountable and correctly unbound — which is exactly why the rule takes a declaration instead of
|
|
114
|
+
guessing from the pixels.
|
|
115
|
+
|
|
116
|
+
**A colour that IS `document.backgroundColor` needs nothing** — no binding, no declaration. It has no
|
|
117
|
+
source and no rect, so no handle can exist, and it is the way a canvas SHOULD be filled: a full-frame
|
|
118
|
+
base rect becomes a click target that shadows everything behind it whenever the pointer is not on a
|
|
119
|
+
smaller tile (founder direction 2026-09-25). Matched case-insensitively, root or child.
|
|
120
|
+
|
|
121
|
+
**A binding in a nested CHILD counts.** A template that composes its content into a child document
|
|
122
|
+
(the hello-world card puts everything in a `card` child) reaches its props perfectly well — Make
|
|
123
|
+
resolves a binding through children. **But the audit renders at `defaultProps`,** so a rect the
|
|
124
|
+
template only creates when a prop is non-empty reads as unbound. That is the "bind even when the value
|
|
125
|
+
is empty" rule biting: bind it unconditionally, or declare it.
|
|
126
|
+
|
|
127
|
+
**A stale declaration is a violation too:** naming a prop that cannot carry a handle, naming one that
|
|
128
|
+
is in fact bound, or leaving the reason empty. An entry claims a reviewer looked at that prop.
|
|
129
|
+
|
|
130
|
+
**Exempt:** any template hashed in the repo's `frozen.manifest.json`. It shipped before the
|
|
131
|
+
convention, it is never edited in place, and the fix would be a vN+1 nobody will write. A repo with no
|
|
132
|
+
manifest has shipped nothing and holds every template to the rule.
|
|
133
|
+
|
|
134
|
+
## The in-context line — `bindingHints` (THROW, 2026-09-27)
|
|
135
|
+
|
|
136
|
+
**Every bound rect shows one line in context.** Make puts it under the inline editor when a person
|
|
137
|
+
double-clicks, on the tile card's row, and in the handle's hover tooltip — what changing the value
|
|
138
|
+
does and what it looks like, so nobody has to open the settings pane or a manual to understand a knob.
|
|
139
|
+
Founder ruling: a production-grade template adheres to all the surfaces of the ecosystem, and the
|
|
140
|
+
canvas is now the primary one; "it's better to take this tax now."
|
|
141
|
+
|
|
142
|
+
The line comes from either of two places, and the gate accepts either:
|
|
143
|
+
|
|
144
|
+
| Where | How | Reaches |
|
|
145
|
+
|---|---|---|
|
|
146
|
+
| the prop | the catalog sidecar: `props.<key>.description` in `<name>.catalog.json` (0.3.1; `propsSchema.<key>.description` in code is the pre-0.3.1 form, kept only by shipped templates) | every rect bound to that prop |
|
|
147
|
+
| the binding | `bindProp(src, key, i, { hint: "…" })` · a `bindProps` entry's `hint` · `withBindingHint(src, "…")` (composes with every binder) | that rect only — the wording for THIS place |
|
|
148
|
+
|
|
149
|
+
One plain sentence, never markdown, never the value itself ("The month this calendar shows; the grid
|
|
150
|
+
re-flows to its weeks", not "October"). Make trims it and caps it near 200 characters. The tax is
|
|
151
|
+
therefore one honest sentence per bound prop, paid once in the sidecar; a per-rect `hint` (code — it
|
|
152
|
+
describes one specific rect) is for the cases where the same prop means something different in
|
|
153
|
+
different places. The gate judges hints AFTER the catalog applies, so a sidecar description satisfies it.
|
|
154
|
+
|
|
155
|
+
**Needs none:** a `companion` leaf (filled only by a media drop, never shown in a form), and any prop
|
|
156
|
+
that is not bound (an `unbound` declaration already carries its reason). A binding on an unknown prop
|
|
157
|
+
is `bindingsSound`'s finding, not this one.
|
|
158
|
+
|
|
159
|
+
**Exempt:** any template hashed in the repo's `frozen.manifest.json`, like the roll call — it reports
|
|
160
|
+
in `lagging`, never `findings`. The CLI ignores the field entirely; it is extra data there.
|
|
161
|
+
|
|
162
|
+
## The `bindingsCover` convention — what the gate checks
|
|
163
|
+
|
|
164
|
+
The roll call above is the gate. `bindingsCover` is the WEAKER SECOND SIGNAL kept beside it
|
|
165
|
+
(posture `record` → a warning): it reads the drawn text, so it is the only rule that can catch a prop
|
|
166
|
+
bound to the WRONG rect, and it still fires on frozen templates where the roll call cannot. Both
|
|
167
|
+
`check-registry.mjs` copies and `m0saic doctor <repo>` run both.
|
|
168
|
+
|
|
169
|
+
- A **free-text `string`** prop — not `meta.ui.hidden`, not `consumer: "human"`, not a closed /
|
|
170
|
+
picked set — whose default is ≥2 characters and appears verbatim in drawn text must be bound.
|
|
171
|
+
- A **`number`** prop, same exclusions, whose default appears in drawn text in one of its honest
|
|
172
|
+
spellings: `String(v)`, `toLocaleString("en-US")`, and `toFixed(1|2)` **only when the value already
|
|
173
|
+
has decimals** (nothing draws an integer count as `"1.0"`, but chrome draws versions that read that
|
|
174
|
+
way). A one-character spelling never counts.
|
|
175
|
+
- Numbers match on a **digit boundary**: `12` is not read out of `2012` or `3.12`, and a drawn
|
|
176
|
+
`1,200` is not read as the prop `200`.
|
|
177
|
+
- Coverage is per PROP, not per rect — a prop bound anywhere on the root document is covered.
|
|
178
|
+
|
|
179
|
+
### One rect, two props — a composite line
|
|
180
|
+
|
|
181
|
+
`"@qsbuilds · 2026 on GitHub"` is one rect drawing two props, and a single `editor.binding` names one
|
|
182
|
+
of them. A bare `bindProp` there would REPLACE the existing handle, so the rule says so and names the
|
|
183
|
+
fix that keeps both:
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
bindProps(src, [{ propKey: "handle" }, { propKey: "year", kind: "number" }])
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
— several handles on one rect — or split the line so each prop gets its own rect. (`year-card/v1` is
|
|
190
|
+
the live example; it is frozen, so its fix is v2 and it warns until then.)
|
|
191
|
+
|
|
192
|
+
Colour coverage is not checked: a colour is never drawn as text, so it needs a different detector.
|
|
193
|
+
|
|
194
|
+
## Authoring helpers (`@m0saic/template-utils`)
|
|
195
|
+
|
|
196
|
+
- `bindProp(src, propKey, index?)` — the basic case.
|
|
197
|
+
- `bindProps(src, entries)` — several leaves on one rect (a multi-layer text,
|
|
198
|
+
a cell that moves AND edits AND takes a drop). Writes `editor.bindings`,
|
|
199
|
+
which wins over the single `binding`.
|
|
200
|
+
- `bindPropPath(src, propKey, path, kind, { onClear?, seedDraft? })` — one
|
|
201
|
+
structured leaf.
|
|
202
|
+
- `bindPropRect(src, propKey)` — a one-region regions picker edited in place.
|
|
203
|
+
- `bindPropRange(src, propKey, index, range, focus?)` — one line of a
|
|
204
|
+
multi-line string prop (a code state, a lyric block); offsets index the RAW
|
|
205
|
+
prop string.
|
|
206
|
+
- `stripPropBindings(doc)` — a host composing ANOTHER template's render drops
|
|
207
|
+
its bindings (they name the inner template's props).
|
|
208
|
+
- `tag(src, label)` composes either way round with all of them.
|
|
209
|
+
|
|
210
|
+
## `onClear` — what an EMPTY commit means
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
{ propKey: "days", path: [rowIndex, "day"], kind: "number", onClear: "remove-element" }
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
- `"remove-element"` — splice the element at the leading numeric path segment
|
|
217
|
+
(the whole row, or one element of a basic list) out of its array. Needs an
|
|
218
|
+
`index` or a numeric first `path` segment.
|
|
219
|
+
- `"unset-leaf"` — delete the leaf key from its object, or unset a basic prop
|
|
220
|
+
so its default shows again. Not for array-element leaves (no key).
|
|
221
|
+
- Absent — an OPTIONAL colour prop (a basic prop or a group field, not a leaf
|
|
222
|
+
inside a row or list) unsets, back to the template's own colour (platform
|
|
223
|
+
`defaultOnClear`); a required colour and other numbers refuse an empty commit;
|
|
224
|
+
strings write `""`; a scalar media clears to `""`; a `media[]` element refuses
|
|
225
|
+
(a hole in a media list is not a value the engine can open). `"none"` is never
|
|
226
|
+
a clear — it is a colour (transparent).
|
|
227
|
+
|
|
228
|
+
Editor rules: "empty" is blank for numbers / colours, `""` for text. An empty
|
|
229
|
+
commit against an already-empty leaf writes nothing. In a multi-field session a
|
|
230
|
+
row removal supersedes its siblings' writes; rows go highest index first. The
|
|
231
|
+
panel stays the primary place rows are deleted — canvas clear is an accelerator.
|
|
232
|
+
|
|
233
|
+
## `seedDraft` — prefill an EMPTY leaf from the rect's context
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
{ propKey: "days", path: [len, "day"], kind: "number", onClear: "remove-element", seedDraft: String(info.day) }
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
- Applies only when the bound leaf reads EMPTY / absent; a leaf with a value
|
|
240
|
+
ignores it. A DRAFT: shown pre-selected (Enter alone accepts it), written on
|
|
241
|
+
commit like typed text, never applied by itself. Deleting it and committing
|
|
242
|
+
empty still runs `onClear`.
|
|
243
|
+
- Blur commits too, so an untouched seeded form that loses focus WRITES the
|
|
244
|
+
seed — mind this when seeding.
|
|
245
|
+
- Wire shape is a string; a blank seed, or a non-numeric seed on a number
|
|
246
|
+
leaf, throws at author time; `rect` and `media` leaves take no seed.
|
|
247
|
+
- Focus lands on the FIRST field: order a seeded field first when the seed is
|
|
248
|
+
the whole suggestion.
|
|
249
|
+
|
|
250
|
+
## `kind: "media"` — a rect that takes a dropped file
|
|
251
|
+
|
|
252
|
+
A media-bound rect is a DROP target on the Make canvas (a file dragged onto it
|
|
253
|
+
writes the path) with a picture-glyph handle that opens the media chip —
|
|
254
|
+
`Choose file…` / `Replace…` · `Remove` (when clearable) · "or drop a file on
|
|
255
|
+
the cell". A file in flight lights every media slot; a slot whose prop refuses
|
|
256
|
+
the kind lights muted.
|
|
257
|
+
|
|
258
|
+
- What may land is the PROP's say: `meta.control.accept` (`["image","video"]`)
|
|
259
|
+
and `meta.control.extensions`. Judged by MIME while in flight, by extension
|
|
260
|
+
at drop.
|
|
261
|
+
- `media[]`: index `< length` replaces, `=== length` appends (an add handle),
|
|
262
|
+
`> length` is refused. A media list is never padded with `""`.
|
|
263
|
+
- A tile pairs handles freely — the drop-calendar's facecam is
|
|
264
|
+
`bindProps(src, [{ propKey: "facecamRegion", kind: "rect" }, { propKey: "facecam" }])`:
|
|
265
|
+
move it, or drop on it. Put the MEDIA entry first when a double-click should
|
|
266
|
+
mean "replace the picture".
|
|
267
|
+
|
|
268
|
+
### A drop commits the tile's seeded companions
|
|
269
|
+
|
|
270
|
+
When a file lands, every EMPTY sibling leaf on the tile that carries a
|
|
271
|
+
`seedDraft` is written with its seed — the rect's meaning travels with the
|
|
272
|
+
gesture (the clicked date; the slot number). Leaves with a value, or empty
|
|
273
|
+
leaves without a seed, are untouched.
|
|
274
|
+
|
|
275
|
+
`companion: true` marks a seeded leaf ONLY the drop fills:
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
{ propKey: "days", path: [row, "teaser"], kind: "number", seedDraft: String(teasers.length + 1), companion: true }
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
It never shows in the text form (a blur-commit there would write the seed on
|
|
282
|
+
an unrelated edit) and never earns a badge. Needs a kept `seedDraft`; refused
|
|
283
|
+
on media / rect leaves. The drop-calendar date cell, in full — one drop births
|
|
284
|
+
a pictured row:
|
|
285
|
+
|
|
286
|
+
```ts
|
|
287
|
+
bindProps(cell, [
|
|
288
|
+
{ propKey: "days", path: [n, "day"], kind: "number", onClear: "remove-element", seedDraft: String(day) },
|
|
289
|
+
{ propKey: "days", path: [n, "title"], kind: "string" },
|
|
290
|
+
{ propKey: "teasers", index: teasers.length, kind: "media" },
|
|
291
|
+
{ propKey: "days", path: [n, "teaser"], kind: "number", seedDraft: String(teasers.length + 1), companion: true },
|
|
292
|
+
])
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Starter media — the slot before the footage
|
|
296
|
+
|
|
297
|
+
A template that wants the slot present (and droppable) before the user has a
|
|
298
|
+
file renders a stand-in while the prop is empty. Two sources:
|
|
299
|
+
|
|
300
|
+
1. **Bring your own** — media bundled next to the template
|
|
301
|
+
(`assets/*.png|mp4|svg`, mirrored by copy-assets), built with
|
|
302
|
+
`fileAsset(resolve(__dirname, "assets"), name, kind)` from
|
|
303
|
+
`@m0saic/template-utils/dist/m0saic/assetPath` (asar-safe).
|
|
304
|
+
2. **Included defaults** — `starterMedia(role)` from
|
|
305
|
+
`@m0saic/template-utils/dist/media/defaultMedia` (node-only deep import):
|
|
306
|
+
roles `portrait` `landscape` `square` `facecam` `avatar` `logo`, one small
|
|
307
|
+
viewBox-only SVG each (`assets/starter/`, minted by
|
|
308
|
+
`tools/mint-starter-svg.mjs`). Returns `null` when the file is not on disk —
|
|
309
|
+
degrade to the template's own stand-in, never an error mosaic.
|
|
310
|
+
|
|
311
|
+
An `.svg` file asset is rasterized to a PNG at plan time by the engine, and
|
|
312
|
+
Make's preview still-extractor rasterizes it the same way before ffmpeg sees
|
|
313
|
+
it — ffmpeg itself has no svg decoder, so never hand an svg path to it directly.
|
|
314
|
+
A still stand-in in a video slot keeps a no-footage render a poster (PNG);
|
|
315
|
+
motion arrives with the real clip.
|
|
316
|
+
|
|
317
|
+
Make marks an EXISTING slot with no path (a starter showing) with a persistent
|
|
318
|
+
dashed outline and an "Add …" glyph. An add handle (`teasers[len]`, an unborn
|
|
319
|
+
row) is not a slot and stays quiet — otherwise every empty date cell would light.
|
|
320
|
+
|
|
321
|
+
## What Make does with them (the host side, for orientation)
|
|
322
|
+
|
|
323
|
+
- Badge row on hover: one glyph per kind (T · 123 · swatch · move · picture),
|
|
324
|
+
collapsing to one dot on a tile under ~60 on-screen px. A click on a glyph is
|
|
325
|
+
a double-click WITH that intent.
|
|
326
|
+
- Text / number / colour → the inline form over the rect (Enter / blur commit,
|
|
327
|
+
Esc cancels, an unchanged draft writes nothing). Rect → the regions draw
|
|
328
|
+
session seeded from the painted cell. Media → the chip; a drop needs no click.
|
|
329
|
+
- Every write goes through the ONE prop writer, so it survives every other
|
|
330
|
+
edit and re-renders the template; the panel field updates because it IS the
|
|
331
|
+
prop.
|
|
332
|
+
- The double-clicked tile is often chrome stacked over the bound rect (gridlines,
|
|
333
|
+
glass) — Make looks THROUGH the stack under the pointer for the topmost bound
|
|
334
|
+
tile, for clicks and drops alike.
|
|
335
|
+
|
|
336
|
+
First implementers: `@m0saic-dev/creator/drop-calendar/v1` (every kind, the
|
|
337
|
+
companion, the facecam slot); `@m0saic/alpine/*` (text / number / colour);
|
|
338
|
+
`@m0saic-dev/music/lyric-video/v1` (ranges).
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# Template status flags: `internal` / `primitive` / `deprecated`
|
|
2
|
+
|
|
3
|
+
Lookup reference for the three orthogonal discovery/visibility flags on
|
|
4
|
+
`MosaicTemplate`. A template may carry any combination; conflating them is the
|
|
5
|
+
standard mistake. Declared in https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/template/template.ts —
|
|
6
|
+
`internal?`, `primitive?`, `deprecated?` (a `MosaicTemplateDeprecation`), each
|
|
7
|
+
with its truth table in the JSDoc (re-verify:
|
|
8
|
+
`grep -n "internal?: boolean\|primitive?: boolean\|deprecated?: MosaicTemplateDeprecation" https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/template/template.ts).
|
|
9
|
+
|
|
10
|
+
**All three are CATALOG fields (0.3.1).** They describe a template without
|
|
11
|
+
changing what it renders, so they are declared in the template's catalog
|
|
12
|
+
sidecar — `<name>.catalog.json` beside its module — never in its code
|
|
13
|
+
(`catalogSidecar`, throw). The registry applies the sidecar catalog-first when
|
|
14
|
+
the template is defined, so hosts read `template.internal` / `.primitive` /
|
|
15
|
+
`.deprecated` exactly as before. Templates shipped before 0.3.1 keep the values
|
|
16
|
+
in their (frozen) code; a sidecar entry overrides them. The same goes for
|
|
17
|
+
`label`, `description`, `tags`, `platforms`, `channels` and `preview`.
|
|
18
|
+
|
|
19
|
+
| Flag | Question | Renderable alone? | Default UI |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| `primitive?: boolean` | "Is this a base others build on?" | **Yes** | Shown + **PRIMITIVE** badge (teal) |
|
|
22
|
+
| `internal?: boolean` | "Is this intended as a **top-level selection**?" (No → hidden) | **Sometimes** — the flag doesn't decide this | **Hidden**; **INTERNAL** badge (violet) when revealed |
|
|
23
|
+
| `deprecated?: MosaicTemplateDeprecation` (`{reason?, replacement?, since?}`) | "Is this still the recommended pick?" | Yes | **Hidden**; **DEPRECATED** tag + "use X instead" |
|
|
24
|
+
|
|
25
|
+
**`primitive` is informational — it does NOT hide anything.** `internal` and
|
|
26
|
+
`deprecated` are the visibility gates.
|
|
27
|
+
|
|
28
|
+
## Why `primitive` ≠ `internal`
|
|
29
|
+
|
|
30
|
+
- **`primitive` is a quality** — foundational, widely reused. `charts/donut`,
|
|
31
|
+
`charts/stat-card`, `charts/bar-graph`, `primitives/grid` are primitives *and*
|
|
32
|
+
perfectly good standalone picks.
|
|
33
|
+
- **`internal` is an INTENT/visibility flag, not a capability statement** — it says
|
|
34
|
+
"not intended as a top-level pick": excluded from public listings and template
|
|
35
|
+
pickers by default, but fully available to `renderNestedTemplate()`
|
|
36
|
+
(`internal` JSDoc, `template.ts:1375-1384`). Whether it can render standalone
|
|
37
|
+
varies by template and is NOT what the flag encodes: the ffmpeg-pulse piece
|
|
38
|
+
templates are internal yet render fine on their own; `bar-graph`'s `bar-cell`
|
|
39
|
+
leaf is internal AND genuinely expects parent-injected context. Don't infer
|
|
40
|
+
either way from the flag — read the template.
|
|
41
|
+
- **Both** is a real combination: a shared building block many templates reuse
|
|
42
|
+
that still isn't meant to be picked top-level.
|
|
43
|
+
|
|
44
|
+
(The `primitive` flag's orthogonality table in `template.ts` used to gloss
|
|
45
|
+
`internal` as "can this render on its own?", contradicting the `internal` JSDoc —
|
|
46
|
+
fixed in-code 2026-07-27; both JSDoc now carry the top-level-selection semantics.)
|
|
47
|
+
|
|
48
|
+
## Where the flags surface
|
|
49
|
+
|
|
50
|
+
- **Electron `templates:get`** (the Mosaic Desktop / Web app source (not published)) serializes all
|
|
51
|
+
three into the meta the desktop Templates page consumes.
|
|
52
|
+
- **Desktop Templates page** — PRIMITIVE / INTERNAL badges with explanatory tooltips.
|
|
53
|
+
- **CLI `list-templates` / `browse-templates`** — annotates
|
|
54
|
+
`(primitive) (internal) (deprecated)` in that **fixed order**
|
|
55
|
+
(the CLI source (not published)-33`).
|
|
56
|
+
|
|
57
|
+
## Curation is a content decision
|
|
58
|
+
|
|
59
|
+
`primitive` started as 4 seeded entries and is on **29 templates** as of 2026-07-27
|
|
60
|
+
(re-verify: `grep -rn "primitive: true" https://github.com/m0saic-project/m0saic-packages/blob/main/packages/templates/src/m0saic | wc -l`).
|
|
61
|
+
There is no rule that derives it — like `deprecated`, someone decides. If you're
|
|
62
|
+
adding a template that other templates will compose, set it (in its catalog
|
|
63
|
+
sidecar); don't wait for a sweep.
|
|
64
|
+
|
|
65
|
+
⚠️ **Deprecating obligates a pruning pass** — declare `deprecated` in the old
|
|
66
|
+
version's catalog sidecar (never its frozen code; a shipped deprecation is
|
|
67
|
+
permanent), then repoint the curated registry,
|
|
68
|
+
and remove the id from the CLI E2E cases and the e2e variant list. The full ordered
|
|
69
|
+
procedure is in the maintainers' agent contract §10 (not published) "Deprecating a template"; a deprecated id must
|
|
70
|
+
never linger in those lists. The default e2e sweep auto-excludes deprecated
|
|
71
|
+
templates; opt back in with `M0SAIC_INCLUDE_DEPRECATED=1`.
|
|
72
|
+
|
|
73
|
+
### Deprecation also silences convention advice (2026-09-09)
|
|
74
|
+
|
|
75
|
+
`M0SAIC_INCLUDE_DEPRECATED=1` governs more than the e2e render sweep: it also
|
|
76
|
+
controls **convention findings** in https://github.com/m0saic-project/m0saic-packages/blob/main/packages/templates/tools/check-registry.mjs,
|
|
77
|
+
which gates `npm run build`.
|
|
78
|
+
|
|
79
|
+
By default a deprecated template's definition-time and render-time convention
|
|
80
|
+
warnings/errors are **suppressed** — the template is defunct, so the advice will
|
|
81
|
+
never be acted on and repeating it forever is noise. This makes the intended
|
|
82
|
+
workflow self-cleaning: for a shipped template that violates a convention, **bump
|
|
83
|
+
to vN+1 and deprecate the old one — the old one goes quiet automatically.** There
|
|
84
|
+
is no exclusion list to maintain.
|
|
85
|
+
|
|
86
|
+
The `outputFormat` convention (2026-09-13: a public template declares
|
|
87
|
+
`outputHints.format`; record posture) treats both visibility gates as
|
|
88
|
+
exemptions at the audit itself, not only through this suppression: an
|
|
89
|
+
`internal` building block renders only nested and a `deprecated` template is
|
|
90
|
+
frozen history, so neither owes a deliverable declaration
|
|
91
|
+
(`auditOutputFormat`, https://github.com/m0saic-project/m0saic-packages/blob/main/packages/template-utils/src/template/auditSchemaConventions.ts).
|
|
92
|
+
|
|
93
|
+
The suppressed count is always printed, never silent:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
[check-registry] ℹ 14 finding(s) on 22 deprecated template(s) suppressed
|
|
97
|
+
(advice only — freeze + fingerprints still apply).
|
|
98
|
+
M0SAIC_INCLUDE_DEPRECATED=1 to see them.
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
⭐ **Suppression is ADVICE ONLY.** The freeze gate (`frozen.manifest.json`, every
|
|
102
|
+
template shipped in 0.1.0) and the layout fingerprints still cover deprecated
|
|
103
|
+
templates in full, byte for byte, in both modes. Deprecation means "stop
|
|
104
|
+
suggesting improvements" — it NEVER grants permission to change a shipped
|
|
105
|
+
template. See the maintainers' agent contract §10 (not published).
|
|
106
|
+
|
|
107
|
+
Measured when introduced (103 registered templates, 22 deprecated): render-time
|
|
108
|
+
warnings 21 → 12, definition-time warning knobs 208 → 165 across 30 → 25
|
|
109
|
+
templates; freeze (327 files) and fingerprints (89) identical either way.
|
|
110
|
+
|
|
111
|
+
## The repo's front door — `repo.helloWorld` (2026-09-14)
|
|
112
|
+
|
|
113
|
+
Not a template flag but a **repo-descriptor** field beside them
|
|
114
|
+
(`MosaicTemplateRepoDescriptor.helloWorld?: TemplateId`,
|
|
115
|
+
https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/template-repo/template-repo.ts): the id of the template a
|
|
116
|
+
newcomer renders first. Core names `@m0saic/hello-world/v1`; each starter names
|
|
117
|
+
its own `…/basics/hello-world/v1`. It is deliberately NOT a `TemplateRole` — roles
|
|
118
|
+
say what a template *produces*; this says which one is the door.
|
|
119
|
+
|
|
120
|
+
Readers: the CLI alias (`m0saic hello-world --template-repo <path>`), the manifest
|
|
121
|
+
(the descriptor is embedded, so `template-manifest.json` carries it zero-exec; the
|
|
122
|
+
platform loader passes it through), and — follow-up — Make's "Start here" chip.
|
|
123
|
+
The gate's `repoFrontDoor` convention (record posture) warns when the field is
|
|
124
|
+
unset or names an id the repo does not register; `internal` / `deprecated`
|
|
125
|
+
templates are fine to name, just unusual. Authoring recipe: `standalone-pack-authoring.md`
|
|
126
|
+
§1.
|
|
127
|
+
|
|
128
|
+
## A canvas that is a knob — `resolveOutputHints` (2026-09-15)
|
|
129
|
+
|
|
130
|
+
Also not a flag but a **template field** beside `outputHints`:
|
|
131
|
+
`resolveOutputHints?: (props) => Partial<MosaicTemplateOutputHints>`. The
|
|
132
|
+
static `outputHints` stay what the manifest and the cards show; the resolver
|
|
133
|
+
is what a host asks with the current props before rendering, through the one
|
|
134
|
+
helper `resolveTemplateOutputHints(tmpl, props)` (`@m0saic/template-utils`).
|
|
135
|
+
Readers: CLI `make` (+ wireframe / tutorial paths), Electron preview / cover /
|
|
136
|
+
render-to-file + the `templates:resolveOutputHints` IPC, the web design
|
|
137
|
+
preview, and Make's Device anchor (re-resolved on every prop change). The
|
|
138
|
+
seam's `outputHintsResolve` convention (THROW posture) checks it returns an
|
|
139
|
+
object, is deterministic at `defaultProps`, and agrees with the static hints
|
|
140
|
+
for every field it returns there. Precedence: [`../output-resolution-tree.md`](../output-resolution-tree.md) §size.
|
|
141
|
+
|
|
142
|
+
**Image or video is part of the same answer (2026-09-26).** `format` rides the same
|
|
143
|
+
resolver. A template whose kind depends on its inputs — a `media` prop that accepts
|
|
144
|
+
both kinds — declares it per props, `resolveOutputHints: (props) => ({ format: … })`,
|
|
145
|
+
and its static `outputHints.format` is that function's value at `defaultProps`, which
|
|
146
|
+
for an EMPTY media slot is **image** even when the template is "for" video (the
|
|
147
|
+
`outputHintsResolve` throw holds the two equal). The resolver is pure and prop-only:
|
|
148
|
+
it runs before any probe, so a path's extension is the evidence available. Exactly
|
|
149
|
+
three answers exist — the static hint at defaults, the resolver at the current
|
|
150
|
+
props, and the user's override — and nothing else authors one. Every host asks the
|
|
151
|
+
author through `resolveTemplateOutputHints(tmpl, props).format` and passes it into
|
|
152
|
+
`createDesignContext` / `createEngineContext` as `format`, so the `format` the
|
|
153
|
+
`defineMosaicTemplate` wrapper stamps on the rendered document is a RECORD of the
|
|
154
|
+
decision, never a source of it. `inferOutputKind` (`@m0saic/platform`) is a last
|
|
155
|
+
resort for a bare `.mosaic` opened cold with no template behind it, and since
|
|
156
|
+
2026-09-26 it counts a `type: "media"` video source as motion (`videoMedia`) — the
|
|
157
|
+
omission that made footage-through-a-mask read as a still. The defect class and the
|
|
158
|
+
seven-surface audit that produced this rule:
|
|
159
|
+
(internal design history).
|
|
160
|
+
|
|
161
|
+
## The lattice declarations — `lattice` (2026-09-16)
|
|
162
|
+
|
|
163
|
+
**Convention `latticeSmooth` (throw):** every split count above 12 in the rendered
|
|
164
|
+
layout — root document and every nested child, walked as documents (a nested doc
|
|
165
|
+
whose flatten fails below its floor is still measured) — is 5-smooth, `N = 2ᵃ·3ᵇ·5ᶜ`.
|
|
166
|
+
Counts ≤ 12 with a rough factor (7 weekdays, 11 tiles) pass as small-basis ratio
|
|
167
|
+
fill. Measured at the hinted canvas and, under `--sweep`, on the standard canvases.
|
|
168
|
+
Why: all delivery canvases are 5-smooth with family gcd 120, so 5-smooth counts
|
|
169
|
+
divide them (pixel-exact), any two 5-smooth self-lattices LCM to a small number,
|
|
170
|
+
and a child never inherits a rough cell size (handbook
|
|
171
|
+
[`composition-arithmetic.md`](../../handbook/composition-arithmetic.md) §1–3).
|
|
172
|
+
`m0saic doctor <repo>` reports it for external packs at error severity — the
|
|
173
|
+
publish requirement. Plan + numbers: (internal design history).
|
|
174
|
+
|
|
175
|
+
`MosaicTemplate.lattice?` (https://github.com/m0saic-project/m0saic-packages/blob/main/packages/types/src/template/template.ts, beside
|
|
176
|
+
`primitive?` / `deprecated?`) is the declaration surface — every override is typed,
|
|
177
|
+
reasoned, and printed by the gate:
|
|
178
|
+
|
|
179
|
+
| field | when it is honest | effect |
|
|
180
|
+
|---|---|---|
|
|
181
|
+
| `mode: "bitmap"` | the split counts ARE a raster (QR modules, barcode bars, a logo trace, the community M) — handbook §3c BITMAP, baked once, never live-composed | the template is skipped with a note |
|
|
182
|
+
| `allow: [{ count, reason }]` | a count above 12 that is content cardinality (53 ISO weeks; a 335-tile fixture grid) | the count is accepted; the reason is printed and carried in `--json` |
|
|
183
|
+
| `canvas: "physical"` | the hinted size is a millimetre spec at a dpi (business card 1130×678 = 2·5·113 × 2·3·113) | the rough-axis finding is not raised, counts the canvas hands down are charged to it (not to the construction), and the `--sweep` canvases are skipped — a print size cannot move |
|
|
184
|
+
|
|
185
|
+
Per DOCUMENT, `MosaicEngineMeta.lattice?: { mode: "bitmap" }` (`doc.engine.lattice`)
|
|
186
|
+
marks a raster a parent assembles itself (the business card's QR child, built from
|
|
187
|
+
`qrToRenderable` pieces) — that subtree is skipped, the parent is still measured.
|
|
188
|
+
(The layout-fingerprint sidecar cannot carry this marker: the fleet lock
|
|
189
|
+
https://github.com/m0saic-project/m0saic-packages/blob/main/packages/templates/src/lattice-audit.test.ts re-measures such a template with
|
|
190
|
+
`auditRenderedTemplate` instead of trusting the flattened string.)
|
|
191
|
+
|
|
192
|
+
**Not honest:** a count that came from your arithmetic — independent rounding to a
|
|
193
|
+
cap (121/119/241/245), a pitch matched to a grid that no longer exists (499),
|
|
194
|
+
`round(side/K)` + `ceil` self-frames (99/101), pixel splits inside an already
|
|
195
|
+
quantized cell. The finding names the nearest 5-smooth neighbours and the LCM cost;
|
|
196
|
+
the neighbour almost always looks identical.
|
|
197
|
+
|
|
198
|
+
## Reading the dictionary from a template — web vs node (2026-09-16)
|
|
199
|
+
|
|
200
|
+
`@m0saic/dictionary` has two entries: node (`index.ts`, reads `.m0`/`.m0c` from
|
|
201
|
+
disk) and browser (`browser.ts`, what the Mosaic Desktop / Web app source (not published) bundles via the package's
|
|
202
|
+
`browser` field). Every jest suite resolves the NODE entry, so a template that reads
|
|
203
|
+
a brand entry synchronously can be green under test and an error mosaic on
|
|
204
|
+
app.m0saic.io — which is exactly what QR Code's centre M, Brand Marks v3 and
|
|
205
|
+
community-m did until 2026-09-16 (the browser entry shipped every brand `m0` as `""`
|
|
206
|
+
and its `getRankSet` threw). Rules that hold on BOTH entries now:
|
|
207
|
+
|
|
208
|
+
- **`entry.m0` is populated for every entry whose canonical m0 is ≤ 40 KB**
|
|
209
|
+
(`INLINE_M0_MAX_CHARS` in https://github.com/m0saic-project/m0saic-packages/blob/main/packages/dictionary/tools/validate.js, which emits a
|
|
210
|
+
committed sibling `m0.json` per entry that `browser.ts` imports). Only
|
|
211
|
+
`brand/m-33_bitmap` (149 KB) ships `m0: ""` on web — a template that can take it
|
|
212
|
+
must guard `if (!entry.m0)` and say "Desktop renders this" (Brand Marks v3 does).
|
|
213
|
+
- **`entry.masks`, `entry.rankSets`, `entry.sourceCount` ride in `metadata.json`** →
|
|
214
|
+
identical on web. `registry.getRankSet(id, name)` works on web (same lookup as
|
|
215
|
+
node). Named mask SETS (`getMaskSet`) are node-only.
|
|
216
|
+
- **The guards, in order of reach:** https://github.com/m0saic-project/m0saic-packages/blob/main/packages/dictionary/src/browser.test.ts
|
|
217
|
+
(browser m0 == node m0 for every inlined entry; only the bitmap lazy) ·
|
|
218
|
+
https://github.com/m0saic-project/m0saic-packages/blob/main/packages/templates/src/webDictionary.test.ts (renders QR Code / Brand Marks /
|
|
219
|
+
community-m against the browser entry via `jest.mock`) · the Playwright web lane
|
|
220
|
+
the Mosaic Desktop / Web app source (not published) (the shipped bundle).
|
|
221
|
+
**Add your template to `webDictionary.test.ts` if it reads a brand entry.**
|
|
222
|
+
|
|
223
|
+
the Mosaic Desktop / Web app source (not published) copies `*.json`, so `m0.json`
|
|
224
|
+
also lands under `public/dictionary/` — harmless (≤ 10 KB each). The light entries in
|
|
225
|
+
`browser.ts` are still hand-written F-form literals; the drift test compares them
|
|
226
|
+
canonically to the generated `m0.json`.
|
|
227
|
+
|
|
228
|
+
## Known wrinkle
|
|
229
|
+
|
|
230
|
+
The Templates page's **"Show layout primitives" toggle** (renamed from "Show
|
|
231
|
+
primitives" on 2026-09-16 so the label says what it does) gates a *tag-derived*
|
|
232
|
+
Primitives **category** (tags `grid` / `primitive` — in practice the `primitives/`
|
|
233
|
+
family) — separate from the cross-cutting `primitive` **flag**, which only ranks and
|
|
234
|
+
badges. They coexist cleanly, but they are two mechanisms with one word. Driving the
|
|
235
|
+
toggle off the flag would hide most of the alpine/charts shelf by default, so the
|
|
236
|
+
founder kept the category gate and fixed the label instead.
|