@litfamily/litopencode 1.0.7 → 1.0.10
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/CHANGELOG.md +26 -0
- package/README-Ko-KR.md +348 -31
- package/README.md +347 -29
- package/dist/activation-primary-prompts.d.ts +1 -0
- package/dist/activation-primary-prompts.js +16 -0
- package/dist/activation-probe.js +4 -1
- package/dist/activation-prompt-utils.d.ts +1 -1
- package/dist/activation-routing.d.ts +6 -1
- package/dist/activation-routing.js +174 -16
- package/dist/activation-workflow-prompts.d.ts +1 -1
- package/dist/activation-workflow-prompts.js +18 -17
- package/dist/activation.d.ts +15 -8
- package/dist/activation.js +61 -7
- package/dist/agents/defaults.js +14 -6
- package/dist/cli/command-aliases.js +24 -22
- package/dist/cli/doctor.js +5 -0
- package/dist/cli/install-report.d.ts +1 -0
- package/dist/cli/install-report.js +4 -0
- package/dist/cli/install.js +7 -4
- package/dist/cli/managed-skill-assets.d.ts +1 -1
- package/dist/cli/managed-skill-assets.js +15 -5
- package/dist/cli/motion-runtime.d.ts +6 -0
- package/dist/cli/motion-runtime.js +46 -0
- package/dist/cli/native-skill-install.js +32 -9
- package/dist/cli/native-skill-integrity.js +1 -0
- package/dist/cli/native-skills.d.ts +2 -0
- package/dist/cli/native-skills.js +2 -1
- package/dist/cli/office-dependencies.d.ts +14 -0
- package/dist/cli/office-dependencies.js +24 -0
- package/dist/cli.js +13 -3
- package/dist/commands.d.ts +2 -11
- package/dist/commands.js +9 -17
- package/dist/deliverable-hedge-guard.d.ts +20 -21
- package/dist/deliverable-hedge-guard.js +234 -275
- package/dist/features.d.ts +81 -2
- package/dist/features.js +80 -13
- package/dist/hooks.d.ts +3 -2
- package/dist/hooks.js +4 -4
- package/dist/ignition.d.ts +1 -1
- package/dist/ignition.js +15 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/interface-handoff.d.ts +1 -0
- package/dist/interface-handoff.js +1 -0
- package/dist/jev-skill-hint.d.ts +48 -0
- package/dist/jev-skill-hint.js +291 -0
- package/dist/motion-image-reads.d.ts +6 -0
- package/dist/motion-image-reads.js +46 -0
- package/dist/server.js +38 -20
- package/dist/skill-renames.d.ts +4 -2
- package/dist/skill-renames.js +12 -4
- package/dist/skills.d.ts +31 -3
- package/dist/skills.js +53 -9
- package/dist/tools.js +4 -4
- package/docs/ab/S11/baseline-desktop.webp +0 -0
- package/docs/ab/S11/baseline-phone.webp +0 -0
- package/docs/ab/S11/lit-desktop.webp +0 -0
- package/docs/ab/S11/lit-phone.webp +0 -0
- package/docs/ab/S3/baseline-desktop.webp +0 -0
- package/docs/ab/S3/baseline-phone.webp +0 -0
- package/docs/ab/S3/lit-desktop.webp +0 -0
- package/docs/ab/S3/lit-phone.webp +0 -0
- package/docs/ab/S4/baseline-desktop.webp +0 -0
- package/docs/ab/S4/baseline-phone.webp +0 -0
- package/docs/ab/S4/lit-desktop.webp +0 -0
- package/docs/ab/S4/lit-phone.webp +0 -0
- package/docs/ab/S5/lit-slides.webp +0 -0
- package/docs/ab/S7/lit-diagram.webp +0 -0
- package/docs/ab/S8/baseline-slides.webp +0 -0
- package/docs/ab/S8/lit-slides.webp +0 -0
- package/docs/ab/S9/lit-pages.webp +0 -0
- package/docs/assets/cover-motion-still.webp +0 -0
- package/docs/assets/cover-motion.webp +0 -0
- package/docs/assets/readme/badge-version.svg +1 -1
- package/docs/assets/skills/autoconference.webp +0 -0
- package/docs/assets/skills/automatic-guards.webp +0 -0
- package/docs/assets/skills/autoresearch.webp +0 -0
- package/docs/assets/skills/browser-drive.webp +0 -0
- package/docs/assets/skills/debugging.webp +0 -0
- package/docs/assets/skills/deep-interview.webp +0 -0
- package/docs/assets/skills/doctor-installer.webp +0 -0
- package/docs/assets/skills/durable-litgoal.webp +0 -0
- package/docs/assets/skills/frontend-ui-ux.webp +0 -0
- package/docs/assets/skills/lit-burnoff-file.webp +0 -0
- package/docs/assets/skills/lit-burnoff.webp +0 -0
- package/docs/assets/skills/lit-code.webp +0 -0
- package/docs/assets/skills/lit-commit.webp +0 -0
- package/docs/assets/skills/lit-comprehend.webp +0 -0
- package/docs/assets/skills/lit-crucible.webp +0 -0
- package/docs/assets/skills/lit-diagram-drawer.webp +0 -0
- package/docs/assets/skills/lit-docx.webp +0 -0
- package/docs/assets/skills/lit-fetch.webp +0 -0
- package/docs/assets/skills/lit-handoff.webp +0 -0
- package/docs/assets/skills/lit-humanizer.webp +0 -0
- package/docs/assets/skills/lit-init.webp +0 -0
- package/docs/assets/skills/lit-plan.webp +0 -0
- package/docs/assets/skills/lit-pptx.webp +0 -0
- package/docs/assets/skills/lit-recap.webp +0 -0
- package/docs/assets/skills/lit-scientific-visualization.webp +0 -0
- package/docs/assets/skills/lit-typographic-motion.webp +0 -0
- package/docs/assets/skills/litresearch.webp +0 -0
- package/docs/assets/skills/litwork.webp +0 -0
- package/docs/assets/skills/lsp-setup.webp +0 -0
- package/docs/assets/skills/lsp.webp +0 -0
- package/docs/assets/skills/readme-studio.webp +0 -0
- package/docs/assets/skills/refactor.webp +0 -0
- package/docs/assets/skills/review-work.webp +0 -0
- package/docs/assets/skills/rules.webp +0 -0
- package/docs/assets/skills/start-work.webp +0 -0
- package/docs/assets/skills/structural-search.webp +0 -0
- package/docs/assets/skills/visual-qa.webp +0 -0
- package/docs/assets/skills/wikify.webp +0 -0
- package/docs/privacy.md +12 -0
- package/docs/reference-Ko-KR.md +44 -1
- package/docs/reference.md +49 -2
- package/package.json +1 -1
- package/rules/bundled-rules/lit-humanizer.md +12 -0
- package/skills/autoconference/SKILL.md +1 -1
- package/skills/autoconference/assets/report_template.md +1 -1
- package/skills/autoresearch/references/type-checklists.md +1 -1
- package/skills/browser-drive/SKILL.md +19 -5
- package/skills/browser-drive/scripts/capability-probe.mjs +26 -5
- package/skills/frontend-ui-ux/SKILL.md +10 -15
- package/skills/frontend-ui-ux/data/THIRD-PARTY-NOTICE.txt +10 -0
- package/skills/frontend-ui-ux/references/adaptive-layout.md +3 -11
- package/skills/frontend-ui-ux/references/brand-and-imagery.md +6 -11
- package/skills/frontend-ui-ux/references/complete-contract.md +10 -3
- package/skills/frontend-ui-ux/references/composition.md +1 -7
- package/skills/frontend-ui-ux/references/craft-floor.md +94 -0
- package/skills/frontend-ui-ux/references/creative-directions.md +1 -7
- package/skills/frontend-ui-ux/references/evidence-review.md +2 -12
- package/skills/frontend-ui-ux/references/implementation-platforms.md +1 -4
- package/skills/frontend-ui-ux/references/inclusive-interface.md +1 -3
- package/skills/frontend-ui-ux/references/interaction-motion.md +1 -7
- package/skills/frontend-ui-ux/references/motion-guide.md +125 -0
- package/skills/frontend-ui-ux/references/operating-lanes.md +2 -8
- package/skills/frontend-ui-ux/references/product-direction.md +1 -6
- package/skills/frontend-ui-ux/references/production.md +12 -5
- package/skills/frontend-ui-ux/references/redesign-playbook.md +1 -7
- package/skills/frontend-ui-ux/references/slop-register.md +103 -0
- package/skills/frontend-ui-ux/references/system-foundations.md +1 -8
- package/skills/frontend-ui-ux/references/taste-direction.md +4 -11
- package/skills/frontend-ui-ux/references/visual-language.md +1 -6
- package/skills/frontend-ui-ux/references/visual-reconstruction.md +2 -7
- package/skills/frontend-ui-ux/scripts/probe-page.mjs +326 -0
- package/skills/frontend-ui-ux/scripts/probe-server.mjs +24 -0
- package/skills/frontend-ui-ux/scripts/probe-static.mjs +42 -0
- package/skills/frontend-ui-ux/scripts/probe-thresholds.json +86 -0
- package/skills/frontend-ui-ux/scripts/probe.mjs +183 -0
- package/skills/lit-comprehend/SKILL.md +10 -11
- package/skills/lit-comprehend/references/artifact-template.md +2 -18
- package/skills/lit-comprehend/scripts/verify-explainer.ts +0 -14
- package/skills/lit-diagram-drawer/NOTICE.md +33 -0
- package/skills/lit-diagram-drawer/SKILL.md +101 -0
- package/skills/lit-diagram-drawer/assets/examples/type-architecture-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-architecture-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-architecture-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bar-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bar-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bar-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-beeswarm-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-beeswarm-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-beeswarm-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bubble-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bubble-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bubble-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bump-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bump-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-bump-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-data-flow-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-data-flow-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-data-flow-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-datalake-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-datalake-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-datalake-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-db-schema-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-db-schema-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-db-schema-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dependency-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dependency-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dependency-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-deployment-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-deployment-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-deployment-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dp-integration-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dp-integration-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dp-integration-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-er-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-er-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-er-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-fishbone-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-fishbone-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-fishbone-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-flowchart-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-flowchart-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-flowchart-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-gantt-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-gantt-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-gantt-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-heatmap-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-heatmap-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-heatmap-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-high-level-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-high-level-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-high-level-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-drawio-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-drawio-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-drawio-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-it-state-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-it-state-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-it-state-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-journey-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-journey-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-journey-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-kanban-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-kanban-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-kanban-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-layers-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-layers-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-layers-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-line-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-line-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-line-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-loop-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-loop-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-loop-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-marimekko-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-marimekko-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-marimekko-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-medallion-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-medallion-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-medallion-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-nested-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-nested-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-nested-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-org-chart-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-org-chart-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-org-chart-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-polar-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-polar-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-polar-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-process-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-process-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-process-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-pyramid-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-pyramid-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-pyramid-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-quadrant-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-quadrant-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-quadrant-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-queue-animated-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-queue-animated-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-queue-animated-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-radar-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-radar-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-radar-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-ridgeline-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-ridgeline-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-ridgeline-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sankey-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sankey-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sankey-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-scatter-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-scatter-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-scatter-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sequence-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sequence-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sequence-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-slopegraph-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-slopegraph-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-slopegraph-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-state-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-state-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-state-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-story-map-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-story-map-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-story-map-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-streamgraph-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-streamgraph-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-streamgraph-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-swimlane-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-swimlane-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-swimlane-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-timeline-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-timeline-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-timeline-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-tree-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-tree-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-tree-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-treemap-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-treemap-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-treemap-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-uml-class-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-uml-class-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-uml-class-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-venn-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-venn-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-venn-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-wardley-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-wardley-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-wardley-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-waterfall-dark.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-waterfall-full.html +1 -0
- package/skills/lit-diagram-drawer/assets/examples/type-waterfall-light.html +1 -0
- package/skills/lit-diagram-drawer/assets/fonts/OFL.txt +94 -0
- package/skills/lit-diagram-drawer/assets/fonts/PretendardVariable.woff2 +0 -0
- package/skills/lit-diagram-drawer/assets/fonts/provenance.json +23 -0
- package/skills/lit-diagram-drawer/assets/icons.html +231 -0
- package/skills/lit-diagram-drawer/assets/licenses/devicon-MIT.txt +20 -0
- package/skills/lit-diagram-drawer/assets/licenses/diagram-design-MIT.txt +21 -0
- package/skills/lit-diagram-drawer/assets/licenses/log-z-MIT.txt +21 -0
- package/skills/lit-diagram-drawer/assets/licenses/simple-icons-CC0.md +30 -0
- package/skills/lit-diagram-drawer/assets/licenses/tabler-MIT.txt +21 -0
- package/skills/lit-diagram-drawer/examples/01-service-architecture/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/01-service-architecture/brief.md +33 -0
- package/skills/lit-diagram-drawer/examples/02-release-decision/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/02-release-decision/brief.md +18 -0
- package/skills/lit-diagram-drawer/examples/03-data-retention/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/03-data-retention/brief.md +19 -0
- package/skills/lit-diagram-drawer/examples/04-oauth-sequence/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/04-oauth-sequence/brief.md +17 -0
- package/skills/lit-diagram-drawer/examples/05-review-lanes/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/05-review-lanes/brief.md +17 -0
- package/skills/lit-diagram-drawer/examples/06-rollout-gates/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/06-rollout-gates/brief.md +17 -0
- package/skills/lit-diagram-drawer/examples/07-deployment-boundary/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/07-deployment-boundary/brief.md +19 -0
- package/skills/lit-diagram-drawer/examples/08-policy-traces/after.html +1 -0
- package/skills/lit-diagram-drawer/examples/08-policy-traces/brief.md +20 -0
- package/skills/lit-diagram-drawer/references/accessibility.md +37 -0
- package/skills/lit-diagram-drawer/references/export.md +17 -0
- package/skills/lit-diagram-drawer/references/import-drawio.md +13 -0
- package/skills/lit-diagram-drawer/references/import-excalidraw.md +11 -0
- package/skills/lit-diagram-drawer/references/import-mermaid.md +12 -0
- package/skills/lit-diagram-drawer/references/import-schema.md +28 -0
- package/skills/lit-diagram-drawer/references/korean-typography.md +34 -0
- package/skills/lit-diagram-drawer/references/motion.md +29 -0
- package/skills/lit-diagram-drawer/references/office-pptx-docx.md +28 -0
- package/skills/lit-diagram-drawer/references/output-spec.md +48 -0
- package/skills/lit-diagram-drawer/references/primitive-annotation.md +12 -0
- package/skills/lit-diagram-drawer/references/primitive-icons.md +21 -0
- package/skills/lit-diagram-drawer/references/primitive-sketchy.md +11 -0
- package/skills/lit-diagram-drawer/references/primitive-terminal.md +11 -0
- package/skills/lit-diagram-drawer/references/profiles.md +24 -0
- package/skills/lit-diagram-drawer/references/semantic-patterns.md +27 -0
- package/skills/lit-diagram-drawer/references/style-guide.md +67 -0
- package/skills/lit-diagram-drawer/references/type-architecture.md +51 -0
- package/skills/lit-diagram-drawer/references/type-bar.md +51 -0
- package/skills/lit-diagram-drawer/references/type-beeswarm.md +49 -0
- package/skills/lit-diagram-drawer/references/type-bubble.md +49 -0
- package/skills/lit-diagram-drawer/references/type-bump.md +49 -0
- package/skills/lit-diagram-drawer/references/type-catalog.json +1433 -0
- package/skills/lit-diagram-drawer/references/type-data-flow.md +51 -0
- package/skills/lit-diagram-drawer/references/type-datalake.md +49 -0
- package/skills/lit-diagram-drawer/references/type-db-schema.md +49 -0
- package/skills/lit-diagram-drawer/references/type-dependency.md +49 -0
- package/skills/lit-diagram-drawer/references/type-deployment.md +49 -0
- package/skills/lit-diagram-drawer/references/type-dp-integration.md +49 -0
- package/skills/lit-diagram-drawer/references/type-dp-security-matrix.md +49 -0
- package/skills/lit-diagram-drawer/references/type-er.md +49 -0
- package/skills/lit-diagram-drawer/references/type-fishbone.md +49 -0
- package/skills/lit-diagram-drawer/references/type-flowchart.md +49 -0
- package/skills/lit-diagram-drawer/references/type-gantt.md +49 -0
- package/skills/lit-diagram-drawer/references/type-heatmap.md +53 -0
- package/skills/lit-diagram-drawer/references/type-high-level-vertical.md +53 -0
- package/skills/lit-diagram-drawer/references/type-high-level.md +53 -0
- package/skills/lit-diagram-drawer/references/type-import-drawio.md +53 -0
- package/skills/lit-diagram-drawer/references/type-import-excalidraw.md +53 -0
- package/skills/lit-diagram-drawer/references/type-import-mermaid.md +53 -0
- package/skills/lit-diagram-drawer/references/type-it-state.md +54 -0
- package/skills/lit-diagram-drawer/references/type-journey.md +54 -0
- package/skills/lit-diagram-drawer/references/type-kanban.md +54 -0
- package/skills/lit-diagram-drawer/references/type-layers.md +54 -0
- package/skills/lit-diagram-drawer/references/type-line.md +54 -0
- package/skills/lit-diagram-drawer/references/type-loop-terminal.md +53 -0
- package/skills/lit-diagram-drawer/references/type-loop.md +54 -0
- package/skills/lit-diagram-drawer/references/type-marimekko.md +54 -0
- package/skills/lit-diagram-drawer/references/type-medallion.md +54 -0
- package/skills/lit-diagram-drawer/references/type-nested.md +59 -0
- package/skills/lit-diagram-drawer/references/type-org-chart.md +58 -0
- package/skills/lit-diagram-drawer/references/type-paved-road-animated.md +72 -0
- package/skills/lit-diagram-drawer/references/type-polar.md +67 -0
- package/skills/lit-diagram-drawer/references/type-policy-trace-animated.md +69 -0
- package/skills/lit-diagram-drawer/references/type-process.md +58 -0
- package/skills/lit-diagram-drawer/references/type-pyramid.md +59 -0
- package/skills/lit-diagram-drawer/references/type-quadrant-consultant.md +60 -0
- package/skills/lit-diagram-drawer/references/type-quadrant.md +57 -0
- package/skills/lit-diagram-drawer/references/type-queue-animated.md +63 -0
- package/skills/lit-diagram-drawer/references/type-radar.md +57 -0
- package/skills/lit-diagram-drawer/references/type-ridgeline.md +63 -0
- package/skills/lit-diagram-drawer/references/type-sankey.md +68 -0
- package/skills/lit-diagram-drawer/references/type-scatter.md +60 -0
- package/skills/lit-diagram-drawer/references/type-sequence-oauth.md +66 -0
- package/skills/lit-diagram-drawer/references/type-sequence.md +63 -0
- package/skills/lit-diagram-drawer/references/type-slopegraph.md +65 -0
- package/skills/lit-diagram-drawer/references/type-state-lifecycle.md +53 -0
- package/skills/lit-diagram-drawer/references/type-state.md +59 -0
- package/skills/lit-diagram-drawer/references/type-story-map.md +52 -0
- package/skills/lit-diagram-drawer/references/type-streamgraph.md +53 -0
- package/skills/lit-diagram-drawer/references/type-swimlane.md +52 -0
- package/skills/lit-diagram-drawer/references/type-timeline.md +52 -0
- package/skills/lit-diagram-drawer/references/type-tree-block-decomposition.md +57 -0
- package/skills/lit-diagram-drawer/references/type-tree.md +54 -0
- package/skills/lit-diagram-drawer/references/type-treemap.md +54 -0
- package/skills/lit-diagram-drawer/references/type-uml-class.md +52 -0
- package/skills/lit-diagram-drawer/references/type-venn.md +51 -0
- package/skills/lit-diagram-drawer/references/type-wardley.md +52 -0
- package/skills/lit-diagram-drawer/references/type-waterfall.md +54 -0
- package/skills/lit-diagram-drawer/references/verifier-guide.md +59 -0
- package/skills/lit-diagram-drawer/scripts/block-registry.mjs +43 -0
- package/skills/lit-diagram-drawer/scripts/brief-contract.mjs +94 -0
- package/skills/lit-diagram-drawer/scripts/capability-probe.mjs +132 -0
- package/skills/lit-diagram-drawer/scripts/check-visible-text.mjs +15 -0
- package/skills/lit-diagram-drawer/scripts/craft-thresholds.json +15 -0
- package/skills/lit-diagram-drawer/scripts/diagram-metrics.mjs +216 -0
- package/skills/lit-diagram-drawer/scripts/doctor.mjs +8 -0
- package/skills/lit-diagram-drawer/scripts/drawio-extract.mjs +214 -0
- package/skills/lit-diagram-drawer/scripts/excalidraw-extract.mjs +151 -0
- package/skills/lit-diagram-drawer/scripts/export.mjs +133 -0
- package/skills/lit-diagram-drawer/scripts/import-shared.mjs +130 -0
- package/skills/lit-diagram-drawer/scripts/mermaid-extract.mjs +173 -0
- package/skills/lit-diagram-drawer/scripts/office-safety.mjs +120 -0
- package/skills/lit-diagram-drawer/scripts/renderer-safety.mjs +46 -0
- package/skills/lit-diagram-drawer/scripts/test-block-registry.mjs +20 -0
- package/skills/lit-diagram-drawer/scripts/test-brief-contract.mjs +27 -0
- package/skills/lit-diagram-drawer/scripts/test-importers.mjs +119 -0
- package/skills/lit-diagram-drawer/scripts/test-office-safety.mjs +67 -0
- package/skills/lit-diagram-drawer/scripts/test-sequence-verifier.mjs +28 -0
- package/skills/lit-diagram-drawer/scripts/test-visual-quality.mjs +68 -0
- package/skills/lit-diagram-drawer/scripts/verify-all.mjs +74 -0
- package/skills/lit-diagram-drawer/scripts/verify-brief.mjs +47 -0
- package/skills/lit-diagram-drawer/scripts/verify-coverage.mjs +56 -0
- package/skills/lit-diagram-drawer/scripts/verify-diagram.mjs +26 -0
- package/skills/lit-diagram-drawer/scripts/verify-motion.mjs +12 -0
- package/skills/lit-diagram-drawer/scripts/verify-type.mjs +48 -0
- package/skills/lit-diagram-drawer/scripts/visual-quality.mjs +363 -0
- package/skills/lit-docx/LICENSE-MIT.txt +21 -0
- package/skills/lit-docx/SKILL.md +78 -0
- package/skills/lit-docx/references/frontmatter_schema.md +42 -0
- package/skills/lit-docx/references/journal_style_spec.md +17 -0
- package/skills/lit-docx/references/markdown_quality_checklist.md +37 -0
- package/skills/lit-docx/references/slop_phrase_list.yaml +58 -0
- package/skills/lit-docx/references/slop_rules.md +35 -0
- package/skills/lit-docx/requirements.in +5 -0
- package/skills/lit-docx/requirements.lock +289 -0
- package/skills/lit-docx/run.py +64 -0
- package/skills/lit-docx/scripts/clean_markdown.py +95 -0
- package/skills/lit-docx/scripts/convert_md_to_docx.py +1047 -0
- package/skills/lit-docx/scripts/convert_md_to_pdf.py +281 -0
- package/skills/lit-docx/scripts/convert_pdf.py +130 -0
- package/skills/lit-docx/scripts/craft-thresholds.json +11 -0
- package/skills/lit-docx/scripts/craft_docx.py +83 -0
- package/skills/lit-docx/scripts/edit_docx.py +297 -0
- package/skills/lit-docx/scripts/embed_images.py +78 -0
- package/skills/lit-docx/scripts/generate_docx_templates.py +491 -0
- package/skills/lit-docx/scripts/slop_lint.py +485 -0
- package/skills/lit-docx/scripts/visual_audit.py +41 -0
- package/skills/lit-docx/templates/docx/acs.docx +0 -0
- package/skills/lit-docx/templates/docx/elsevier.docx +0 -0
- package/skills/lit-docx/templates/docx/ieee.docx +0 -0
- package/skills/lit-docx/templates/docx/korean-generic.docx +0 -0
- package/skills/lit-docx/templates/docx/nature.docx +0 -0
- package/skills/lit-docx/templates/latex/acs/README.md +5 -0
- package/skills/lit-docx/templates/latex/acs/template.tex +37 -0
- package/skills/lit-docx/templates/latex/elsevier/README.md +5 -0
- package/skills/lit-docx/templates/latex/elsevier/template.tex +38 -0
- package/skills/lit-docx/templates/latex/ieee/README.md +5 -0
- package/skills/lit-docx/templates/latex/ieee/template.tex +37 -0
- package/skills/lit-docx/templates/latex/korean-generic/README.md +5 -0
- package/skills/lit-docx/templates/latex/korean-generic/template.tex +37 -0
- package/skills/lit-docx/templates/latex/nature/README.md +5 -0
- package/skills/lit-docx/templates/latex/nature/template.tex +37 -0
- package/skills/lit-docx/templates/registry.yaml +1366 -0
- package/skills/lit-humanizer/NOTICE +160 -0
- package/skills/lit-humanizer/SKILL.md +122 -0
- package/skills/lit-humanizer/assets/always-on-rule.md +9 -0
- package/skills/lit-humanizer/assets/report-skeleton.md +25 -0
- package/skills/lit-humanizer/assets/slide-text-skeleton.md +28 -0
- package/skills/lit-humanizer/examples/accessibility-note/after.md +7 -0
- package/skills/lit-humanizer/examples/accessibility-note/before.md +7 -0
- package/skills/lit-humanizer/examples/api-reference/after.md +9 -0
- package/skills/lit-humanizer/examples/api-reference/before.md +15 -0
- package/skills/lit-humanizer/examples/changelog/after.md +5 -0
- package/skills/lit-humanizer/examples/changelog/before.md +12 -0
- package/skills/lit-humanizer/examples/code-comments/after.md +10 -0
- package/skills/lit-humanizer/examples/code-comments/before.md +19 -0
- package/skills/lit-humanizer/examples/commit/after.md +5 -0
- package/skills/lit-humanizer/examples/commit/before.md +7 -0
- package/skills/lit-humanizer/examples/data-release/after.md +7 -0
- package/skills/lit-humanizer/examples/data-release/before.md +9 -0
- package/skills/lit-humanizer/examples/english-essay/after.md +5 -0
- package/skills/lit-humanizer/examples/english-essay/before.md +5 -0
- package/skills/lit-humanizer/examples/incident-update/after.md +7 -0
- package/skills/lit-humanizer/examples/incident-update/before.md +7 -0
- package/skills/lit-humanizer/examples/ko-essay/after.md +7 -0
- package/skills/lit-humanizer/examples/ko-essay/before.md +9 -0
- package/skills/lit-humanizer/examples/ko-report/after.md +9 -0
- package/skills/lit-humanizer/examples/ko-report/before.md +13 -0
- package/skills/lit-humanizer/examples/ko-slide/after.md +19 -0
- package/skills/lit-humanizer/examples/ko-slide/before.md +21 -0
- package/skills/lit-humanizer/examples/meeting-brief/after.md +9 -0
- package/skills/lit-humanizer/examples/meeting-brief/before.md +11 -0
- package/skills/lit-humanizer/examples/policy-faq/after.md +9 -0
- package/skills/lit-humanizer/examples/policy-faq/before.md +9 -0
- package/skills/lit-humanizer/examples/pr/after.md +15 -0
- package/skills/lit-humanizer/examples/pr/before.md +17 -0
- package/skills/lit-humanizer/examples/project-update/after.md +7 -0
- package/skills/lit-humanizer/examples/project-update/before.md +9 -0
- package/skills/lit-humanizer/examples/readme/after.md +12 -0
- package/skills/lit-humanizer/examples/readme/before.md +14 -0
- package/skills/lit-humanizer/examples/report/after.md +13 -0
- package/skills/lit-humanizer/examples/report/before.md +11 -0
- package/skills/lit-humanizer/examples/research-abstract/after.md +5 -0
- package/skills/lit-humanizer/examples/research-abstract/before.md +5 -0
- package/skills/lit-humanizer/examples/slides/after.md +19 -0
- package/skills/lit-humanizer/examples/slides/before.md +19 -0
- package/skills/lit-humanizer/examples/troubleshooting/after.md +11 -0
- package/skills/lit-humanizer/examples/troubleshooting/before.md +11 -0
- package/skills/lit-humanizer/fixtures/ko-metrics-golden.json +49 -0
- package/skills/lit-humanizer/fixtures/office/minimal.docx +0 -0
- package/skills/lit-humanizer/fixtures/office/minimal.pptx +0 -0
- package/skills/lit-humanizer/fixtures/pos-real.txt +26 -0
- package/skills/lit-humanizer/fixtures/rule-cases.json +306 -0
- package/skills/lit-humanizer/references/code-patterns.md +468 -0
- package/skills/lit-humanizer/references/deliverable-channels.md +111 -0
- package/skills/lit-humanizer/references/en-patterns-checklist.md +43 -0
- package/skills/lit-humanizer/references/en-patterns-content.md +243 -0
- package/skills/lit-humanizer/references/en-patterns-structure.md +375 -0
- package/skills/lit-humanizer/references/en-patterns.md +57 -0
- package/skills/lit-humanizer/references/ko-metrics.md +33 -0
- package/skills/lit-humanizer/references/ko-patterns-a-d.md +659 -0
- package/skills/lit-humanizer/references/ko-patterns-e-j.md +387 -0
- package/skills/lit-humanizer/references/ko-patterns.md +31 -0
- package/skills/lit-humanizer/references/rewrite-playbook.md +54 -0
- package/skills/lit-humanizer/references/taxonomy.md +153 -0
- package/skills/lit-humanizer/rules.json +884 -0
- package/skills/lit-humanizer/scripts/core.mjs +208 -0
- package/skills/lit-humanizer/scripts/detect.mjs +91 -0
- package/skills/lit-humanizer/scripts/extract_office_text.py +89 -0
- package/skills/lit-humanizer/scripts/guard-scan.mjs +36 -0
- package/skills/lit-humanizer/scripts/ko-metrics.mjs +124 -0
- package/skills/lit-humanizer/scripts/test-fixtures.mjs +54 -0
- package/skills/lit-humanizer/scripts/test-ko-metrics.mjs +27 -0
- package/skills/lit-pptx/FORBIDDEN_TERMS.json +55 -0
- package/skills/lit-pptx/NOTICE.md +3 -0
- package/skills/lit-pptx/SKILL.md +76 -0
- package/skills/lit-pptx/agents/analyst.md +49 -0
- package/skills/lit-pptx/agents/antithesis.md +59 -0
- package/skills/lit-pptx/agents/architect.md +44 -0
- package/skills/lit-pptx/agents/critic.md +42 -0
- package/skills/lit-pptx/agents/synthesizer.md +47 -0
- package/skills/lit-pptx/agents/thesis.md +33 -0
- package/skills/lit-pptx/assets/azure/circle-lg.png +0 -0
- package/skills/lit-pptx/assets/azure/circle-md.png +0 -0
- package/skills/lit-pptx/assets/azure/circle-sm.png +0 -0
- package/skills/lit-pptx/fonts/a2z-font/A2Z-Black.otf +0 -0
- package/skills/lit-pptx/fonts/a2z-font/A2Z-Bold.otf +0 -0
- package/skills/lit-pptx/fonts/a2z-font/A2Z-Light.otf +0 -0
- package/skills/lit-pptx/fonts/a2z-font/A2Z-Medium.otf +0 -0
- package/skills/lit-pptx/fonts/a2z-font/A2Z-Regular.otf +0 -0
- package/skills/lit-pptx/fonts/a2z-font/OFL.txt +94 -0
- package/skills/lit-pptx/fonts/a2z-font/SOURCE.md +29 -0
- package/skills/lit-pptx/package-lock.json +747 -0
- package/skills/lit-pptx/package.json +13 -0
- package/skills/lit-pptx/pretendard-font/LICENSE.txt +94 -0
- package/skills/lit-pptx/pretendard-font/public/static/LitOpenCodeSans-Bold.otf +0 -0
- package/skills/lit-pptx/pretendard-font/public/static/LitOpenCodeSans-Regular.otf +0 -0
- package/skills/lit-pptx/requirements.in +2 -0
- package/skills/lit-pptx/requirements.lock +285 -0
- package/skills/lit-pptx/run.mjs +71 -0
- package/skills/lit-pptx/scripts/check_ooxml.py +47 -0
- package/skills/lit-pptx/scripts/compile-deck.js +447 -0
- package/skills/lit-pptx/scripts/craft-thresholds.json +26 -0
- package/skills/lit-pptx/scripts/craft_extras.py +224 -0
- package/skills/lit-pptx/scripts/embed_fonts.py +204 -0
- package/skills/lit-pptx/scripts/layout_inventory.py +70 -0
- package/skills/lit-pptx/scripts/learn_template.py +433 -0
- package/skills/lit-pptx/scripts/lib/derive-palette.js +176 -0
- package/skills/lit-pptx/scripts/lib/directive-parser.js +244 -0
- package/skills/lit-pptx/scripts/lib/font-map.js +79 -0
- package/skills/lit-pptx/scripts/lib/gen-bg.js +85 -0
- package/skills/lit-pptx/scripts/lib/gen-gradient-assets.js +36 -0
- package/skills/lit-pptx/scripts/lib/layout-resolver.js +737 -0
- package/skills/lit-pptx/scripts/lib/markdown-loader.js +136 -0
- package/skills/lit-pptx/scripts/lib/render-adapter-html.js +364 -0
- package/skills/lit-pptx/scripts/lib/render-adapter-pptx.js +1848 -0
- package/skills/lit-pptx/scripts/lib/slide-ast.js +534 -0
- package/skills/lit-pptx/scripts/lib/spec-validator.js +94 -0
- package/skills/lit-pptx/scripts/lib/template-registry.js +355 -0
- package/skills/lit-pptx/scripts/qa_deck.py +773 -0
- package/skills/lit-pptx/scripts/validate_pptx.py +206 -0
- package/skills/lit-pptx/specs/markdown-slide-spec-v1.md +251 -0
- package/skills/lit-pptx/specs/markdown-slide-spec-v2.md +223 -0
- package/skills/lit-pptx/specs/slide-ast-v1.schema.json +229 -0
- package/skills/lit-pptx/specs/slide-ast-v2.schema.json +144 -0
- package/skills/lit-pptx/specs/template-enrollment-contract.md +379 -0
- package/skills/lit-pptx/templates/bauhaus_light.css +4 -0
- package/skills/lit-pptx/templates/boilerplate_professional.css +508 -0
- package/skills/lit-pptx/templates/enrolled/AZURE-A2Z/capabilities.yaml +146 -0
- package/skills/lit-pptx/templates/enrolled/AZURE-A2Z/layout-mapping.yaml +454 -0
- package/skills/lit-pptx/templates/enrolled/AZURE-A2Z/template.yaml +37 -0
- package/skills/lit-pptx/templates/enrolled/AZURE-PRO/capabilities.yaml +154 -0
- package/skills/lit-pptx/templates/enrolled/AZURE-PRO/layout-mapping.yaml +483 -0
- package/skills/lit-pptx/templates/enrolled/AZURE-PRO/template.yaml +37 -0
- package/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/capabilities.yaml +179 -0
- package/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/layout-mapping.yaml +299 -0
- package/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/template.yaml +45 -0
- package/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/capabilities.yaml +181 -0
- package/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/layout-mapping.yaml +299 -0
- package/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/template.yaml +44 -0
- package/skills/lit-scientific-visualization/SKILL.md +2 -0
- package/skills/lit-typographic-motion/NOTICE +23 -0
- package/skills/lit-typographic-motion/SKILL.md +77 -0
- package/skills/lit-typographic-motion/THIRD_PARTY_NOTICES +25 -0
- package/skills/lit-typographic-motion/audio-analysis.py +52 -0
- package/skills/lit-typographic-motion/engine/browser.mjs +83 -0
- package/skills/lit-typographic-motion/engine/constants.mjs +177 -0
- package/skills/lit-typographic-motion/engine/contrast.mjs +101 -0
- package/skills/lit-typographic-motion/engine/encode.mjs +46 -0
- package/skills/lit-typographic-motion/engine/flash.mjs +216 -0
- package/skills/lit-typographic-motion/engine/look.mjs +166 -0
- package/skills/lit-typographic-motion/engine/page/common.js +105 -0
- package/skills/lit-typographic-motion/engine/page/engine.js +451 -0
- package/skills/lit-typographic-motion/engine/page/gl.js +213 -0
- package/skills/lit-typographic-motion/engine/page/lines.js +88 -0
- package/skills/lit-typographic-motion/engine/page/passes.js +144 -0
- package/skills/lit-typographic-motion/engine/page/post.js +119 -0
- package/skills/lit-typographic-motion/engine/page/scenes.js +187 -0
- package/skills/lit-typographic-motion/engine/page/type.js +321 -0
- package/skills/lit-typographic-motion/engine/png.mjs +139 -0
- package/skills/lit-typographic-motion/engine/sound.mjs +291 -0
- package/skills/lit-typographic-motion/engine/stage/capture.mjs +133 -0
- package/skills/lit-typographic-motion/engine/stage/clock.js +171 -0
- package/skills/lit-typographic-motion/engine/stage/frame-worker.mjs +47 -0
- package/skills/lit-typographic-motion/engine/stage/gate.mjs +119 -0
- package/skills/lit-typographic-motion/engine/stage/qa-page.js +158 -0
- package/skills/lit-typographic-motion/engine/stage/qa.mjs +208 -0
- package/skills/lit-typographic-motion/engine/stage/render.mjs +418 -0
- package/skills/lit-typographic-motion/engine/stage/scan.mjs +162 -0
- package/skills/lit-typographic-motion/engine/stage/stage-kit.js +310 -0
- package/skills/lit-typographic-motion/engine/stills.mjs +60 -0
- package/skills/lit-typographic-motion/engine/text.mjs +126 -0
- package/skills/lit-typographic-motion/engine/timing.mjs +289 -0
- package/skills/lit-typographic-motion/engine/treatment.mjs +254 -0
- package/skills/lit-typographic-motion/fonts/Archivo-100-400.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-100-700.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-100-900.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-125-400.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-125-700.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-125-900.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-75-400.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-75-700.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-75-900.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Archivo-OFL.txt +93 -0
- package/skills/lit-typographic-motion/fonts/Silkscreen-Bold.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/Silkscreen-OFL.txt +93 -0
- package/skills/lit-typographic-motion/fonts/Silkscreen-Regular.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/VT323-OFL.txt +93 -0
- package/skills/lit-typographic-motion/fonts/VT323-Regular.ttf +0 -0
- package/skills/lit-typographic-motion/fonts/pins.json +44 -0
- package/skills/lit-typographic-motion/fonts/stroke/CREDITS +52 -0
- package/skills/lit-typographic-motion/fonts/stroke/EMSAllure.svg +216 -0
- package/skills/lit-typographic-motion/fonts/stroke/EMSFelix.svg +216 -0
- package/skills/lit-typographic-motion/fonts/stroke/EMSOsmotron.svg +216 -0
- package/skills/lit-typographic-motion/fonts/stroke/EMSReadability.svg +216 -0
- package/skills/lit-typographic-motion/fonts/stroke/EMSTech.svg +217 -0
- package/skills/lit-typographic-motion/fonts/stroke/OFL.txt +85 -0
- package/skills/lit-typographic-motion/gate.mjs +593 -0
- package/skills/lit-typographic-motion/package-lock.json +78 -0
- package/skills/lit-typographic-motion/package.json +11 -0
- package/skills/lit-typographic-motion/probe.mjs +74 -0
- package/skills/lit-typographic-motion/references/authoring.md +110 -0
- package/skills/lit-typographic-motion/references/craft-loop.md +110 -0
- package/skills/lit-typographic-motion/references/runtime.md +88 -0
- package/skills/lit-typographic-motion/references/stage.md +164 -0
- package/skills/lit-typographic-motion/references/style-bibles.md +88 -0
- package/skills/lit-typographic-motion/references/treatment.md +143 -0
- package/skills/lit-typographic-motion/references/type-craft.md +55 -0
- package/skills/lit-typographic-motion/render.mjs +654 -0
- package/skills/lit-typographic-motion/requirements-audio.in +1 -0
- package/skills/lit-typographic-motion/requirements-audio.txt +790 -0
- package/skills/lit-typographic-motion/runtime.mjs +259 -0
- package/skills/lit-typographic-motion/word-timing-models.json +25 -0
- package/skills/litresearch/SKILL.md +41 -12
- package/skills/managed-skill-manifest.json +2367 -63
- package/skills/skill-rename-aliases.json +6 -1
- package/tools/check-pack-payload.mjs +22 -1
- package/tools/check-payload-substance.mjs +2 -2
- package/tools/payload-reference-exemptions.json +4 -0
- package/tools/payload-substance-allowlist.json +2 -3
- package/tools/payload-substance-parity.json +7 -7
- package/tools/version-manifests.json +2 -8
- package/skills/lit-korean/SKILL.md +0 -231
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
// Phase 1: brief -> timeline, pass ranges and the per-shot event schedule. Every cut is resolved
|
|
2
|
+
// here, ahead of any frame, against this brief's own text and this run's BPM or beat grid
|
|
3
|
+
// (the anchor-and-snap method, MO-A-06); scenes never carry literal frame numbers.
|
|
4
|
+
import { FRAME, flashEventThreshold, isSoftwareRenderer, limits, presets } from "./constants.mjs";
|
|
5
|
+
import { cpsFloor, eojeols, mulberry32, passSeed, readingFloor, smart, textScript } from "./text.mjs";
|
|
6
|
+
|
|
7
|
+
export const sceneKinds = Object.freeze(["title-slam", "karaoke", "kinetic-list", "counter", "signature", "end-card"]);
|
|
8
|
+
const strokeFontNames = Object.freeze(["EMSAllure", "EMSFelix", "EMSOsmotron", "EMSReadability", "EMSTech"]);
|
|
9
|
+
|
|
10
|
+
function requireText(value, label) {
|
|
11
|
+
if (typeof value !== "string" || value.trim() === "") throw new Error(`${label} needs non-empty text`);
|
|
12
|
+
return smart(value.trim().replace(/\s+/gu, " "));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Normalize the brief's scene list. A brief may give `scenes` explicitly or only `lines`.
|
|
16
|
+
export function normalizeScenes(brief) {
|
|
17
|
+
const source = Array.isArray(brief.scenes) && brief.scenes.length > 0 ? brief.scenes
|
|
18
|
+
: Array.isArray(brief.lines) && brief.lines.length > 0 ? defaultScenes(brief)
|
|
19
|
+
: typeof brief.title === "string" ? defaultScenes({ ...brief, lines: [brief.title] })
|
|
20
|
+
: undefined;
|
|
21
|
+
if (source === undefined) throw new Error("the brief needs `scenes`, `lines` or a `title`");
|
|
22
|
+
return source.map((entry, index) => {
|
|
23
|
+
const scene = entry.scene ?? entry.kind;
|
|
24
|
+
if (!sceneKinds.includes(scene)) throw new Error(`scene ${index + 1}: unknown scene "${scene}" (use ${sceneKinds.join(", ")})`);
|
|
25
|
+
const base = { scene, sceneId: entry.sceneId ?? scene, params: {} };
|
|
26
|
+
if (scene === "kinetic-list") {
|
|
27
|
+
if (!Array.isArray(entry.items) || entry.items.length < 2) throw new Error(`scene ${index + 1}: kinetic-list needs at least two items`);
|
|
28
|
+
base.params.items = entry.items.map((item, i) => requireText(item, `kinetic-list item ${i + 1}`));
|
|
29
|
+
base.params.heading = entry.heading ? requireText(entry.heading, "kinetic-list heading") : undefined;
|
|
30
|
+
base.text = [base.params.heading, ...base.params.items].filter(Boolean).join("\n");
|
|
31
|
+
} else if (scene === "counter") {
|
|
32
|
+
const to = Number(entry.to), from = Number(entry.from ?? 0);
|
|
33
|
+
if (!Number.isFinite(to) || !Number.isFinite(from)) throw new Error(`scene ${index + 1}: counter needs numeric from/to`);
|
|
34
|
+
base.params.from = from; base.params.to = to;
|
|
35
|
+
base.params.label = entry.label ? requireText(entry.label, "counter label") : undefined;
|
|
36
|
+
base.text = [String(Math.round(to)), base.params.label].filter(Boolean).join("\n");
|
|
37
|
+
} else if (scene === "signature") {
|
|
38
|
+
base.params.font = entry.font ?? "EMSAllure";
|
|
39
|
+
if (!strokeFontNames.includes(base.params.font)) throw new Error(`scene ${index + 1}: signature font must be one of ${strokeFontNames.join(", ")}`);
|
|
40
|
+
base.text = requireText(entry.text, "signature");
|
|
41
|
+
} else if (scene === "end-card") {
|
|
42
|
+
base.params.title = requireText(entry.text ?? entry.title, "end-card");
|
|
43
|
+
base.params.sub = entry.sub ? requireText(entry.sub, "end-card sub line") : undefined;
|
|
44
|
+
base.params.paragraph = entry.paragraph ? requireText(entry.paragraph, "end-card paragraph") : undefined;
|
|
45
|
+
base.text = [base.params.title, base.params.sub, base.params.paragraph].filter(Boolean).join("\n");
|
|
46
|
+
} else {
|
|
47
|
+
base.text = requireText(entry.text, scene);
|
|
48
|
+
}
|
|
49
|
+
return base;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function defaultScenes(brief) {
|
|
54
|
+
const lines = brief.lines.map((line) => String(line));
|
|
55
|
+
const title = typeof brief.title === "string" && brief.title.trim() ? brief.title : lines[0];
|
|
56
|
+
const body = typeof brief.title === "string" && brief.title.trim() ? lines : lines.slice(1);
|
|
57
|
+
const scenes = [{ scene: "title-slam", text: title }];
|
|
58
|
+
for (const line of body.slice(0, -1)) scenes.push({ scene: "karaoke", text: line });
|
|
59
|
+
const last = body.at(-1);
|
|
60
|
+
scenes.push({ scene: "end-card", text: title, sub: last && last !== title ? last : undefined });
|
|
61
|
+
return scenes;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// The beat grid: Tier 1 is k * 60 / bpm; Tier 2 is the analysed beats. Both start at film time 0.
|
|
65
|
+
export function makeGrid({ bpm, beatGrid }) {
|
|
66
|
+
if (Array.isArray(beatGrid) && beatGrid.length >= 2) {
|
|
67
|
+
const beats = [0, ...beatGrid.filter((t) => t > 1 / FRAME.fps)].sort((a, b) => a - b);
|
|
68
|
+
const intervals = beatGrid.slice(1).map((t, i) => t - beatGrid[i]).filter((d) => d > 0).sort((a, b) => a - b);
|
|
69
|
+
const beat = intervals[Math.floor(intervals.length / 2)] ?? 60 / limits.defaultBpm;
|
|
70
|
+
return {
|
|
71
|
+
beat,
|
|
72
|
+
at(index) { return index < beats.length ? beats[index] : beats.at(-1) + (index - beats.length + 1) * beat; },
|
|
73
|
+
indexAtOrAfter(time) {
|
|
74
|
+
for (let i = 0; ; i++) if (this.at(i) >= time - 1e-9) return i;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const beat = 60 / bpm;
|
|
79
|
+
return {
|
|
80
|
+
beat,
|
|
81
|
+
at(index) { return index * beat; },
|
|
82
|
+
indexAtOrAfter(time) { return Math.max(0, Math.ceil(time / beat - 1e-9)); }
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const round6 = (value) => Math.round(value * 1e6) / 1e6;
|
|
87
|
+
|
|
88
|
+
function holdFor(scene) {
|
|
89
|
+
const kind = scene.scene === "kinetic-list" || scene.scene === "end-card" ? "scene" : "line";
|
|
90
|
+
const floor = Math.max(readingFloor(scene.text, kind), cpsFloor(scene.text, kind));
|
|
91
|
+
return { kind, floor };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// MO-A-09..16: each shot holds 1.25 x its floor, at least two beats, and every start lands on a grid beat.
|
|
95
|
+
// A treatment's durationSec is the target: when the natural film is shorter, every hold scales up by the
|
|
96
|
+
// same factor (never below its floor) and the last shot reaches the target; when the reading floors
|
|
97
|
+
// force a longer film, the film keeps its floors and `floorForced` says so.
|
|
98
|
+
export function buildTimeline(brief, { bpm = limits.defaultBpm, beatGrid, targetDurationSec } = {}) {
|
|
99
|
+
const natural = layoutTimeline(brief, { bpm, beatGrid, holdScale: 1 });
|
|
100
|
+
if (!(targetDurationSec > 0)) return natural;
|
|
101
|
+
if (natural.durationSec > targetDurationSec + 1e-9) return { ...natural, targetDurationSec, floorForced: true };
|
|
102
|
+
const holdScale = targetDurationSec / natural.durationSec;
|
|
103
|
+
const scaled = layoutTimeline(brief, { bpm, beatGrid, holdScale, targetDurationSec });
|
|
104
|
+
return { ...scaled, targetDurationSec, floorForced: false };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function layoutTimeline(brief, { bpm, beatGrid, holdScale, targetDurationSec = 0 }) {
|
|
108
|
+
const scenes = normalizeScenes(brief);
|
|
109
|
+
const grid = makeGrid({ bpm, beatGrid });
|
|
110
|
+
const shotCounts = new Map();
|
|
111
|
+
const timeline = [];
|
|
112
|
+
let index = 0;
|
|
113
|
+
const minDuration = Math.max(limits.minDurationSec, Number(brief.minDurationSec ?? 0) || 0, targetDurationSec);
|
|
114
|
+
scenes.forEach((scene, sceneIndex) => {
|
|
115
|
+
const shotIndex = shotCounts.get(scene.sceneId) ?? 0;
|
|
116
|
+
shotCounts.set(scene.sceneId, shotIndex + 1);
|
|
117
|
+
const { kind, floor } = holdFor(scene);
|
|
118
|
+
const start = grid.at(index);
|
|
119
|
+
const units = revealTexts(scene);
|
|
120
|
+
let unitIndex = index;
|
|
121
|
+
const unitStarts = [];
|
|
122
|
+
for (let i = 0; i < units.length; i++) {
|
|
123
|
+
unitStarts.push(grid.at(unitIndex));
|
|
124
|
+
let step = unitIndex + 1;
|
|
125
|
+
while (grid.at(step) - grid.at(unitIndex) < Math.max(limits.revealFloor, scene.scene === "kinetic-list" ? 0.5 : 0) - 1e-9) step++;
|
|
126
|
+
unitIndex = step;
|
|
127
|
+
}
|
|
128
|
+
const revealSpan = units.length > 0 ? grid.at(unitIndex) - start : 0;
|
|
129
|
+
let needed = Math.max(limits.generatorMargin * floor, revealSpan + limits.minSceneBeats * grid.beat, limits.minSceneBeats * grid.beat) * holdScale;
|
|
130
|
+
if (sceneIndex === scenes.length - 1) needed = Math.max(needed, minDuration - start);
|
|
131
|
+
let endIndex = grid.indexAtOrAfter(start + needed - 1e-9);
|
|
132
|
+
while (endIndex - index < limits.minSceneBeats) endIndex++;
|
|
133
|
+
const end = grid.at(endIndex);
|
|
134
|
+
const shot = {
|
|
135
|
+
id: `${scene.sceneId}#${shotIndex}`, sceneId: scene.sceneId, shotIndex,
|
|
136
|
+
start: round6(start), end: round6(end), holdSec: round6(end - start),
|
|
137
|
+
kind, text: scene.text, script: textScript(scene.text), beatSec: round6(start),
|
|
138
|
+
scene: scene.scene, params: scene.params, floorSec: round6(floor), stateful: false, prerollMax: 0
|
|
139
|
+
};
|
|
140
|
+
timeline.push(shot);
|
|
141
|
+
units.forEach((text, i) => {
|
|
142
|
+
const unitStart = unitStarts[i];
|
|
143
|
+
const unitEnd = i + 1 < units.length ? unitStarts[i + 1] : end;
|
|
144
|
+
timeline.push({
|
|
145
|
+
id: `${shot.id}/r${i}`, sceneId: scene.sceneId, shotIndex, start: round6(unitStart), end: round6(unitEnd),
|
|
146
|
+
holdSec: round6(unitEnd - unitStart), kind: "reveal", text, script: textScript(text), beatSec: round6(unitStart)
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
index = endIndex;
|
|
150
|
+
});
|
|
151
|
+
return { timeline, grid, durationSec: timeline.filter(isShot).at(-1).end };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export const isShot = (entry) => entry.kind === "line" || entry.kind === "scene";
|
|
155
|
+
|
|
156
|
+
// MO-A-28: sub-sample i of N for output frame n sits at t_n + (shutter/fps)((i + 0.5)/N - 0.5), >= 0.
|
|
157
|
+
export function pinnedSampleTimes(frame, samples, shutter, fps = FRAME.fps) {
|
|
158
|
+
return Array.from({ length: samples }, (_, i) => Math.max(0, frame / fps + (shutter / fps) * ((i + 0.5) / samples - 0.5)));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function revealTexts(scene) {
|
|
162
|
+
if (scene.scene === "karaoke") return eojeols(scene.text);
|
|
163
|
+
if (scene.scene === "kinetic-list") return scene.params.items;
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// MO-C-29: the accent belongs to one timeline entry and at most 10% of frames.
|
|
168
|
+
export function chooseAccentEntry(timeline, presetId, durationSec) {
|
|
169
|
+
if (!presets[presetId].palette.accent) return undefined;
|
|
170
|
+
const shots = timeline.filter(isShot);
|
|
171
|
+
const candidate = [...shots].reverse().find((shot) => shot.scene === "end-card" || shot.scene === "counter");
|
|
172
|
+
if (!candidate) return undefined;
|
|
173
|
+
return candidate.holdSec / durationSec <= limits.accentMaxFrameFraction ? candidate.id : undefined;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// MO-SH-03: the precomputed per-shot event schedule (glitch hits, surges, boot-flicker bursts).
|
|
177
|
+
// Events are admitted only while every 1 s window of the shot holds at most two of them.
|
|
178
|
+
export function eventSchedule(timeline, presetId, runSeed) {
|
|
179
|
+
const look = presets[presetId];
|
|
180
|
+
const events = [];
|
|
181
|
+
for (const shot of timeline.filter(isShot)) {
|
|
182
|
+
const accepted = [];
|
|
183
|
+
const admit = (event) => {
|
|
184
|
+
const times = [...accepted.map((other) => other.time), event.time].sort((a, b) => a - b);
|
|
185
|
+
const cap = limits.eventsPerSecondPerShot;
|
|
186
|
+
for (let i = 0; i + cap < times.length; i++) if (times[i + cap] - times[i] < 1 - 1e-9) return false;
|
|
187
|
+
accepted.push(event);
|
|
188
|
+
return true;
|
|
189
|
+
};
|
|
190
|
+
const shotRef = { sceneId: shot.sceneId, shotIndex: shot.shotIndex };
|
|
191
|
+
if (look.passes.includes("terminal-ui")) admit({ kind: "boot-flicker", time: shot.start, durationSec: look.motion.bootFlickerSec, ...shotRef });
|
|
192
|
+
if (look.passes.includes("tidal-gradient")) {
|
|
193
|
+
const p = look.params["tidal-gradient"];
|
|
194
|
+
const gap = Math.max(1 / p.surgeCapPerSec, 2.4);
|
|
195
|
+
for (let t = shot.start + 0.3; t < shot.end - p.surgeAttackSec - p.surgeDecaySec; t += gap) {
|
|
196
|
+
admit({ kind: "surge", time: round6(t), attackSec: p.surgeAttackSec, decaySec: p.surgeDecaySec, amount: p.surgeOnHit, ...shotRef });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (look.passes.includes("glitch")) {
|
|
200
|
+
const p = look.params.glitch;
|
|
201
|
+
const random = mulberry32(passSeed(runSeed, shot.sceneId, shot.shotIndex, "glitch"));
|
|
202
|
+
const gap = 1 / p.hitRatePerSec;
|
|
203
|
+
const holdSec = p.holdFrames / FRAME.fps;
|
|
204
|
+
const firstAt = shot.start + (presetId === "tidal" ? shot.holdSec * 0.55 : 0.6);
|
|
205
|
+
for (let t = firstAt; t < shot.end - 0.3 - holdSec; t += gap) {
|
|
206
|
+
const hit = glitchHit(random, p, round6(t));
|
|
207
|
+
admit({ kind: "glitch", ...hit, ...shotRef });
|
|
208
|
+
if (presetId === "tidal") break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
events.push(...accepted.sort((a, b) => a.time - b.time));
|
|
212
|
+
}
|
|
213
|
+
return events;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// One glitch hit = one displace plus one restore: slices, an RGB split and a few corrupt blocks,
|
|
217
|
+
// drawn once from the shot's seeded stream and held for `holdFrames` without re-rolling.
|
|
218
|
+
function glitchHit(random, p, time) {
|
|
219
|
+
const areaRows = Math.floor(FRAME.height * Math.min(p.areaCapPct, limits.glitchAreaCapPct) / 100);
|
|
220
|
+
const slices = [];
|
|
221
|
+
let rows = 0;
|
|
222
|
+
for (let i = 0; i < p.sliceCount && rows < areaRows; i++) {
|
|
223
|
+
const height = Math.min(areaRows - rows, Math.round(8 + random() * (areaRows / p.sliceCount)));
|
|
224
|
+
const y = Math.round(random() * (FRAME.height - height));
|
|
225
|
+
const offset = Math.round((random() * 2 - 1) * p.maxOffsetPx);
|
|
226
|
+
slices.push([y, height, offset]);
|
|
227
|
+
rows += height;
|
|
228
|
+
}
|
|
229
|
+
const blocks = Array.from({ length: 3 }, () => [
|
|
230
|
+
Math.round(random() * (FRAME.width - p.blockCorruptSize[0])), Math.round(random() * (FRAME.height - p.blockCorruptSize[1])),
|
|
231
|
+
Math.round((random() * 2 - 1) * 64), Math.round((random() * 2 - 1) * 36)
|
|
232
|
+
]);
|
|
233
|
+
return { time, holdFrames: p.holdFrames, slices, blocks, rgbSplitPx: p.rgbSplitPx, areaPct: round6((rows / FRAME.height) * 100) };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// MO-SH-00 / §A10: one passRanges entry per pass per shot, with MO-SH-01 seeds.
|
|
237
|
+
export function buildPassRanges({ timeline, presetId, runSeed, renderer, events }) {
|
|
238
|
+
const look = presets[presetId];
|
|
239
|
+
const software = isSoftwareRenderer(renderer);
|
|
240
|
+
const ranges = [];
|
|
241
|
+
for (const shot of timeline.filter(isShot)) {
|
|
242
|
+
const frameStart = Math.round(shot.start * FRAME.fps);
|
|
243
|
+
const frameEnd = Math.round(shot.end * FRAME.fps) - 1;
|
|
244
|
+
const shotEvents = events.filter((event) => event.sceneId === shot.sceneId && event.shotIndex === shot.shotIndex);
|
|
245
|
+
for (const pass of look.passes) {
|
|
246
|
+
const p = look.params[pass] ?? {};
|
|
247
|
+
let params = {};
|
|
248
|
+
let downgraded = false;
|
|
249
|
+
if (pass === "swiss-grid") params = { columns: p.columns, gutterPx: p.gutterPx, marginPx: p.marginPx, baselinePx: p.baselinePx, showGuides: p.showGuides };
|
|
250
|
+
else if (pass === "dither") params = { mode: p.mode, paletteSize: p.paletteSize, pixelScale: p.pixelScale, ditherStrength: p.ditherStrength };
|
|
251
|
+
else if (pass === "glitch") {
|
|
252
|
+
const hits = shotEvents.filter((event) => event.kind === "glitch");
|
|
253
|
+
params = { intensity: p.intensity, hitRatePerSecRealized: round6(hits.length / shot.holdSec), areaCapPct: p.areaCapPct,
|
|
254
|
+
maxAreaPctRealized: Math.max(0, ...hits.map((hit) => hit.areaPct)), holdFrames: p.holdFrames };
|
|
255
|
+
} else if (pass === "tidal-gradient") {
|
|
256
|
+
const octaves = software ? Math.max(3, Math.floor(p.octaves / 2)) : p.octaves;
|
|
257
|
+
downgraded = software;
|
|
258
|
+
params = { paletteStopsHex: [look.palette.signal, look.palette.stopB], octaves, flowSpeed: p.flowSpeed,
|
|
259
|
+
surgeCountRealized: shotEvents.filter((event) => event.kind === "surge").length, surgeCapPerSec: p.surgeCapPerSec,
|
|
260
|
+
surgeAttackSec: p.surgeAttackSec, surgeDecaySec: p.surgeDecaySec, ditherAmount: p.ditherAmount };
|
|
261
|
+
} else if (pass === "crt") {
|
|
262
|
+
downgraded = software;
|
|
263
|
+
params = { flickerAmpRealized: p.flickerAmp, scanlineFreq: p.scanlineFreqPerFrame, scanlineDepth: p.scanlineDepth,
|
|
264
|
+
curvature: p.curvature, vignette: p.vignette, persistenceEnabled: !software && p.phosphorPersistence > 0 };
|
|
265
|
+
} else if (pass === "terminal-ui") {
|
|
266
|
+
params = { compositedThrough: look.passes.filter((id) => id === "crt" || id === "dither"), meterCount: p.meterCount,
|
|
267
|
+
logLineRateCharsPerSec: p.logLineRateCharsPerSec, wordTimingSource: p.wordTimingSource, layers: 1 };
|
|
268
|
+
}
|
|
269
|
+
ranges.push({
|
|
270
|
+
pass, frameStart, frameEnd, sceneId: shot.sceneId, shotIndex: shot.shotIndex,
|
|
271
|
+
seed: pass === "swiss-grid" ? null : passSeed(runSeed, shot.sceneId, shot.shotIndex, pass), params, downgraded
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return ranges;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// A shot composited through CRT phosphor persistence carries state across frames (the previous
|
|
279
|
+
// frame's pre-CRT image), so it is stateful with a one-frame preroll (MO-A-05, MO-SH-07).
|
|
280
|
+
export const persistenceFrames = 1;
|
|
281
|
+
export function markStateful(timeline, passRanges) {
|
|
282
|
+
for (const shot of timeline.filter(isShot)) {
|
|
283
|
+
const crt = passRanges.find((range) => range.pass === "crt" && range.sceneId === shot.sceneId && range.shotIndex === shot.shotIndex);
|
|
284
|
+
shot.stateful = Boolean(crt?.params.persistenceEnabled);
|
|
285
|
+
shot.prerollMax = shot.stateful ? round6(persistenceFrames / FRAME.fps) : 0;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export { flashEventThreshold };
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// The film treatment (`treatment.json` in the run's output directory). Every render validates it
|
|
2
|
+
// first, on both paths, and stops with exit 16 naming the first field that fails. The rules keep a
|
|
3
|
+
// film from restating the request as its copy, from shipping a copied example, and from claiming a
|
|
4
|
+
// drawn subject it does not have. Pure functions; nothing here reads a clock or the network.
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
export const TREATMENT_EXIT = 16;
|
|
10
|
+
export const genres = Object.freeze(["announcement", "brand-mood", "event", "explainer", "motion-graphics", "type-led", "other"]);
|
|
11
|
+
export const arcStages = Object.freeze({ announcement: 5, event: 4, explainer: 4, "brand-mood": 4, "motion-graphics": 5, other: 3 });
|
|
12
|
+
export const deviceKinds = Object.freeze(["illustration", "diagram", "chart", "icon", "shape", "path", "mask", "depth3d", "particles", "grid", "gradient", "photo-texture"]);
|
|
13
|
+
export const textureKinds = Object.freeze(["grid", "gradient", "particles", "photo-texture"]);
|
|
14
|
+
export const soundModes = Object.freeze(["generated", "supplied", "authored", "none"]);
|
|
15
|
+
export const soundPalettes = Object.freeze(["glass", "warm", "pulse", "air"]);
|
|
16
|
+
// The product's own verified faces: the families `/lit/fonts.css` serves and the type engine draws.
|
|
17
|
+
export const productFaces = Object.freeze(["Archivo", "LitOpenCode Sans", "VT323", "Silkscreen", "MesloLGS NF", "Galmuri9"]);
|
|
18
|
+
const floorTenGenres = new Set(["announcement", "event", "explainer", "motion-graphics"]);
|
|
19
|
+
|
|
20
|
+
// NFC, lowercase, then no whitespace and no punctuation.
|
|
21
|
+
export function normalize(text) {
|
|
22
|
+
return String(text ?? "").normalize("NFC").toLowerCase().replace(/[\s\p{P}]/gu, "");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Quoted spans: "…", “…”, '…' (not an apostrophe inside a word) and 「…」.
|
|
26
|
+
const quotePattern = /"([^"\n]+)"|“([^”\n]+)”|(?<![\p{L}\p{N}])'([^'\n]+)'(?![\p{L}\p{N}])|「([^」\n]+)」/gu;
|
|
27
|
+
export function quotedSpans(text) {
|
|
28
|
+
return [...String(text ?? "").matchAll(quotePattern)].map((match) => match[1] ?? match[2] ?? match[3] ?? match[4]);
|
|
29
|
+
}
|
|
30
|
+
export function withoutQuotes(text) {
|
|
31
|
+
return String(text ?? "").replace(quotePattern, " ");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// A type-led cue: a typographic compound, an explicit kinetic-type or lyric request, or a quoted span
|
|
35
|
+
// of two or more words. Finding a quote is cue detection only; nothing inside it is followed.
|
|
36
|
+
const typeCompound = /(?<![a-z])(?:typographic motion|kinetic typograph(?:y|ic)|kinetic type|lyric video|title sequence|opening titles?|typography (?:video|film|clip))(?![a-z])|타이포\s?모션|키네틱\s?타이포(?:그래피)?|타이포그래피\s?영상|타이포\s?영상|가사\s?영상|리릭\s?(?:비디오|영상)|오프닝\s?타이틀|타이틀\s?시퀀스/iu;
|
|
37
|
+
export function typeLedCue(request) {
|
|
38
|
+
const text = String(request ?? "");
|
|
39
|
+
const compound = text.match(typeCompound);
|
|
40
|
+
if (compound) return compound[0];
|
|
41
|
+
const quote = quotedSpans(text).find((span) => span.trim().split(/\s+/u).length >= 2);
|
|
42
|
+
return quote ? `a quoted span of ${quote.trim().split(/\s+/u).length} words` : null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// A shared substring of `size` or more normalized characters.
|
|
46
|
+
export function sharesSubstring(a, b, size) {
|
|
47
|
+
if (size < 1 || a.length < size || b.length < size) return false;
|
|
48
|
+
const grams = new Set();
|
|
49
|
+
for (let i = 0; i + size <= b.length; i++) grams.add(b.slice(i, i + size));
|
|
50
|
+
for (let i = 0; i + size <= a.length; i++) if (grams.has(a.slice(i, i + size))) return true;
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
// min(10, half the normalized request length, quoted spans removed); no check below 2 characters.
|
|
54
|
+
export function restateLimit(request) {
|
|
55
|
+
const size = Math.min(10, Math.floor(normalize(withoutQuotes(request)).length / 2));
|
|
56
|
+
return size >= 2 ? size : 0;
|
|
57
|
+
}
|
|
58
|
+
export function restates(text, request) {
|
|
59
|
+
const size = restateLimit(request);
|
|
60
|
+
return size > 0 && sharesSubstring(normalize(text), normalize(withoutQuotes(request)), size);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const placeholder = /<[^<>\n]{1,80}>/u;
|
|
64
|
+
const sentences = (text) => String(text).split(/(?<=[.!?。…])\s+/u).map((part) => part.trim()).filter(Boolean);
|
|
65
|
+
const lengthAsked = /\d+(?:\.\d+)?\s*(?:s|sec|secs|seconds?|min|mins|minutes?|초|분)(?![a-z])/iu;
|
|
66
|
+
const silenceAsked = /(?<![a-z])(?:silent|silence|no (?:sound|music|audio)|without (?:sound|music|audio)|muted?)(?![a-z])|무음|소리\s?없|음악\s?없|소리\s?빼/iu;
|
|
67
|
+
const keyPattern = /^[A-G][#b]? (?:major|minor)$/u;
|
|
68
|
+
|
|
69
|
+
class Invalid extends Error {
|
|
70
|
+
constructor(field, detail) { super(detail); this.field = field; }
|
|
71
|
+
}
|
|
72
|
+
const need = (condition, field, detail) => { if (!condition) throw new Invalid(field, detail); };
|
|
73
|
+
const text = (value) => typeof value === "string" && value.trim().length > 0;
|
|
74
|
+
|
|
75
|
+
// Every string leaf, for the placeholder check.
|
|
76
|
+
function stringLeaves(value, at = "", out = []) {
|
|
77
|
+
if (typeof value === "string") out.push([at, value]);
|
|
78
|
+
else if (Array.isArray(value)) value.forEach((item, i) => stringLeaves(item, `${at}[${i}]`, out));
|
|
79
|
+
else if (value && typeof value === "object") for (const [key, item] of Object.entries(value)) stringLeaves(item, at ? `${at}.${key}` : key, out);
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// The free-text leaves the copied-example rule compares.
|
|
84
|
+
export function freeTextLeaves(t) {
|
|
85
|
+
const leaves = [t?.idea, t?.audience, t?.channel, t?.ambition];
|
|
86
|
+
for (const beat of Array.isArray(t?.beats) ? t.beats : []) leaves.push(beat?.purpose, beat?.onScreen, beat?.motion, beat?.sound);
|
|
87
|
+
for (const line of Array.isArray(t?.copy?.lines) ? t.copy.lines : []) leaves.push(line);
|
|
88
|
+
for (const entry of Array.isArray(t?.palette) ? t.palette : []) leaves.push(entry?.role);
|
|
89
|
+
return leaves.filter((leaf) => typeof leaf === "string").map(normalize).filter(Boolean);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Shipped examples: every ```json block in references/treatment.md.
|
|
93
|
+
const skillRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
94
|
+
export function shippedExamples(root = skillRoot) {
|
|
95
|
+
const file = path.join(root, "references", "treatment.md");
|
|
96
|
+
if (!existsSync(file)) return [];
|
|
97
|
+
return [...readFileSync(file, "utf8").matchAll(/```json\n([\s\S]*?)```/gu)].flatMap((match) => {
|
|
98
|
+
try { return [JSON.parse(match[1])]; } catch { return []; }
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
export function copiesExample(t, examples = shippedExamples()) {
|
|
102
|
+
const leaves = freeTextLeaves(t);
|
|
103
|
+
if (leaves.length === 0) return false;
|
|
104
|
+
return examples.some((example) => {
|
|
105
|
+
// A placeholder's angle brackets are markup, so an unbracketed copy still counts as the example.
|
|
106
|
+
const known = new Set(freeTextLeaves(example).map((leaf) => leaf.replace(/[<>]/gu, "")));
|
|
107
|
+
return leaves.filter((leaf) => known.has(leaf)).length * 2 >= leaves.length;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function checkBeats(t) {
|
|
112
|
+
need(Array.isArray(t.beats) && t.beats.length > 0, "beats", "beats must be a non-empty array");
|
|
113
|
+
t.beats.forEach((beat, i) => {
|
|
114
|
+
need(beat && typeof beat === "object", "beats", `beat ${i} must be an object`);
|
|
115
|
+
for (const key of ["purpose", "onScreen", "motion", "sound"]) need(text(beat[key]), "beats", `beat ${i} needs ${key}`);
|
|
116
|
+
need(Number.isFinite(beat.t0) && Number.isFinite(beat.t1), "beats", `beat ${i} needs numeric t0 and t1`);
|
|
117
|
+
need(beat.t1 - beat.t0 >= 1.2 - 1e-9, "beats", `beat ${i} lasts ${(beat.t1 - beat.t0).toFixed(2)} s; every beat is at least 1.2 s`);
|
|
118
|
+
if (i > 0) {
|
|
119
|
+
need(beat.t0 >= t.beats[i - 1].t0, "beats", `beat ${i} starts before beat ${i - 1}`);
|
|
120
|
+
need(beat.t0 - t.beats[i - 1].t1 <= 0.25 + 1e-9, "beats", `a gap of ${(beat.t0 - t.beats[i - 1].t1).toFixed(2)} s before beat ${i}; gaps are at most 0.25 s`);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
need(t.beats[0].t0 <= 0.25 + 1e-9, "beats", "the first beat must start within 0.25 s of 0");
|
|
124
|
+
need(t.beats.at(-1).t1 >= t.durationSec - 0.25 - 1e-9, "beats", "the last beat must reach durationSec (gap at most 0.25 s)");
|
|
125
|
+
const stages = t.genre === "type-led" ? (t.copy?.source === "user" ? t.copy.lines.length : 1) : arcStages[t.genre];
|
|
126
|
+
need(t.beats.length >= stages, "beats", `${t.genre} needs at least ${stages} beats (its arc), found ${t.beats.length}`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function beatSeconds(t, indices) {
|
|
130
|
+
const covered = new Set(indices);
|
|
131
|
+
return [...covered].reduce((sum, i) => sum + (t.beats[i].t1 - t.beats[i].t0), 0);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Returns { ok: true } or { ok: false, field, detail }.
|
|
135
|
+
export function validateTreatment(t, { examples } = {}) {
|
|
136
|
+
try {
|
|
137
|
+
need(t && typeof t === "object" && !Array.isArray(t), "treatment", "treatment.json must hold a JSON object");
|
|
138
|
+
const leaf = stringLeaves(t).find(([, value]) => placeholder.test(value));
|
|
139
|
+
need(!leaf, leaf?.[0].split(/[.[]/u)[0] || "treatment", `${leaf?.[0]} still holds a placeholder (${leaf?.[1]})`);
|
|
140
|
+
need(text(t.request), "request", "request must be the user's words, verbatim");
|
|
141
|
+
need(genres.includes(t.genre), "genre", `genre must be one of ${genres.join(", ")}`);
|
|
142
|
+
need(["type", "stage"].includes(t.path), "path", "path must be type or stage");
|
|
143
|
+
need(text(t.pathReason), "pathReason", "pathReason must say why this path fits");
|
|
144
|
+
need(text(t.idea), "idea", "idea must be one sentence");
|
|
145
|
+
need(sentences(t.idea).length === 1, "idea", "idea must be exactly one sentence");
|
|
146
|
+
need(!restates(t.idea, t.request), "idea", "idea restates the request; say the film's own idea");
|
|
147
|
+
need(text(t.audience), "audience", "audience must say who watches");
|
|
148
|
+
need(text(t.channel), "channel", "channel must say where it plays");
|
|
149
|
+
need(["16:9", "9:16"].includes(t.format), "format", "format must be 16:9 or 9:16");
|
|
150
|
+
need(text(t.formatReason), "formatReason", "formatReason must tie the format to the channel");
|
|
151
|
+
need(Number.isFinite(t.durationSec) && t.durationSec >= 4 && t.durationSec <= 90, "durationSec", "durationSec must be 4-90");
|
|
152
|
+
if (floorTenGenres.has(t.genre) && !lengthAsked.test(t.request)) need(t.durationSec >= 10, "durationSec", `a ${t.genre} film runs at least 10 s unless the user asked for a length`);
|
|
153
|
+
need(t.copy && typeof t.copy === "object", "copy", "copy must be { source, lines[] }");
|
|
154
|
+
need(["user", "invented"].includes(t.copy.source), "copy", "copy.source must be user or invented");
|
|
155
|
+
need(Array.isArray(t.copy.lines) && t.copy.lines.length > 0 && t.copy.lines.every(text), "copy", "copy.lines must be non-empty strings");
|
|
156
|
+
checkBeats(t);
|
|
157
|
+
need(t.subject && typeof t.subject === "object", "subject", "subject must be { name, source, specifics[] }");
|
|
158
|
+
need(text(t.subject.name), "subject", "subject.name is required");
|
|
159
|
+
need(["user", "invented"].includes(t.subject.source), "subject", "subject.source must be user or invented");
|
|
160
|
+
need(Array.isArray(t.subject.specifics) && t.subject.specifics.filter(text).length >= 2, "subject", "subject.specifics needs at least 2 concrete specifics");
|
|
161
|
+
if (t.subject.source === "user") need(normalize(t.request).includes(normalize(t.subject.name)), "subject", "subject.source is user, but the request does not name it; mark it invented");
|
|
162
|
+
need(Array.isArray(t.visualDevices), "visualDevices", "visualDevices must be an array");
|
|
163
|
+
t.visualDevices.forEach((device, i) => {
|
|
164
|
+
need(device && deviceKinds.includes(device.kind), "visualDevices", `device ${i}: kind must be one of ${deviceKinds.join(", ")}`);
|
|
165
|
+
need(["subject", "support", "texture"].includes(device.role), "visualDevices", `device ${i}: role must be subject, support or texture`);
|
|
166
|
+
need(!textureKinds.includes(device.kind) || device.role === "texture", "visualDevices", `device ${i}: ${device.kind} is always a texture`);
|
|
167
|
+
need(Array.isArray(device.beats) && device.beats.length > 0 && device.beats.every((b) => Number.isInteger(b) && b >= 0 && b < t.beats.length), "visualDevices", `device ${i}: beats must list beat indices`);
|
|
168
|
+
});
|
|
169
|
+
if (t.path === "stage") {
|
|
170
|
+
const subjects = t.visualDevices.filter((device) => device.role === "subject");
|
|
171
|
+
need(subjects.length > 0, "visualDevices", "the stage path needs at least one role: subject device, a drawn depiction of what the film is about");
|
|
172
|
+
need(subjects.some((device) => beatSeconds(t, device.beats) >= 0.5 * t.durationSec - 1e-9), "visualDevices", "a subject device must be on screen for at least half of durationSec");
|
|
173
|
+
const counting = new Set(t.visualDevices.map((device) => device.kind).filter((kind) => !textureKinds.includes(kind)));
|
|
174
|
+
need(counting.size >= 2, "visualDevices", "the stage path needs at least 2 distinct non-texture device kinds");
|
|
175
|
+
}
|
|
176
|
+
need(t.path !== "type" || t.format === "16:9", "path", "a 9:16 film always takes the stage path");
|
|
177
|
+
need(t.path !== "type" || t.copy.source === "user" || typeLedCue(t.request), "path", "the type path needs the user's own words or a type-led cue in the request");
|
|
178
|
+
need(t.typePlan && typeof t.typePlan === "object", "typePlan", "typePlan must be { faces[], hierarchy, maxWordsOnScreen }");
|
|
179
|
+
need(Array.isArray(t.typePlan.faces) && t.typePlan.faces.length > 0 && t.typePlan.faces.every((face) => productFaces.includes(face)), "typePlan", `typePlan.faces must come from ${productFaces.join(", ")}`);
|
|
180
|
+
need(text(t.typePlan.hierarchy), "typePlan", "typePlan.hierarchy is required");
|
|
181
|
+
need(Number.isInteger(t.typePlan.maxWordsOnScreen) && t.typePlan.maxWordsOnScreen >= 1, "typePlan", "typePlan.maxWordsOnScreen must be a positive integer");
|
|
182
|
+
need(Array.isArray(t.palette) && t.palette.length >= 3 && t.palette.length <= 6, "palette", "palette needs 3-6 colours");
|
|
183
|
+
t.palette.forEach((entry, i) => need(entry && /^#[0-9a-f]{6}$/iu.test(entry.hex ?? "") && text(entry.role), "palette", `palette ${i} must be { hex: "#rrggbb", role }`));
|
|
184
|
+
need(t.sound && soundModes.includes(t.sound.mode), "sound", `sound.mode must be one of ${soundModes.join(", ")}`);
|
|
185
|
+
need(text(t.sound.plan), "sound", "sound.plan is required");
|
|
186
|
+
if (t.sound.mode === "generated") {
|
|
187
|
+
need(soundPalettes.includes(t.sound.palette), "sound", `sound.palette must be one of ${soundPalettes.join(", ")}`);
|
|
188
|
+
need(Number.isFinite(t.sound.tempo) && t.sound.tempo >= 60 && t.sound.tempo <= 180, "sound", "sound.tempo must be 60-180 BPM");
|
|
189
|
+
need(keyPattern.test(t.sound.key ?? ""), "sound", "sound.key must look like \"D minor\" or \"F# major\"");
|
|
190
|
+
}
|
|
191
|
+
if (t.sound.mode === "supplied" || t.sound.mode === "authored") need(text(t.sound.file), "sound", `sound.file is required for ${t.sound.mode} sound`);
|
|
192
|
+
if (t.sound.mode === "none") need(silenceAsked.test(t.request) || t.sound.mutedByDesign === true, "sound", "silence needs a user request for it, or sound.mutedByDesign for a channel that plays muted");
|
|
193
|
+
if (t.copy.source === "user") {
|
|
194
|
+
const request = normalize(t.request);
|
|
195
|
+
const missing = t.copy.lines.find((line) => !request.includes(normalize(line)));
|
|
196
|
+
need(missing === undefined, "copy", `copy.source is user, but "${missing}" is not in the request`);
|
|
197
|
+
} else {
|
|
198
|
+
const restated = t.copy.lines.find((line) => restates(line, t.request));
|
|
199
|
+
need(restated === undefined, "copy", `invented copy restates the request: "${restated}"`);
|
|
200
|
+
}
|
|
201
|
+
const invented = t.copy.source === "invented" || t.subject.source === "invented";
|
|
202
|
+
if (invented) {
|
|
203
|
+
need(Array.isArray(t.inventions) && t.inventions.filter(text).length > 0, "inventions", "inventions must list every invented subject, line and fact");
|
|
204
|
+
if (t.subject.source === "invented") need(t.inventions.some((entry) => text(entry) && normalize(entry).includes(normalize(t.subject.name))), "inventions", "inventions must include subject.name");
|
|
205
|
+
}
|
|
206
|
+
need(text(t.ambition) && sentences(t.ambition).length <= 2, "ambition", "ambition must be 1-2 sentences in craft terms");
|
|
207
|
+
if (t.seed !== undefined) need(Number.isSafeInteger(t.seed), "seed", "seed must be an integer");
|
|
208
|
+
if (t.fps !== undefined) need(t.fps === 60 || t.fps === 30, "fps", "fps must be 60 or 30");
|
|
209
|
+
need(!copiesExample(t, examples), "copiedExample", "half or more of the free-text fields equal a shipped example; write this film's own treatment");
|
|
210
|
+
return { ok: true };
|
|
211
|
+
} catch (error) {
|
|
212
|
+
if (error instanceof Invalid) return { ok: false, field: error.field, detail: error.message };
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function frameSize(t) {
|
|
218
|
+
return t.format === "9:16" ? { width: 1080, height: 1920 } : { width: 1920, height: 1080 };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Read and validate `<out>/treatment.json`; throws an error carrying exitCode 16 and the field.
|
|
222
|
+
export function loadTreatment(out) {
|
|
223
|
+
const file = path.join(out, "treatment.json");
|
|
224
|
+
const fail = (field, detail) => {
|
|
225
|
+
const error = new Error(`BLOCKED_TREATMENT_INVALID (16): field ${field}: ${detail}`);
|
|
226
|
+
error.exitCode = TREATMENT_EXIT; error.field = field;
|
|
227
|
+
return error;
|
|
228
|
+
};
|
|
229
|
+
if (!existsSync(file)) throw fail("treatment", `no treatment.json in ${out}; write it first (references/treatment.md)`);
|
|
230
|
+
let parsed;
|
|
231
|
+
try { parsed = JSON.parse(readFileSync(file, "utf8")); } catch (error) { throw fail("treatment", `treatment.json is not JSON (${error.message})`); }
|
|
232
|
+
const result = validateTreatment(parsed);
|
|
233
|
+
if (!result.ok) throw fail(result.field, result.detail);
|
|
234
|
+
return { treatment: parsed, file };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Section 9 "never downgrade to pass": compare the final treatment with the first valid one.
|
|
238
|
+
export function downgrades(first, last) {
|
|
239
|
+
if (!first || !last) return [];
|
|
240
|
+
const found = [];
|
|
241
|
+
if (last.durationSec < first.durationSec * 0.8 - 1e-9) found.push(`durationSec dropped from ${first.durationSec} to ${last.durationSec}`);
|
|
242
|
+
const subjectBeats = (t) => new Set((t.visualDevices ?? []).filter((d) => d.role === "subject").flatMap((d) => d.beats)).size;
|
|
243
|
+
if (subjectBeats(last) < subjectBeats(first)) found.push(`subject beats fell from ${subjectBeats(first)} to ${subjectBeats(last)}`);
|
|
244
|
+
if (first.sound?.mode !== "none" && last.sound?.mode === "none" && !silenceAsked.test(last.request ?? "")) found.push("sound changed to none without a user request");
|
|
245
|
+
if (first.path === "stage" && last.path === "type") found.push("path changed from stage to type");
|
|
246
|
+
return found;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// The first valid treatment is kept so the done check can tell a downgrade from a fix.
|
|
250
|
+
export function keepFirstTreatment(out, treatment) {
|
|
251
|
+
const first = path.join(out, ".run", "treatment-first.json");
|
|
252
|
+
mkdirSync(path.dirname(first), { recursive: true });
|
|
253
|
+
if (!existsSync(first)) writeFileSync(first, JSON.stringify(treatment, null, 2) + "\n");
|
|
254
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|