@amrhas82/agentic-kit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin-lite.json +38 -0
- package/.claude-plugin/plugin-pro.json +183 -0
- package/.claude-plugin/plugin-standard.json +147 -0
- package/.claude-plugin/plugin.json +47 -0
- package/LICENSE +21 -0
- package/QUICK-START.md +318 -0
- package/README.md +449 -0
- package/TROUBLESHOOTING.md +788 -0
- package/VARIANTS.md +480 -0
- package/agents/1-create-prd.md +56 -0
- package/agents/2-generate-tasks.md +73 -0
- package/agents/3-process-task-list.md +101 -0
- package/agents/business-analyst.md +76 -0
- package/agents/full-stack-dev.md +80 -0
- package/agents/holistic-architect.md +91 -0
- package/agents/master.md +55 -0
- package/agents/orchestrator.md +103 -0
- package/agents/product-manager.md +82 -0
- package/agents/product-owner.md +97 -0
- package/agents/qa-test-architect.md +72 -0
- package/agents/scrum-master.md +64 -0
- package/agents/ux-expert.md +74 -0
- package/cli.js +230 -0
- package/hooks/register-agents.js +123 -0
- package/package.json +61 -0
- package/resources/agent-teams.yaml +50 -0
- package/resources/checklists.md +1724 -0
- package/resources/data.md +1372 -0
- package/resources/task-briefs.md +4428 -0
- package/resources/templates.yaml +5634 -0
- package/resources/workflows.yaml +1253 -0
- package/skills/algorithmic-art/LICENSE.txt +202 -0
- package/skills/algorithmic-art/SKILL.md +405 -0
- package/skills/algorithmic-art/templates/generator_template.js +223 -0
- package/skills/algorithmic-art/templates/viewer.html +599 -0
- package/skills/artifacts-builder/LICENSE.txt +202 -0
- package/skills/artifacts-builder/SKILL.md +74 -0
- package/skills/artifacts-builder/scripts/bundle-artifact.sh +54 -0
- package/skills/artifacts-builder/scripts/init-artifact.sh +322 -0
- package/skills/artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
- package/skills/brainstorming/SKILL.md +54 -0
- package/skills/brand-guidelines/LICENSE.txt +202 -0
- package/skills/brand-guidelines/SKILL.md +73 -0
- package/skills/canvas-design/LICENSE.txt +202 -0
- package/skills/canvas-design/SKILL.md +130 -0
- package/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +94 -0
- package/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/Jura-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
- package/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- package/skills/code-review/SKILL.md +105 -0
- package/skills/code-review/code-reviewer.md +146 -0
- package/skills/condition-based-waiting/SKILL.md +120 -0
- package/skills/condition-based-waiting/example.ts +158 -0
- package/skills/docx/LICENSE.txt +30 -0
- package/skills/docx/SKILL.md +197 -0
- package/skills/docx/docx-js.md +350 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/skills/docx/ooxml/schemas/mce/mc.xsd +75 -0
- package/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/skills/docx/ooxml/scripts/pack.py +159 -0
- package/skills/docx/ooxml/scripts/unpack.py +29 -0
- package/skills/docx/ooxml/scripts/validate.py +69 -0
- package/skills/docx/ooxml/scripts/validation/__init__.py +15 -0
- package/skills/docx/ooxml/scripts/validation/base.py +951 -0
- package/skills/docx/ooxml/scripts/validation/docx.py +274 -0
- package/skills/docx/ooxml/scripts/validation/pptx.py +315 -0
- package/skills/docx/ooxml/scripts/validation/redlining.py +279 -0
- package/skills/docx/ooxml.md +610 -0
- package/skills/docx/scripts/__init__.py +1 -0
- package/skills/docx/scripts/document.py +1276 -0
- package/skills/docx/scripts/templates/comments.xml +3 -0
- package/skills/docx/scripts/templates/commentsExtended.xml +3 -0
- package/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/skills/docx/scripts/templates/commentsIds.xml +3 -0
- package/skills/docx/scripts/templates/people.xml +3 -0
- package/skills/docx/scripts/utilities.py +374 -0
- package/skills/internal-comms/LICENSE.txt +202 -0
- package/skills/internal-comms/SKILL.md +32 -0
- package/skills/internal-comms/examples/3p-updates.md +47 -0
- package/skills/internal-comms/examples/company-newsletter.md +65 -0
- package/skills/internal-comms/examples/faq-answers.md +30 -0
- package/skills/internal-comms/examples/general-comms.md +16 -0
- package/skills/mcp-builder/LICENSE.txt +202 -0
- package/skills/mcp-builder/SKILL.md +328 -0
- package/skills/mcp-builder/reference/evaluation.md +602 -0
- package/skills/mcp-builder/reference/mcp_best_practices.md +915 -0
- package/skills/mcp-builder/reference/node_mcp_server.md +916 -0
- package/skills/mcp-builder/reference/python_mcp_server.md +752 -0
- package/skills/mcp-builder/scripts/connections.py +151 -0
- package/skills/mcp-builder/scripts/evaluation.py +373 -0
- package/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/skills/mcp-builder/scripts/requirements.txt +2 -0
- package/skills/pdf/LICENSE.txt +30 -0
- package/skills/pdf/SKILL.md +294 -0
- package/skills/pdf/forms.md +205 -0
- package/skills/pdf/reference.md +612 -0
- package/skills/pdf/scripts/check_bounding_boxes.py +70 -0
- package/skills/pdf/scripts/check_bounding_boxes_test.py +226 -0
- package/skills/pdf/scripts/check_fillable_fields.py +12 -0
- package/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
- package/skills/pdf/scripts/create_validation_image.py +41 -0
- package/skills/pdf/scripts/extract_form_field_info.py +152 -0
- package/skills/pdf/scripts/fill_fillable_fields.py +114 -0
- package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
- package/skills/pptx/LICENSE.txt +30 -0
- package/skills/pptx/SKILL.md +484 -0
- package/skills/pptx/html2pptx.md +625 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/skills/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/skills/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/skills/pptx/ooxml/schemas/mce/mc.xsd +75 -0
- package/skills/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/skills/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/skills/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/skills/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/skills/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/skills/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/skills/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/skills/pptx/ooxml/scripts/pack.py +159 -0
- package/skills/pptx/ooxml/scripts/unpack.py +29 -0
- package/skills/pptx/ooxml/scripts/validate.py +69 -0
- package/skills/pptx/ooxml/scripts/validation/__init__.py +15 -0
- package/skills/pptx/ooxml/scripts/validation/base.py +951 -0
- package/skills/pptx/ooxml/scripts/validation/docx.py +274 -0
- package/skills/pptx/ooxml/scripts/validation/pptx.py +315 -0
- package/skills/pptx/ooxml/scripts/validation/redlining.py +279 -0
- package/skills/pptx/ooxml.md +427 -0
- package/skills/pptx/scripts/html2pptx.js +979 -0
- package/skills/pptx/scripts/inventory.py +1020 -0
- package/skills/pptx/scripts/rearrange.py +231 -0
- package/skills/pptx/scripts/replace.py +385 -0
- package/skills/pptx/scripts/thumbnail.py +450 -0
- package/skills/root-cause-tracing/SKILL.md +174 -0
- package/skills/root-cause-tracing/find-polluter.sh +63 -0
- package/skills/skill-creator/LICENSE.txt +202 -0
- package/skills/skill-creator/SKILL.md +209 -0
- package/skills/skill-creator/scripts/init_skill.py +303 -0
- package/skills/skill-creator/scripts/package_skill.py +110 -0
- package/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/skills/slack-gif-creator/LICENSE.txt +202 -0
- package/skills/slack-gif-creator/SKILL.md +646 -0
- package/skills/slack-gif-creator/core/color_palettes.py +302 -0
- package/skills/slack-gif-creator/core/easing.py +230 -0
- package/skills/slack-gif-creator/core/frame_composer.py +469 -0
- package/skills/slack-gif-creator/core/gif_builder.py +246 -0
- package/skills/slack-gif-creator/core/typography.py +357 -0
- package/skills/slack-gif-creator/core/validators.py +264 -0
- package/skills/slack-gif-creator/core/visual_effects.py +494 -0
- package/skills/slack-gif-creator/requirements.txt +4 -0
- package/skills/slack-gif-creator/templates/bounce.py +106 -0
- package/skills/slack-gif-creator/templates/explode.py +331 -0
- package/skills/slack-gif-creator/templates/fade.py +329 -0
- package/skills/slack-gif-creator/templates/flip.py +291 -0
- package/skills/slack-gif-creator/templates/kaleidoscope.py +211 -0
- package/skills/slack-gif-creator/templates/morph.py +329 -0
- package/skills/slack-gif-creator/templates/move.py +293 -0
- package/skills/slack-gif-creator/templates/pulse.py +268 -0
- package/skills/slack-gif-creator/templates/shake.py +127 -0
- package/skills/slack-gif-creator/templates/slide.py +291 -0
- package/skills/slack-gif-creator/templates/spin.py +269 -0
- package/skills/slack-gif-creator/templates/wiggle.py +300 -0
- package/skills/slack-gif-creator/templates/zoom.py +312 -0
- package/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/skills/systematic-debugging/SKILL.md +295 -0
- package/skills/systematic-debugging/test-academic.md +14 -0
- package/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/skills/test-driven-development/SKILL.md +364 -0
- package/skills/testing-anti-patterns/SKILL.md +302 -0
- package/skills/theme-factory/LICENSE.txt +202 -0
- package/skills/theme-factory/SKILL.md +59 -0
- package/skills/theme-factory/theme-showcase.pdf +0 -0
- package/skills/theme-factory/themes/arctic-frost.md +19 -0
- package/skills/theme-factory/themes/botanical-garden.md +19 -0
- package/skills/theme-factory/themes/desert-rose.md +19 -0
- package/skills/theme-factory/themes/forest-canopy.md +19 -0
- package/skills/theme-factory/themes/golden-hour.md +19 -0
- package/skills/theme-factory/themes/midnight-galaxy.md +19 -0
- package/skills/theme-factory/themes/modern-minimalist.md +19 -0
- package/skills/theme-factory/themes/ocean-depths.md +19 -0
- package/skills/theme-factory/themes/sunset-boulevard.md +19 -0
- package/skills/theme-factory/themes/tech-innovation.md +19 -0
- package/skills/verification-before-completion/SKILL.md +139 -0
- package/skills/webapp-testing/LICENSE.txt +202 -0
- package/skills/webapp-testing/SKILL.md +96 -0
- package/skills/webapp-testing/examples/console_logging.py +35 -0
- package/skills/webapp-testing/examples/element_discovery.py +40 -0
- package/skills/webapp-testing/examples/static_html_automation.py +33 -0
- package/skills/webapp-testing/scripts/with_server.py +106 -0
- package/skills/xlsx/LICENSE.txt +30 -0
- package/skills/xlsx/SKILL.md +289 -0
- package/skills/xlsx/recalc.py +178 -0
- package/validate-references.sh +86 -0
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Visual Effects - Particles, motion blur, impacts, and other effects for GIFs.
|
|
4
|
+
|
|
5
|
+
This module provides high-impact visual effects that make animations feel
|
|
6
|
+
professional and dynamic while keeping file sizes reasonable.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from PIL import Image, ImageDraw, ImageFilter
|
|
10
|
+
import numpy as np
|
|
11
|
+
import math
|
|
12
|
+
import random
|
|
13
|
+
from typing import Optional
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Particle:
|
|
17
|
+
"""A single particle in a particle system."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, x: float, y: float, vx: float, vy: float,
|
|
20
|
+
lifetime: float, color: tuple[int, int, int],
|
|
21
|
+
size: int = 3, shape: str = 'circle'):
|
|
22
|
+
"""
|
|
23
|
+
Initialize a particle.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
x, y: Starting position
|
|
27
|
+
vx, vy: Velocity
|
|
28
|
+
lifetime: How long particle lives (in frames)
|
|
29
|
+
color: RGB color
|
|
30
|
+
size: Particle size in pixels
|
|
31
|
+
shape: 'circle', 'square', or 'star'
|
|
32
|
+
"""
|
|
33
|
+
self.x = x
|
|
34
|
+
self.y = y
|
|
35
|
+
self.vx = vx
|
|
36
|
+
self.vy = vy
|
|
37
|
+
self.lifetime = lifetime
|
|
38
|
+
self.max_lifetime = lifetime
|
|
39
|
+
self.color = color
|
|
40
|
+
self.size = size
|
|
41
|
+
self.shape = shape
|
|
42
|
+
self.gravity = 0.5 # Pixels per frame squared
|
|
43
|
+
self.drag = 0.98 # Velocity multiplier per frame
|
|
44
|
+
|
|
45
|
+
def update(self):
|
|
46
|
+
"""Update particle position and lifetime."""
|
|
47
|
+
# Apply physics
|
|
48
|
+
self.vy += self.gravity
|
|
49
|
+
self.vx *= self.drag
|
|
50
|
+
self.vy *= self.drag
|
|
51
|
+
|
|
52
|
+
# Update position
|
|
53
|
+
self.x += self.vx
|
|
54
|
+
self.y += self.vy
|
|
55
|
+
|
|
56
|
+
# Decrease lifetime
|
|
57
|
+
self.lifetime -= 1
|
|
58
|
+
|
|
59
|
+
def is_alive(self) -> bool:
|
|
60
|
+
"""Check if particle is still alive."""
|
|
61
|
+
return self.lifetime > 0
|
|
62
|
+
|
|
63
|
+
def get_alpha(self) -> float:
|
|
64
|
+
"""Get particle opacity based on lifetime."""
|
|
65
|
+
return max(0, min(1, self.lifetime / self.max_lifetime))
|
|
66
|
+
|
|
67
|
+
def render(self, frame: Image.Image):
|
|
68
|
+
"""
|
|
69
|
+
Render particle to frame.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
frame: PIL Image to draw on
|
|
73
|
+
"""
|
|
74
|
+
if not self.is_alive():
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
draw = ImageDraw.Draw(frame)
|
|
78
|
+
alpha = self.get_alpha()
|
|
79
|
+
|
|
80
|
+
# Calculate faded color
|
|
81
|
+
color = tuple(int(c * alpha) for c in self.color)
|
|
82
|
+
|
|
83
|
+
# Draw based on shape
|
|
84
|
+
x, y = int(self.x), int(self.y)
|
|
85
|
+
size = max(1, int(self.size * alpha))
|
|
86
|
+
|
|
87
|
+
if self.shape == 'circle':
|
|
88
|
+
bbox = [x - size, y - size, x + size, y + size]
|
|
89
|
+
draw.ellipse(bbox, fill=color)
|
|
90
|
+
elif self.shape == 'square':
|
|
91
|
+
bbox = [x - size, y - size, x + size, y + size]
|
|
92
|
+
draw.rectangle(bbox, fill=color)
|
|
93
|
+
elif self.shape == 'star':
|
|
94
|
+
# Simple 4-point star
|
|
95
|
+
points = [
|
|
96
|
+
(x, y - size),
|
|
97
|
+
(x - size // 2, y),
|
|
98
|
+
(x, y),
|
|
99
|
+
(x, y + size),
|
|
100
|
+
(x, y),
|
|
101
|
+
(x + size // 2, y),
|
|
102
|
+
]
|
|
103
|
+
draw.line(points, fill=color, width=2)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class ParticleSystem:
|
|
107
|
+
"""Manages a collection of particles."""
|
|
108
|
+
|
|
109
|
+
def __init__(self):
|
|
110
|
+
"""Initialize particle system."""
|
|
111
|
+
self.particles: list[Particle] = []
|
|
112
|
+
|
|
113
|
+
def emit(self, x: int, y: int, count: int = 10,
|
|
114
|
+
spread: float = 2.0, speed: float = 5.0,
|
|
115
|
+
color: tuple[int, int, int] = (255, 200, 0),
|
|
116
|
+
lifetime: float = 20.0, size: int = 3, shape: str = 'circle'):
|
|
117
|
+
"""
|
|
118
|
+
Emit a burst of particles.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
x, y: Emission position
|
|
122
|
+
count: Number of particles to emit
|
|
123
|
+
spread: Angle spread (radians)
|
|
124
|
+
speed: Initial speed
|
|
125
|
+
color: Particle color
|
|
126
|
+
lifetime: Particle lifetime in frames
|
|
127
|
+
size: Particle size
|
|
128
|
+
shape: Particle shape
|
|
129
|
+
"""
|
|
130
|
+
for _ in range(count):
|
|
131
|
+
# Random angle and speed
|
|
132
|
+
angle = random.uniform(0, 2 * math.pi)
|
|
133
|
+
vel_mag = random.uniform(speed * 0.5, speed * 1.5)
|
|
134
|
+
vx = math.cos(angle) * vel_mag
|
|
135
|
+
vy = math.sin(angle) * vel_mag
|
|
136
|
+
|
|
137
|
+
# Random lifetime variation
|
|
138
|
+
life = random.uniform(lifetime * 0.7, lifetime * 1.3)
|
|
139
|
+
|
|
140
|
+
particle = Particle(x, y, vx, vy, life, color, size, shape)
|
|
141
|
+
self.particles.append(particle)
|
|
142
|
+
|
|
143
|
+
def emit_confetti(self, x: int, y: int, count: int = 20,
|
|
144
|
+
colors: Optional[list[tuple[int, int, int]]] = None):
|
|
145
|
+
"""
|
|
146
|
+
Emit confetti particles (colorful, falling).
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
x, y: Emission position
|
|
150
|
+
count: Number of confetti pieces
|
|
151
|
+
colors: List of colors (random if None)
|
|
152
|
+
"""
|
|
153
|
+
if colors is None:
|
|
154
|
+
colors = [
|
|
155
|
+
(255, 107, 107), (255, 159, 64), (255, 218, 121),
|
|
156
|
+
(107, 185, 240), (162, 155, 254), (255, 182, 193)
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
for _ in range(count):
|
|
160
|
+
color = random.choice(colors)
|
|
161
|
+
vx = random.uniform(-3, 3)
|
|
162
|
+
vy = random.uniform(-8, -2)
|
|
163
|
+
shape = random.choice(['square', 'circle'])
|
|
164
|
+
size = random.randint(2, 4)
|
|
165
|
+
lifetime = random.uniform(40, 60)
|
|
166
|
+
|
|
167
|
+
particle = Particle(x, y, vx, vy, lifetime, color, size, shape)
|
|
168
|
+
particle.gravity = 0.3 # Lighter gravity for confetti
|
|
169
|
+
self.particles.append(particle)
|
|
170
|
+
|
|
171
|
+
def emit_sparkles(self, x: int, y: int, count: int = 15):
|
|
172
|
+
"""
|
|
173
|
+
Emit sparkle particles (twinkling stars).
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
x, y: Emission position
|
|
177
|
+
count: Number of sparkles
|
|
178
|
+
"""
|
|
179
|
+
colors = [(255, 255, 200), (255, 255, 255), (255, 255, 150)]
|
|
180
|
+
|
|
181
|
+
for _ in range(count):
|
|
182
|
+
color = random.choice(colors)
|
|
183
|
+
angle = random.uniform(0, 2 * math.pi)
|
|
184
|
+
speed = random.uniform(1, 3)
|
|
185
|
+
vx = math.cos(angle) * speed
|
|
186
|
+
vy = math.sin(angle) * speed
|
|
187
|
+
lifetime = random.uniform(15, 30)
|
|
188
|
+
|
|
189
|
+
particle = Particle(x, y, vx, vy, lifetime, color, 2, 'star')
|
|
190
|
+
particle.gravity = 0
|
|
191
|
+
particle.drag = 0.95
|
|
192
|
+
self.particles.append(particle)
|
|
193
|
+
|
|
194
|
+
def update(self):
|
|
195
|
+
"""Update all particles."""
|
|
196
|
+
# Update alive particles
|
|
197
|
+
for particle in self.particles:
|
|
198
|
+
particle.update()
|
|
199
|
+
|
|
200
|
+
# Remove dead particles
|
|
201
|
+
self.particles = [p for p in self.particles if p.is_alive()]
|
|
202
|
+
|
|
203
|
+
def render(self, frame: Image.Image):
|
|
204
|
+
"""Render all particles to frame."""
|
|
205
|
+
for particle in self.particles:
|
|
206
|
+
particle.render(frame)
|
|
207
|
+
|
|
208
|
+
def get_particle_count(self) -> int:
|
|
209
|
+
"""Get number of active particles."""
|
|
210
|
+
return len(self.particles)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def add_motion_blur(frame: Image.Image, prev_frame: Optional[Image.Image],
|
|
214
|
+
blur_amount: float = 0.5) -> Image.Image:
|
|
215
|
+
"""
|
|
216
|
+
Add motion blur by blending with previous frame.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
frame: Current frame
|
|
220
|
+
prev_frame: Previous frame (None for first frame)
|
|
221
|
+
blur_amount: Amount of blur (0.0-1.0)
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
Frame with motion blur applied
|
|
225
|
+
"""
|
|
226
|
+
if prev_frame is None:
|
|
227
|
+
return frame
|
|
228
|
+
|
|
229
|
+
# Blend current frame with previous frame
|
|
230
|
+
frame_array = np.array(frame, dtype=np.float32)
|
|
231
|
+
prev_array = np.array(prev_frame, dtype=np.float32)
|
|
232
|
+
|
|
233
|
+
blended = frame_array * (1 - blur_amount) + prev_array * blur_amount
|
|
234
|
+
blended = np.clip(blended, 0, 255).astype(np.uint8)
|
|
235
|
+
|
|
236
|
+
return Image.fromarray(blended)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def create_impact_flash(frame: Image.Image, position: tuple[int, int],
|
|
240
|
+
radius: int = 100, intensity: float = 0.7) -> Image.Image:
|
|
241
|
+
"""
|
|
242
|
+
Create a bright flash effect at impact point.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
frame: PIL Image to draw on
|
|
246
|
+
position: Center of flash
|
|
247
|
+
radius: Flash radius
|
|
248
|
+
intensity: Flash intensity (0.0-1.0)
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
Modified frame
|
|
252
|
+
"""
|
|
253
|
+
# Create overlay
|
|
254
|
+
overlay = Image.new('RGBA', frame.size, (0, 0, 0, 0))
|
|
255
|
+
draw = ImageDraw.Draw(overlay)
|
|
256
|
+
|
|
257
|
+
x, y = position
|
|
258
|
+
|
|
259
|
+
# Draw concentric circles with decreasing opacity
|
|
260
|
+
num_circles = 5
|
|
261
|
+
for i in range(num_circles):
|
|
262
|
+
alpha = int(255 * intensity * (1 - i / num_circles))
|
|
263
|
+
r = radius * (1 - i / num_circles)
|
|
264
|
+
color = (255, 255, 240, alpha) # Warm white
|
|
265
|
+
|
|
266
|
+
bbox = [x - r, y - r, x + r, y + r]
|
|
267
|
+
draw.ellipse(bbox, fill=color)
|
|
268
|
+
|
|
269
|
+
# Composite onto frame
|
|
270
|
+
frame_rgba = frame.convert('RGBA')
|
|
271
|
+
frame_rgba = Image.alpha_composite(frame_rgba, overlay)
|
|
272
|
+
return frame_rgba.convert('RGB')
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def create_shockwave_rings(frame: Image.Image, position: tuple[int, int],
|
|
276
|
+
radii: list[int], color: tuple[int, int, int] = (255, 200, 0),
|
|
277
|
+
width: int = 3) -> Image.Image:
|
|
278
|
+
"""
|
|
279
|
+
Create expanding ring effects.
|
|
280
|
+
|
|
281
|
+
Args:
|
|
282
|
+
frame: PIL Image to draw on
|
|
283
|
+
position: Center of rings
|
|
284
|
+
radii: List of ring radii
|
|
285
|
+
color: Ring color
|
|
286
|
+
width: Ring width
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
Modified frame
|
|
290
|
+
"""
|
|
291
|
+
draw = ImageDraw.Draw(frame)
|
|
292
|
+
x, y = position
|
|
293
|
+
|
|
294
|
+
for radius in radii:
|
|
295
|
+
bbox = [x - radius, y - radius, x + radius, y + radius]
|
|
296
|
+
draw.ellipse(bbox, outline=color, width=width)
|
|
297
|
+
|
|
298
|
+
return frame
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def create_explosion_effect(frame: Image.Image, position: tuple[int, int],
|
|
302
|
+
radius: int, progress: float,
|
|
303
|
+
color: tuple[int, int, int] = (255, 150, 0)) -> Image.Image:
|
|
304
|
+
"""
|
|
305
|
+
Create an explosion effect that expands and fades.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
frame: PIL Image to draw on
|
|
309
|
+
position: Explosion center
|
|
310
|
+
radius: Maximum radius
|
|
311
|
+
progress: Animation progress (0.0-1.0)
|
|
312
|
+
color: Explosion color
|
|
313
|
+
|
|
314
|
+
Returns:
|
|
315
|
+
Modified frame
|
|
316
|
+
"""
|
|
317
|
+
current_radius = int(radius * progress)
|
|
318
|
+
fade = 1 - progress
|
|
319
|
+
|
|
320
|
+
# Create overlay
|
|
321
|
+
overlay = Image.new('RGBA', frame.size, (0, 0, 0, 0))
|
|
322
|
+
draw = ImageDraw.Draw(overlay)
|
|
323
|
+
|
|
324
|
+
x, y = position
|
|
325
|
+
|
|
326
|
+
# Draw expanding circle with fade
|
|
327
|
+
alpha = int(255 * fade)
|
|
328
|
+
r, g, b = color
|
|
329
|
+
circle_color = (r, g, b, alpha)
|
|
330
|
+
|
|
331
|
+
bbox = [x - current_radius, y - current_radius, x + current_radius, y + current_radius]
|
|
332
|
+
draw.ellipse(bbox, fill=circle_color)
|
|
333
|
+
|
|
334
|
+
# Composite
|
|
335
|
+
frame_rgba = frame.convert('RGBA')
|
|
336
|
+
frame_rgba = Image.alpha_composite(frame_rgba, overlay)
|
|
337
|
+
return frame_rgba.convert('RGB')
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def add_glow_effect(frame: Image.Image, mask_color: tuple[int, int, int],
|
|
341
|
+
glow_color: tuple[int, int, int],
|
|
342
|
+
blur_radius: int = 10) -> Image.Image:
|
|
343
|
+
"""
|
|
344
|
+
Add a glow effect to areas of a specific color.
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
frame: PIL Image
|
|
348
|
+
mask_color: Color to create glow around
|
|
349
|
+
glow_color: Color of glow
|
|
350
|
+
blur_radius: Blur amount
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
Frame with glow
|
|
354
|
+
"""
|
|
355
|
+
# Create mask of target color
|
|
356
|
+
frame_array = np.array(frame)
|
|
357
|
+
mask = np.all(frame_array == mask_color, axis=-1)
|
|
358
|
+
|
|
359
|
+
# Create glow layer
|
|
360
|
+
glow = Image.new('RGB', frame.size, (0, 0, 0))
|
|
361
|
+
glow_array = np.array(glow)
|
|
362
|
+
glow_array[mask] = glow_color
|
|
363
|
+
glow = Image.fromarray(glow_array)
|
|
364
|
+
|
|
365
|
+
# Blur the glow
|
|
366
|
+
glow = glow.filter(ImageFilter.GaussianBlur(blur_radius))
|
|
367
|
+
|
|
368
|
+
# Blend with original
|
|
369
|
+
blended = Image.blend(frame, glow, 0.5)
|
|
370
|
+
return blended
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
def add_drop_shadow(frame: Image.Image, object_bounds: tuple[int, int, int, int],
|
|
374
|
+
shadow_offset: tuple[int, int] = (5, 5),
|
|
375
|
+
shadow_color: tuple[int, int, int] = (0, 0, 0),
|
|
376
|
+
blur: int = 5) -> Image.Image:
|
|
377
|
+
"""
|
|
378
|
+
Add drop shadow to an object.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
frame: PIL Image
|
|
382
|
+
object_bounds: (x1, y1, x2, y2) bounds of object
|
|
383
|
+
shadow_offset: (x, y) offset of shadow
|
|
384
|
+
shadow_color: Shadow color
|
|
385
|
+
blur: Shadow blur amount
|
|
386
|
+
|
|
387
|
+
Returns:
|
|
388
|
+
Frame with shadow
|
|
389
|
+
"""
|
|
390
|
+
# Extract object
|
|
391
|
+
x1, y1, x2, y2 = object_bounds
|
|
392
|
+
obj = frame.crop((x1, y1, x2, y2))
|
|
393
|
+
|
|
394
|
+
# Create shadow
|
|
395
|
+
shadow = Image.new('RGBA', obj.size, (*shadow_color, 180))
|
|
396
|
+
|
|
397
|
+
# Create frame with alpha
|
|
398
|
+
frame_rgba = frame.convert('RGBA')
|
|
399
|
+
|
|
400
|
+
# Paste shadow
|
|
401
|
+
shadow_pos = (x1 + shadow_offset[0], y1 + shadow_offset[1])
|
|
402
|
+
frame_rgba.paste(shadow, shadow_pos, shadow)
|
|
403
|
+
|
|
404
|
+
# Paste object on top
|
|
405
|
+
frame_rgba.paste(obj, (x1, y1))
|
|
406
|
+
|
|
407
|
+
return frame_rgba.convert('RGB')
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def create_speed_lines(frame: Image.Image, position: tuple[int, int],
|
|
411
|
+
direction: float, length: int = 50,
|
|
412
|
+
count: int = 5, color: tuple[int, int, int] = (200, 200, 200)) -> Image.Image:
|
|
413
|
+
"""
|
|
414
|
+
Create speed lines for motion effect.
|
|
415
|
+
|
|
416
|
+
Args:
|
|
417
|
+
frame: PIL Image to draw on
|
|
418
|
+
position: Center position
|
|
419
|
+
direction: Angle in radians (0 = right, pi/2 = down)
|
|
420
|
+
length: Line length
|
|
421
|
+
count: Number of lines
|
|
422
|
+
color: Line color
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
Modified frame
|
|
426
|
+
"""
|
|
427
|
+
draw = ImageDraw.Draw(frame)
|
|
428
|
+
x, y = position
|
|
429
|
+
|
|
430
|
+
# Opposite direction (lines trail behind)
|
|
431
|
+
trail_angle = direction + math.pi
|
|
432
|
+
|
|
433
|
+
for i in range(count):
|
|
434
|
+
# Offset from center
|
|
435
|
+
offset_angle = trail_angle + random.uniform(-0.3, 0.3)
|
|
436
|
+
offset_dist = random.uniform(10, 30)
|
|
437
|
+
start_x = x + math.cos(offset_angle) * offset_dist
|
|
438
|
+
start_y = y + math.sin(offset_angle) * offset_dist
|
|
439
|
+
|
|
440
|
+
# End point
|
|
441
|
+
line_length = random.uniform(length * 0.7, length * 1.3)
|
|
442
|
+
end_x = start_x + math.cos(trail_angle) * line_length
|
|
443
|
+
end_y = start_y + math.sin(trail_angle) * line_length
|
|
444
|
+
|
|
445
|
+
# Draw line with varying opacity
|
|
446
|
+
alpha = random.randint(100, 200)
|
|
447
|
+
width = random.randint(1, 3)
|
|
448
|
+
|
|
449
|
+
# Simple line (full opacity simulation)
|
|
450
|
+
draw.line([(start_x, start_y), (end_x, end_y)], fill=color, width=width)
|
|
451
|
+
|
|
452
|
+
return frame
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def create_screen_shake_offset(intensity: int, frame_index: int) -> tuple[int, int]:
|
|
456
|
+
"""
|
|
457
|
+
Calculate screen shake offset for a frame.
|
|
458
|
+
|
|
459
|
+
Args:
|
|
460
|
+
intensity: Shake intensity in pixels
|
|
461
|
+
frame_index: Current frame number
|
|
462
|
+
|
|
463
|
+
Returns:
|
|
464
|
+
(x, y) offset tuple
|
|
465
|
+
"""
|
|
466
|
+
# Use frame index for deterministic but random-looking shake
|
|
467
|
+
random.seed(frame_index)
|
|
468
|
+
offset_x = random.randint(-intensity, intensity)
|
|
469
|
+
offset_y = random.randint(-intensity, intensity)
|
|
470
|
+
random.seed() # Reset seed
|
|
471
|
+
return (offset_x, offset_y)
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def apply_screen_shake(frame: Image.Image, intensity: int, frame_index: int) -> Image.Image:
|
|
475
|
+
"""
|
|
476
|
+
Apply screen shake effect to entire frame.
|
|
477
|
+
|
|
478
|
+
Args:
|
|
479
|
+
frame: PIL Image
|
|
480
|
+
intensity: Shake intensity
|
|
481
|
+
frame_index: Current frame number
|
|
482
|
+
|
|
483
|
+
Returns:
|
|
484
|
+
Shaken frame
|
|
485
|
+
"""
|
|
486
|
+
offset_x, offset_y = create_screen_shake_offset(intensity, frame_index)
|
|
487
|
+
|
|
488
|
+
# Create new frame with background
|
|
489
|
+
shaken = Image.new('RGB', frame.size, (0, 0, 0))
|
|
490
|
+
|
|
491
|
+
# Paste original frame with offset
|
|
492
|
+
shaken.paste(frame, (offset_x, offset_y))
|
|
493
|
+
|
|
494
|
+
return shaken
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Bounce Animation Template - Creates bouncing motion for objects.
|
|
4
|
+
|
|
5
|
+
Use this to make objects bounce up and down or horizontally with realistic physics.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
# Add parent directory to path
|
|
12
|
+
sys.path.append(str(Path(__file__).parent.parent))
|
|
13
|
+
|
|
14
|
+
from core.gif_builder import GIFBuilder
|
|
15
|
+
from core.frame_composer import create_blank_frame, draw_circle, draw_emoji
|
|
16
|
+
from core.easing import ease_out_bounce, interpolate
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def create_bounce_animation(
|
|
20
|
+
object_type: str = 'circle',
|
|
21
|
+
object_data: dict = None,
|
|
22
|
+
num_frames: int = 30,
|
|
23
|
+
bounce_height: int = 150,
|
|
24
|
+
ground_y: int = 350,
|
|
25
|
+
start_x: int = 240,
|
|
26
|
+
frame_width: int = 480,
|
|
27
|
+
frame_height: int = 480,
|
|
28
|
+
bg_color: tuple[int, int, int] = (255, 255, 255)
|
|
29
|
+
) -> list:
|
|
30
|
+
"""
|
|
31
|
+
Create frames for a bouncing animation.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
object_type: 'circle', 'emoji', or 'custom'
|
|
35
|
+
object_data: Data for the object (e.g., {'radius': 30, 'color': (255, 0, 0)})
|
|
36
|
+
num_frames: Number of frames in the animation
|
|
37
|
+
bounce_height: Maximum height of bounce
|
|
38
|
+
ground_y: Y position of ground
|
|
39
|
+
start_x: X position (or starting X if moving horizontally)
|
|
40
|
+
frame_width: Frame width
|
|
41
|
+
frame_height: Frame height
|
|
42
|
+
bg_color: Background color
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
List of frames
|
|
46
|
+
"""
|
|
47
|
+
frames = []
|
|
48
|
+
|
|
49
|
+
# Default object data
|
|
50
|
+
if object_data is None:
|
|
51
|
+
if object_type == 'circle':
|
|
52
|
+
object_data = {'radius': 30, 'color': (255, 100, 100)}
|
|
53
|
+
elif object_type == 'emoji':
|
|
54
|
+
object_data = {'emoji': '⚽', 'size': 60}
|
|
55
|
+
|
|
56
|
+
for i in range(num_frames):
|
|
57
|
+
# Create blank frame
|
|
58
|
+
frame = create_blank_frame(frame_width, frame_height, bg_color)
|
|
59
|
+
|
|
60
|
+
# Calculate progress (0.0 to 1.0)
|
|
61
|
+
t = i / (num_frames - 1) if num_frames > 1 else 0
|
|
62
|
+
|
|
63
|
+
# Calculate Y position using bounce easing
|
|
64
|
+
y = ground_y - int(ease_out_bounce(t) * bounce_height)
|
|
65
|
+
|
|
66
|
+
# Draw object
|
|
67
|
+
if object_type == 'circle':
|
|
68
|
+
draw_circle(
|
|
69
|
+
frame,
|
|
70
|
+
center=(start_x, y),
|
|
71
|
+
radius=object_data['radius'],
|
|
72
|
+
fill_color=object_data['color']
|
|
73
|
+
)
|
|
74
|
+
elif object_type == 'emoji':
|
|
75
|
+
draw_emoji(
|
|
76
|
+
frame,
|
|
77
|
+
emoji=object_data['emoji'],
|
|
78
|
+
position=(start_x - object_data['size'] // 2, y - object_data['size'] // 2),
|
|
79
|
+
size=object_data['size']
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
frames.append(frame)
|
|
83
|
+
|
|
84
|
+
return frames
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# Example usage
|
|
88
|
+
if __name__ == '__main__':
|
|
89
|
+
print("Creating bouncing ball GIF...")
|
|
90
|
+
|
|
91
|
+
# Create GIF builder
|
|
92
|
+
builder = GIFBuilder(width=480, height=480, fps=20)
|
|
93
|
+
|
|
94
|
+
# Generate bounce animation
|
|
95
|
+
frames = create_bounce_animation(
|
|
96
|
+
object_type='circle',
|
|
97
|
+
object_data={'radius': 40, 'color': (255, 100, 100)},
|
|
98
|
+
num_frames=40,
|
|
99
|
+
bounce_height=200
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Add frames to builder
|
|
103
|
+
builder.add_frames(frames)
|
|
104
|
+
|
|
105
|
+
# Save GIF
|
|
106
|
+
builder.save('bounce_test.gif', num_colors=64)
|