@rosetears/aili-pi 0.1.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/LICENSE +21 -0
- package/README.md +109 -0
- package/THIRD_PARTY_NOTICES.md +64 -0
- package/extensions/index.ts +6 -0
- package/install.sh +5 -0
- package/manifests/adapter-evidence.json +45 -0
- package/manifests/capabilities.json +124 -0
- package/manifests/live-verification.json +26 -0
- package/manifests/provenance.json +71 -0
- package/manifests/roles.json +474 -0
- package/manifests/sbom.json +7797 -0
- package/manifests/skill-compatibility.json +8100 -0
- package/manifests/subagent-provenance.json +37 -0
- package/package.json +91 -0
- package/prompts/build.md +8 -0
- package/prompts/define.md +8 -0
- package/prompts/ideate.md +8 -0
- package/prompts/local-review.md +8 -0
- package/prompts/ship.md +8 -0
- package/roles/agent-evaluator.md +47 -0
- package/roles/ai-regression-scout.md +47 -0
- package/roles/browser-qa-runner.md +47 -0
- package/roles/code-reviewer.md +47 -0
- package/roles/code-scout.md +47 -0
- package/roles/convergence-reviewer.md +55 -0
- package/roles/doc-researcher.md +47 -0
- package/roles/e2e-artifact-runner.md +47 -0
- package/roles/implementer.md +47 -0
- package/roles/opensource-sanitizer.md +47 -0
- package/roles/plan-auditor.md +47 -0
- package/roles/pr-test-analyzer.md +47 -0
- package/roles/security-auditor.md +47 -0
- package/roles/silent-failure-reviewer.md +47 -0
- package/roles/spec-miner.md +47 -0
- package/roles/test-coverage-reviewer.md +47 -0
- package/roles/test-engineer.md +48 -0
- package/roles/web-performance-auditor.md +47 -0
- package/roles/web-researcher.md +47 -0
- package/scripts/apply-adapter-evidence.ts +73 -0
- package/scripts/bootstrap.sh +180 -0
- package/scripts/generate-provenance.ts +143 -0
- package/scripts/local-package-e2e.ts +51 -0
- package/scripts/sync-roles.ts +213 -0
- package/scripts/sync-skills.ts +356 -0
- package/scripts/validate-runtime.ts +11 -0
- package/skills/academic-paper-review/SKILL.md +81 -0
- package/skills/agents-md-initialization/SKILL.md +121 -0
- package/skills/agents-md-initialization/references/agents-template.md +83 -0
- package/skills/agents-md-initialization/references/agents_md.py +215 -0
- package/skills/ai-regression-scout/SKILL.md +24 -0
- package/skills/aili-delivery-flow/SKILL.md +125 -0
- package/skills/aili-delivery-flow/references/artifact-contracts.md +138 -0
- package/skills/aili-delivery-flow/references/backend-routing.md +40 -0
- package/skills/aili-delivery-flow/references/build-execution-loop.md +113 -0
- package/skills/aili-delivery-flow/references/build-goal-mode.md +3 -0
- package/skills/aili-delivery-flow/references/direct-vs-delegated-work.md +38 -0
- package/skills/aili-delivery-flow/references/implementation-packages.md +54 -0
- package/skills/aili-delivery-flow/references/lifecycle.md +127 -0
- package/skills/aili-delivery-flow/references/protocols/acceptance-test-plan.md +18 -0
- package/skills/aili-delivery-flow/references/protocols/alignment-questionnaire.md +10 -0
- package/skills/aili-delivery-flow/references/protocols/closeout-report.md +101 -0
- package/skills/aili-delivery-flow/references/protocols/compact-evidence-pack.md +46 -0
- package/skills/aili-delivery-flow/references/protocols/idea-brief.md +10 -0
- package/skills/aili-delivery-flow/references/protocols/implementation-package.md +53 -0
- package/skills/aili-delivery-flow/references/protocols/research-evidence-pack.md +19 -0
- package/skills/aili-delivery-flow/references/protocols/review-report.md +7 -0
- package/skills/aili-delivery-flow/references/protocols/spec-draft.md +12 -0
- package/skills/aili-delivery-flow/references/protocols/subagent-result.md +60 -0
- package/skills/aili-delivery-flow/references/protocols/subagent-task-packet.md +29 -0
- package/skills/aili-delivery-flow/references/protocols/worktree-context.md +109 -0
- package/skills/aili-delivery-flow/references/questionnaire-policy.md +62 -0
- package/skills/aili-delivery-flow/references/review-repair-loop.md +16 -0
- package/skills/aili-delivery-flow/references/test-document-policy.md +35 -0
- package/skills/android-native-dev/SKILL.md +722 -0
- package/skills/android-native-dev/references/accessibility.md +209 -0
- package/skills/android-native-dev/references/adaptive-screens.md +231 -0
- package/skills/android-native-dev/references/design-style-guide.md +365 -0
- package/skills/android-native-dev/references/functional-requirements.md +229 -0
- package/skills/android-native-dev/references/motion-system.md +203 -0
- package/skills/android-native-dev/references/performance-stability.md +223 -0
- package/skills/android-native-dev/references/privacy-security.md +244 -0
- package/skills/android-native-dev/references/testing.md +554 -0
- package/skills/android-native-dev/references/visual-design.md +246 -0
- package/skills/api-and-interface-design/SKILL.md +318 -0
- package/skills/browser-qa/SKILL.md +32 -0
- package/skills/browser-testing-with-devtools/SKILL.md +323 -0
- package/skills/build-failure-repair/SKILL.md +49 -0
- package/skills/chart-visualization/SKILL.md +73 -0
- package/skills/ci-cd-and-automation/SKILL.md +353 -0
- package/skills/code-review-and-quality/SKILL.md +375 -0
- package/skills/code-review-quality-gates/SKILL.md +132 -0
- package/skills/code-simplification/SKILL.md +371 -0
- package/skills/comment-accuracy-review/SKILL.md +37 -0
- package/skills/consulting-analysis/SKILL.md +69 -0
- package/skills/context-engineering/SKILL.md +375 -0
- package/skills/coverage-review/SKILL.md +24 -0
- package/skills/data-analysis/SKILL.md +74 -0
- package/skills/deprecation-and-migration/SKILL.md +222 -0
- package/skills/documentation-and-adrs/SKILL.md +330 -0
- package/skills/e2e-artifact-handling/SKILL.md +30 -0
- package/skills/evidence-scoped-retrospective/SKILL.md +156 -0
- package/skills/explain-by-allegory/SKILL.md +99 -0
- package/skills/flutter-dev/SKILL.md +162 -0
- package/skills/flutter-dev/references/animations.md +497 -0
- package/skills/flutter-dev/references/bloc-state.md +281 -0
- package/skills/flutter-dev/references/forms.md +656 -0
- package/skills/flutter-dev/references/gorouter-navigation.md +257 -0
- package/skills/flutter-dev/references/localization.md +510 -0
- package/skills/flutter-dev/references/networking.md +566 -0
- package/skills/flutter-dev/references/performance.md +305 -0
- package/skills/flutter-dev/references/platform-specific.md +417 -0
- package/skills/flutter-dev/references/project-structure.md +273 -0
- package/skills/flutter-dev/references/riverpod-state.md +232 -0
- package/skills/flutter-dev/references/testing.md +364 -0
- package/skills/flutter-dev/references/widget-patterns.md +233 -0
- package/skills/frontend-dev/SKILL.md +468 -0
- package/skills/frontend-dev/canvas-fonts/ArsenalSC-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/BigShoulders-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Boldonse-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/CrimsonPro-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/DMMono-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/EricaOne-OFL.txt +94 -0
- package/skills/frontend-dev/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/GeistMono-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Gloock-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/InstrumentSans-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Italiana-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Jura-Light.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Jura-Medium.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Jura-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Lora-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Lora-Italic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Lora-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Lora-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/NationalPark-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Outfit-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/PixelifySans-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/PoiretOne-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/RedHatMono-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Silkscreen-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/SmoochSans-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/Tektur-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/WorkSans-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/skills/frontend-dev/canvas-fonts/YoungSerif-OFL.txt +93 -0
- package/skills/frontend-dev/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- package/skills/frontend-dev/references/asset-prompt-guide.md +43 -0
- package/skills/frontend-dev/references/env-setup.md +33 -0
- package/skills/frontend-dev/references/minimax-cli-reference.md +133 -0
- package/skills/frontend-dev/references/minimax-image-guide.md +65 -0
- package/skills/frontend-dev/references/minimax-music-guide.md +216 -0
- package/skills/frontend-dev/references/minimax-tts-guide.md +78 -0
- package/skills/frontend-dev/references/minimax-video-guide.md +82 -0
- package/skills/frontend-dev/references/minimax-voice-catalog.md +685 -0
- package/skills/frontend-dev/references/motion-recipes.md +407 -0
- package/skills/frontend-dev/references/troubleshooting.md +85 -0
- package/skills/frontend-dev/scripts/minimax_image.py +137 -0
- package/skills/frontend-dev/scripts/minimax_music.py +157 -0
- package/skills/frontend-dev/scripts/minimax_tts.py +127 -0
- package/skills/frontend-dev/scripts/minimax_video.py +187 -0
- package/skills/frontend-dev/templates/generator_template.js +223 -0
- package/skills/frontend-dev/templates/viewer.html +599 -0
- package/skills/frontend-ui-engineering/SKILL.md +367 -0
- package/skills/fullstack-dev/SKILL.md +819 -0
- package/skills/fullstack-dev/references/api-design.md +444 -0
- package/skills/fullstack-dev/references/auth-flow.md +165 -0
- package/skills/fullstack-dev/references/db-schema.md +706 -0
- package/skills/fullstack-dev/references/django-best-practices.md +466 -0
- package/skills/fullstack-dev/references/environment-management.md +78 -0
- package/skills/fullstack-dev/references/release-checklist.md +278 -0
- package/skills/fullstack-dev/references/technology-selection.md +254 -0
- package/skills/fullstack-dev/references/testing-strategy.md +404 -0
- package/skills/git-workflow-and-versioning/SKILL.md +446 -0
- package/skills/github-evidence-triage/SKILL.md +115 -0
- package/skills/harness-evolution/SKILL.md +59 -0
- package/skills/harness-evolution/references/activation-matrix.md +13 -0
- package/skills/harness-evolution/references/approval-policy.md +20 -0
- package/skills/harness-evolution/references/change-report-template.md +33 -0
- package/skills/harness-evolution/references/component-taxonomy.md +19 -0
- package/skills/harness-evolution/references/verdict-policy.md +13 -0
- package/skills/harness-issue-triage/SKILL.md +72 -0
- package/skills/harness-issue-triage/references/component-diagnosis.md +25 -0
- package/skills/harness-issue-triage/references/triage-report-template.md +34 -0
- package/skills/harness-optimization-audit/SKILL.md +125 -0
- package/skills/idea-refine/SKILL.md +191 -0
- package/skills/idea-refine/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/LICENSE +21 -0
- package/skills/idea-refine/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/NOTICE.md +9 -0
- package/skills/idea-refine/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/idea-refine/SKILL.upstream.md +178 -0
- package/skills/idea-refine/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/idea-refine/examples.md +238 -0
- package/skills/idea-refine/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/idea-refine/frameworks.md +99 -0
- package/skills/idea-refine/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/idea-refine/refinement-criteria.md +113 -0
- package/skills/idea-refine/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/idea-refine/scripts/idea-refine.upstream.sh +15 -0
- package/skills/incremental-implementation/SKILL.md +252 -0
- package/skills/ios-application-dev/SKILL.md +212 -0
- package/skills/ios-application-dev/references/accessibility.md +259 -0
- package/skills/ios-application-dev/references/graphics-animation.md +350 -0
- package/skills/ios-application-dev/references/layout-system.md +199 -0
- package/skills/ios-application-dev/references/metal-shader.md +178 -0
- package/skills/ios-application-dev/references/navigation-patterns.md +175 -0
- package/skills/ios-application-dev/references/swift-coding-standards.md +757 -0
- package/skills/ios-application-dev/references/swiftui-design-guidelines.md +1167 -0
- package/skills/ios-application-dev/references/system-integration.md +401 -0
- package/skills/ios-application-dev/references/uikit-components.md +297 -0
- package/skills/local-review-gate/SKILL.md +207 -0
- package/skills/local-review-gate/references/addyosmani-code-review-rubric.md +33 -0
- package/skills/local-review-gate/references/codex-github-compatibility.md +26 -0
- package/skills/local-review-gate/references/ecc-code-review-adaptation.md +40 -0
- package/skills/local-review-gate/references/graphify-local-review.md +33 -0
- package/skills/local-review-gate/references/orchestration-adaptation.md +51 -0
- package/skills/local-review-gate/references/review-repair-lane-adaptation.md +46 -0
- package/skills/local-review-gate/references/upstream-provenance.md +61 -0
- package/skills/mature-project-pattern-research/SKILL.md +155 -0
- package/skills/mature-project-pattern-research/references/research-rubric.md +45 -0
- package/skills/minimax-docx/LICENSE +21 -0
- package/skills/minimax-docx/SKILL.md +273 -0
- package/skills/minimax-docx/assets/styles/academic_styles.xml +250 -0
- package/skills/minimax-docx/assets/styles/corporate_styles.xml +284 -0
- package/skills/minimax-docx/assets/styles/default_styles.xml +449 -0
- package/skills/minimax-docx/assets/xsd/aesthetic-rules.xsd +470 -0
- package/skills/minimax-docx/assets/xsd/business-rules.xsd +130 -0
- package/skills/minimax-docx/assets/xsd/common-types.xsd +159 -0
- package/skills/minimax-docx/assets/xsd/wml-subset.xsd +589 -0
- package/skills/minimax-docx/references/cjk_typography.md +357 -0
- package/skills/minimax-docx/references/cjk_university_template_guide.md +184 -0
- package/skills/minimax-docx/references/comments_guide.md +191 -0
- package/skills/minimax-docx/references/design_good_bad_examples.md +829 -0
- package/skills/minimax-docx/references/design_principles.md +819 -0
- package/skills/minimax-docx/references/openxml_element_order.md +308 -0
- package/skills/minimax-docx/references/openxml_encyclopedia_part1.md +4061 -0
- package/skills/minimax-docx/references/openxml_encyclopedia_part2.md +2820 -0
- package/skills/minimax-docx/references/openxml_encyclopedia_part3.md +3381 -0
- package/skills/minimax-docx/references/openxml_namespaces.md +82 -0
- package/skills/minimax-docx/references/openxml_units.md +72 -0
- package/skills/minimax-docx/references/scenario_a_create.md +284 -0
- package/skills/minimax-docx/references/scenario_b_edit_content.md +295 -0
- package/skills/minimax-docx/references/scenario_c_apply_template.md +456 -0
- package/skills/minimax-docx/references/track_changes_guide.md +200 -0
- package/skills/minimax-docx/references/troubleshooting.md +506 -0
- package/skills/minimax-docx/references/typography_guide.md +294 -0
- package/skills/minimax-docx/references/xsd_validation_guide.md +158 -0
- package/skills/minimax-docx/scripts/doc_to_docx.sh +40 -0
- package/skills/minimax-docx/scripts/docx_preview.sh +37 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Cli/MiniMaxAIDocx.Cli.csproj +19 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Cli/Program.cs +18 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/AnalyzeCommand.cs +147 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/ApplyTemplateCommand.cs +322 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/CreateCommand.cs +324 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/DiffCommand.cs +155 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/EditContentCommand.cs +487 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/FixOrderCommand.cs +108 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/MergeRunsCommand.cs +122 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/ValidateCommand.cs +107 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/MiniMaxAIDocx.Core.csproj +15 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/CommentSynchronizer.cs +169 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/ElementOrder.cs +80 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/NamespaceConstants.cs +42 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/RunMerger.cs +81 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/StyleAnalyzer.cs +81 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/TrackChangesHelper.cs +99 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/UnitConverter.cs +23 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples.cs +1832 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch1.cs +910 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch2.cs +999 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch3.cs +1048 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch4.cs +1038 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/CharacterFormattingSamples.cs +1020 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/DocumentCreationSamples.cs +1121 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/FieldAndTocSamples.cs +624 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/FootnoteAndCommentSamples.cs +675 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/HeaderFooterSamples.cs +838 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ImageSamples.cs +917 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ListAndNumberingSamples.cs +826 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ParagraphFormattingSamples.cs +1199 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/StyleSystemSamples.cs +1487 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/TableSamples.cs +1163 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/TrackChangesSamples.cs +595 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/CjkHelper.cs +39 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/FontDefaults.cs +24 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/PageSizes.cs +20 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/BusinessRuleValidator.cs +224 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/GateCheckValidator.cs +148 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/ValidationResult.cs +23 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/XsdValidator.cs +69 -0
- package/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.slnx +4 -0
- package/skills/minimax-docx/scripts/env_check.sh +196 -0
- package/skills/minimax-docx/scripts/setup.ps1 +274 -0
- package/skills/minimax-docx/scripts/setup.sh +504 -0
- package/skills/minimax-pdf/README.md +222 -0
- package/skills/minimax-pdf/SKILL.md +218 -0
- package/skills/minimax-pdf/design/design.md +381 -0
- package/skills/minimax-pdf/scripts/cover.py +1579 -0
- package/skills/minimax-pdf/scripts/fill_inspect.py +200 -0
- package/skills/minimax-pdf/scripts/fill_write.py +242 -0
- package/skills/minimax-pdf/scripts/make.sh +491 -0
- package/skills/minimax-pdf/scripts/merge.py +112 -0
- package/skills/minimax-pdf/scripts/palette.py +521 -0
- package/skills/minimax-pdf/scripts/reformat_parse.py +374 -0
- package/skills/minimax-pdf/scripts/render_body.py +1052 -0
- package/skills/minimax-pdf/scripts/render_cover.js +111 -0
- package/skills/minimax-xlsx/SKILL.md +156 -0
- package/skills/minimax-xlsx/references/create.md +691 -0
- package/skills/minimax-xlsx/references/edit.md +684 -0
- package/skills/minimax-xlsx/references/fix.md +37 -0
- package/skills/minimax-xlsx/references/format.md +768 -0
- package/skills/minimax-xlsx/references/ooxml-cheatsheet.md +231 -0
- package/skills/minimax-xlsx/references/read-analyze.md +97 -0
- package/skills/minimax-xlsx/references/validate.md +772 -0
- package/skills/minimax-xlsx/scripts/formula_check.py +422 -0
- package/skills/minimax-xlsx/scripts/libreoffice_recalc.py +248 -0
- package/skills/minimax-xlsx/scripts/shared_strings_builder.py +163 -0
- package/skills/minimax-xlsx/scripts/style_audit.py +575 -0
- package/skills/minimax-xlsx/scripts/xlsx_add_column.py +395 -0
- package/skills/minimax-xlsx/scripts/xlsx_insert_row.py +274 -0
- package/skills/minimax-xlsx/scripts/xlsx_pack.py +87 -0
- package/skills/minimax-xlsx/scripts/xlsx_reader.py +362 -0
- package/skills/minimax-xlsx/scripts/xlsx_shift_rows.py +396 -0
- package/skills/minimax-xlsx/scripts/xlsx_unpack.py +130 -0
- package/skills/minimax-xlsx/templates/minimal_xlsx/[Content_Types].xml +9 -0
- package/skills/minimax-xlsx/templates/minimal_xlsx/_rels/.rels +6 -0
- package/skills/minimax-xlsx/templates/minimal_xlsx/xl/_rels/workbook.xml.rels +19 -0
- package/skills/minimax-xlsx/templates/minimal_xlsx/xl/sharedStrings.xml +33 -0
- package/skills/minimax-xlsx/templates/minimal_xlsx/xl/styles.xml +160 -0
- package/skills/minimax-xlsx/templates/minimal_xlsx/xl/workbook.xml +30 -0
- package/skills/minimax-xlsx/templates/minimal_xlsx/xl/worksheets/sheet1.xml +70 -0
- package/skills/newsletter-generation/SKILL.md +71 -0
- package/skills/oss-release-readiness/SKILL.md +47 -0
- package/skills/parallel-subagent-dispatch/SKILL.md +58 -0
- package/skills/performance-optimization/SKILL.md +364 -0
- package/skills/planning-and-task-breakdown/SKILL.md +290 -0
- package/skills/pptx-generator/SKILL.md +275 -0
- package/skills/pptx-generator/references/design-system.md +392 -0
- package/skills/pptx-generator/references/editing.md +162 -0
- package/skills/pptx-generator/references/pitfalls.md +112 -0
- package/skills/pptx-generator/references/pptxgenjs.md +420 -0
- package/skills/pptx-generator/references/slide-types.md +413 -0
- package/skills/pr-test-analysis/SKILL.md +24 -0
- package/skills/react-native-dev/SKILL.md +180 -0
- package/skills/react-native-dev/references/animations.md +254 -0
- package/skills/react-native-dev/references/components.md +124 -0
- package/skills/react-native-dev/references/engineering.md +527 -0
- package/skills/react-native-dev/references/forms.md +300 -0
- package/skills/react-native-dev/references/native-capabilities.md +163 -0
- package/skills/react-native-dev/references/navigation.md +271 -0
- package/skills/react-native-dev/references/networking.md +346 -0
- package/skills/react-native-dev/references/performance.md +215 -0
- package/skills/react-native-dev/references/state-management.md +230 -0
- package/skills/react-native-dev/references/styling.md +117 -0
- package/skills/react-native-dev/references/testing.md +341 -0
- package/skills/requirements-grilling/SKILL.md +447 -0
- package/skills/requirements-grilling/references/ADR-FORMAT.md +46 -0
- package/skills/requirements-grilling/references/CONTEXT-FORMAT.md +41 -0
- package/skills/requirements-grilling/references/INTERVIEW-PACKET-FORMAT.md +62 -0
- package/skills/requirements-grilling/references/MIT-LICENSE-MATT-POCOCK.md +25 -0
- package/skills/requirements-grilling/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/LICENSE +21 -0
- package/skills/requirements-grilling/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/NOTICE.md +9 -0
- package/skills/requirements-grilling/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/interview-me/SKILL.upstream.md +225 -0
- package/skills/requirements-grilling/references/upstream/mattpocock-skills/9603c1cc8118d08bc1b3bf34cf714f62178dea3b/LICENSE +21 -0
- package/skills/requirements-grilling/references/upstream/mattpocock-skills/9603c1cc8118d08bc1b3bf34cf714f62178dea3b/NOTICE.md +12 -0
- package/skills/requirements-grilling/references/upstream/mattpocock-skills/9603c1cc8118d08bc1b3bf34cf714f62178dea3b/batch-grill-me/SKILL.upstream.md +15 -0
- package/skills/requirements-grilling/references/upstream/mattpocock-skills/9603c1cc8118d08bc1b3bf34cf714f62178dea3b/grill-me/SKILL.upstream.md +7 -0
- package/skills/requirements-grilling/references/upstream/mattpocock-skills/9603c1cc8118d08bc1b3bf34cf714f62178dea3b/grilling/SKILL.upstream.md +12 -0
- package/skills/review-pipeline/SKILL.md +38 -0
- package/skills/rose-memory/SKILL.md +210 -0
- package/skills/rose-memory/references/README.md +48 -0
- package/skills/rose-memory/references/memory_cli.py +2384 -0
- package/skills/rose-memory/references/schema.sql +315 -0
- package/skills/security-and-hardening/SKILL.md +369 -0
- package/skills/session-handoff/SKILL.md +88 -0
- package/skills/session-handoff/references/upstream/mattpocock-skills/391a2701dd948f94f56a39f7533f8eea9a859c87/LICENSE +21 -0
- package/skills/session-handoff/references/upstream/mattpocock-skills/391a2701dd948f94f56a39f7533f8eea9a859c87/NOTICE.md +9 -0
- package/skills/session-handoff/references/upstream/mattpocock-skills/391a2701dd948f94f56a39f7533f8eea9a859c87/productivity/handoff/SKILL.upstream.md +16 -0
- package/skills/session-handoff/scripts/session_handoff.py +764 -0
- package/skills/shader-dev/SKILL.md +316 -0
- package/skills/shader-dev/reference/ambient-occlusion.md +382 -0
- package/skills/shader-dev/reference/analytic-ray-tracing.md +651 -0
- package/skills/shader-dev/reference/anti-aliasing.md +71 -0
- package/skills/shader-dev/reference/atmospheric-scattering.md +571 -0
- package/skills/shader-dev/reference/camera-effects.md +80 -0
- package/skills/shader-dev/reference/cellular-automata.md +635 -0
- package/skills/shader-dev/reference/color-palette.md +481 -0
- package/skills/shader-dev/reference/csg-boolean-operations.md +466 -0
- package/skills/shader-dev/reference/domain-repetition.md +436 -0
- package/skills/shader-dev/reference/domain-warping.md +419 -0
- package/skills/shader-dev/reference/fluid-simulation.md +425 -0
- package/skills/shader-dev/reference/fractal-rendering.md +525 -0
- package/skills/shader-dev/reference/lighting-model.md +639 -0
- package/skills/shader-dev/reference/matrix-transform.md +535 -0
- package/skills/shader-dev/reference/multipass-buffer.md +571 -0
- package/skills/shader-dev/reference/normal-estimation.md +418 -0
- package/skills/shader-dev/reference/particle-system.md +589 -0
- package/skills/shader-dev/reference/path-tracing-gi.md +602 -0
- package/skills/shader-dev/reference/polar-uv-manipulation.md +521 -0
- package/skills/shader-dev/reference/post-processing.md +375 -0
- package/skills/shader-dev/reference/procedural-2d-pattern.md +439 -0
- package/skills/shader-dev/reference/procedural-noise.md +551 -0
- package/skills/shader-dev/reference/ray-marching.md +396 -0
- package/skills/shader-dev/reference/sdf-2d.md +724 -0
- package/skills/shader-dev/reference/sdf-3d.md +805 -0
- package/skills/shader-dev/reference/sdf-tricks.md +63 -0
- package/skills/shader-dev/reference/shadow-techniques.md +476 -0
- package/skills/shader-dev/reference/simulation-physics.md +644 -0
- package/skills/shader-dev/reference/sound-synthesis.md +578 -0
- package/skills/shader-dev/reference/terrain-rendering.md +839 -0
- package/skills/shader-dev/reference/texture-mapping-advanced.md +87 -0
- package/skills/shader-dev/reference/texture-sampling.md +553 -0
- package/skills/shader-dev/reference/volumetric-rendering.md +608 -0
- package/skills/shader-dev/reference/voronoi-cellular-noise.md +486 -0
- package/skills/shader-dev/reference/voxel-rendering.md +701 -0
- package/skills/shader-dev/reference/water-ocean.md +445 -0
- package/skills/shader-dev/reference/webgl-pitfalls.md +41 -0
- package/skills/shader-dev/techniques/ambient-occlusion.md +364 -0
- package/skills/shader-dev/techniques/analytic-ray-tracing.md +542 -0
- package/skills/shader-dev/techniques/anti-aliasing.md +124 -0
- package/skills/shader-dev/techniques/atmospheric-scattering.md +522 -0
- package/skills/shader-dev/techniques/camera-effects.md +115 -0
- package/skills/shader-dev/techniques/cellular-automata.md +531 -0
- package/skills/shader-dev/techniques/color-palette.md +380 -0
- package/skills/shader-dev/techniques/csg-boolean-operations.md +491 -0
- package/skills/shader-dev/techniques/domain-repetition.md +333 -0
- package/skills/shader-dev/techniques/domain-warping.md +414 -0
- package/skills/shader-dev/techniques/fluid-simulation.md +1175 -0
- package/skills/shader-dev/techniques/fractal-rendering.md +436 -0
- package/skills/shader-dev/techniques/lighting-model.md +527 -0
- package/skills/shader-dev/techniques/matrix-transform.md +455 -0
- package/skills/shader-dev/techniques/multipass-buffer.md +922 -0
- package/skills/shader-dev/techniques/normal-estimation.md +318 -0
- package/skills/shader-dev/techniques/particle-system.md +1203 -0
- package/skills/shader-dev/techniques/path-tracing-gi.md +623 -0
- package/skills/shader-dev/techniques/polar-uv-manipulation.md +373 -0
- package/skills/shader-dev/techniques/post-processing.md +788 -0
- package/skills/shader-dev/techniques/procedural-2d-pattern.md +346 -0
- package/skills/shader-dev/techniques/procedural-noise.md +554 -0
- package/skills/shader-dev/techniques/ray-marching.md +467 -0
- package/skills/shader-dev/techniques/sdf-2d.md +631 -0
- package/skills/shader-dev/techniques/sdf-3d.md +589 -0
- package/skills/shader-dev/techniques/sdf-tricks.md +100 -0
- package/skills/shader-dev/techniques/shadow-techniques.md +776 -0
- package/skills/shader-dev/techniques/simulation-physics.md +1542 -0
- package/skills/shader-dev/techniques/sound-synthesis.md +490 -0
- package/skills/shader-dev/techniques/terrain-rendering.md +408 -0
- package/skills/shader-dev/techniques/texture-mapping-advanced.md +121 -0
- package/skills/shader-dev/techniques/texture-sampling.md +382 -0
- package/skills/shader-dev/techniques/volumetric-rendering.md +375 -0
- package/skills/shader-dev/techniques/voronoi-cellular-noise.md +458 -0
- package/skills/shader-dev/techniques/voxel-rendering.md +985 -0
- package/skills/shader-dev/techniques/water-ocean.md +490 -0
- package/skills/shader-dev/techniques/webgl-pitfalls.md +170 -0
- package/skills/shipping-and-launch/SKILL.md +334 -0
- package/skills/silent-failure-hunting/SKILL.md +24 -0
- package/skills/source-driven-development/SKILL.md +223 -0
- package/skills/spec-driven-development/SKILL.md +235 -0
- package/skills/spec-driven-development/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/LICENSE +21 -0
- package/skills/spec-driven-development/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/NOTICE.md +9 -0
- package/skills/spec-driven-development/references/upstream/addyosmani-agent-skills/6bcfeb9dae52b11eaad23511acc165109746dbc3/spec-driven-development/SKILL.upstream.md +206 -0
- package/skills/strategy-stress-test/SKILL.md +185 -0
- package/skills/systematic-literature-review/SKILL.md +77 -0
- package/skills/test-document-generator/SKILL.md +152 -0
- package/skills/test-document-generator/references/test-document-template.md +45 -0
- package/skills/test-driven-development/SKILL.md +399 -0
- package/skills/write-skills/GLOSSARY.md +113 -0
- package/skills/write-skills/SKILL.md +133 -0
- package/skills/write-skills/references/upstream/mattpocock-skills/391a2701dd948f94f56a39f7533f8eea9a859c87/LICENSE +21 -0
- package/skills/write-skills/references/upstream/mattpocock-skills/391a2701dd948f94f56a39f7533f8eea9a859c87/NOTICE.md +9 -0
- package/skills/write-skills/references/upstream/mattpocock-skills/391a2701dd948f94f56a39f7533f8eea9a859c87/productivity/writing-great-skills/GLOSSARY.md +201 -0
- package/skills/write-skills/references/upstream/mattpocock-skills/391a2701dd948f94f56a39f7533f8eea9a859c87/productivity/writing-great-skills/SKILL.upstream.md +83 -0
- package/src/runtime/child-guard.ts +70 -0
- package/src/runtime/conflicts.ts +25 -0
- package/src/runtime/contracts.ts +9 -0
- package/src/runtime/doctor.ts +134 -0
- package/src/runtime/global-resources.ts +152 -0
- package/src/runtime/index.ts +23 -0
- package/src/runtime/lifecycle.ts +19 -0
- package/src/runtime/native-integrations.ts +44 -0
- package/src/runtime/path-boundaries.ts +69 -0
- package/src/runtime/registry.ts +213 -0
- package/src/runtime/roles.ts +64 -0
- package/src/runtime/rose-context.ts +24 -0
- package/src/runtime/subagents.ts +426 -0
- package/templates/APPEND_SYSTEM.md +12 -0
- package/upstream/aili-workflows.lock.json +3226 -0
|
@@ -0,0 +1,1203 @@
|
|
|
1
|
+
# Particle System
|
|
2
|
+
|
|
3
|
+
**IMPORTANT: GLSL ES 3.0 return values**: All code paths in non-void functions must return a value. Every branch of an if statement must have a return.
|
|
4
|
+
|
|
5
|
+
**IMPORTANT: Particle system time cycling**: Must use `mod(time - offset, period)` for cycle computation. **Never use `floor(time / period) * period`**! The latter causes all particles to have negative time initially, resulting in startup delay or blank rendering.
|
|
6
|
+
|
|
7
|
+
**IMPORTANT: Brightness budget (most common failure cause!)**: Each particle's `numerator / (dist² + epsilon)` peak = `numerator / epsilon`. **Total peak = N_particles x (numerator / epsilon) must be < 5.0** (single pass). Exceeding this budget causes washout even with Reinhard. See specific reference values in the comments of each template below. Multi-pass ping-pong systems have a stricter budget, see below.
|
|
8
|
+
|
|
9
|
+
**IMPORTANT: Particle color vs background contrast**: When particle color is close to the background (sand dust/snow/fog), visibility must be enhanced through at least one method: (1) brightness significantly higher than background (2) different hue (3) visible motion trail.
|
|
10
|
+
|
|
11
|
+
**IMPORTANT: Elongated glow (meteor/trail lines)**: Do not use `1/(distPerp² + tiny_epsilon)` for line glow — too-small epsilon makes the line center extremely bright. Correct approach: use `smoothstep` or `exp(-dist)` for lines, see meteor template below.
|
|
12
|
+
|
|
13
|
+
### Correct Pattern
|
|
14
|
+
```glsl
|
|
15
|
+
// Vertex shader
|
|
16
|
+
#version 300 es
|
|
17
|
+
in vec4 aPosition;
|
|
18
|
+
void main() {
|
|
19
|
+
gl_Position = aPosition;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Fragment shader
|
|
23
|
+
#version 300 es
|
|
24
|
+
precision highp float;
|
|
25
|
+
uniform vec2 iResolution;
|
|
26
|
+
uniform float iTime;
|
|
27
|
+
out vec4 fragColor;
|
|
28
|
+
|
|
29
|
+
float hash11(float p) {
|
|
30
|
+
return fract(sin(p * 127.1) * 43758.5453);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
void main() {
|
|
34
|
+
vec2 uv = gl_FragCoord.xy / iResolution.xy;
|
|
35
|
+
// ... particle system logic
|
|
36
|
+
fragColor = vec4(col, 1.0);
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Complete Single-File Template (Fireworks Particle System)
|
|
41
|
+
|
|
42
|
+
```html
|
|
43
|
+
<!DOCTYPE html>
|
|
44
|
+
<html>
|
|
45
|
+
<head>
|
|
46
|
+
<meta charset="utf-8">
|
|
47
|
+
<title>Fireworks</title>
|
|
48
|
+
<style>
|
|
49
|
+
body { margin: 0; overflow: hidden; background: #000; }
|
|
50
|
+
canvas { display: block; width: 100vw; height: 100vh; }
|
|
51
|
+
</style>
|
|
52
|
+
</head>
|
|
53
|
+
<body>
|
|
54
|
+
<canvas id="c"></canvas>
|
|
55
|
+
<script>
|
|
56
|
+
const canvas = document.getElementById('c');
|
|
57
|
+
const gl = canvas.getContext('webgl2');
|
|
58
|
+
|
|
59
|
+
const vs = `#version 300 es
|
|
60
|
+
in vec4 aPosition;
|
|
61
|
+
void main() { gl_Position = aPosition; }`;
|
|
62
|
+
|
|
63
|
+
const fs = `#version 300 es
|
|
64
|
+
precision highp float;
|
|
65
|
+
uniform vec2 iResolution;
|
|
66
|
+
uniform float iTime;
|
|
67
|
+
out vec4 fragColor;
|
|
68
|
+
|
|
69
|
+
#define NUM_FIREWORKS 4
|
|
70
|
+
#define PARTICLES_PER_FIREWORK 40
|
|
71
|
+
#define PI 3.14159265
|
|
72
|
+
|
|
73
|
+
float hash11(float p) {
|
|
74
|
+
return fract(sin(p * 127.1) * 43758.5453);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
vec3 hsv2rgb(vec3 c) {
|
|
78
|
+
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
|
79
|
+
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
|
80
|
+
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
void main() {
|
|
84
|
+
vec2 uv = (gl_FragCoord.xy - 0.5 * iResolution.xy) / iResolution.y;
|
|
85
|
+
vec3 col = vec3(0.01, 0.01, 0.03);
|
|
86
|
+
float t = iTime;
|
|
87
|
+
|
|
88
|
+
for (int fw = 0; fw < NUM_FIREWORKS; fw++) {
|
|
89
|
+
float fwId = float(fw);
|
|
90
|
+
float launchTime = 1.5 + fwId * 1.8 + hash11(fwId * 7.3) * 1.5;
|
|
91
|
+
float cycleTime = 4.5;
|
|
92
|
+
float fireworkTime = mod(t - launchTime, cycleTime);
|
|
93
|
+
|
|
94
|
+
float launchDuration = 0.6;
|
|
95
|
+
float launchPhase = clamp(fireworkTime / launchDuration, 0.0, 1.0);
|
|
96
|
+
|
|
97
|
+
float launchX = (hash11(fwId * 13.7) - 0.5) * 1.2;
|
|
98
|
+
float launchY = -0.8;
|
|
99
|
+
float peakY = 0.2 + hash11(fwId * 17.3) * 0.4;
|
|
100
|
+
|
|
101
|
+
float baseHue = hash11(fwId * 23.0);
|
|
102
|
+
|
|
103
|
+
if (fireworkTime < launchDuration) {
|
|
104
|
+
vec2 rocketPos = vec2(launchX, mix(launchY, peakY, launchPhase));
|
|
105
|
+
vec2 rel = uv - rocketPos;
|
|
106
|
+
float dist = length(rel);
|
|
107
|
+
// Rocket head: peak = 0.008/0.002 = 4.0, only 1 point, OK
|
|
108
|
+
float rocket = 0.008 / (dist * dist + 0.002);
|
|
109
|
+
float tail = 0.004 / (length(vec2(rel.x * 4.0, max(rel.y, 0.0))) + 0.01);
|
|
110
|
+
col += vec3(1.0, 0.8, 0.5) * rocket;
|
|
111
|
+
col += vec3(1.0, 0.5, 0.2) * tail * (1.0 - launchPhase);
|
|
112
|
+
} else {
|
|
113
|
+
float burstTime = fireworkTime - launchDuration;
|
|
114
|
+
float burstDuration = cycleTime - launchDuration;
|
|
115
|
+
float burstPhase = burstTime / burstDuration;
|
|
116
|
+
|
|
117
|
+
for (int p = 0; p < PARTICLES_PER_FIREWORK; p++) {
|
|
118
|
+
float pId = float(p);
|
|
119
|
+
float angle = hash11(fwId * 100.0 + pId * 7.3) * PI * 2.0;
|
|
120
|
+
float speed = 0.3 + hash11(fwId * 100.0 + pId * 13.7) * 0.7;
|
|
121
|
+
|
|
122
|
+
vec2 particleDir = vec2(cos(angle), sin(angle));
|
|
123
|
+
|
|
124
|
+
float damping = exp(-burstPhase * 2.5);
|
|
125
|
+
float travelDist = speed * (1.0 - damping) / 2.5;
|
|
126
|
+
vec2 particlePos = vec2(launchX, peakY) + particleDir * travelDist;
|
|
127
|
+
|
|
128
|
+
particlePos.y -= 0.5 * 1.2 * burstTime * burstTime;
|
|
129
|
+
|
|
130
|
+
vec2 rel = uv - particlePos;
|
|
131
|
+
float dist = length(rel);
|
|
132
|
+
|
|
133
|
+
float fade = smoothstep(1.0, 0.0, burstPhase);
|
|
134
|
+
fade *= fade;
|
|
135
|
+
|
|
136
|
+
// IMPORTANT: Brightness budget: peak = 0.015/0.03 = 0.5, x 40 particles x fade ≈ total peak < 5.0
|
|
137
|
+
float intensity = fade * 0.015 / (dist * dist + 0.03);
|
|
138
|
+
|
|
139
|
+
float hueOffset = (hash11(pId * 3.7 + fwId * 11.0) - 0.5) * 0.15;
|
|
140
|
+
vec3 particleColor = hsv2rgb(vec3(baseHue + hueOffset, 0.8, 1.0));
|
|
141
|
+
|
|
142
|
+
col += particleColor * intensity;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
col = col / (1.0 + col);
|
|
148
|
+
col = pow(col, vec3(0.9));
|
|
149
|
+
fragColor = vec4(col, 1.0);
|
|
150
|
+
}`;
|
|
151
|
+
|
|
152
|
+
function createShader(type, source) {
|
|
153
|
+
const s = gl.createShader(type);
|
|
154
|
+
gl.shaderSource(s, source);
|
|
155
|
+
gl.compileShader(s);
|
|
156
|
+
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {
|
|
157
|
+
console.error(gl.getShaderInfoLog(s));
|
|
158
|
+
}
|
|
159
|
+
return s;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const program = gl.createProgram();
|
|
163
|
+
gl.attachShader(program, createShader(gl.VERTEX_SHADER, vs));
|
|
164
|
+
gl.attachShader(program, createShader(gl.FRAGMENT_SHADER, fs));
|
|
165
|
+
gl.linkProgram(program);
|
|
166
|
+
gl.useProgram(program);
|
|
167
|
+
|
|
168
|
+
const buf = gl.createBuffer();
|
|
169
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
|
|
170
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1,1,-1,-1,1,1,1]), gl.STATIC_DRAW);
|
|
171
|
+
const aPos = gl.getAttribLocation(program, 'aPosition');
|
|
172
|
+
gl.enableVertexAttribArray(aPos);
|
|
173
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);
|
|
174
|
+
|
|
175
|
+
// Cache uniform locations (do NOT look up every frame - causes performance issues)
|
|
176
|
+
const iResolutionLoc = gl.getUniformLocation(program, 'iResolution');
|
|
177
|
+
const iTimeLoc = gl.getUniformLocation(program, 'iTime');
|
|
178
|
+
|
|
179
|
+
// Resize handler: only resize when window size actually changes
|
|
180
|
+
let lastWidth = 0, lastHeight = 0;
|
|
181
|
+
function resize() {
|
|
182
|
+
const w = window.innerWidth, h = window.innerHeight;
|
|
183
|
+
if (w !== lastWidth || h !== lastHeight) {
|
|
184
|
+
lastWidth = w; lastHeight = h;
|
|
185
|
+
canvas.width = w; canvas.height = h;
|
|
186
|
+
gl.viewport(0, 0, w, h);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function render(t) {
|
|
191
|
+
resize();
|
|
192
|
+
gl.uniform2f(iResolutionLoc, canvas.width, canvas.height);
|
|
193
|
+
gl.uniform1f(iTimeLoc, t * 0.001);
|
|
194
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
195
|
+
requestAnimationFrame(render);
|
|
196
|
+
}
|
|
197
|
+
requestAnimationFrame(render);
|
|
198
|
+
</script>
|
|
199
|
+
</body>
|
|
200
|
+
</html>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Stateful Particle System HTML Template (Multi-Pass Ping-Pong)
|
|
204
|
+
|
|
205
|
+
Stateful particles (Boids, cloth, fluid particles, etc.) need Buffers for inter-frame state storage. The following JS skeleton demonstrates the correct WebGL2 multi-pass ping-pong structure; shader code is in Steps 4-5 below:
|
|
206
|
+
|
|
207
|
+
```html
|
|
208
|
+
<!DOCTYPE html>
|
|
209
|
+
<html>
|
|
210
|
+
<head>
|
|
211
|
+
<meta charset="utf-8">
|
|
212
|
+
<title>Stateful Particles</title>
|
|
213
|
+
<style>
|
|
214
|
+
body { margin: 0; overflow: hidden; background: #000; }
|
|
215
|
+
canvas { display: block; width: 100vw; height: 100vh; }
|
|
216
|
+
</style>
|
|
217
|
+
</head>
|
|
218
|
+
<body>
|
|
219
|
+
<canvas id="c"></canvas>
|
|
220
|
+
<script>
|
|
221
|
+
let frameCount = 0;
|
|
222
|
+
let mouse = [0, 0, 0, 0];
|
|
223
|
+
|
|
224
|
+
const canvas = document.getElementById('c');
|
|
225
|
+
const gl = canvas.getContext('webgl2');
|
|
226
|
+
const ext = gl.getExtension('EXT_color_buffer_float');
|
|
227
|
+
|
|
228
|
+
function createShader(type, src) {
|
|
229
|
+
const s = gl.createShader(type);
|
|
230
|
+
gl.shaderSource(s, src);
|
|
231
|
+
gl.compileShader(s);
|
|
232
|
+
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS))
|
|
233
|
+
console.error(gl.getShaderInfoLog(s));
|
|
234
|
+
return s;
|
|
235
|
+
}
|
|
236
|
+
function createProgram(vsSrc, fsSrc) {
|
|
237
|
+
const p = gl.createProgram();
|
|
238
|
+
gl.attachShader(p, createShader(gl.VERTEX_SHADER, vsSrc));
|
|
239
|
+
gl.attachShader(p, createShader(gl.FRAGMENT_SHADER, fsSrc));
|
|
240
|
+
gl.linkProgram(p);
|
|
241
|
+
return p;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const vsSource = `#version 300 es
|
|
245
|
+
in vec2 pos;
|
|
246
|
+
void main(){ gl_Position=vec4(pos,0,1); }`;
|
|
247
|
+
|
|
248
|
+
// fsBuffer: particle physics update (see Step 4)
|
|
249
|
+
// fsImage: particle rendering (see Step 5)
|
|
250
|
+
const progBuf = createProgram(vsSource, fsBuffer);
|
|
251
|
+
const progImg = createProgram(vsSource, fsImage);
|
|
252
|
+
|
|
253
|
+
function createFBO(w, h) {
|
|
254
|
+
const tex = gl.createTexture();
|
|
255
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
256
|
+
const fmt = ext ? gl.RGBA16F : gl.RGBA8;
|
|
257
|
+
const typ = ext ? gl.FLOAT : gl.UNSIGNED_BYTE;
|
|
258
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, fmt, w, h, 0, gl.RGBA, typ, null);
|
|
259
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
260
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
261
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
262
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
263
|
+
const fbo = gl.createFramebuffer();
|
|
264
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
|
265
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
|
|
266
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
267
|
+
return { fbo, tex };
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
let W, H, bufA, bufB;
|
|
271
|
+
|
|
272
|
+
const vao = gl.createVertexArray();
|
|
273
|
+
gl.bindVertexArray(vao);
|
|
274
|
+
const vbo = gl.createBuffer();
|
|
275
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
276
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);
|
|
277
|
+
gl.enableVertexAttribArray(0);
|
|
278
|
+
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
|
|
279
|
+
|
|
280
|
+
function resize() {
|
|
281
|
+
canvas.width = W = innerWidth;
|
|
282
|
+
canvas.height = H = innerHeight;
|
|
283
|
+
bufA = createFBO(W, H);
|
|
284
|
+
bufB = createFBO(W, H);
|
|
285
|
+
frameCount = 0;
|
|
286
|
+
}
|
|
287
|
+
addEventListener('resize', resize);
|
|
288
|
+
resize();
|
|
289
|
+
|
|
290
|
+
canvas.addEventListener('mousedown', e => { mouse[2] = e.clientX; mouse[3] = H - e.clientY; });
|
|
291
|
+
canvas.addEventListener('mouseup', () => { mouse[2] = 0; mouse[3] = 0; });
|
|
292
|
+
canvas.addEventListener('mousemove', e => { mouse[0] = e.clientX; mouse[1] = H - e.clientY; });
|
|
293
|
+
|
|
294
|
+
function render(t) {
|
|
295
|
+
t *= 0.001;
|
|
296
|
+
// Buffer pass: read bufA → write bufB
|
|
297
|
+
gl.useProgram(progBuf);
|
|
298
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, bufB.fbo);
|
|
299
|
+
gl.viewport(0, 0, W, H);
|
|
300
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
301
|
+
gl.bindTexture(gl.TEXTURE_2D, bufA.tex);
|
|
302
|
+
gl.uniform1i(gl.getUniformLocation(progBuf, 'iChannel0'), 0);
|
|
303
|
+
gl.uniform2f(gl.getUniformLocation(progBuf, 'iResolution'), W, H);
|
|
304
|
+
gl.uniform1f(gl.getUniformLocation(progBuf, 'iTime'), t);
|
|
305
|
+
gl.uniform1i(gl.getUniformLocation(progBuf, 'iFrame'), frameCount);
|
|
306
|
+
gl.uniform4f(gl.getUniformLocation(progBuf, 'iMouse'), ...mouse);
|
|
307
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
308
|
+
[bufA, bufB] = [bufB, bufA];
|
|
309
|
+
|
|
310
|
+
// Image pass: read bufA → screen
|
|
311
|
+
gl.useProgram(progImg);
|
|
312
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
313
|
+
gl.viewport(0, 0, W, H);
|
|
314
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
315
|
+
gl.bindTexture(gl.TEXTURE_2D, bufA.tex);
|
|
316
|
+
gl.uniform1i(gl.getUniformLocation(progImg, 'iChannel0'), 0);
|
|
317
|
+
gl.uniform2f(gl.getUniformLocation(progImg, 'iResolution'), W, H);
|
|
318
|
+
gl.uniform1f(gl.getUniformLocation(progImg, 'iTime'), t);
|
|
319
|
+
gl.uniform1i(gl.getUniformLocation(progImg, 'iFrame'), frameCount);
|
|
320
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
321
|
+
|
|
322
|
+
frameCount++;
|
|
323
|
+
requestAnimationFrame(render);
|
|
324
|
+
}
|
|
325
|
+
requestAnimationFrame(render);
|
|
326
|
+
</script>
|
|
327
|
+
</body>
|
|
328
|
+
</html>
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Star Field Function Template (For Meteors, Fireworks, and Other Night Sky Scenes)
|
|
332
|
+
|
|
333
|
+
**IMPORTANT: Star visibility**: Stars must be clearly visible in screenshots as individual light points. Use `exp(-dist*dist*k)` for sharp Gaussian dots rather than `1/(dist²+eps)` broad glow. Each star's peak brightness should be at least 0.3 to be visible against a dark background.
|
|
334
|
+
|
|
335
|
+
```glsl
|
|
336
|
+
#define NUM_STARS 200
|
|
337
|
+
|
|
338
|
+
vec3 starField(vec2 uv) {
|
|
339
|
+
vec3 col = vec3(0.0);
|
|
340
|
+
for (int i = 0; i < NUM_STARS; i++) {
|
|
341
|
+
float fi = float(i);
|
|
342
|
+
vec2 starPos = vec2(hash11(fi * 13.7 + 1.3), hash11(fi * 7.3 + 91.1));
|
|
343
|
+
starPos = starPos * 2.0 - 1.0;
|
|
344
|
+
float brightness = 0.3 + 0.7 * pow(hash11(fi * 3.1 + 47.0), 2.0);
|
|
345
|
+
float twinkle = 0.7 + 0.3 * sin(iTime * (1.0 + hash11(fi * 5.7) * 3.0) + fi * 6.28);
|
|
346
|
+
brightness *= twinkle;
|
|
347
|
+
float dist = length(uv - starPos);
|
|
348
|
+
// Sharp Gaussian dot: peak = brightness (0.3~1.0), very small radius, no accumulation washout
|
|
349
|
+
float glow = brightness * exp(-dist * dist * 8000.0);
|
|
350
|
+
// Add soft halo to make stars more visible
|
|
351
|
+
glow += brightness * 0.0008 / (dist * dist + 0.003);
|
|
352
|
+
float temp = hash11(fi * 11.3 + 23.0);
|
|
353
|
+
vec3 starCol = mix(vec3(0.6, 0.7, 1.0), vec3(1.0, 0.9, 0.7), temp);
|
|
354
|
+
col += starCol * glow;
|
|
355
|
+
}
|
|
356
|
+
return col;
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Incorrect Pattern (Do Not Do This)
|
|
361
|
+
```glsl
|
|
362
|
+
// WRONG: cannot write this in standalone HTML
|
|
363
|
+
void mainImage(out vec4 fragColor, in vec2 fragCoord) { ... }
|
|
364
|
+
void main() {
|
|
365
|
+
mainImage(fragColor, fragCoord); // compilation error!
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## ShaderToy vs Standalone HTML Code Templates
|
|
370
|
+
|
|
371
|
+
The following code examples fall into two categories; be sure to use the correct template:
|
|
372
|
+
|
|
373
|
+
### Standalone HTML Template (complete example provided above)
|
|
374
|
+
|
|
375
|
+
### ShaderToy Template (for the ShaderToy website)
|
|
376
|
+
|
|
377
|
+
## Use Cases
|
|
378
|
+
- **Stateless particle effects**: fireworks, starfields, campfire/flames (flying embers), orbiting light points, and other decorative effects that don't need inter-frame memory
|
|
379
|
+
- **Stateful physics particles**: flocking/boids, raindrops, cloth, fluids, and other simulations requiring persistent position and velocity
|
|
380
|
+
- **Motion blur and trails**: particle trajectories needing afterglow or halo effects
|
|
381
|
+
- **Large-scale particle management**: real-time rendering and interaction with hundreds to thousands of particles
|
|
382
|
+
- **Weather/atmospheric effects**: sandstorms, blizzards, volcanic ash, and other vortex-driven particle systems
|
|
383
|
+
- **Magic/geometric arrays**: magic dust, spiraling ascending light points, magic circle rings, iridescent shimmering particles
|
|
384
|
+
|
|
385
|
+
Core decision tree: Do particles need inter-frame memory?
|
|
386
|
+
- **No** → Single-pass stateless system (using loops + hash functions)
|
|
387
|
+
- **Yes** → Multi-pass stateful system (using Buffer for position/velocity storage)
|
|
388
|
+
|
|
389
|
+
## Core Principles
|
|
390
|
+
|
|
391
|
+
Particle systems manage collections of many independent entities, each with position, velocity, lifetime, and other attributes.
|
|
392
|
+
|
|
393
|
+
**Stateless paradigm**: All attributes are recomputed each frame from particle ID and time, no Buffer needed.
|
|
394
|
+
```
|
|
395
|
+
position_i = trajectory(id_i, time) + randomOffset(hash(id_i))
|
|
396
|
+
lifetime_i = fract((time - spawnTime_i) / lifeDuration_i)
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
**Stateful paradigm**: Particle state is stored in Buffer texture pixels, each frame reading → computing → writing back.
|
|
400
|
+
```
|
|
401
|
+
// Euler method
|
|
402
|
+
velocity += acceleration * dt
|
|
403
|
+
position += velocity * dt
|
|
404
|
+
|
|
405
|
+
// Verlet integration (no explicit velocity, more stable)
|
|
406
|
+
newPos = 2 * currentPos - previousPos + acceleration * dt²
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
**Rendering**: Distance-based falloff `intensity = brightness / (dist² + epsilon)`, with multi-particle superposition creating metaball fusion effects.
|
|
410
|
+
|
|
411
|
+
## Implementation Steps
|
|
412
|
+
|
|
413
|
+
### Step 1: Hash Random Functions
|
|
414
|
+
```glsl
|
|
415
|
+
// 1D -> 1D hash, returns [0, 1)
|
|
416
|
+
float hash11(float p) {
|
|
417
|
+
return fract(sin(p * 127.1) * 43758.5453);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// 1D -> 2D hash
|
|
421
|
+
vec2 hash12(float p) {
|
|
422
|
+
vec3 p3 = fract(vec3(p) * vec3(0.1031, 0.1030, 0.0973));
|
|
423
|
+
p3 += dot(p3, p3.yzx + 33.33);
|
|
424
|
+
return fract((p3.xx + p3.yz) * p3.zy);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// 3D -> 3D hash
|
|
428
|
+
vec3 hash33(vec3 p) {
|
|
429
|
+
p = fract(p * vec3(443.897, 397.297, 491.187));
|
|
430
|
+
p += dot(p.zxy, p.yxz + 19.19);
|
|
431
|
+
return fract(vec3(p.x * p.y, p.z * p.x, p.y * p.z)) - 0.5;
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Step 2: Particle Lifecycle Management
|
|
436
|
+
```glsl
|
|
437
|
+
#define NUM_PARTICLES 100
|
|
438
|
+
#define LIFETIME_MIN 1.0
|
|
439
|
+
#define LIFETIME_MAX 3.0
|
|
440
|
+
#define START_TIME 2.0
|
|
441
|
+
|
|
442
|
+
// Returns: x = normalized age [0,1], y = life cycle number
|
|
443
|
+
vec2 particleAge(int id, float time) {
|
|
444
|
+
float spawnTime = START_TIME * hash11(float(id) * 2.0);
|
|
445
|
+
float lifetime = mix(LIFETIME_MIN, LIFETIME_MAX, hash11(float(id) * 3.0 - 35.0));
|
|
446
|
+
float age = mod(time - spawnTime, lifetime);
|
|
447
|
+
float run = floor((time - spawnTime) / lifetime);
|
|
448
|
+
return vec2(age / lifetime, run);
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### Step 3: Stateless Particle Position Computation
|
|
453
|
+
```glsl
|
|
454
|
+
#define GRAVITY vec2(0.0, -4.5)
|
|
455
|
+
#define DRIFT_MAX vec2(0.28, 0.28)
|
|
456
|
+
|
|
457
|
+
// Harmonic superposition for smooth main trajectory
|
|
458
|
+
float harmonics(vec3 freq, vec3 amp, vec3 phase, float t) {
|
|
459
|
+
float val = 0.0;
|
|
460
|
+
for (int h = 0; h < 3; h++)
|
|
461
|
+
val += amp[h] * cos(t * freq[h] * 6.2832 + phase[h] / 360.0 * 6.2832);
|
|
462
|
+
return (1.0 + val) / 2.0;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
vec2 particlePosition(int id, float time) {
|
|
466
|
+
vec2 ageInfo = particleAge(id, time);
|
|
467
|
+
float age = ageInfo.x;
|
|
468
|
+
float run = ageInfo.y;
|
|
469
|
+
|
|
470
|
+
float slowTime = time * 0.1;
|
|
471
|
+
vec2 mainPos = vec2(
|
|
472
|
+
harmonics(vec3(0.4, 0.66, 0.78), vec3(0.8, 0.24, 0.18), vec3(0.0, 45.0, 55.0), slowTime),
|
|
473
|
+
harmonics(vec3(0.415, 0.61, 0.82), vec3(0.72, 0.28, 0.15), vec3(90.0, 120.0, 10.0), slowTime)
|
|
474
|
+
);
|
|
475
|
+
|
|
476
|
+
vec2 drift = DRIFT_MAX * (vec2(hash11(float(id) * 3.0 + run * 4.0),
|
|
477
|
+
hash11(float(id) * 7.0 - run * 2.5)) - 0.5) * age;
|
|
478
|
+
vec2 grav = GRAVITY * age * age * 0.5;
|
|
479
|
+
|
|
480
|
+
return mainPos + drift + grav;
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Step 4: Buffer-Stored Particle State (Stateful System)
|
|
485
|
+
```glsl
|
|
486
|
+
// === Buffer A: Particle Physics Update ===
|
|
487
|
+
// IMPORTANT: Multi-pass system warning: each fragment shader is compiled independently, helper functions must be redefined in each shader!
|
|
488
|
+
#define NUM_PARTICLES 40
|
|
489
|
+
#define MAX_VEL 0.5
|
|
490
|
+
#define MAX_ACC 3.0
|
|
491
|
+
#define RESIST 0.2
|
|
492
|
+
#define DT 0.03
|
|
493
|
+
|
|
494
|
+
// Helper functions that must be defined in the Buffer A shader
|
|
495
|
+
float hash11(float p) {
|
|
496
|
+
return fract(sin(p * 127.1) * 43758.5453);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
vec2 hash12(float p) {
|
|
500
|
+
vec3 p3 = fract(vec3(p) * vec3(0.1031, 0.1030, 0.0973));
|
|
501
|
+
p3 += dot(p3, p3.yzx + 33.33);
|
|
502
|
+
return fract((p3.xx + p3.yz) * p3.zy);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
vec4 loadParticle(float i) {
|
|
506
|
+
return texelFetch(iChannel0, ivec2(i, 0), 0);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
|
510
|
+
if (fragCoord.y > 0.5 || fragCoord.x > float(NUM_PARTICLES)) discard;
|
|
511
|
+
|
|
512
|
+
float id = floor(fragCoord.x);
|
|
513
|
+
vec2 res = iResolution.xy / iResolution.y;
|
|
514
|
+
|
|
515
|
+
if (iFrame < 5) {
|
|
516
|
+
vec2 rng = hash12(id);
|
|
517
|
+
fragColor = vec4(0.1 + 0.8 * rng * res, 0.0, 0.0);
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
vec4 particle = loadParticle(id); // xy = pos, zw = vel
|
|
522
|
+
vec2 pos = particle.xy;
|
|
523
|
+
vec2 vel = particle.zw;
|
|
524
|
+
|
|
525
|
+
vec2 force = vec2(0.0);
|
|
526
|
+
force += 0.8 * (1.0 / abs(pos) - 1.0 / abs(res - pos)); // boundary repulsion
|
|
527
|
+
for (float i = 0.0; i < float(NUM_PARTICLES); i++) { // inter-particle interaction
|
|
528
|
+
if (i == id) continue;
|
|
529
|
+
vec4 other = loadParticle(i);
|
|
530
|
+
vec2 w = pos - other.xy;
|
|
531
|
+
float d = length(w);
|
|
532
|
+
if (d > 0.0)
|
|
533
|
+
force -= w * (6.3 + log(d * d * 0.02)) / exp(d * d * 2.4) / d;
|
|
534
|
+
}
|
|
535
|
+
force -= vel * RESIST / DT; // friction
|
|
536
|
+
|
|
537
|
+
vec2 acc = force;
|
|
538
|
+
float a = length(acc);
|
|
539
|
+
acc *= a > MAX_ACC ? MAX_ACC / a : 1.0;
|
|
540
|
+
vel += acc * DT;
|
|
541
|
+
float v = length(vel);
|
|
542
|
+
vel *= v > MAX_VEL ? MAX_VEL / v : 1.0;
|
|
543
|
+
pos += vel * DT;
|
|
544
|
+
|
|
545
|
+
fragColor = vec4(pos, vel);
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
### Step 5: Particle Rendering — Metaball Style
|
|
550
|
+
// IMPORTANT: Multi-pass system warning: Image shader must define all the following helper functions (compiled independently)!
|
|
551
|
+
```glsl
|
|
552
|
+
#define BRIGHTNESS 0.002
|
|
553
|
+
#define COLOR_START vec3(0.0, 0.64, 0.2)
|
|
554
|
+
#define COLOR_END vec3(0.06, 0.35, 0.85)
|
|
555
|
+
|
|
556
|
+
// Helper functions that must be defined in the Image shader
|
|
557
|
+
float hash11(float p) {
|
|
558
|
+
return fract(sin(p * 127.1) * 43758.5453);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
vec2 hash12(float p) {
|
|
562
|
+
vec3 p3 = fract(vec3(p) * vec3(0.1031, 0.1030, 0.0973));
|
|
563
|
+
p3 += dot(p3, p3.yzx + 33.33);
|
|
564
|
+
return fract((p3.xx + p3.yz) * p3.zy);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
vec4 loadParticle(float i) {
|
|
568
|
+
return texelFetch(iChannel0, ivec2(i, 0), 0);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// HSV to RGB (correct implementation)
|
|
572
|
+
vec3 hsv2rgb(vec3 c) {
|
|
573
|
+
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
|
574
|
+
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
|
575
|
+
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
vec3 renderParticles(vec2 uv) {
|
|
579
|
+
vec3 col = vec3(0.0);
|
|
580
|
+
float totalWeight = 0.0;
|
|
581
|
+
for (int i = 0; i < NUM_PARTICLES; i++) {
|
|
582
|
+
vec4 particle = loadParticle(float(i));
|
|
583
|
+
vec2 p = uv - particle.xy;
|
|
584
|
+
float mb = BRIGHTNESS / dot(p, p);
|
|
585
|
+
totalWeight += mb;
|
|
586
|
+
float ratio = length(particle.zw) / MAX_VEL;
|
|
587
|
+
vec3 pcol = mix(COLOR_START, COLOR_END, ratio);
|
|
588
|
+
col = mix(col, pcol, mb / totalWeight);
|
|
589
|
+
}
|
|
590
|
+
totalWeight /= float(NUM_PARTICLES);
|
|
591
|
+
col = normalize(col) * clamp(totalWeight, 0.0, 0.4);
|
|
592
|
+
return col;
|
|
593
|
+
}
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### Step 6: Frame Feedback Motion Blur
|
|
597
|
+
```glsl
|
|
598
|
+
// IMPORTANT: Ping-pong brightness budget (most common washout cause!):
|
|
599
|
+
// Steady-state brightness = singleFrameContribution / (1 - TRAIL_DECAY)
|
|
600
|
+
// decay=0.88 → 8.3x amplification, decay=0.95 → 20x amplification
|
|
601
|
+
// Budget formula: N_particles x (numerator/epsilon) x 1/(1-decay) < 10.0
|
|
602
|
+
//
|
|
603
|
+
// Safe parameter lookup table (decay=0.88, 8.3x amplification):
|
|
604
|
+
// 20 particles → single particle peak < 0.06 (numerator=0.002, epsilon=0.03)
|
|
605
|
+
// 50 particles → single particle peak < 0.024 (numerator=0.001, epsilon=0.04)
|
|
606
|
+
// 100 particles → single particle peak < 0.012 (numerator=0.0005, epsilon=0.04)
|
|
607
|
+
//
|
|
608
|
+
// Safe parameter lookup table (decay=0.92, 12.5x amplification):
|
|
609
|
+
// 20 particles → single particle peak < 0.04 (numerator=0.001, epsilon=0.03)
|
|
610
|
+
// 50 particles → single particle peak < 0.016 (numerator=0.0005, epsilon=0.03)
|
|
611
|
+
// 100 particles → single particle peak < 0.008 (numerator=0.0003, epsilon=0.04)
|
|
612
|
+
#define TRAIL_DECAY 0.88
|
|
613
|
+
|
|
614
|
+
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
|
615
|
+
vec2 uv = fragCoord / iResolution.xy;
|
|
616
|
+
vec3 prev = texture(iChannel0, uv).rgb * TRAIL_DECAY;
|
|
617
|
+
vec3 current = renderParticles(fragCoord / iResolution.y);
|
|
618
|
+
fragColor = vec4(prev + current, 1.0);
|
|
619
|
+
}
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### Step 7: HSV Coloring & Star Glare Effect
|
|
623
|
+
```glsl
|
|
624
|
+
// HSV to RGB (correct implementation)
|
|
625
|
+
vec3 hsv2rgb(vec3 c) {
|
|
626
|
+
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
|
627
|
+
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
|
628
|
+
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// Star glare: thin rays in horizontal/vertical/diagonal directions
|
|
632
|
+
float starGlare(vec2 relPos, float intensity) {
|
|
633
|
+
vec2 stretch = vec2(9.0, 0.32);
|
|
634
|
+
float dh = length(relPos * stretch);
|
|
635
|
+
float dv = length(relPos * stretch.yx);
|
|
636
|
+
vec2 diagPos = 0.707 * vec2(dot(relPos, vec2(1, 1)), dot(relPos, vec2(1, -1)));
|
|
637
|
+
float dd1 = length(diagPos * vec2(13.0, 0.61));
|
|
638
|
+
float dd2 = length(diagPos * vec2(0.61, 13.0));
|
|
639
|
+
float glare = 0.25 / (dh * 3.0 + 0.01)
|
|
640
|
+
+ 0.25 / (dv * 3.0 + 0.01)
|
|
641
|
+
+ 0.19 / (dd1 * 3.0 + 0.01)
|
|
642
|
+
+ 0.19 / (dd2 * 3.0 + 0.01);
|
|
643
|
+
return glare * intensity;
|
|
644
|
+
}
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
## Complete Code Template
|
|
648
|
+
|
|
649
|
+
Single-pass stateless particle system, runs directly in ShaderToy's Image tab:
|
|
650
|
+
|
|
651
|
+
```glsl
|
|
652
|
+
// === Particle System — Stateless Single-Pass Template ===
|
|
653
|
+
|
|
654
|
+
#define NUM_PARTICLES 80
|
|
655
|
+
#define LIFETIME_MIN 1.0
|
|
656
|
+
#define LIFETIME_MAX 3.5
|
|
657
|
+
#define START_TIME 2.5
|
|
658
|
+
#define BRIGHTNESS 0.00004
|
|
659
|
+
#define GRAVITY vec2(0.0, -2.0)
|
|
660
|
+
#define DRIFT_SPEED 0.2
|
|
661
|
+
#define HUE_SHIFT 0.035
|
|
662
|
+
#define TRAIL_DECAY 0.92
|
|
663
|
+
#define STAR_ENABLED 1
|
|
664
|
+
|
|
665
|
+
#define PI 3.14159265
|
|
666
|
+
#define TAU 6.28318530
|
|
667
|
+
|
|
668
|
+
float hash11(float p) {
|
|
669
|
+
return fract(sin(p * 127.1) * 43758.5453);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
vec3 hsv2rgb(vec3 c) {
|
|
673
|
+
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
|
674
|
+
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
|
675
|
+
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
float harmonics3(vec3 freq, vec3 amp, vec3 phase, float t) {
|
|
679
|
+
float val = 0.0;
|
|
680
|
+
for (int h = 0; h < 3; h++)
|
|
681
|
+
val += amp[h] * cos(t * freq[h] * TAU + phase[h] / 360.0 * TAU);
|
|
682
|
+
return (1.0 + val) * 0.5;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
vec3 getLifecycle(int id, float time) {
|
|
686
|
+
float spawn = START_TIME * hash11(float(id) * 2.0);
|
|
687
|
+
float life = mix(LIFETIME_MIN, LIFETIME_MAX, hash11(float(id) * 3.0 - 35.0));
|
|
688
|
+
float age = mod(time - spawn, life);
|
|
689
|
+
float run = floor((time - spawn) / life);
|
|
690
|
+
return vec3(age / life, run, spawn);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
vec2 getPosition(int id, float time) {
|
|
694
|
+
vec3 lc = getLifecycle(id, time);
|
|
695
|
+
float age = lc.x;
|
|
696
|
+
float run = lc.y;
|
|
697
|
+
|
|
698
|
+
float tfact = mix(6.0, 20.0, hash11(float(id) * 2.0 + 94.0 + run * 1.5));
|
|
699
|
+
float pt = (run * lc.x * mix(LIFETIME_MIN, LIFETIME_MAX, hash11(float(id)*3.0-35.0)) + lc.z) * (-1.0/tfact + 1.0) + time / tfact;
|
|
700
|
+
|
|
701
|
+
vec2 mainPos = vec2(
|
|
702
|
+
harmonics3(vec3(0.4, 0.66, 0.78), vec3(0.8, 0.24, 0.18), vec3(0.0, 45.0, 55.0), pt),
|
|
703
|
+
harmonics3(vec3(0.415, 0.61, 0.82), vec3(0.72, 0.28, 0.15), vec3(90.0, 120.0, 10.0), pt)
|
|
704
|
+
) + vec2(0.35, 0.15);
|
|
705
|
+
|
|
706
|
+
vec2 drift = DRIFT_SPEED * (vec2(
|
|
707
|
+
hash11(float(id) * 3.0 - 23.0 + run * 4.0),
|
|
708
|
+
hash11(float(id) * 7.0 + 632.0 - run * 2.5)
|
|
709
|
+
) - 0.5) * age;
|
|
710
|
+
|
|
711
|
+
vec2 grav = GRAVITY * age * age * 0.004;
|
|
712
|
+
|
|
713
|
+
return (mainPos + drift + grav) * vec2(0.6, 0.45);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
float starGlare(vec2 rel) {
|
|
717
|
+
#if STAR_ENABLED == 0
|
|
718
|
+
return 0.0;
|
|
719
|
+
#endif
|
|
720
|
+
vec2 stretchHV = vec2(9.0, 0.32);
|
|
721
|
+
float dh = length(rel * stretchHV);
|
|
722
|
+
float dv = length(rel * stretchHV.yx);
|
|
723
|
+
vec2 dRel = 0.707 * vec2(dot(rel, vec2(1, 1)), dot(rel, vec2(1, -1)));
|
|
724
|
+
vec2 stretchDiag = vec2(13.0, 0.61);
|
|
725
|
+
float dd1 = length(dRel * stretchDiag);
|
|
726
|
+
float dd2 = length(dRel * stretchDiag.yx);
|
|
727
|
+
return 0.25 / (dh * 3.0 + 0.01) + 0.25 / (dv * 3.0 + 0.01)
|
|
728
|
+
+ 0.19 / (dd1 * 3.0 + 0.01) + 0.19 / (dd2 * 3.0 + 0.01);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
|
732
|
+
vec2 uv = fragCoord.xy / iResolution.xx;
|
|
733
|
+
float time = iTime * 0.75;
|
|
734
|
+
|
|
735
|
+
vec3 col = vec3(0.0);
|
|
736
|
+
|
|
737
|
+
for (int i = 1; i < NUM_PARTICLES; i++) {
|
|
738
|
+
vec3 lc = getLifecycle(i, time);
|
|
739
|
+
float age = lc.x;
|
|
740
|
+
float run = lc.y;
|
|
741
|
+
|
|
742
|
+
vec2 ppos = getPosition(i, time);
|
|
743
|
+
vec2 rel = uv - ppos;
|
|
744
|
+
float dist = length(rel);
|
|
745
|
+
|
|
746
|
+
float baseInt = mix(0.1, 3.2, hash11(run * 4.0 + float(i) - 55.0));
|
|
747
|
+
float glow = 1.0 / (dist * 3.0 + 0.015);
|
|
748
|
+
|
|
749
|
+
float star = starGlare(rel);
|
|
750
|
+
float intensity = baseInt * pow(glow + star, 2.3) / 40000.0;
|
|
751
|
+
|
|
752
|
+
intensity *= (1.0 - age);
|
|
753
|
+
intensity *= smoothstep(0.0, 0.15, age);
|
|
754
|
+
float sparkFreq = mix(2.5, 6.0, hash11(float(i) * 5.0 + 72.0 - run * 1.8));
|
|
755
|
+
intensity *= 0.5 * sin(sparkFreq * TAU * time) + 1.0;
|
|
756
|
+
|
|
757
|
+
float hue = mix(-0.13, 0.13, hash11(float(i) + 124.0 + run * 1.5)) + HUE_SHIFT * time;
|
|
758
|
+
float sat = mix(0.5, 0.9, hash11(float(i) * 6.0 + 44.0 + run * 3.3)) * 0.45 / max(intensity, 0.001);
|
|
759
|
+
col += hsv2rgb(vec3(hue, clamp(sat, 0.0, 1.0), intensity));
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
col = pow(max(col, 0.0), vec3(1.0 / 2.2));
|
|
763
|
+
fragColor = vec4(col, 1.0);
|
|
764
|
+
}
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
## Common Variants
|
|
768
|
+
|
|
769
|
+
### Variant 1: Metaball Polar Coordinate Particles
|
|
770
|
+
```glsl
|
|
771
|
+
float d = fract(time * 0.51 + 48934.4238 * sin(float(i) * 692.7398));
|
|
772
|
+
float angle = TAU * float(i) / float(NUM_PARTICLES);
|
|
773
|
+
vec2 particlePos = d * vec2(cos(angle), sin(angle)) * 4.0;
|
|
774
|
+
|
|
775
|
+
vec2 p = uv - particlePos;
|
|
776
|
+
float mb = 0.84 / dot(p, p);
|
|
777
|
+
col = mix(col, mix(startColor, endColor, d), mb / totalSum);
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
### Variant 2: Buffer Storage + Boids Flocking Behavior
|
|
781
|
+
```glsl
|
|
782
|
+
vec2 sumForce = vec2(0.0);
|
|
783
|
+
for (float j = 0.0; j < NUM_PARTICLES; j++) {
|
|
784
|
+
if (j == id) continue;
|
|
785
|
+
vec4 other = texelFetch(iChannel0, ivec2(j, 0), 0);
|
|
786
|
+
vec2 w = pos - other.xy;
|
|
787
|
+
float d = length(w);
|
|
788
|
+
sumForce -= w * (6.3 + log(d * d * 0.02)) / exp(d * d * 2.4) / d;
|
|
789
|
+
}
|
|
790
|
+
sumForce -= vel * 0.2 / dt;
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
### Variant 3: Verlet Integration Cloth Simulation
|
|
794
|
+
```glsl
|
|
795
|
+
vec2 newPos = 2.0 * particle.xy - particle.zw + vec2(0.0, -0.6) * dt * dt;
|
|
796
|
+
particle.zw = particle.xy;
|
|
797
|
+
particle.xy = newPos;
|
|
798
|
+
|
|
799
|
+
vec4 neighbor = texelFetch(iChannel0, neighborId, 0);
|
|
800
|
+
vec2 delta = neighbor.xy - particle.xy;
|
|
801
|
+
float dist = length(delta);
|
|
802
|
+
float restLength = 0.1;
|
|
803
|
+
particle.xy += 0.1 * (dist - restLength) * (delta / dist);
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
### Variant 4: 3D Particles + Ray Rendering
|
|
807
|
+
```glsl
|
|
808
|
+
vec3 ro = vec3(0.0, 0.0, 2.5);
|
|
809
|
+
vec3 rd = normalize(vec3(uv, -0.5));
|
|
810
|
+
for (int i = 0; i < numParticles; i++) {
|
|
811
|
+
vec3 pos = texture(iChannel0, vec2(i, 100.0) * w).rgb;
|
|
812
|
+
float d = dot(cross(pos - ro, rd), cross(pos - ro, rd));
|
|
813
|
+
d *= 1000.0;
|
|
814
|
+
float glow = 0.14 / (pow(d, 1.1) + 0.03);
|
|
815
|
+
col += glow * particleColor;
|
|
816
|
+
}
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
### Variant 5: Raindrop Particles (3D Scene Integration)
|
|
820
|
+
```glsl
|
|
821
|
+
float speedScale = 0.0015 * (0.1 + 1.9 * sin(PI * 0.5 * pow(age / lifetime, 2.0)));
|
|
822
|
+
particle.x += (windShieldOffset.x + windIntensity * dot(rayRight, windDir)) * fallSpeed * speedScale * dt;
|
|
823
|
+
particle.y += (windShieldOffset.y + windIntensity * dot(rayUp, windDir)) * fallSpeed * speedScale * dt;
|
|
824
|
+
particle.xy += 0.001 * (randVec2(particle.xy + iTime) - 0.5) * jitterSpeed * dt;
|
|
825
|
+
if (particle.z > particle.a) {
|
|
826
|
+
particle.xy = vec2(rand(seedX), rand(seedY)) * iResolution.xy;
|
|
827
|
+
particle.a = lifetimeMin + rand(pid) * (lifetimeMax - lifetimeMin);
|
|
828
|
+
particle.z = 0.0;
|
|
829
|
+
}
|
|
830
|
+
```
|
|
831
|
+
|
|
832
|
+
### Variant 6: Vortex/Storm Particle System (Sandstorm, Blizzard, Whirlwind, etc.)
|
|
833
|
+
|
|
834
|
+
Uses stateless single pass. Key: spiral trajectory + high-visibility particles + vortex eye dark zone + separated background fog layer.
|
|
835
|
+
|
|
836
|
+
```glsl
|
|
837
|
+
// IMPORTANT: Particle color must be 2-3x brighter than background to be visible (sand-colored particles on sand-colored background easily disappear)
|
|
838
|
+
// IMPORTANT: Brightness budget: 150 particles x peak(0.005/0.003=1.67) x fade(avg~0.3) ≈ 75, overexposed!
|
|
839
|
+
// Must increase epsilon or decrease numerator. Safe values: numerator=0.002, epsilon=0.008 → peak=0.25, total=11 → OK after Reinhard
|
|
840
|
+
#define NUM_DUST 150
|
|
841
|
+
#define VORTEX_CENTER vec2(0.0)
|
|
842
|
+
|
|
843
|
+
void main() {
|
|
844
|
+
vec2 uv = (gl_FragCoord.xy - 0.5 * iResolution.xy) / iResolution.y;
|
|
845
|
+
float t = iTime;
|
|
846
|
+
|
|
847
|
+
vec3 bg = mix(vec3(0.25, 0.18, 0.08), vec3(0.4, 0.28, 0.12), gl_FragCoord.y / iResolution.y);
|
|
848
|
+
|
|
849
|
+
vec3 col = vec3(0.0);
|
|
850
|
+
for (int i = 0; i < NUM_DUST; i++) {
|
|
851
|
+
float fi = float(i);
|
|
852
|
+
float life = mix(2.0, 5.0, hash11(fi * 3.7));
|
|
853
|
+
float age = mod(t - hash11(fi * 2.0) * life, life);
|
|
854
|
+
float norm = age / life;
|
|
855
|
+
|
|
856
|
+
float initAngle = hash11(fi * 7.3) * 6.2832;
|
|
857
|
+
float initR = 0.05 + hash11(fi * 11.0) * 0.5;
|
|
858
|
+
float angularSpeed = 2.0 / (0.3 + initR);
|
|
859
|
+
float angle = initAngle + norm * angularSpeed;
|
|
860
|
+
float radius = initR + norm * 0.15;
|
|
861
|
+
|
|
862
|
+
vec2 pos = VORTEX_CENTER + vec2(cos(angle), sin(angle)) * radius;
|
|
863
|
+
|
|
864
|
+
vec2 rel = uv - pos;
|
|
865
|
+
float dist = length(rel);
|
|
866
|
+
|
|
867
|
+
float fade = smoothstep(0.0, 0.1, norm) * smoothstep(1.0, 0.5, norm);
|
|
868
|
+
// Safe brightness: peak = 0.002/0.008 = 0.25, x 150 x avg_fade(0.3) ≈ 11 → Reinhard OK
|
|
869
|
+
float glow = 0.002 / (dist * dist + 0.008) * fade;
|
|
870
|
+
|
|
871
|
+
// Particles need to be noticeably brighter than background, use light sand + white blend
|
|
872
|
+
vec3 dustColor = mix(vec3(1.0, 0.9, 0.6), vec3(1.0, 0.95, 0.85), hash11(fi * 5.0));
|
|
873
|
+
col += dustColor * glow;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
float eyeDist = length(uv - VORTEX_CENTER);
|
|
877
|
+
float eye = smoothstep(0.06, 0.15, eyeDist);
|
|
878
|
+
|
|
879
|
+
vec3 final = bg + col * eye;
|
|
880
|
+
final = final / (1.0 + final);
|
|
881
|
+
fragColor = vec4(final, 1.0);
|
|
882
|
+
}
|
|
883
|
+
```
|
|
884
|
+
|
|
885
|
+
### Variant 7: Meteor/Trail Line Rendering (Single-Pass Stateless)
|
|
886
|
+
|
|
887
|
+
Meteors, magic projectiles, etc. need elongated glow (stretched luminous lines). **Do not use `1/(distPerp² + tiny_epsilon)` for lines** — too-small epsilon makes line centers extremely bright and washed out. Use `exp(-dist)` or `smoothstep` for safe line glow.
|
|
888
|
+
|
|
889
|
+
**IMPORTANT: Common meteor failures**: (1) Star background too dark to see — must call `starField()` above and ensure stars use Gaussian dots `exp(-dist²*k)` for rendering (2) Meteor trail too faint — `core` multiplier should be at least 0.15, each step after dividing by `NUM_TRAIL_STEPS` still needs >= 0.005 contribution
|
|
890
|
+
|
|
891
|
+
```glsl
|
|
892
|
+
#define NUM_METEORS 6
|
|
893
|
+
#define NUM_TRAIL_STEPS 20
|
|
894
|
+
|
|
895
|
+
void main() {
|
|
896
|
+
vec2 uv = (gl_FragCoord.xy - 0.5 * iResolution.xy) / iResolution.y;
|
|
897
|
+
float t = iTime;
|
|
898
|
+
|
|
899
|
+
// Deep blue night sky background + must call starField to draw stars
|
|
900
|
+
vec3 col = vec3(0.005, 0.005, 0.02);
|
|
901
|
+
col += starField(uv);
|
|
902
|
+
|
|
903
|
+
for (int m = 0; m < NUM_METEORS; m++) {
|
|
904
|
+
float fm = float(m);
|
|
905
|
+
float cycleTime = mix(3.0, 7.0, hash11(fm * 17.3));
|
|
906
|
+
float meteorTime = mod(t - hash11(fm * 23.7) * cycleTime, cycleTime);
|
|
907
|
+
float travelDuration = mix(0.5, 1.2, hash11(fm * 31.1));
|
|
908
|
+
|
|
909
|
+
if (meteorTime > travelDuration + 0.3) continue;
|
|
910
|
+
|
|
911
|
+
float angle = mix(-0.4, -1.3, hash11(fm * 41.3));
|
|
912
|
+
vec2 dir = normalize(vec2(cos(angle), sin(angle)));
|
|
913
|
+
vec2 startPos = vec2(
|
|
914
|
+
mix(-0.3, 0.8, hash11(fm * 53.7)),
|
|
915
|
+
mix(0.2, 0.7, hash11(fm * 61.1))
|
|
916
|
+
);
|
|
917
|
+
float speed = mix(1.0, 2.0, hash11(fm * 71.3));
|
|
918
|
+
float headT = clamp(meteorTime / travelDuration, 0.0, 1.0);
|
|
919
|
+
vec2 headPos = startPos + dir * speed * headT;
|
|
920
|
+
|
|
921
|
+
float headFade = smoothstep(0.0, 0.1, meteorTime)
|
|
922
|
+
* smoothstep(travelDuration + 0.3, travelDuration, meteorTime);
|
|
923
|
+
|
|
924
|
+
float trailLen = mix(0.15, 0.35, hash11(fm * 83.7));
|
|
925
|
+
|
|
926
|
+
for (int s = 0; s < NUM_TRAIL_STEPS; s++) {
|
|
927
|
+
float sf = float(s) / float(NUM_TRAIL_STEPS);
|
|
928
|
+
vec2 samplePos = headPos - dir * trailLen * sf;
|
|
929
|
+
vec2 rel = uv - samplePos;
|
|
930
|
+
|
|
931
|
+
float distPerp = abs(dot(rel, vec2(-dir.y, dir.x)));
|
|
932
|
+
|
|
933
|
+
// Line width: narrow at head, wide at tail
|
|
934
|
+
float width = mix(0.003, 0.015, sf);
|
|
935
|
+
// core multiplier 0.15 ensures trail is visible even under SwiftShader
|
|
936
|
+
float core = exp(-distPerp / width) * 0.15;
|
|
937
|
+
|
|
938
|
+
float trailFade = (1.0 - sf) * (1.0 - sf);
|
|
939
|
+
float intensity = core * trailFade * headFade / float(NUM_TRAIL_STEPS);
|
|
940
|
+
|
|
941
|
+
float hue = mix(0.05, 0.12, sf);
|
|
942
|
+
vec3 meteorCol = hsv2rgb(vec3(hue, mix(0.1, 0.4, sf), 1.0));
|
|
943
|
+
col += meteorCol * intensity;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// Meteor head: bright point
|
|
947
|
+
float headDist = length(uv - headPos);
|
|
948
|
+
float headGlow = headFade * 0.005 / (headDist * headDist + 0.0008);
|
|
949
|
+
col += vec3(1.0, 0.95, 0.85) * headGlow;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
col = col / (1.0 + col);
|
|
953
|
+
col = pow(col, vec3(0.95));
|
|
954
|
+
fragColor = vec4(col, 1.0);
|
|
955
|
+
}
|
|
956
|
+
```
|
|
957
|
+
|
|
958
|
+
### Variant 8: Fountain/Upward Jet Particle System (Single-Pass Stateless)
|
|
959
|
+
|
|
960
|
+
Water/sparks jetting upward from a point, parabolic descent. Key: **Particles must be sharp, individually visible points** (small epsilon), not just a diffuse glow blob. Must include: (1) main water column particles (upward jet + parabola) (2) splash particles (spread sideways after hitting water) (3) water surface/pool visuals.
|
|
961
|
+
|
|
962
|
+
**IMPORTANT: Most common fountain failure**: Only produces blurry glow without visible individual water droplet trajectories! Must use small epsilon (<=0.002) so each particle is clearly visible as an individual light point. Numerator must also be proportionally reduced to control total brightness.
|
|
963
|
+
|
|
964
|
+
```glsl
|
|
965
|
+
#define NUM_WATER 60
|
|
966
|
+
#define NUM_SPLASH 40
|
|
967
|
+
#define FOUNTAIN_BASE vec2(0.0, -0.3)
|
|
968
|
+
#define WATER_LEVEL -0.3
|
|
969
|
+
|
|
970
|
+
void main() {
|
|
971
|
+
vec2 uv = (gl_FragCoord.xy - 0.5 * iResolution.xy) / iResolution.y;
|
|
972
|
+
float t = iTime;
|
|
973
|
+
|
|
974
|
+
// Dark background
|
|
975
|
+
vec3 col = vec3(0.01, 0.02, 0.06);
|
|
976
|
+
|
|
977
|
+
// --- Water pool/surface ---
|
|
978
|
+
float waterDist = abs(uv.y - WATER_LEVEL);
|
|
979
|
+
float waterLine = smoothstep(0.01, 0.0, waterDist) * 0.3;
|
|
980
|
+
float waterBody = smoothstep(WATER_LEVEL, WATER_LEVEL - 0.15, uv.y);
|
|
981
|
+
col += vec3(0.02, 0.06, 0.12) * waterBody;
|
|
982
|
+
col += vec3(0.3, 0.5, 0.7) * waterLine;
|
|
983
|
+
|
|
984
|
+
// --- Main water column particles: upward jet + parabola ---
|
|
985
|
+
for (int i = 0; i < NUM_WATER; i++) {
|
|
986
|
+
float fi = float(i);
|
|
987
|
+
float lifetime = mix(1.0, 2.0, hash11(fi * 3.7));
|
|
988
|
+
float age = mod(t - hash11(fi * 2.3) * lifetime, lifetime);
|
|
989
|
+
float norm = age / lifetime;
|
|
990
|
+
|
|
991
|
+
float spreadAngle = (hash11(fi * 7.3) - 0.5) * 0.6;
|
|
992
|
+
float speed = mix(0.9, 1.6, hash11(fi * 11.0));
|
|
993
|
+
vec2 vel0 = vec2(sin(spreadAngle), cos(spreadAngle)) * speed;
|
|
994
|
+
|
|
995
|
+
vec2 pos = FOUNTAIN_BASE + vel0 * age + vec2(0.0, -1.8) * age * age;
|
|
996
|
+
|
|
997
|
+
if (pos.y < WATER_LEVEL - 0.02) continue;
|
|
998
|
+
|
|
999
|
+
vec2 rel = uv - pos;
|
|
1000
|
+
float dist = length(rel);
|
|
1001
|
+
|
|
1002
|
+
float fade = smoothstep(0.0, 0.05, norm) * smoothstep(1.0, 0.6, norm);
|
|
1003
|
+
// Sharp light point: small epsilon makes each particle clearly visible as an individual dot
|
|
1004
|
+
// peak = 0.004/0.0015 = 2.67, x 60 x avg_fade(0.25) ≈ 40 → Reinhard OK
|
|
1005
|
+
float glow = 0.004 / (dist * dist + 0.0015) * fade;
|
|
1006
|
+
|
|
1007
|
+
vec3 waterCol = mix(vec3(0.5, 0.8, 1.0), vec3(0.9, 0.97, 1.0), hash11(fi * 5.0));
|
|
1008
|
+
col += waterCol * glow;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// --- Splash particles: spread sideways at water surface ---
|
|
1012
|
+
for (int i = 0; i < NUM_SPLASH; i++) {
|
|
1013
|
+
float fi = float(i) + 200.0;
|
|
1014
|
+
float lifetime = mix(0.3, 0.8, hash11(fi * 3.7));
|
|
1015
|
+
float age = mod(t - hash11(fi * 2.3) * lifetime, lifetime);
|
|
1016
|
+
float norm = age / lifetime;
|
|
1017
|
+
|
|
1018
|
+
float xOffset = (hash11(fi * 7.3) - 0.5) * 0.5;
|
|
1019
|
+
vec2 splashBase = vec2(xOffset, WATER_LEVEL);
|
|
1020
|
+
float splashAngle = (hash11(fi * 11.0) - 0.5) * 2.5;
|
|
1021
|
+
float splashSpeed = mix(0.2, 0.5, hash11(fi * 13.0));
|
|
1022
|
+
vec2 splashVel = vec2(sin(splashAngle), abs(cos(splashAngle))) * splashSpeed;
|
|
1023
|
+
|
|
1024
|
+
vec2 pos = splashBase + splashVel * age + vec2(0.0, -2.0) * age * age;
|
|
1025
|
+
if (pos.y < WATER_LEVEL - 0.01) continue;
|
|
1026
|
+
|
|
1027
|
+
vec2 rel = uv - pos;
|
|
1028
|
+
float dist = length(rel);
|
|
1029
|
+
|
|
1030
|
+
float fade = smoothstep(0.0, 0.05, norm) * smoothstep(1.0, 0.3, norm);
|
|
1031
|
+
float glow = 0.002 / (dist * dist + 0.001) * fade;
|
|
1032
|
+
|
|
1033
|
+
col += vec3(0.7, 0.85, 1.0) * glow;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
col = col / (1.0 + col);
|
|
1037
|
+
fragColor = vec4(col, 1.0);
|
|
1038
|
+
}
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1041
|
+
### Variant 9: Campfire/Flame Particle System (Single-Pass Stateless)
|
|
1042
|
+
|
|
1043
|
+
Flame effects must include **two layers**: (1) smooth flame body at the base (noise-driven cone gradient) (2) many **discrete ember/spark particles** above, drifting upward and gradually extinguishing. Using only a smooth gradient will be judged as "no particle system."
|
|
1044
|
+
|
|
1045
|
+
**IMPORTANT: Most common flame failure**: Only draws a smooth gradient without discrete particles! Must have NUM_SPARKS individual point-like particles drifting out from the flame top.
|
|
1046
|
+
|
|
1047
|
+
```glsl
|
|
1048
|
+
#define NUM_SPARKS 60
|
|
1049
|
+
#define FIRE_BASE vec2(0.0, -0.35)
|
|
1050
|
+
|
|
1051
|
+
float noise(vec2 p) {
|
|
1052
|
+
vec2 i = floor(p);
|
|
1053
|
+
vec2 f = fract(p);
|
|
1054
|
+
f = f * f * (3.0 - 2.0 * f);
|
|
1055
|
+
float a = hash11(dot(i, vec2(127.1, 311.7)));
|
|
1056
|
+
float b = hash11(dot(i + vec2(1.0, 0.0), vec2(127.1, 311.7)));
|
|
1057
|
+
float c = hash11(dot(i + vec2(0.0, 1.0), vec2(127.1, 311.7)));
|
|
1058
|
+
float d = hash11(dot(i + vec2(1.0, 1.0), vec2(127.1, 311.7)));
|
|
1059
|
+
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
void main() {
|
|
1063
|
+
vec2 uv = (gl_FragCoord.xy - 0.5 * iResolution.xy) / iResolution.y;
|
|
1064
|
+
float t = iTime;
|
|
1065
|
+
vec3 col = vec3(0.02, 0.01, 0.01);
|
|
1066
|
+
|
|
1067
|
+
// --- Layer 1: flame body (smooth noise cone) ---
|
|
1068
|
+
vec2 fireUV = uv - FIRE_BASE;
|
|
1069
|
+
float fireH = clamp(fireUV.y / 0.5, 0.0, 1.0);
|
|
1070
|
+
float width = mix(0.15, 0.01, fireH);
|
|
1071
|
+
float n = noise(vec2(fireUV.x * 6.0, fireUV.y * 4.0 - t * 3.0));
|
|
1072
|
+
float flameShape = smoothstep(width, 0.0, abs(fireUV.x + (n - 0.5) * 0.08))
|
|
1073
|
+
* smoothstep(-0.02, 0.05, fireUV.y)
|
|
1074
|
+
* smoothstep(0.55, 0.0, fireUV.y);
|
|
1075
|
+
vec3 innerCol = vec3(1.0, 0.95, 0.7);
|
|
1076
|
+
vec3 outerCol = vec3(1.0, 0.35, 0.05);
|
|
1077
|
+
vec3 flameCol = mix(outerCol, innerCol, smoothstep(0.3, 0.8, flameShape));
|
|
1078
|
+
col += flameCol * flameShape * 1.5;
|
|
1079
|
+
|
|
1080
|
+
// --- Layer 2: discrete ember particles (required!) ---
|
|
1081
|
+
for (int i = 0; i < NUM_SPARKS; i++) {
|
|
1082
|
+
float fi = float(i);
|
|
1083
|
+
float lifetime = mix(0.8, 2.0, hash11(fi * 3.7));
|
|
1084
|
+
float age = mod(t - hash11(fi * 2.3) * lifetime, lifetime);
|
|
1085
|
+
float norm = age / lifetime;
|
|
1086
|
+
|
|
1087
|
+
float xSpread = (hash11(fi * 7.3) - 0.5) * 0.2;
|
|
1088
|
+
float riseSpeed = mix(0.3, 0.7, hash11(fi * 11.0));
|
|
1089
|
+
float wobble = sin(t * 3.0 + fi * 2.7) * 0.03 * norm;
|
|
1090
|
+
vec2 sparkPos = FIRE_BASE + vec2(0.0, 0.25)
|
|
1091
|
+
+ vec2(xSpread + wobble, riseSpeed * age);
|
|
1092
|
+
|
|
1093
|
+
vec2 rel = uv - sparkPos;
|
|
1094
|
+
float dist = length(rel);
|
|
1095
|
+
|
|
1096
|
+
float fade = smoothstep(0.0, 0.1, norm) * smoothstep(1.0, 0.3, norm);
|
|
1097
|
+
// peak = 0.003/0.0008 = 3.75, x 60 x avg_fade(0.2) ≈ 45 → Reinhard OK
|
|
1098
|
+
float glow = 0.003 / (dist * dist + 0.0008) * fade;
|
|
1099
|
+
|
|
1100
|
+
float hue = mix(0.03, 0.12, norm);
|
|
1101
|
+
vec3 sparkCol = hsv2rgb(vec3(hue, mix(0.9, 0.3, norm), 1.0));
|
|
1102
|
+
col += sparkCol * glow;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
col = col / (1.0 + col);
|
|
1106
|
+
col = pow(col, vec3(0.95));
|
|
1107
|
+
fragColor = vec4(col, 1.0);
|
|
1108
|
+
}
|
|
1109
|
+
```
|
|
1110
|
+
|
|
1111
|
+
### Variant 10: Spiral Array/Magic Particle System (Single-Pass Stateless)
|
|
1112
|
+
|
|
1113
|
+
Magic effects, spiral ascent, magic circles, etc. require particles arranged in **geometric arrays** with **iridescent shimmer**. Key: particles must be individually visible glowing points (not a blurry glow blob), and the spiral structure must be clearly discernible.
|
|
1114
|
+
|
|
1115
|
+
**IMPORTANT: Most common magic failure**: Only produces a blob of blurry light (diffuse glow blob) without visible individual particles or geometric structure! Ensure each particle is an independently visible small light point, and the overall arrangement forms spiral/ring/other geometric shapes. Reduce epsilon to make each particle sharper (small light dot) rather than a large blurry halo.
|
|
1116
|
+
|
|
1117
|
+
```glsl
|
|
1118
|
+
#define NUM_SPIRAL 80
|
|
1119
|
+
#define NUM_RING 40
|
|
1120
|
+
#define WAND_TIP vec2(0.0, -0.15)
|
|
1121
|
+
|
|
1122
|
+
void main() {
|
|
1123
|
+
vec2 uv = (gl_FragCoord.xy - 0.5 * iResolution.xy) / iResolution.y;
|
|
1124
|
+
float t = iTime;
|
|
1125
|
+
vec3 col = vec3(0.01, 0.005, 0.02);
|
|
1126
|
+
|
|
1127
|
+
// --- Layer 1: spiral ascending particles (emanating from emission point) ---
|
|
1128
|
+
for (int i = 0; i < NUM_SPIRAL; i++) {
|
|
1129
|
+
float fi = float(i);
|
|
1130
|
+
float lifetime = mix(2.0, 4.0, hash11(fi * 3.7));
|
|
1131
|
+
float age = mod(t - hash11(fi * 2.3) * lifetime, lifetime);
|
|
1132
|
+
float norm = age / lifetime;
|
|
1133
|
+
|
|
1134
|
+
// Spiral trajectory: angle increases with time and height
|
|
1135
|
+
float baseAngle = fi / float(NUM_SPIRAL) * 6.2832 * 3.0;
|
|
1136
|
+
float spiralAngle = baseAngle + norm * 8.0 + t * 1.5;
|
|
1137
|
+
float radius = 0.05 + norm * 0.25;
|
|
1138
|
+
float height = norm * 0.7;
|
|
1139
|
+
|
|
1140
|
+
vec2 pos = WAND_TIP + vec2(cos(spiralAngle) * radius, height);
|
|
1141
|
+
|
|
1142
|
+
vec2 rel = uv - pos;
|
|
1143
|
+
float dist = length(rel);
|
|
1144
|
+
|
|
1145
|
+
float fade = smoothstep(0.0, 0.08, norm) * smoothstep(1.0, 0.4, norm);
|
|
1146
|
+
// Sharp small light point: small epsilon makes particles clearly visible as individual dots
|
|
1147
|
+
// peak = 0.004/0.0006 = 6.67, x 80 x avg_fade(0.25) ≈ 133 → Reinhard OK
|
|
1148
|
+
float glow = 0.004 / (dist * dist + 0.0006) * fade;
|
|
1149
|
+
|
|
1150
|
+
// Iridescent effect: hue varies with particle ID + time, producing rainbow shimmer
|
|
1151
|
+
float hue = fract(fi / float(NUM_SPIRAL) + t * 0.3 + norm * 0.5);
|
|
1152
|
+
float shimmer = 0.7 + 0.3 * sin(t * 8.0 + fi * 3.7);
|
|
1153
|
+
vec3 pCol = hsv2rgb(vec3(hue, 0.7, 1.0)) * shimmer;
|
|
1154
|
+
col += pCol * glow;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
// --- Layer 2: magic circle ring (horizontally rotating light point ring) ---
|
|
1158
|
+
float ringY = WAND_TIP.y + 0.45;
|
|
1159
|
+
float ringRadius = 0.2 + 0.03 * sin(t * 2.0);
|
|
1160
|
+
for (int i = 0; i < NUM_RING; i++) {
|
|
1161
|
+
float fi = float(i);
|
|
1162
|
+
float angle = fi / float(NUM_RING) * 6.2832 + t * 2.0;
|
|
1163
|
+
// Simulated perspective: ellipse (cos full width, sin compressed)
|
|
1164
|
+
vec2 ringPos = vec2(cos(angle) * ringRadius, ringY + sin(angle) * ringRadius * 0.3);
|
|
1165
|
+
|
|
1166
|
+
vec2 rel = uv - ringPos;
|
|
1167
|
+
float dist = length(rel);
|
|
1168
|
+
|
|
1169
|
+
float pulse = 0.6 + 0.4 * sin(t * 5.0 + fi * 1.5);
|
|
1170
|
+
// peak = 0.003/0.0004 = 7.5, x 40 x avg_pulse(0.6) ≈ 180 → Reinhard OK
|
|
1171
|
+
float glow = 0.003 / (dist * dist + 0.0004) * pulse;
|
|
1172
|
+
|
|
1173
|
+
float hue = fract(fi / float(NUM_RING) + t * 0.5);
|
|
1174
|
+
vec3 rCol = hsv2rgb(vec3(hue, 0.6, 1.0));
|
|
1175
|
+
col += rCol * glow;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
col = col / (1.0 + col);
|
|
1179
|
+
col = pow(col, vec3(0.9));
|
|
1180
|
+
fragColor = vec4(col, 1.0);
|
|
1181
|
+
}
|
|
1182
|
+
```
|
|
1183
|
+
|
|
1184
|
+
## Performance & Composition
|
|
1185
|
+
|
|
1186
|
+
**Performance**:
|
|
1187
|
+
- Particle count is the biggest performance lever; use early exit `if (dist > threshold) continue;` for optimization
|
|
1188
|
+
- Frame feedback trails (`prev * 0.95 + current`) can achieve high visual density with fewer particles
|
|
1189
|
+
- N-body O(N²) interaction: reduce to O(1) neighbor queries using spatial grid partitioning or Voronoi tracking
|
|
1190
|
+
- High-speed particles use sub-frame stepping to eliminate trajectory gaps
|
|
1191
|
+
- Velocity/acceleration need clamp to prevent numerical explosion; Verlet is more stable than Euler
|
|
1192
|
+
-
|
|
1193
|
+
|
|
1194
|
+
**Composition**:
|
|
1195
|
+
- **Raymarching**: sample particle density during march steps, or particles in separate Buffer then composited
|
|
1196
|
+
- **Noise / Flow Field**: use noise gradients to drive particle velocity, producing organic flow effects
|
|
1197
|
+
- **Post-Processing**: Bloom (Gaussian blur overlay), chromatic aberration, Reinhard tone mapping
|
|
1198
|
+
- **SDF shapes**: rotate local coordinates based on velocity direction to render fish/droplet specific shapes
|
|
1199
|
+
- **Voronoi acceleration**: large-scale particles use Voronoi tracking, reducing rendering and physics queries from O(N) to O(1)
|
|
1200
|
+
|
|
1201
|
+
## Further Reading
|
|
1202
|
+
|
|
1203
|
+
Full step-by-step tutorial, mathematical derivations, and advanced usage in [reference](../reference/particle-system.md)
|