@prismer/runtime 2.2.55 → 2.2.63
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 +574 -0
- package/apc/skills/releasing-test/SKILL.md +9 -0
- package/built-in-skills/agent-coordination/SKILL.md +21 -4
- package/built-in-skills/agent-meta/SKILL.md +11 -0
- package/built-in-skills/assets/SKILL.md +1 -1
- package/built-in-skills/canvas-design/SKILL.md +3 -3
- package/built-in-skills/canvas-design/canvas-fonts/IBMPlexSerif-OFL.txt +93 -0
- package/built-in-skills/canvas-design/canvas-fonts/InstrumentSerif-OFL.txt +93 -0
- package/built-in-skills/canvas-design/canvas-fonts/LICENSE-SOURCES.md +16 -0
- package/built-in-skills/claim-agent-ownership/SKILL.md +7 -3
- package/built-in-skills/claude-api/SKILL.md +1 -1
- package/built-in-skills/claude-api/python/claude-api/README.md +2 -2
- package/built-in-skills/claude-api/python/claude-api/tool-use.md +9 -5
- package/built-in-skills/claude-api/python/managed-agents/README.md +11 -1
- package/built-in-skills/claude-api/shared/error-codes.md +4 -4
- package/built-in-skills/claude-api/shared/managed-agents-client-patterns.md +4 -2
- package/built-in-skills/claude-api/shared/managed-agents-core.md +1 -2
- package/built-in-skills/claude-api/shared/managed-agents-events.md +41 -22
- package/built-in-skills/claude-api/shared/managed-agents-multiagent.md +5 -3
- package/built-in-skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md +1 -1
- package/built-in-skills/claude-api/shared/managed-agents-tools.md +2 -3
- package/built-in-skills/claude-api/shared/model-migration.md +3 -3
- package/built-in-skills/claude-api/shared/models.md +1 -1
- package/built-in-skills/claude-api/typescript/claude-api/batches.md +1 -1
- package/built-in-skills/claude-api/typescript/claude-api/files-api.md +3 -1
- package/built-in-skills/claude-api/typescript/claude-api/tool-use.md +8 -2
- package/built-in-skills/claude-api/typescript/managed-agents/README.md +8 -2
- package/built-in-skills/codebase-design/SKILL.md +15 -1
- package/built-in-skills/codebase-design/references/requesting-code-review/GUIDE.md +291 -0
- package/built-in-skills/codebase-design/references/requesting-code-review/LICENSE +21 -0
- package/built-in-skills/codebase-design/references/requesting-code-review/LICENSE.superpowers +21 -0
- package/built-in-skills/codebase-design/references/requesting-code-review/NOTICE.md +37 -0
- package/built-in-skills/codebase-design/references/sdlc-review/GUIDE.md +130 -0
- package/built-in-skills/codebase-design/references/sdlc-review/LICENSE +21 -0
- package/built-in-skills/codebase-design/references/sdlc-review/NOTICE.md +17 -0
- package/built-in-skills/codebase-design/references/simplify-code/GUIDE.md +269 -0
- package/built-in-skills/codebase-design/references/simplify-code/LICENSE +21 -0
- package/built-in-skills/codebase-design/references/simplify-code/NOTICE.md +37 -0
- package/built-in-skills/competitor-intelligence/LICENSE +21 -0
- package/built-in-skills/competitor-intelligence/NOTICE.md +6 -0
- package/built-in-skills/competitor-intelligence/SKILL.md +125 -0
- package/built-in-skills/competitor-intelligence/scripts/watch_state.py +160 -0
- package/built-in-skills/conversation-compaction/SKILL.md +3 -0
- package/built-in-skills/council-creator/SKILL.md +4 -3
- package/built-in-skills/diagnosing-bugs/SKILL.md +12 -0
- package/built-in-skills/diagnosing-bugs/references/desktop-dom/GUIDE.md +64 -0
- package/built-in-skills/diagnosing-bugs/references/desktop-dom/LICENSE +21 -0
- package/built-in-skills/diagnosing-bugs/references/desktop-dom/NOTICE.md +17 -0
- package/built-in-skills/diagnosing-bugs/references/systematic-debugging/GUIDE.md +410 -0
- package/built-in-skills/diagnosing-bugs/references/systematic-debugging/LICENSE +21 -0
- package/built-in-skills/diagnosing-bugs/references/systematic-debugging/LICENSE.superpowers +21 -0
- package/built-in-skills/diagnosing-bugs/references/systematic-debugging/NOTICE.md +37 -0
- package/built-in-skills/doc-coauthoring/SKILL.md +6 -0
- package/built-in-skills/doc-coauthoring/references/humanizer/GUIDE.md +647 -0
- package/built-in-skills/doc-coauthoring/references/humanizer/LICENSE +21 -0
- package/built-in-skills/doc-coauthoring/references/humanizer/LICENSE.hermes +21 -0
- package/built-in-skills/doc-coauthoring/references/humanizer/PROVENANCE.md +7 -0
- package/built-in-skills/document-actions/LICENSE +21 -0
- package/built-in-skills/document-actions/NOTICE.md +21 -0
- package/built-in-skills/document-actions/SKILL.md +46 -0
- package/built-in-skills/evidence-citations/LICENSE +21 -0
- package/built-in-skills/evidence-citations/NOTICE.md +21 -0
- package/built-in-skills/evidence-citations/SKILL.md +46 -0
- package/built-in-skills/evidence-citations/references/citation-formats.md +68 -0
- package/built-in-skills/evidence-citations/references/grounding-rationale.md +64 -0
- package/built-in-skills/evidence-citations/scripts/sources.py +720 -0
- package/built-in-skills/frontend-design/SKILL.md +6 -0
- package/built-in-skills/frontend-design/references/claude-design/GUIDE.md +650 -0
- package/built-in-skills/frontend-design/references/claude-design/LICENSE +21 -0
- package/built-in-skills/frontend-design/references/claude-design/LICENSE.hermes +21 -0
- package/built-in-skills/frontend-design/references/claude-design/PROVENANCE.md +7 -0
- package/built-in-skills/image-generate/SKILL.md +5 -0
- package/built-in-skills/image-generate/scripts/generate-and-deliver.mjs +24 -3
- package/built-in-skills/mcp-builder/reference/evaluation.md +11 -2
- package/built-in-skills/mcp-builder/reference/node_mcp_server.md +34 -5
- package/built-in-skills/mcp-builder/reference/python_mcp_server.md +6 -2
- package/built-in-skills/mcp-builder/scripts/connections.py +1 -1
- package/built-in-skills/mcp-builder/scripts/evaluation.py +52 -34
- package/built-in-skills/mcp-builder/scripts/requirements.txt +2 -2
- package/built-in-skills/meeting-actions/LICENSE +21 -0
- package/built-in-skills/meeting-actions/NOTICE.md +21 -0
- package/built-in-skills/meeting-actions/SKILL.md +48 -0
- package/built-in-skills/memory/SKILL.md +27 -3
- package/built-in-skills/memory/references/llm-wiki/GUIDE.md +468 -0
- package/built-in-skills/memory/references/llm-wiki/LICENSE +21 -0
- package/built-in-skills/memory/references/llm-wiki/NOTICE.md +4 -0
- package/built-in-skills/memory/references/llm-wiki/scripts/lint_wiki.py +84 -0
- package/built-in-skills/memory/references/llm-wiki/scripts/requirements.txt +1 -0
- package/built-in-skills/memory/references/llm-wiki/templates/SCHEMA.md +19 -0
- package/built-in-skills/memory/references/llm-wiki/templates/index.md +9 -0
- package/built-in-skills/memory/references/llm-wiki/templates/log.md +4 -0
- package/built-in-skills/memory-dream/SKILL.md +8 -15
- package/built-in-skills/memory-import/SKILL.md +51 -0
- package/built-in-skills/office-artifacts/NOTICE.md +15 -0
- package/built-in-skills/office-artifacts/SKILL.md +20 -0
- package/built-in-skills/office-artifacts/references/RESOURCE-LIMITS.md +44 -0
- package/built-in-skills/office-artifacts/references/docx/GUIDE.md +196 -0
- package/built-in-skills/office-artifacts/references/docx/LICENSE +21 -0
- package/built-in-skills/office-artifacts/references/docx/NOTICE.md +21 -0
- package/built-in-skills/office-artifacts/references/docx/references/revisions-and-comments.md +88 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_comments.py +292 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_common.py +93 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_create.py +177 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_edit.py +250 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_read.py +169 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_revisions.py +149 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_template.py +70 -0
- package/built-in-skills/office-artifacts/references/docx/scripts/docx_validate.py +155 -0
- package/built-in-skills/office-artifacts/references/docx/tests/test_docx_skill.py +525 -0
- package/built-in-skills/office-artifacts/references/pdf/GUIDE.md +125 -0
- package/built-in-skills/office-artifacts/references/pdf/LICENSE +21 -0
- package/built-in-skills/office-artifacts/references/pdf/NOTICE.md +21 -0
- package/built-in-skills/office-artifacts/references/pdf/references/forms.md +99 -0
- package/built-in-skills/office-artifacts/references/pdf/references/nano-pdf-editing.md +40 -0
- package/built-in-skills/office-artifacts/references/pdf/references/ocr-extraction.md +165 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/_raster.py +87 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/extract_marker.py +95 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/extract_pymupdf.py +107 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_create.py +153 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_fill_form.py +97 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_form_layout.py +168 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_make_form.py +145 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_merge.py +50 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_meta.py +123 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_page_image.py +101 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_read.py +153 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_secure.py +71 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_split.py +86 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_stamp.py +145 -0
- package/built-in-skills/office-artifacts/references/pdf/scripts/pdf_watermark.py +51 -0
- package/built-in-skills/office-artifacts/references/pdf/tests/test_pdf_skill.py +414 -0
- package/built-in-skills/office-artifacts/references/powerpoint/GUIDE.md +220 -0
- package/built-in-skills/office-artifacts/references/powerpoint/LICENSE +21 -0
- package/built-in-skills/office-artifacts/references/powerpoint/NOTICE.md +21 -0
- package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_create.py +214 -0
- package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_edit.py +442 -0
- package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_from_template.py +88 -0
- package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_read.py +131 -0
- package/built-in-skills/office-artifacts/references/powerpoint/scripts/pptx_render.py +104 -0
- package/built-in-skills/office-artifacts/references/powerpoint/tests/test_powerpoint_skill.py +478 -0
- package/built-in-skills/office-artifacts/references/xlsx/GUIDE.md +196 -0
- package/built-in-skills/office-artifacts/references/xlsx/LICENSE +21 -0
- package/built-in-skills/office-artifacts/references/xlsx/NOTICE.md +21 -0
- package/built-in-skills/office-artifacts/references/xlsx/references/restructuring.md +74 -0
- package/built-in-skills/office-artifacts/references/xlsx/scripts/csv_to_xlsx.py +108 -0
- package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_create.py +259 -0
- package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_edit.py +269 -0
- package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_read.py +160 -0
- package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_recalc.py +111 -0
- package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_restructure.py +418 -0
- package/built-in-skills/office-artifacts/references/xlsx/scripts/xlsx_to_csv.py +69 -0
- package/built-in-skills/office-artifacts/references/xlsx/tests/test_xlsx_skill.py +542 -0
- package/built-in-skills/office-artifacts/tests/test_resource_regressions.py +272 -0
- package/built-in-skills/persona-generator/SKILL.md +9 -9
- package/built-in-skills/pkf-svg/SKILL.md +5 -0
- package/built-in-skills/pkf-svg/references/architecture-diagram/GUIDE.md +148 -0
- package/built-in-skills/pkf-svg/references/architecture-diagram/LICENSE +21 -0
- package/built-in-skills/pkf-svg/references/architecture-diagram/LICENSE.hermes +21 -0
- package/built-in-skills/pkf-svg/references/architecture-diagram/PROVENANCE.md +7 -0
- package/built-in-skills/pkf-svg/references/architecture-diagram/templates/template.html +345 -0
- package/built-in-skills/pkf-writing/SKILL.md +36 -14
- package/built-in-skills/prismer-airtable/LICENSE +21 -0
- package/built-in-skills/prismer-airtable/NOTICE.md +11 -0
- package/built-in-skills/prismer-airtable/SKILL.md +248 -0
- package/built-in-skills/prismer-airtable/scripts/airtable_client.py +76 -0
- package/built-in-skills/prismer-apple-notes/LICENSE +21 -0
- package/built-in-skills/prismer-apple-notes/NOTICE.md +17 -0
- package/built-in-skills/prismer-apple-notes/SKILL.md +118 -0
- package/built-in-skills/prismer-apple-notes/scripts/readiness.py +47 -0
- package/built-in-skills/prismer-apple-reminders/LICENSE +21 -0
- package/built-in-skills/prismer-apple-reminders/NOTICE.md +17 -0
- package/built-in-skills/prismer-apple-reminders/SKILL.md +155 -0
- package/built-in-skills/prismer-apple-reminders/scripts/readiness.py +47 -0
- package/built-in-skills/prismer-ascii-video/LICENSE +21 -0
- package/built-in-skills/prismer-ascii-video/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-ascii-video/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-ascii-video/README.md +290 -0
- package/built-in-skills/prismer-ascii-video/SKILL.md +252 -0
- package/built-in-skills/prismer-ascii-video/provenance/category-DESCRIPTION.md +3 -0
- package/built-in-skills/prismer-ascii-video/references/architecture.md +807 -0
- package/built-in-skills/prismer-ascii-video/references/composition.md +900 -0
- package/built-in-skills/prismer-ascii-video/references/effects.md +1877 -0
- package/built-in-skills/prismer-ascii-video/references/inputs.md +693 -0
- package/built-in-skills/prismer-ascii-video/references/optimization.md +688 -0
- package/built-in-skills/prismer-ascii-video/references/scenes.md +1018 -0
- package/built-in-skills/prismer-ascii-video/references/shaders.md +1408 -0
- package/built-in-skills/prismer-ascii-video/references/troubleshooting.md +360 -0
- package/built-in-skills/prismer-baoyu-infographic/LICENSE +21 -0
- package/built-in-skills/prismer-baoyu-infographic/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-baoyu-infographic/LICENSE.origin +21 -0
- package/built-in-skills/prismer-baoyu-infographic/PORT_NOTES.md +37 -0
- package/built-in-skills/prismer-baoyu-infographic/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-baoyu-infographic/SKILL.md +240 -0
- package/built-in-skills/prismer-baoyu-infographic/references/analysis-framework.md +182 -0
- package/built-in-skills/prismer-baoyu-infographic/references/base-prompt.md +43 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/bento-grid.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/binary-comparison.md +48 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/bridge.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/circular-flow.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/comic-strip.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/comparison-matrix.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/dashboard.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/dense-modules.md +72 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/funnel.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/hierarchical-layers.md +48 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/hub-spoke.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/iceberg.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/isometric-map.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/jigsaw.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/linear-progression.md +48 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/periodic-table.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/story-mountain.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/structural-breakdown.md +48 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/tree-branching.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/venn-diagram.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/layouts/winding-roadmap.md +41 -0
- package/built-in-skills/prismer-baoyu-infographic/references/structured-content-template.md +244 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/aged-academia.md +36 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/bold-graphic.md +36 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/chalkboard.md +61 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/claymation.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/corporate-memphis.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/craft-handmade.md +44 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/cyberpunk-neon.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/hand-drawn-edu.md +63 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/ikea-manual.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/kawaii.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/knolling.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/lego-brick.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/morandi-journal.md +60 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/origami.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/pixel-art.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/pop-laboratory.md +48 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/retro-pop-grid.md +47 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/storybook-watercolor.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/subway-map.md +29 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/technical-schematic.md +36 -0
- package/built-in-skills/prismer-baoyu-infographic/references/styles/ui-wireframe.md +29 -0
- package/built-in-skills/prismer-blocked-page-recovery/LICENSE +21 -0
- package/built-in-skills/prismer-blocked-page-recovery/NOTICE.md +17 -0
- package/built-in-skills/prismer-blocked-page-recovery/SKILL.md +158 -0
- package/built-in-skills/prismer-blocked-page-recovery/scripts/recover_page.py +311 -0
- package/built-in-skills/prismer-box/LICENSE +21 -0
- package/built-in-skills/prismer-box/NOTICE.md +11 -0
- package/built-in-skills/prismer-box/SKILL.md +147 -0
- package/built-in-skills/prismer-box/references/bulk-operations.md +43 -0
- package/built-in-skills/prismer-box/references/cli-guide.md +133 -0
- package/built-in-skills/prismer-box/references/content-workflows.md +86 -0
- package/built-in-skills/prismer-box/references/hubs.md +77 -0
- package/built-in-skills/prismer-box/references/oauth-setup.md +92 -0
- package/built-in-skills/prismer-box/references/rest-api.md +37 -0
- package/built-in-skills/prismer-box/references/sdk-development.md +85 -0
- package/built-in-skills/prismer-box/references/search-and-ai.md +147 -0
- package/built-in-skills/prismer-box/references/troubleshooting.md +33 -0
- package/built-in-skills/prismer-box/references/webhooks-and-events.md +43 -0
- package/built-in-skills/prismer-codebase-inspection/LICENSE +21 -0
- package/built-in-skills/prismer-codebase-inspection/NOTICE.md +17 -0
- package/built-in-skills/prismer-codebase-inspection/SKILL.md +141 -0
- package/built-in-skills/prismer-computer-use/LICENSE +21 -0
- package/built-in-skills/prismer-computer-use/NOTICE.md +17 -0
- package/built-in-skills/prismer-computer-use/SKILL.md +372 -0
- package/built-in-skills/prismer-design-md/LICENSE +21 -0
- package/built-in-skills/prismer-design-md/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-design-md/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-design-md/SKILL.md +227 -0
- package/built-in-skills/prismer-design-md/templates/starter.md +99 -0
- package/built-in-skills/prismer-email-inbox-triage/LICENSE +21 -0
- package/built-in-skills/prismer-email-inbox-triage/NOTICE.md +11 -0
- package/built-in-skills/prismer-email-inbox-triage/SKILL.md +116 -0
- package/built-in-skills/prismer-findmy/LICENSE +21 -0
- package/built-in-skills/prismer-findmy/NOTICE.md +17 -0
- package/built-in-skills/prismer-findmy/SKILL.md +150 -0
- package/built-in-skills/prismer-findmy/scripts/readiness.py +47 -0
- package/built-in-skills/prismer-gif-search/LICENSE +21 -0
- package/built-in-skills/prismer-gif-search/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-gif-search/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-gif-search/SKILL.md +97 -0
- package/built-in-skills/prismer-gif-search/scripts/tenor.py +81 -0
- package/built-in-skills/prismer-github/LICENSE +21 -0
- package/built-in-skills/prismer-github/NOTICE.md +17 -0
- package/built-in-skills/prismer-github/SKILL.md +74 -0
- package/built-in-skills/prismer-github/references/auth.md +91 -0
- package/built-in-skills/prismer-github/references/ci-troubleshooting.md +193 -0
- package/built-in-skills/prismer-github/references/code-review.md +465 -0
- package/built-in-skills/prismer-github/references/conventional-commits.md +81 -0
- package/built-in-skills/prismer-github/references/github-api-cheatsheet.md +177 -0
- package/built-in-skills/prismer-github/references/issue-to-pr.md +74 -0
- package/built-in-skills/prismer-github/references/issues.md +336 -0
- package/built-in-skills/prismer-github/references/pr-workflow.md +346 -0
- package/built-in-skills/prismer-github/references/repo-management.md +484 -0
- package/built-in-skills/prismer-github/references/review-output-template.md +84 -0
- package/built-in-skills/prismer-github/scripts/ensure-gh.py +132 -0
- package/built-in-skills/prismer-github/scripts/gh-env.sh +25 -0
- package/built-in-skills/prismer-github/scripts/git-credential-token.py +68 -0
- package/built-in-skills/prismer-github/scripts/github-api.py +71 -0
- package/built-in-skills/prismer-github/scripts/github-context.py +28 -0
- package/built-in-skills/prismer-github/templates/bug-report.md +35 -0
- package/built-in-skills/prismer-github/templates/feature-request.md +31 -0
- package/built-in-skills/prismer-github/templates/pr-body-bugfix.md +35 -0
- package/built-in-skills/prismer-github/templates/pr-body-feature.md +33 -0
- package/built-in-skills/prismer-google-workspace/LICENSE +21 -0
- package/built-in-skills/prismer-google-workspace/NOTICE.md +11 -0
- package/built-in-skills/prismer-google-workspace/SKILL.md +369 -0
- package/built-in-skills/prismer-google-workspace/references/daily-brief.md +65 -0
- package/built-in-skills/prismer-google-workspace/references/gmail-search-syntax.md +63 -0
- package/built-in-skills/prismer-google-workspace/scripts/_hermes_home.py +17 -0
- package/built-in-skills/prismer-google-workspace/scripts/_private_state.py +39 -0
- package/built-in-skills/prismer-google-workspace/scripts/google_api.py +1339 -0
- package/built-in-skills/prismer-google-workspace/scripts/gws_bridge.py +121 -0
- package/built-in-skills/prismer-google-workspace/scripts/setup.py +563 -0
- package/built-in-skills/prismer-google-workspace/tests/test_productivity_regressions.py +214 -0
- package/built-in-skills/prismer-hermes-agent/LICENSE +21 -0
- package/built-in-skills/prismer-hermes-agent/NOTICE.md +17 -0
- package/built-in-skills/prismer-hermes-agent/SKILL.md +247 -0
- package/built-in-skills/prismer-hermes-agent/references/background-systems.md +108 -0
- package/built-in-skills/prismer-hermes-agent/references/cli-reference.md +158 -0
- package/built-in-skills/prismer-hermes-agent/references/configuration.md +96 -0
- package/built-in-skills/prismer-hermes-agent/references/contributor-guide.md +151 -0
- package/built-in-skills/prismer-hermes-agent/references/delegate-task-concurrency-diagnosis.md +47 -0
- package/built-in-skills/prismer-hermes-agent/references/desktop-plugins.md +215 -0
- package/built-in-skills/prismer-hermes-agent/references/native-mcp.md +351 -0
- package/built-in-skills/prismer-hermes-agent/references/petdex.md +82 -0
- package/built-in-skills/prismer-hermes-agent/references/portal-auth-for-third-party-apps.md +135 -0
- package/built-in-skills/prismer-hermes-agent/references/project-context-files.md +55 -0
- package/built-in-skills/prismer-hermes-agent/references/providers-and-models.md +81 -0
- package/built-in-skills/prismer-hermes-agent/references/security-privacy.md +73 -0
- package/built-in-skills/prismer-hermes-agent/references/slash-commands.md +119 -0
- package/built-in-skills/prismer-hermes-agent/references/themes.md +134 -0
- package/built-in-skills/prismer-hermes-agent/references/troubleshooting.md +87 -0
- package/built-in-skills/prismer-hermes-agent/references/tui-widgets.md +144 -0
- package/built-in-skills/prismer-hermes-agent/references/webhooks.md +219 -0
- package/built-in-skills/prismer-hermes-agent/references/windows-quirks.md +64 -0
- package/built-in-skills/prismer-hermes-agent/templates/clock.mjs +51 -0
- package/built-in-skills/prismer-hermes-agent/templates/plugin.js +97 -0
- package/built-in-skills/prismer-hermes-agent/templates/skin.yaml +49 -0
- package/built-in-skills/prismer-himalaya/LICENSE +21 -0
- package/built-in-skills/prismer-himalaya/NOTICE.md +11 -0
- package/built-in-skills/prismer-himalaya/SKILL.md +340 -0
- package/built-in-skills/prismer-himalaya/references/configuration.md +227 -0
- package/built-in-skills/prismer-himalaya/references/message-composition.md +206 -0
- package/built-in-skills/prismer-himalaya/scripts/compose_draft.py +48 -0
- package/built-in-skills/prismer-im-collab/SKILL.md +1 -1
- package/built-in-skills/prismer-imessage/LICENSE +21 -0
- package/built-in-skills/prismer-imessage/NOTICE.md +17 -0
- package/built-in-skills/prismer-imessage/SKILL.md +128 -0
- package/built-in-skills/prismer-imessage/scripts/readiness.py +47 -0
- package/built-in-skills/prismer-manim-video/LICENSE +21 -0
- package/built-in-skills/prismer-manim-video/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-manim-video/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-manim-video/README.md +23 -0
- package/built-in-skills/prismer-manim-video/SKILL.md +279 -0
- package/built-in-skills/prismer-manim-video/references/animation-design-thinking.md +161 -0
- package/built-in-skills/prismer-manim-video/references/animations.md +282 -0
- package/built-in-skills/prismer-manim-video/references/camera-and-3d.md +135 -0
- package/built-in-skills/prismer-manim-video/references/decorations.md +202 -0
- package/built-in-skills/prismer-manim-video/references/equations.md +216 -0
- package/built-in-skills/prismer-manim-video/references/graphs-and-data.md +163 -0
- package/built-in-skills/prismer-manim-video/references/mobjects.md +333 -0
- package/built-in-skills/prismer-manim-video/references/paper-explainer.md +255 -0
- package/built-in-skills/prismer-manim-video/references/production-quality.md +190 -0
- package/built-in-skills/prismer-manim-video/references/rendering.md +187 -0
- package/built-in-skills/prismer-manim-video/references/scene-planning.md +118 -0
- package/built-in-skills/prismer-manim-video/references/troubleshooting.md +135 -0
- package/built-in-skills/prismer-manim-video/references/updaters-and-trackers.md +260 -0
- package/built-in-skills/prismer-manim-video/references/visual-design.md +124 -0
- package/built-in-skills/prismer-manim-video/scripts/setup.sh +15 -0
- package/built-in-skills/prismer-maps/LICENSE +21 -0
- package/built-in-skills/prismer-maps/NOTICE.md +11 -0
- package/built-in-skills/prismer-maps/SKILL.md +240 -0
- package/built-in-skills/prismer-maps/scripts/maps_client.py +1324 -0
- package/built-in-skills/prismer-node-inspect-debugger/LICENSE +21 -0
- package/built-in-skills/prismer-node-inspect-debugger/NOTICE.md +17 -0
- package/built-in-skills/prismer-node-inspect-debugger/SKILL.md +347 -0
- package/built-in-skills/prismer-notion/LICENSE +21 -0
- package/built-in-skills/prismer-notion/NOTICE.md +11 -0
- package/built-in-skills/prismer-notion/SKILL.md +495 -0
- package/built-in-skills/prismer-notion/references/block-types.md +112 -0
- package/built-in-skills/prismer-obsidian/LICENSE +21 -0
- package/built-in-skills/prismer-obsidian/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-obsidian/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-obsidian/SKILL.md +80 -0
- package/built-in-skills/prismer-obsidian/provenance/category-DESCRIPTION.md +3 -0
- package/built-in-skills/prismer-obsidian/scripts/write_note.py +84 -0
- package/built-in-skills/prismer-p5js/LICENSE +21 -0
- package/built-in-skills/prismer-p5js/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-p5js/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-p5js/README.md +64 -0
- package/built-in-skills/prismer-p5js/SKILL.md +574 -0
- package/built-in-skills/prismer-p5js/references/animation.md +439 -0
- package/built-in-skills/prismer-p5js/references/color-systems.md +355 -0
- package/built-in-skills/prismer-p5js/references/core-api.md +410 -0
- package/built-in-skills/prismer-p5js/references/export-pipeline.md +534 -0
- package/built-in-skills/prismer-p5js/references/interaction.md +398 -0
- package/built-in-skills/prismer-p5js/references/shapes-and-geometry.md +300 -0
- package/built-in-skills/prismer-p5js/references/troubleshooting.md +532 -0
- package/built-in-skills/prismer-p5js/references/typography.md +302 -0
- package/built-in-skills/prismer-p5js/references/visual-effects.md +905 -0
- package/built-in-skills/prismer-p5js/references/webgl-and-3d.md +423 -0
- package/built-in-skills/prismer-p5js/scripts/export-frames.js +91 -0
- package/built-in-skills/prismer-p5js/scripts/render.sh +113 -0
- package/built-in-skills/prismer-p5js/scripts/serve.sh +25 -0
- package/built-in-skills/prismer-p5js/scripts/setup.sh +87 -0
- package/built-in-skills/prismer-p5js/templates/viewer.html +401 -0
- package/built-in-skills/prismer-popular-web-designs/LICENSE +21 -0
- package/built-in-skills/prismer-popular-web-designs/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-popular-web-designs/LICENSE.origin +21 -0
- package/built-in-skills/prismer-popular-web-designs/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-popular-web-designs/SKILL.md +218 -0
- package/built-in-skills/prismer-popular-web-designs/templates/airbnb.md +259 -0
- package/built-in-skills/prismer-popular-web-designs/templates/airtable.md +102 -0
- package/built-in-skills/prismer-popular-web-designs/templates/apple.md +326 -0
- package/built-in-skills/prismer-popular-web-designs/templates/bmw.md +193 -0
- package/built-in-skills/prismer-popular-web-designs/templates/cal.md +272 -0
- package/built-in-skills/prismer-popular-web-designs/templates/claude.md +325 -0
- package/built-in-skills/prismer-popular-web-designs/templates/clay.md +317 -0
- package/built-in-skills/prismer-popular-web-designs/templates/clickhouse.md +294 -0
- package/built-in-skills/prismer-popular-web-designs/templates/cohere.md +279 -0
- package/built-in-skills/prismer-popular-web-designs/templates/coinbase.md +142 -0
- package/built-in-skills/prismer-popular-web-designs/templates/composio.md +320 -0
- package/built-in-skills/prismer-popular-web-designs/templates/cursor.md +322 -0
- package/built-in-skills/prismer-popular-web-designs/templates/elevenlabs.md +278 -0
- package/built-in-skills/prismer-popular-web-designs/templates/expo.md +294 -0
- package/built-in-skills/prismer-popular-web-designs/templates/figma.md +233 -0
- package/built-in-skills/prismer-popular-web-designs/templates/framer.md +259 -0
- package/built-in-skills/prismer-popular-web-designs/templates/hashicorp.md +291 -0
- package/built-in-skills/prismer-popular-web-designs/templates/ibm.md +345 -0
- package/built-in-skills/prismer-popular-web-designs/templates/intercom.md +159 -0
- package/built-in-skills/prismer-popular-web-designs/templates/kraken.md +138 -0
- package/built-in-skills/prismer-popular-web-designs/templates/linear.app.md +380 -0
- package/built-in-skills/prismer-popular-web-designs/templates/lovable.md +311 -0
- package/built-in-skills/prismer-popular-web-designs/templates/minimax.md +270 -0
- package/built-in-skills/prismer-popular-web-designs/templates/mintlify.md +339 -0
- package/built-in-skills/prismer-popular-web-designs/templates/miro.md +121 -0
- package/built-in-skills/prismer-popular-web-designs/templates/mistral.ai.md +274 -0
- package/built-in-skills/prismer-popular-web-designs/templates/mongodb.md +279 -0
- package/built-in-skills/prismer-popular-web-designs/templates/notion.md +322 -0
- package/built-in-skills/prismer-popular-web-designs/templates/nvidia.md +306 -0
- package/built-in-skills/prismer-popular-web-designs/templates/ollama.md +280 -0
- package/built-in-skills/prismer-popular-web-designs/templates/opencode.ai.md +294 -0
- package/built-in-skills/prismer-popular-web-designs/templates/pinterest.md +243 -0
- package/built-in-skills/prismer-popular-web-designs/templates/posthog.md +269 -0
- package/built-in-skills/prismer-popular-web-designs/templates/raycast.md +281 -0
- package/built-in-skills/prismer-popular-web-designs/templates/replicate.md +274 -0
- package/built-in-skills/prismer-popular-web-designs/templates/resend.md +316 -0
- package/built-in-skills/prismer-popular-web-designs/templates/revolut.md +198 -0
- package/built-in-skills/prismer-popular-web-designs/templates/runwayml.md +257 -0
- package/built-in-skills/prismer-popular-web-designs/templates/sanity.md +370 -0
- package/built-in-skills/prismer-popular-web-designs/templates/sentry.md +275 -0
- package/built-in-skills/prismer-popular-web-designs/templates/spacex.md +207 -0
- package/built-in-skills/prismer-popular-web-designs/templates/spotify.md +259 -0
- package/built-in-skills/prismer-popular-web-designs/templates/stripe.md +335 -0
- package/built-in-skills/prismer-popular-web-designs/templates/supabase.md +268 -0
- package/built-in-skills/prismer-popular-web-designs/templates/superhuman.md +265 -0
- package/built-in-skills/prismer-popular-web-designs/templates/together.ai.md +276 -0
- package/built-in-skills/prismer-popular-web-designs/templates/uber.md +308 -0
- package/built-in-skills/prismer-popular-web-designs/templates/vercel.md +323 -0
- package/built-in-skills/prismer-popular-web-designs/templates/voltagent.md +336 -0
- package/built-in-skills/prismer-popular-web-designs/templates/warp.md +266 -0
- package/built-in-skills/prismer-popular-web-designs/templates/webflow.md +105 -0
- package/built-in-skills/prismer-popular-web-designs/templates/wise.md +186 -0
- package/built-in-skills/prismer-popular-web-designs/templates/x.ai.md +270 -0
- package/built-in-skills/prismer-popular-web-designs/templates/zapier.md +341 -0
- package/built-in-skills/prismer-product-price-monitor/LICENSE +21 -0
- package/built-in-skills/prismer-product-price-monitor/NOTICE.md +11 -0
- package/built-in-skills/prismer-product-price-monitor/SKILL.md +97 -0
- package/built-in-skills/prismer-product-price-monitor/scripts/watch_state.py +116 -0
- package/built-in-skills/prismer-python-debugpy/LICENSE +21 -0
- package/built-in-skills/prismer-python-debugpy/NOTICE.md +17 -0
- package/built-in-skills/prismer-python-debugpy/SKILL.md +377 -0
- package/built-in-skills/prismer-python-debugpy/scripts/dap_client.py +68 -0
- package/built-in-skills/prismer-songsee/LICENSE +21 -0
- package/built-in-skills/prismer-songsee/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-songsee/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-songsee/SKILL.md +91 -0
- package/built-in-skills/prismer-songwriting-and-ai-music/LICENSE +21 -0
- package/built-in-skills/prismer-songwriting-and-ai-music/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-songwriting-and-ai-music/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-songwriting-and-ai-music/SKILL.md +317 -0
- package/built-in-skills/prismer-spike/LICENSE +21 -0
- package/built-in-skills/prismer-spike/LICENSE.gsd +21 -0
- package/built-in-skills/prismer-spike/NOTICE.md +17 -0
- package/built-in-skills/prismer-spike/SKILL.md +212 -0
- package/built-in-skills/prismer-teams-meeting-pipeline/LICENSE +21 -0
- package/built-in-skills/prismer-teams-meeting-pipeline/NOTICE.md +11 -0
- package/built-in-skills/prismer-teams-meeting-pipeline/SKILL.md +156 -0
- package/built-in-skills/prismer-xurl/LICENSE +21 -0
- package/built-in-skills/prismer-xurl/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-xurl/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-xurl/SKILL.md +444 -0
- package/built-in-skills/prismer-xurl/provenance/category-DESCRIPTION.md +3 -0
- package/built-in-skills/prismer-youtube-content/LICENSE +21 -0
- package/built-in-skills/prismer-youtube-content/LICENSE.hermes +21 -0
- package/built-in-skills/prismer-youtube-content/PROVENANCE.md +7 -0
- package/built-in-skills/prismer-youtube-content/SKILL.md +86 -0
- package/built-in-skills/prismer-youtube-content/provenance/category-DESCRIPTION.md +3 -0
- package/built-in-skills/prismer-youtube-content/references/output-formats.md +56 -0
- package/built-in-skills/prismer-youtube-content/scripts/fetch_transcript.py +146 -0
- package/built-in-skills/research-arxiv/LICENSE +21 -0
- package/built-in-skills/research-arxiv/NOTICE.md +4 -0
- package/built-in-skills/research-arxiv/SKILL.md +263 -0
- package/built-in-skills/research-arxiv/scripts/search_arxiv.py +111 -0
- package/built-in-skills/role-builder/SKILL.md +7 -1
- package/built-in-skills/role-builder/scripts/author-role.mjs +23 -7
- package/built-in-skills/role-builder/scripts/ingest-role.mjs +15 -117
- package/built-in-skills/role-builder/scripts/instantiate-and-run.mjs +15 -1
- package/built-in-skills/role-builder/scripts/operation-harness.mjs +6 -4
- package/built-in-skills/skill-creator/LICENSE.prismer +21 -0
- package/built-in-skills/skill-creator/NOTICE.md +18 -0
- package/built-in-skills/skill-creator/SKILL.md +20 -1
- package/built-in-skills/skill-creator/eval-viewer/generate_review.py +20 -31
- package/built-in-skills/skill-creator/eval-viewer/viewer.html +35 -23
- package/built-in-skills/skill-creator/references/hermes-agent-skill-authoring/GUIDE.md +220 -0
- package/built-in-skills/skill-creator/references/hermes-agent-skill-authoring/LICENSE +21 -0
- package/built-in-skills/{skill-authoring/SKILL.md → skill-creator/references/skill-authoring/GUIDE.md} +1 -1
- package/built-in-skills/{skill-builder/SKILL.md → skill-creator/references/skill-builder/GUIDE.md} +8 -12
- package/built-in-skills/skill-creator/references/skill-builder/scripts/ingest.mjs +93 -0
- package/built-in-skills/skill-creator/scripts/aggregate_benchmark.py +3 -2
- package/built-in-skills/skill-creator/scripts/import-library.mjs +30 -7
- package/built-in-skills/skill-creator/scripts/improve_description.py +14 -16
- package/built-in-skills/skill-creator/scripts/package_skill.py +16 -9
- package/built-in-skills/skill-creator/scripts/quick_validate.py +22 -5
- package/built-in-skills/skill-creator/scripts/run_eval.py +63 -144
- package/built-in-skills/skill-creator/scripts/run_loop.py +24 -16
- package/built-in-skills/slack-gif-creator/core/gif_builder.py +13 -2
- package/built-in-skills/slack-gif-creator/core/validators.py +17 -7
- package/built-in-skills/tasks/SKILL.md +2 -2
- package/built-in-skills/tdd/SKILL.md +7 -0
- package/built-in-skills/tdd/references/test-driven-development/GUIDE.md +356 -0
- package/built-in-skills/tdd/references/test-driven-development/LICENSE +21 -0
- package/built-in-skills/tdd/references/test-driven-development/LICENSE.superpowers +21 -0
- package/built-in-skills/tdd/references/test-driven-development/NOTICE.md +37 -0
- package/built-in-skills/team/SKILL.md +1 -1
- package/built-in-skills/web-artifacts-builder/SKILL.md +3 -3
- package/built-in-skills/web-artifacts-builder/scripts/bundle-artifact.sh +9 -7
- package/built-in-skills/web-artifacts-builder/scripts/init-artifact.sh +28 -55
- package/built-in-skills/webapp-qa/LICENSE +21 -0
- package/built-in-skills/webapp-qa/NOTICE.md +37 -0
- package/built-in-skills/webapp-qa/SKILL.md +41 -0
- package/built-in-skills/webapp-qa/references/dogfood/GUIDE.md +161 -0
- package/built-in-skills/webapp-qa/references/issue-taxonomy.md +109 -0
- package/built-in-skills/webapp-qa/templates/dogfood-report-template.md +86 -0
- package/built-in-skills/webapp-testing/SKILL.md +9 -2
- package/built-in-skills/webapp-testing/examples/console_logging.py +10 -4
- package/built-in-skills/webapp-testing/examples/element_discovery.py +11 -4
- package/built-in-skills/webapp-testing/examples/static_html_automation.py +14 -9
- package/built-in-skills/webapp-testing/scripts/with_server.py +34 -10
- package/built-in-skills/weekly-review/LICENSE +21 -0
- package/built-in-skills/weekly-review/NOTICE.md +21 -0
- package/built-in-skills/weekly-review/SKILL.md +49 -0
- package/components/eaas-pi-components.manifest.json +37 -0
- package/dist/cli.cjs +7017 -3340
- package/dist/cli.js +6631 -2936
- package/dist/index.cjs +7863 -3830
- package/dist/index.d.cts +459 -5
- package/dist/index.d.ts +459 -5
- package/dist/index.js +7106 -3064
- package/package.json +7 -2
- package/plugins/memory/prismer/__init__.py +4 -0
- package/plugins/memory/prismer/tool-schemas.generated.json +8 -0
- package/built-in-skills/skill-builder/scripts/ingest.mjs +0 -265
- package/built-in-skills/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
- /package/built-in-skills/{document-generation/SKILL.md → office-artifacts/references/document-generation/GUIDE.md} +0 -0
- /package/built-in-skills/{skill-authoring/skill.json → skill-creator/references/skill-authoring/draft-contract.json} +0 -0
|
@@ -0,0 +1,693 @@
|
|
|
1
|
+
# Input Sources
|
|
2
|
+
|
|
3
|
+
> **See also:** architecture.md · effects.md · scenes.md · shaders.md · optimization.md · troubleshooting.md
|
|
4
|
+
|
|
5
|
+
## Audio Analysis
|
|
6
|
+
|
|
7
|
+
### Loading
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temporary:
|
|
11
|
+
tmp = temporary.name
|
|
12
|
+
subprocess.run(["ffmpeg", "-y", "-i", input_path, "-ac", "1", "-ar", "22050",
|
|
13
|
+
"-sample_fmt", "s16", tmp], capture_output=True, check=True)
|
|
14
|
+
with wave.open(tmp) as wf:
|
|
15
|
+
sr = wf.getframerate()
|
|
16
|
+
raw = wf.readframes(wf.getnframes())
|
|
17
|
+
samples = np.frombuffer(raw, dtype=np.int16).astype(np.float32) / 32768.0
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Per-Frame FFT
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
hop = sr // fps # samples per frame
|
|
24
|
+
win = hop * 2 # analysis window (2x hop for overlap)
|
|
25
|
+
window = np.hanning(win)
|
|
26
|
+
freqs = rfftfreq(win, 1.0 / sr)
|
|
27
|
+
|
|
28
|
+
bands = {
|
|
29
|
+
"sub": (freqs >= 20) & (freqs < 80),
|
|
30
|
+
"bass": (freqs >= 80) & (freqs < 250),
|
|
31
|
+
"lomid": (freqs >= 250) & (freqs < 500),
|
|
32
|
+
"mid": (freqs >= 500) & (freqs < 2000),
|
|
33
|
+
"himid": (freqs >= 2000)& (freqs < 6000),
|
|
34
|
+
"hi": (freqs >= 6000),
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
For each frame: extract chunk, apply window, FFT, compute band energies.
|
|
39
|
+
|
|
40
|
+
### Feature Set
|
|
41
|
+
|
|
42
|
+
| Feature | Formula | Controls |
|
|
43
|
+
|---------|---------|----------|
|
|
44
|
+
| `rms` | `sqrt(mean(chunk²))` | Overall loudness/energy |
|
|
45
|
+
| `sub`..`hi` | `sqrt(mean(band_magnitudes²))` | Per-band energy |
|
|
46
|
+
| `centroid` | `sum(freq*mag) / sum(mag)` | Brightness/timbre |
|
|
47
|
+
| `flatness` | `geomean(mag) / mean(mag)` | Noise vs tone |
|
|
48
|
+
| `flux` | `sum(max(0, mag - prev_mag))` | Transient strength |
|
|
49
|
+
| `sub_r`..`hi_r` | `band / sum(all_bands)` | Spectral shape (volume-independent) |
|
|
50
|
+
| `cent_d` | `abs(gradient(centroid))` | Timbral change rate |
|
|
51
|
+
| `beat` | Flux peak detection | Binary beat onset |
|
|
52
|
+
| `bdecay` | Exponential decay from beats | Smooth beat pulse (0→1→0) |
|
|
53
|
+
|
|
54
|
+
**Band ratios are critical** — they decouple spectral shape from volume, so a quiet bass section and a loud bass section both read as "bassy" rather than just "loud" vs "quiet".
|
|
55
|
+
|
|
56
|
+
### Smoothing
|
|
57
|
+
|
|
58
|
+
EMA prevents visual jitter:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
def ema(arr, alpha):
|
|
62
|
+
out = np.empty_like(arr); out[0] = arr[0]
|
|
63
|
+
for i in range(1, len(arr)):
|
|
64
|
+
out[i] = alpha * arr[i] + (1 - alpha) * out[i-1]
|
|
65
|
+
return out
|
|
66
|
+
|
|
67
|
+
# Slow-moving features (alpha=0.12): centroid, flatness, band ratios, cent_d
|
|
68
|
+
# Fast-moving features (alpha=0.3): rms, flux, raw bands
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Beat Detection
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
flux_smooth = np.convolve(flux, np.ones(5)/5, mode="same")
|
|
75
|
+
peaks, _ = signal.find_peaks(flux_smooth, height=0.15, distance=fps//5, prominence=0.05)
|
|
76
|
+
|
|
77
|
+
beat = np.zeros(n_frames)
|
|
78
|
+
bdecay = np.zeros(n_frames, dtype=np.float32)
|
|
79
|
+
for p in peaks:
|
|
80
|
+
beat[p] = 1.0
|
|
81
|
+
for d in range(fps // 2):
|
|
82
|
+
if p + d < n_frames:
|
|
83
|
+
bdecay[p + d] = max(bdecay[p + d], math.exp(-d * 2.5 / (fps // 2)))
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`bdecay` gives smooth 0→1→0 pulse per beat, decaying over ~0.5s. Use for flash/glitch/mirror triggers.
|
|
87
|
+
|
|
88
|
+
### Normalization
|
|
89
|
+
|
|
90
|
+
After computing all frames, normalize each feature to 0-1:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
for k in features:
|
|
94
|
+
a = features[k]
|
|
95
|
+
lo, hi = a.min(), a.max()
|
|
96
|
+
features[k] = (a - lo) / (hi - lo + 1e-10)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Video Sampling
|
|
100
|
+
|
|
101
|
+
### Frame Extraction
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
# Method 1: ffmpeg pipe (memory efficient)
|
|
105
|
+
cmd = ["ffmpeg", "-i", input_video, "-f", "rawvideo", "-pix_fmt", "rgb24",
|
|
106
|
+
"-s", f"{target_w}x{target_h}", "-r", str(fps), "-"]
|
|
107
|
+
pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
|
108
|
+
frame_size = target_w * target_h * 3
|
|
109
|
+
for fi in range(n_frames):
|
|
110
|
+
raw = pipe.stdout.read(frame_size)
|
|
111
|
+
if len(raw) < frame_size: break
|
|
112
|
+
frame = np.frombuffer(raw, dtype=np.uint8).reshape(target_h, target_w, 3)
|
|
113
|
+
# process frame...
|
|
114
|
+
|
|
115
|
+
# Method 2: OpenCV (if available)
|
|
116
|
+
cap = cv2.VideoCapture(input_video)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Luminance-to-Character Mapping
|
|
120
|
+
|
|
121
|
+
Convert video pixels to ASCII characters based on brightness:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
def frame_to_ascii(frame_rgb, grid, pal=PAL_DEFAULT):
|
|
125
|
+
"""Convert video frame to character + color arrays."""
|
|
126
|
+
rows, cols = grid.rows, grid.cols
|
|
127
|
+
# Resize frame to grid dimensions
|
|
128
|
+
small = np.array(Image.fromarray(frame_rgb).resize((cols, rows), Image.LANCZOS))
|
|
129
|
+
# Luminance
|
|
130
|
+
lum = (0.299 * small[:,:,0] + 0.587 * small[:,:,1] + 0.114 * small[:,:,2]) / 255.0
|
|
131
|
+
# Map to chars
|
|
132
|
+
chars = val2char(lum, lum > 0.02, pal)
|
|
133
|
+
# Colors: use source pixel colors, scaled by luminance for visibility
|
|
134
|
+
colors = np.clip(small * np.clip(lum[:,:,None] * 1.5 + 0.3, 0.3, 1), 0, 255).astype(np.uint8)
|
|
135
|
+
return chars, colors
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Edge-Weighted Character Mapping
|
|
139
|
+
|
|
140
|
+
Use edge detection for more detail in contour regions:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
def frame_to_ascii_edges(frame_rgb, grid, pal=PAL_DEFAULT, edge_pal=PAL_BOX):
|
|
144
|
+
from PIL import Image
|
|
145
|
+
colors = np.array(Image.fromarray(frame_rgb).resize((grid.cols, grid.rows), Image.Resampling.LANCZOS))
|
|
146
|
+
small_gray = colors.astype(np.float32).mean(axis=2)
|
|
147
|
+
lum = small_gray / 255.0
|
|
148
|
+
|
|
149
|
+
# Sobel edge detection
|
|
150
|
+
gx = np.abs(small_gray[:, 2:] - small_gray[:, :-2])
|
|
151
|
+
gy = np.abs(small_gray[2:, :] - small_gray[:-2, :])
|
|
152
|
+
edge = np.zeros_like(small_gray)
|
|
153
|
+
edge[:, 1:-1] += gx; edge[1:-1, :] += gy
|
|
154
|
+
edge = np.clip(edge / max(float(edge.max()), 1e-6), 0, 1)
|
|
155
|
+
|
|
156
|
+
# Edge regions get box drawing chars, flat regions get brightness chars
|
|
157
|
+
is_edge = edge > 0.15
|
|
158
|
+
chars = val2char(lum, lum > 0.02, pal)
|
|
159
|
+
edge_chars = val2char(edge, is_edge, edge_pal)
|
|
160
|
+
chars[is_edge] = edge_chars[is_edge]
|
|
161
|
+
|
|
162
|
+
return chars, colors
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Motion Detection
|
|
166
|
+
|
|
167
|
+
Detect pixel changes between frames for motion-reactive effects:
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
prev_frame = None
|
|
171
|
+
def compute_motion(frame):
|
|
172
|
+
global prev_frame
|
|
173
|
+
if prev_frame is None:
|
|
174
|
+
prev_frame = frame.astype(np.float32)
|
|
175
|
+
return np.zeros(frame.shape[:2])
|
|
176
|
+
diff = np.abs(frame.astype(np.float32) - prev_frame).mean(axis=2)
|
|
177
|
+
prev_frame = frame.astype(np.float32) * 0.7 + prev_frame * 0.3 # smoothed
|
|
178
|
+
return np.clip(diff / 30.0, 0, 1) # normalized motion map
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Use motion map to drive particle emission, glitch intensity, or character density.
|
|
182
|
+
|
|
183
|
+
### Video Feature Extraction
|
|
184
|
+
|
|
185
|
+
Per-frame features analogous to audio features, for driving effects:
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
def analyze_video_frame(frame_rgb):
|
|
189
|
+
gray = np.mean(frame_rgb, axis=2)
|
|
190
|
+
return {
|
|
191
|
+
"brightness": gray.mean() / 255.0,
|
|
192
|
+
"contrast": gray.std() / 128.0,
|
|
193
|
+
"edge_density": compute_edge_density(gray),
|
|
194
|
+
"motion": compute_motion(frame_rgb).mean(),
|
|
195
|
+
"dominant_hue": compute_dominant_hue(frame_rgb),
|
|
196
|
+
"color_variance": compute_color_variance(frame_rgb),
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Image Sequence
|
|
201
|
+
|
|
202
|
+
### Static Image to ASCII
|
|
203
|
+
|
|
204
|
+
Same as single video frame conversion. For animated sequences:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
import glob
|
|
208
|
+
frames = sorted(glob.glob("frames/*.png"))
|
|
209
|
+
for fi, path in enumerate(frames):
|
|
210
|
+
img = np.array(Image.open(path).resize((VW, VH)))
|
|
211
|
+
chars, colors = frame_to_ascii(img, grid, pal)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Image as Texture Source
|
|
215
|
+
|
|
216
|
+
Use an image as a background texture that effects modulate:
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
def load_texture(path, grid):
|
|
220
|
+
img = np.array(Image.open(path).resize((grid.cols, grid.rows)))
|
|
221
|
+
lum = np.mean(img, axis=2) / 255.0
|
|
222
|
+
return lum, img # luminance for char mapping, RGB for colors
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Text / Lyrics
|
|
226
|
+
|
|
227
|
+
### SRT Parsing
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
import re
|
|
231
|
+
def parse_srt(path):
|
|
232
|
+
"""Returns [(start_sec, end_sec, text), ...]"""
|
|
233
|
+
entries = []
|
|
234
|
+
with open(path) as f:
|
|
235
|
+
content = f.read()
|
|
236
|
+
blocks = content.strip().split("\n\n")
|
|
237
|
+
for block in blocks:
|
|
238
|
+
lines = block.strip().split("\n")
|
|
239
|
+
if len(lines) >= 3:
|
|
240
|
+
times = lines[1]
|
|
241
|
+
m = re.match(r"(\d+):(\d+):(\d+),(\d+) --> (\d+):(\d+):(\d+),(\d+)", times)
|
|
242
|
+
if m:
|
|
243
|
+
g = [int(x) for x in m.groups()]
|
|
244
|
+
start = g[0]*3600 + g[1]*60 + g[2] + g[3]/1000
|
|
245
|
+
end = g[4]*3600 + g[5]*60 + g[6] + g[7]/1000
|
|
246
|
+
text = " ".join(lines[2:])
|
|
247
|
+
entries.append((start, end, text))
|
|
248
|
+
return entries
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Lyrics Display Modes
|
|
252
|
+
|
|
253
|
+
- **Typewriter**: characters appear left-to-right over the time window
|
|
254
|
+
- **Fade-in**: whole line fades from dark to bright
|
|
255
|
+
- **Flash**: appear instantly on beat, fade out
|
|
256
|
+
- **Scatter**: characters start at random positions, converge to final position
|
|
257
|
+
- **Wave**: text follows a sine wave path
|
|
258
|
+
|
|
259
|
+
```python
|
|
260
|
+
def lyrics_typewriter(ch, co, text, row, col, t, t_start, t_end, color):
|
|
261
|
+
"""Reveal characters progressively over time window."""
|
|
262
|
+
progress = np.clip((t - t_start) / (t_end - t_start), 0, 1)
|
|
263
|
+
n_visible = int(len(text) * progress)
|
|
264
|
+
stamp(ch, co, text[:n_visible], row, col, color)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Generative (No Input)
|
|
268
|
+
|
|
269
|
+
For pure generative ASCII art, the "features" dict is synthesized from time:
|
|
270
|
+
|
|
271
|
+
```python
|
|
272
|
+
def synthetic_features(t, bpm=120):
|
|
273
|
+
"""Generate audio-like features from time alone."""
|
|
274
|
+
beat_period = 60.0 / bpm
|
|
275
|
+
beat_phase = (t % beat_period) / beat_period
|
|
276
|
+
return {
|
|
277
|
+
"rms": 0.5 + 0.3 * math.sin(t * 0.5),
|
|
278
|
+
"bass": 0.5 + 0.4 * math.sin(t * 2 * math.pi / beat_period),
|
|
279
|
+
"sub": 0.3 + 0.3 * math.sin(t * 0.8),
|
|
280
|
+
"mid": 0.4 + 0.3 * math.sin(t * 1.3),
|
|
281
|
+
"hi": 0.3 + 0.2 * math.sin(t * 2.1),
|
|
282
|
+
"cent": 0.5 + 0.2 * math.sin(t * 0.3),
|
|
283
|
+
"flat": 0.4,
|
|
284
|
+
"flux": 0.3 + 0.2 * math.sin(t * 3),
|
|
285
|
+
"beat": 1.0 if beat_phase < 0.05 else 0.0,
|
|
286
|
+
"bdecay": max(0, 1.0 - beat_phase * 4),
|
|
287
|
+
# ratios
|
|
288
|
+
"sub_r": 0.2, "bass_r": 0.25, "lomid_r": 0.15,
|
|
289
|
+
"mid_r": 0.2, "himid_r": 0.12, "hi_r": 0.08,
|
|
290
|
+
"cent_d": 0.1,
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## TTS Integration
|
|
295
|
+
|
|
296
|
+
For narrated videos (testimonials, quotes, storytelling), generate speech audio per segment and mix with background music.
|
|
297
|
+
|
|
298
|
+
### ElevenLabs Voice Generation
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
import requests, time, os
|
|
302
|
+
|
|
303
|
+
def generate_tts(text, voice_id, api_key, output_path, model="eleven_multilingual_v2"):
|
|
304
|
+
"""Generate TTS audio via ElevenLabs API. Streams response to disk."""
|
|
305
|
+
# No size-only cache: it can reuse a different text or voice.
|
|
306
|
+
if os.path.exists(output_path):
|
|
307
|
+
raise FileExistsError("Select a new task-owned TTS output path")
|
|
308
|
+
|
|
309
|
+
url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}"
|
|
310
|
+
headers = {"xi-api-key": api_key, "Content-Type": "application/json"}
|
|
311
|
+
data = {
|
|
312
|
+
"text": text,
|
|
313
|
+
"model_id": model,
|
|
314
|
+
"voice_settings": {
|
|
315
|
+
"stability": 0.65,
|
|
316
|
+
"similarity_boost": 0.80,
|
|
317
|
+
"style": 0.15,
|
|
318
|
+
"use_speaker_boost": True,
|
|
319
|
+
},
|
|
320
|
+
}
|
|
321
|
+
resp = requests.post(url, json=data, headers=headers, stream=True, timeout=(10, 60))
|
|
322
|
+
resp.raise_for_status()
|
|
323
|
+
with open(output_path, "xb") as f:
|
|
324
|
+
for chunk in resp.iter_content(chunk_size=4096):
|
|
325
|
+
f.write(chunk)
|
|
326
|
+
time.sleep(0.3) # rate limit: avoid 429s on batch generation
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Voice settings notes:
|
|
330
|
+
- `stability` 0.65 gives natural variation without drift. Lower (0.3-0.5) for more expressive reads, higher (0.7-0.9) for monotone/narration.
|
|
331
|
+
- `similarity_boost` 0.80 keeps it close to the voice profile. Lower for more generic sound.
|
|
332
|
+
- `style` 0.15 adds slight stylistic variation. Keep low (0-0.2) for straightforward reads.
|
|
333
|
+
- `use_speaker_boost` True improves clarity at the cost of slightly more processing time.
|
|
334
|
+
|
|
335
|
+
### Voice Pool
|
|
336
|
+
|
|
337
|
+
ElevenLabs has ~20 built-in voices. Use multiple voices for variety across quotes. Reference pool:
|
|
338
|
+
|
|
339
|
+
```python
|
|
340
|
+
VOICE_POOL = [
|
|
341
|
+
("JBFqnCBsd6RMkjVDRZzb", "George"),
|
|
342
|
+
("nPczCjzI2devNBz1zQrb", "Brian"),
|
|
343
|
+
("pqHfZKP75CvOlQylNhV4", "Bill"),
|
|
344
|
+
("CwhRBWXzGAHq8TQ4Fs17", "Roger"),
|
|
345
|
+
("cjVigY5qzO86Huf0OWal", "Eric"),
|
|
346
|
+
("onwK4e9ZLuTAKqWW03F9", "Daniel"),
|
|
347
|
+
("IKne3meq5aSn9XLyUdCD", "Charlie"),
|
|
348
|
+
("iP95p4xoKVk53GoZ742B", "Chris"),
|
|
349
|
+
("bIHbv24MWmeRgasZH58o", "Will"),
|
|
350
|
+
("TX3LPaxmHKxFdv7VOQHJ", "Liam"),
|
|
351
|
+
("SAz9YHcvj6GT2YYXdXww", "River"),
|
|
352
|
+
("EXAVITQu4vr4xnSDxMaL", "Sarah"),
|
|
353
|
+
("Xb7hH8MSUJpSbSDYk0k2", "Alice"),
|
|
354
|
+
("pFZP5JQG7iQjIQuC4Bku", "Lily"),
|
|
355
|
+
("XrExE9yKIg1WjnnlVkGX", "Matilda"),
|
|
356
|
+
("FGY2WhTYpPnrIDTdsKH5", "Laura"),
|
|
357
|
+
("SOYHLrjzK2X1ezoPC6cr", "Harry"),
|
|
358
|
+
("hpp4J3VqNfWAUOO0d1Us", "Bella"),
|
|
359
|
+
("N2lVS1w4EtoT3dr4eOWO", "Callum"),
|
|
360
|
+
("cgSgspJ2msm6clMCkdW9", "Jessica"),
|
|
361
|
+
("pNInz6obpgDQGcFmaJgB", "Adam"),
|
|
362
|
+
]
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Voice Assignment
|
|
366
|
+
|
|
367
|
+
Shuffle deterministically so re-runs produce the same voice mapping:
|
|
368
|
+
|
|
369
|
+
```python
|
|
370
|
+
import random as _rng
|
|
371
|
+
|
|
372
|
+
def assign_voices(n_quotes, voice_pool, seed=42):
|
|
373
|
+
"""Assign a different voice to each quote, cycling if needed."""
|
|
374
|
+
r = _rng.Random(seed)
|
|
375
|
+
ids = [v[0] for v in voice_pool]
|
|
376
|
+
r.shuffle(ids)
|
|
377
|
+
return [ids[i % len(ids)] for i in range(n_quotes)]
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Pronunciation Control
|
|
381
|
+
|
|
382
|
+
TTS text must be separate from display text. The display text has line breaks for visual layout; the TTS text is a flat sentence with phonetic fixes.
|
|
383
|
+
|
|
384
|
+
Common fixes:
|
|
385
|
+
- Brand names: spell phonetically ("Nous" -> "Noose", "nginx" -> "engine-x")
|
|
386
|
+
- Abbreviations: expand ("API" -> "A P I", "CLI" -> "C L I")
|
|
387
|
+
- Technical terms: add phonetic hints
|
|
388
|
+
- Punctuation for pacing: periods create pauses, commas create slight pauses
|
|
389
|
+
|
|
390
|
+
```python
|
|
391
|
+
# Display text: line breaks control visual layout
|
|
392
|
+
QUOTES = [
|
|
393
|
+
("It can do far more than the Claws,\nand you don't need to buy a Mac Mini.\nNous Research has a winner here.", "Brian Roemmele"),
|
|
394
|
+
]
|
|
395
|
+
|
|
396
|
+
# TTS text: flat, phonetically corrected for speech
|
|
397
|
+
QUOTES_TTS = [
|
|
398
|
+
"It can do far more than the Claws, and you don't need to buy a Mac Mini. Noose Research has a winner here.",
|
|
399
|
+
]
|
|
400
|
+
# Keep both arrays in sync -- same indices
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Audio Pipeline
|
|
404
|
+
|
|
405
|
+
1. Generate individual TTS clips (MP3 per quote, skipping existing)
|
|
406
|
+
2. Convert each to WAV (mono, 22050 Hz) for duration measurement and concatenation
|
|
407
|
+
3. Calculate timing: intro pad + speech + gaps + outro pad = target duration
|
|
408
|
+
4. Concatenate into single TTS track with silence padding
|
|
409
|
+
5. Mix with background music
|
|
410
|
+
|
|
411
|
+
```python
|
|
412
|
+
def build_tts_track(tts_clips, target_duration, intro_pad=5.0, outro_pad=4.0):
|
|
413
|
+
"""Concatenate TTS clips with calculated gaps, pad to target duration.
|
|
414
|
+
|
|
415
|
+
Returns:
|
|
416
|
+
timing: list of (start_time, end_time, quote_index) tuples
|
|
417
|
+
"""
|
|
418
|
+
sr = 22050
|
|
419
|
+
|
|
420
|
+
# Convert MP3s to WAV for duration and sample-level concatenation
|
|
421
|
+
durations = []
|
|
422
|
+
for clip in tts_clips:
|
|
423
|
+
wav = str(clip) + ".decoded.wav"
|
|
424
|
+
subprocess.run(
|
|
425
|
+
["ffmpeg", "-y", "-i", clip, "-ac", "1", "-ar", str(sr),
|
|
426
|
+
"-sample_fmt", "s16", wav],
|
|
427
|
+
capture_output=True, check=True)
|
|
428
|
+
result = subprocess.run(
|
|
429
|
+
["ffprobe", "-v", "error", "-show_entries", "format=duration",
|
|
430
|
+
"-of", "csv=p=0", wav],
|
|
431
|
+
capture_output=True, text=True)
|
|
432
|
+
durations.append(float(result.stdout.strip()))
|
|
433
|
+
|
|
434
|
+
# Calculate gap to fill target duration
|
|
435
|
+
total_speech = sum(durations)
|
|
436
|
+
n_gaps = len(tts_clips) - 1
|
|
437
|
+
remaining = target_duration - total_speech - intro_pad - outro_pad
|
|
438
|
+
gap = max(1.0, remaining / max(1, n_gaps))
|
|
439
|
+
|
|
440
|
+
# Build timing and concatenate samples
|
|
441
|
+
timing = []
|
|
442
|
+
t = intro_pad
|
|
443
|
+
all_audio = [np.zeros(int(sr * intro_pad), dtype=np.int16)]
|
|
444
|
+
|
|
445
|
+
for i, dur in enumerate(durations):
|
|
446
|
+
wav = str(tts_clips[i]) + ".decoded.wav"
|
|
447
|
+
with wave.open(wav) as wf:
|
|
448
|
+
samples = np.frombuffer(wf.readframes(wf.getnframes()), dtype=np.int16)
|
|
449
|
+
timing.append((t, t + dur, i))
|
|
450
|
+
all_audio.append(samples)
|
|
451
|
+
t += dur
|
|
452
|
+
if i < len(tts_clips) - 1:
|
|
453
|
+
all_audio.append(np.zeros(int(sr * gap), dtype=np.int16))
|
|
454
|
+
t += gap
|
|
455
|
+
|
|
456
|
+
all_audio.append(np.zeros(int(sr * outro_pad), dtype=np.int16))
|
|
457
|
+
|
|
458
|
+
# Pad or trim to exactly target_duration
|
|
459
|
+
full = np.concatenate(all_audio)
|
|
460
|
+
target_samples = int(sr * target_duration)
|
|
461
|
+
if len(full) < target_samples:
|
|
462
|
+
full = np.pad(full, (0, target_samples - len(full)))
|
|
463
|
+
else:
|
|
464
|
+
full = full[:target_samples]
|
|
465
|
+
|
|
466
|
+
# Write concatenated TTS track
|
|
467
|
+
with wave.open("tts_full.wav", "w") as wf:
|
|
468
|
+
wf.setnchannels(1)
|
|
469
|
+
wf.setsampwidth(2)
|
|
470
|
+
wf.setframerate(sr)
|
|
471
|
+
wf.writeframes(full.tobytes())
|
|
472
|
+
|
|
473
|
+
return timing
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Audio Mixing
|
|
477
|
+
|
|
478
|
+
Mix TTS (center) with background music (wide stereo, low volume). The filter chain:
|
|
479
|
+
1. TTS mono duplicated to both channels (centered)
|
|
480
|
+
2. BGM loudness-normalized, volume reduced to 15%, stereo widened with `extrastereo`
|
|
481
|
+
3. Mixed together with dropout transition for smooth endings
|
|
482
|
+
|
|
483
|
+
```python
|
|
484
|
+
def mix_audio(tts_path, bgm_path, output_path, bgm_volume=0.15):
|
|
485
|
+
"""Mix TTS centered with BGM panned wide stereo."""
|
|
486
|
+
filter_complex = (
|
|
487
|
+
# TTS: mono -> stereo center
|
|
488
|
+
"[0:a]aformat=sample_fmts=fltp:sample_rates=44100:channel_layouts=mono,"
|
|
489
|
+
"pan=stereo|c0=c0|c1=c0[tts];"
|
|
490
|
+
# BGM: normalize loudness, reduce volume, widen stereo
|
|
491
|
+
f"[1:a]aformat=sample_fmts=fltp:sample_rates=44100:channel_layouts=stereo,"
|
|
492
|
+
f"loudnorm=I=-16:TP=-1.5:LRA=11,"
|
|
493
|
+
f"volume={bgm_volume},"
|
|
494
|
+
f"extrastereo=m=2.5[bgm];"
|
|
495
|
+
# Mix with smooth dropout at end
|
|
496
|
+
"[tts][bgm]amix=inputs=2:duration=longest:dropout_transition=3,"
|
|
497
|
+
"aformat=sample_fmts=s16:sample_rates=44100:channel_layouts=stereo[out]"
|
|
498
|
+
)
|
|
499
|
+
cmd = [
|
|
500
|
+
"ffmpeg", "-y",
|
|
501
|
+
"-i", tts_path,
|
|
502
|
+
"-i", bgm_path,
|
|
503
|
+
"-filter_complex", filter_complex,
|
|
504
|
+
"-map", "[out]", output_path,
|
|
505
|
+
]
|
|
506
|
+
subprocess.run(cmd, capture_output=True, check=True)
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### Per-Quote Visual Style
|
|
510
|
+
|
|
511
|
+
Cycle through visual presets per quote for variety. Each preset defines a background effect, color scheme, and text color:
|
|
512
|
+
|
|
513
|
+
```python
|
|
514
|
+
QUOTE_STYLES = [
|
|
515
|
+
{"hue": 0.08, "accent": 0.7, "bg": "spiral", "text_rgb": (255, 220, 140)}, # warm gold
|
|
516
|
+
{"hue": 0.55, "accent": 0.6, "bg": "rings", "text_rgb": (180, 220, 255)}, # cool blue
|
|
517
|
+
{"hue": 0.75, "accent": 0.7, "bg": "wave", "text_rgb": (220, 180, 255)}, # purple
|
|
518
|
+
{"hue": 0.35, "accent": 0.6, "bg": "matrix", "text_rgb": (140, 255, 180)}, # green
|
|
519
|
+
{"hue": 0.95, "accent": 0.8, "bg": "fire", "text_rgb": (255, 180, 160)}, # red/coral
|
|
520
|
+
{"hue": 0.12, "accent": 0.5, "bg": "interference", "text_rgb": (255, 240, 200)}, # amber
|
|
521
|
+
{"hue": 0.60, "accent": 0.7, "bg": "tunnel", "text_rgb": (160, 210, 255)}, # cyan
|
|
522
|
+
{"hue": 0.45, "accent": 0.6, "bg": "aurora", "text_rgb": (180, 255, 220)}, # teal
|
|
523
|
+
]
|
|
524
|
+
|
|
525
|
+
style = QUOTE_STYLES[quote_index % len(QUOTE_STYLES)]
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
This guarantees no two adjacent quotes share the same look, even without randomness.
|
|
529
|
+
|
|
530
|
+
### Typewriter Text Rendering
|
|
531
|
+
|
|
532
|
+
Display quote text character-by-character synced to speech progress. Recently revealed characters are brighter, creating a "just typed" glow:
|
|
533
|
+
|
|
534
|
+
```python
|
|
535
|
+
def render_typewriter(ch, co, lines, block_start, cols, progress, total_chars, text_rgb, t):
|
|
536
|
+
"""Overlay typewriter text onto character/color grids.
|
|
537
|
+
progress: 0.0 (nothing visible) to 1.0 (all text visible)."""
|
|
538
|
+
chars_visible = int(total_chars * min(1.0, progress * 1.2)) # slight overshoot for snappy feel
|
|
539
|
+
tr, tg, tb = text_rgb
|
|
540
|
+
char_count = 0
|
|
541
|
+
for li, line in enumerate(lines):
|
|
542
|
+
row = block_start + li
|
|
543
|
+
col = (cols - len(line)) // 2
|
|
544
|
+
for ci, c in enumerate(line):
|
|
545
|
+
if char_count < chars_visible:
|
|
546
|
+
age = chars_visible - char_count
|
|
547
|
+
bri_factor = min(1.0, 0.5 + 0.5 / (1 + age * 0.015)) # newer = brighter
|
|
548
|
+
hue_shift = math.sin(char_count * 0.3 + t * 2) * 0.05
|
|
549
|
+
stamp(ch, co, c, row, col + ci,
|
|
550
|
+
(int(min(255, tr * bri_factor * (1.0 + hue_shift))),
|
|
551
|
+
int(min(255, tg * bri_factor)),
|
|
552
|
+
int(min(255, tb * bri_factor * (1.0 - hue_shift)))))
|
|
553
|
+
char_count += 1
|
|
554
|
+
|
|
555
|
+
# Blinking cursor at insertion point
|
|
556
|
+
if progress < 1.0 and int(t * 3) % 2 == 0:
|
|
557
|
+
# Find cursor position (char_count == chars_visible)
|
|
558
|
+
cc = 0
|
|
559
|
+
for li, line in enumerate(lines):
|
|
560
|
+
for ci, c in enumerate(line):
|
|
561
|
+
if cc == chars_visible:
|
|
562
|
+
stamp(ch, co, "\u258c", block_start + li,
|
|
563
|
+
(cols - len(line)) // 2 + ci, (255, 220, 100))
|
|
564
|
+
return
|
|
565
|
+
cc += 1
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### Feature Analysis on Mixed Audio
|
|
569
|
+
|
|
570
|
+
Run the standard audio analysis (FFT, beat detection) on the final mixed track so visual effects react to both TTS and music:
|
|
571
|
+
|
|
572
|
+
```python
|
|
573
|
+
# Analyze mixed_final.wav (not individual tracks)
|
|
574
|
+
features = analyze_audio("mixed_final.wav", fps=24)
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
Visuals pulse with both the music beats and the speech energy.
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
## Audio-Video Sync Verification
|
|
582
|
+
|
|
583
|
+
After rendering, verify that visual beat markers align with actual audio beats. Drift accumulates from frame timing errors, ffmpeg concat boundaries, and rounding in `fi / fps`.
|
|
584
|
+
|
|
585
|
+
### Beat Timestamp Extraction
|
|
586
|
+
|
|
587
|
+
```python
|
|
588
|
+
def extract_beat_timestamps(features, fps, threshold=0.5):
|
|
589
|
+
"""Extract timestamps where beat feature exceeds threshold."""
|
|
590
|
+
beat = features["beat"]
|
|
591
|
+
timestamps = []
|
|
592
|
+
for fi in range(len(beat)):
|
|
593
|
+
if beat[fi] > threshold:
|
|
594
|
+
timestamps.append(fi / fps)
|
|
595
|
+
return timestamps
|
|
596
|
+
|
|
597
|
+
def extract_visual_beat_timestamps(video_path, fps, brightness_jump=30):
|
|
598
|
+
"""Detect visual beats by brightness jumps between consecutive frames.
|
|
599
|
+
Returns timestamps where mean brightness increases by more than threshold."""
|
|
600
|
+
import subprocess
|
|
601
|
+
if not 0 < fps <= 120:
|
|
602
|
+
raise ValueError("Invalid sample FPS")
|
|
603
|
+
# Explicit sampling FPS and bounded resolution; stream one frame at a time.
|
|
604
|
+
width, height = 320, 180
|
|
605
|
+
cmd = ["ffmpeg", "-v", "error", "-i", video_path, "-t", "600",
|
|
606
|
+
"-vf", f"fps={fps},scale={width}:{height}", "-f", "rawvideo", "-pix_fmt", "gray", "-"]
|
|
607
|
+
timestamps = []
|
|
608
|
+
previous = None
|
|
609
|
+
index = 0
|
|
610
|
+
with subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) as proc:
|
|
611
|
+
try:
|
|
612
|
+
while True:
|
|
613
|
+
raw = proc.stdout.read(width * height)
|
|
614
|
+
if not raw:
|
|
615
|
+
break
|
|
616
|
+
if len(raw) != width * height:
|
|
617
|
+
raise ValueError("Truncated video frame")
|
|
618
|
+
mean = np.frombuffer(raw, dtype=np.uint8).mean()
|
|
619
|
+
if previous is not None and mean - previous > brightness_jump:
|
|
620
|
+
timestamps.append(index / fps)
|
|
621
|
+
previous = mean
|
|
622
|
+
index += 1
|
|
623
|
+
if proc.wait(timeout=30) != 0:
|
|
624
|
+
raise RuntimeError("Video decoding failed")
|
|
625
|
+
finally:
|
|
626
|
+
if proc.poll() is None:
|
|
627
|
+
proc.kill()
|
|
628
|
+
proc.wait()
|
|
629
|
+
return timestamps
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### Sync Report
|
|
633
|
+
|
|
634
|
+
```python
|
|
635
|
+
def sync_report(audio_beats, visual_beats, tolerance_ms=50):
|
|
636
|
+
"""Compare audio beat timestamps to visual beat timestamps.
|
|
637
|
+
|
|
638
|
+
Args:
|
|
639
|
+
audio_beats: list of timestamps (seconds) from audio analysis
|
|
640
|
+
visual_beats: list of timestamps (seconds) from video brightness analysis
|
|
641
|
+
tolerance_ms: max acceptable drift in milliseconds
|
|
642
|
+
|
|
643
|
+
Returns:
|
|
644
|
+
dict with matched/unmatched/drift statistics
|
|
645
|
+
"""
|
|
646
|
+
tolerance = tolerance_ms / 1000.0
|
|
647
|
+
matched = []
|
|
648
|
+
unmatched_audio = []
|
|
649
|
+
unmatched_visual = list(visual_beats)
|
|
650
|
+
|
|
651
|
+
for at in audio_beats:
|
|
652
|
+
best_match = None
|
|
653
|
+
best_delta = float("inf")
|
|
654
|
+
for vt in unmatched_visual:
|
|
655
|
+
delta = abs(at - vt)
|
|
656
|
+
if delta < best_delta:
|
|
657
|
+
best_delta = delta
|
|
658
|
+
best_match = vt
|
|
659
|
+
if best_match is not None and best_delta < tolerance:
|
|
660
|
+
matched.append({"audio": at, "visual": best_match, "drift_ms": best_delta * 1000})
|
|
661
|
+
unmatched_visual.remove(best_match)
|
|
662
|
+
else:
|
|
663
|
+
unmatched_audio.append(at)
|
|
664
|
+
|
|
665
|
+
drifts = [m["drift_ms"] for m in matched]
|
|
666
|
+
return {
|
|
667
|
+
"matched": len(matched),
|
|
668
|
+
"unmatched_audio": len(unmatched_audio),
|
|
669
|
+
"unmatched_visual": len(unmatched_visual),
|
|
670
|
+
"total_audio_beats": len(audio_beats),
|
|
671
|
+
"total_visual_beats": len(visual_beats),
|
|
672
|
+
"mean_drift_ms": np.mean(drifts) if drifts else 0,
|
|
673
|
+
"max_drift_ms": np.max(drifts) if drifts else None,
|
|
674
|
+
"p95_drift_ms": np.percentile(drifts, 95) if len(drifts) > 1 else 0,
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
# Usage:
|
|
678
|
+
audio_beats = extract_beat_timestamps(features, fps=24)
|
|
679
|
+
visual_beats = extract_visual_beat_timestamps("output.mp4", fps=24)
|
|
680
|
+
report = sync_report(audio_beats, visual_beats)
|
|
681
|
+
print(f"Matched: {report['matched']}/{report['total_audio_beats']} beats")
|
|
682
|
+
print(f"Mean drift: {report['mean_drift_ms']:.1f}ms, Max: {report['max_drift_ms']:.1f}ms")
|
|
683
|
+
# Target: mean drift < 20ms, max drift < 42ms (1 frame at 24fps)
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
### Common Sync Issues
|
|
687
|
+
|
|
688
|
+
| Symptom | Cause | Fix |
|
|
689
|
+
|---------|-------|-----|
|
|
690
|
+
| Consistent late visual beats | ffmpeg concat adds frames at boundaries | Use `-vsync cfr` flag; pad segments to exact frame count |
|
|
691
|
+
| Drift increases over time | Floating-point accumulation in `t = fi / fps` | Use integer frame counter, compute `t` fresh each frame |
|
|
692
|
+
| Random missed beats | Beat threshold too high / feature smoothing too aggressive | Lower threshold; reduce EMA alpha for beat feature |
|
|
693
|
+
| Beats land on wrong frame | Off-by-one in frame indexing | Verify: frame 0 = t=0, frame 1 = t=1/fps (not t=0) |
|