@wazir-dev/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +111 -0
- package/CHANGELOG.md +14 -0
- package/CONTRIBUTING.md +101 -0
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/assets/composition-engine.mmd +34 -0
- package/assets/demo-script.sh +17 -0
- package/assets/logo-dark.svg +14 -0
- package/assets/logo.svg +14 -0
- package/assets/pipeline.mmd +39 -0
- package/assets/record-demo.sh +51 -0
- package/docs/README.md +51 -0
- package/docs/adapters/context-mode.md +60 -0
- package/docs/concepts/architecture.md +87 -0
- package/docs/concepts/artifact-model.md +60 -0
- package/docs/concepts/composition-engine.md +36 -0
- package/docs/concepts/indexing-and-recall.md +160 -0
- package/docs/concepts/observability.md +41 -0
- package/docs/concepts/roles-and-workflows.md +59 -0
- package/docs/concepts/terminology-policy.md +27 -0
- package/docs/getting-started/01-installation.md +78 -0
- package/docs/getting-started/02-first-run.md +102 -0
- package/docs/getting-started/03-adding-to-project.md +15 -0
- package/docs/getting-started/04-host-setup.md +15 -0
- package/docs/guides/ci-integration.md +15 -0
- package/docs/guides/creating-skills.md +15 -0
- package/docs/guides/expertise-module-authoring.md +15 -0
- package/docs/guides/hook-development.md +15 -0
- package/docs/guides/memory-and-learnings.md +34 -0
- package/docs/guides/multi-host-export.md +15 -0
- package/docs/guides/troubleshooting.md +101 -0
- package/docs/guides/writing-custom-roles.md +15 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-design.md +592 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-plan.md +598 -0
- package/docs/plans/2026-03-15-docs-enforcement-plan.md +238 -0
- package/docs/readmes/INDEX.md +99 -0
- package/docs/readmes/features/expertise/README.md +171 -0
- package/docs/readmes/features/exports/README.md +222 -0
- package/docs/readmes/features/hooks/README.md +103 -0
- package/docs/readmes/features/hooks/loop-cap-guard.md +133 -0
- package/docs/readmes/features/hooks/post-tool-capture.md +121 -0
- package/docs/readmes/features/hooks/post-tool-lint.md +130 -0
- package/docs/readmes/features/hooks/pre-compact-summary.md +122 -0
- package/docs/readmes/features/hooks/pre-tool-capture-route.md +100 -0
- package/docs/readmes/features/hooks/protected-path-write-guard.md +128 -0
- package/docs/readmes/features/hooks/session-start.md +119 -0
- package/docs/readmes/features/hooks/stop-handoff-harvest.md +125 -0
- package/docs/readmes/features/roles/README.md +157 -0
- package/docs/readmes/features/roles/clarifier.md +152 -0
- package/docs/readmes/features/roles/content-author.md +190 -0
- package/docs/readmes/features/roles/designer.md +193 -0
- package/docs/readmes/features/roles/executor.md +184 -0
- package/docs/readmes/features/roles/learner.md +210 -0
- package/docs/readmes/features/roles/planner.md +182 -0
- package/docs/readmes/features/roles/researcher.md +164 -0
- package/docs/readmes/features/roles/reviewer.md +184 -0
- package/docs/readmes/features/roles/specifier.md +162 -0
- package/docs/readmes/features/roles/verifier.md +215 -0
- package/docs/readmes/features/schemas/README.md +178 -0
- package/docs/readmes/features/skills/README.md +63 -0
- package/docs/readmes/features/skills/brainstorming.md +96 -0
- package/docs/readmes/features/skills/debugging.md +148 -0
- package/docs/readmes/features/skills/design.md +120 -0
- package/docs/readmes/features/skills/prepare-next.md +109 -0
- package/docs/readmes/features/skills/run-audit.md +159 -0
- package/docs/readmes/features/skills/scan-project.md +109 -0
- package/docs/readmes/features/skills/self-audit.md +176 -0
- package/docs/readmes/features/skills/tdd.md +137 -0
- package/docs/readmes/features/skills/using-skills.md +92 -0
- package/docs/readmes/features/skills/verification.md +120 -0
- package/docs/readmes/features/skills/writing-plans.md +104 -0
- package/docs/readmes/features/tooling/README.md +320 -0
- package/docs/readmes/features/workflows/README.md +186 -0
- package/docs/readmes/features/workflows/author.md +181 -0
- package/docs/readmes/features/workflows/clarify.md +154 -0
- package/docs/readmes/features/workflows/design-review.md +171 -0
- package/docs/readmes/features/workflows/design.md +169 -0
- package/docs/readmes/features/workflows/discover.md +162 -0
- package/docs/readmes/features/workflows/execute.md +173 -0
- package/docs/readmes/features/workflows/learn.md +167 -0
- package/docs/readmes/features/workflows/plan-review.md +165 -0
- package/docs/readmes/features/workflows/plan.md +170 -0
- package/docs/readmes/features/workflows/prepare-next.md +167 -0
- package/docs/readmes/features/workflows/review.md +169 -0
- package/docs/readmes/features/workflows/run-audit.md +191 -0
- package/docs/readmes/features/workflows/spec-challenge.md +159 -0
- package/docs/readmes/features/workflows/specify.md +160 -0
- package/docs/readmes/features/workflows/verify.md +177 -0
- package/docs/readmes/packages/README.md +50 -0
- package/docs/readmes/packages/ajv.md +117 -0
- package/docs/readmes/packages/context-mode.md +118 -0
- package/docs/readmes/packages/gray-matter.md +116 -0
- package/docs/readmes/packages/node-test.md +137 -0
- package/docs/readmes/packages/yaml.md +112 -0
- package/docs/reference/configuration-reference.md +159 -0
- package/docs/reference/expertise-index.md +52 -0
- package/docs/reference/git-flow.md +43 -0
- package/docs/reference/hooks.md +87 -0
- package/docs/reference/host-exports.md +50 -0
- package/docs/reference/launch-checklist.md +172 -0
- package/docs/reference/marketplace-listings.md +76 -0
- package/docs/reference/release-process.md +34 -0
- package/docs/reference/roles-reference.md +77 -0
- package/docs/reference/skills.md +33 -0
- package/docs/reference/templates.md +29 -0
- package/docs/reference/tooling-cli.md +94 -0
- package/docs/truth-claims.yaml +222 -0
- package/expertise/PROGRESS.md +63 -0
- package/expertise/README.md +18 -0
- package/expertise/antipatterns/PROGRESS.md +56 -0
- package/expertise/antipatterns/backend/api-design-antipatterns.md +1271 -0
- package/expertise/antipatterns/backend/auth-antipatterns.md +1195 -0
- package/expertise/antipatterns/backend/caching-antipatterns.md +622 -0
- package/expertise/antipatterns/backend/database-antipatterns.md +1038 -0
- package/expertise/antipatterns/backend/index.md +24 -0
- package/expertise/antipatterns/backend/microservices-antipatterns.md +850 -0
- package/expertise/antipatterns/code/architecture-antipatterns.md +919 -0
- package/expertise/antipatterns/code/async-antipatterns.md +622 -0
- package/expertise/antipatterns/code/code-smells.md +1186 -0
- package/expertise/antipatterns/code/dependency-antipatterns.md +1209 -0
- package/expertise/antipatterns/code/error-handling-antipatterns.md +1360 -0
- package/expertise/antipatterns/code/index.md +27 -0
- package/expertise/antipatterns/code/naming-and-abstraction.md +1118 -0
- package/expertise/antipatterns/code/state-management-antipatterns.md +1076 -0
- package/expertise/antipatterns/code/testing-antipatterns.md +1053 -0
- package/expertise/antipatterns/design/accessibility-antipatterns.md +1136 -0
- package/expertise/antipatterns/design/dark-patterns.md +1121 -0
- package/expertise/antipatterns/design/index.md +22 -0
- package/expertise/antipatterns/design/ui-antipatterns.md +1202 -0
- package/expertise/antipatterns/design/ux-antipatterns.md +680 -0
- package/expertise/antipatterns/frontend/css-layout-antipatterns.md +691 -0
- package/expertise/antipatterns/frontend/flutter-antipatterns.md +1827 -0
- package/expertise/antipatterns/frontend/index.md +23 -0
- package/expertise/antipatterns/frontend/mobile-antipatterns.md +573 -0
- package/expertise/antipatterns/frontend/react-antipatterns.md +1128 -0
- package/expertise/antipatterns/frontend/spa-antipatterns.md +1235 -0
- package/expertise/antipatterns/index.md +31 -0
- package/expertise/antipatterns/performance/index.md +20 -0
- package/expertise/antipatterns/performance/performance-antipatterns.md +1013 -0
- package/expertise/antipatterns/performance/premature-optimization.md +623 -0
- package/expertise/antipatterns/performance/scaling-antipatterns.md +785 -0
- package/expertise/antipatterns/process/ai-coding-antipatterns.md +853 -0
- package/expertise/antipatterns/process/code-review-antipatterns.md +656 -0
- package/expertise/antipatterns/process/deployment-antipatterns.md +920 -0
- package/expertise/antipatterns/process/index.md +23 -0
- package/expertise/antipatterns/process/technical-debt-antipatterns.md +647 -0
- package/expertise/antipatterns/security/index.md +20 -0
- package/expertise/antipatterns/security/secrets-antipatterns.md +849 -0
- package/expertise/antipatterns/security/security-theater.md +843 -0
- package/expertise/antipatterns/security/vulnerability-patterns.md +801 -0
- package/expertise/architecture/PROGRESS.md +70 -0
- package/expertise/architecture/data/caching-architecture.md +671 -0
- package/expertise/architecture/data/data-consistency.md +574 -0
- package/expertise/architecture/data/data-modeling.md +536 -0
- package/expertise/architecture/data/event-streams-and-queues.md +634 -0
- package/expertise/architecture/data/index.md +25 -0
- package/expertise/architecture/data/search-architecture.md +663 -0
- package/expertise/architecture/data/sql-vs-nosql.md +708 -0
- package/expertise/architecture/decisions/architecture-decision-records.md +640 -0
- package/expertise/architecture/decisions/build-vs-buy.md +616 -0
- package/expertise/architecture/decisions/index.md +23 -0
- package/expertise/architecture/decisions/monolith-to-microservices.md +790 -0
- package/expertise/architecture/decisions/technology-selection.md +616 -0
- package/expertise/architecture/distributed/cap-theorem-and-tradeoffs.md +800 -0
- package/expertise/architecture/distributed/circuit-breaker-bulkhead.md +741 -0
- package/expertise/architecture/distributed/consensus-and-coordination.md +796 -0
- package/expertise/architecture/distributed/distributed-systems-fundamentals.md +564 -0
- package/expertise/architecture/distributed/idempotency-and-retry.md +796 -0
- package/expertise/architecture/distributed/index.md +25 -0
- package/expertise/architecture/distributed/saga-pattern.md +797 -0
- package/expertise/architecture/foundations/architectural-thinking.md +460 -0
- package/expertise/architecture/foundations/coupling-and-cohesion.md +770 -0
- package/expertise/architecture/foundations/design-principles-solid.md +649 -0
- package/expertise/architecture/foundations/domain-driven-design.md +719 -0
- package/expertise/architecture/foundations/index.md +25 -0
- package/expertise/architecture/foundations/separation-of-concerns.md +472 -0
- package/expertise/architecture/foundations/twelve-factor-app.md +797 -0
- package/expertise/architecture/index.md +34 -0
- package/expertise/architecture/integration/api-design-graphql.md +638 -0
- package/expertise/architecture/integration/api-design-grpc.md +804 -0
- package/expertise/architecture/integration/api-design-rest.md +892 -0
- package/expertise/architecture/integration/index.md +25 -0
- package/expertise/architecture/integration/third-party-integration.md +795 -0
- package/expertise/architecture/integration/webhooks-and-callbacks.md +1152 -0
- package/expertise/architecture/integration/websockets-realtime.md +791 -0
- package/expertise/architecture/mobile-architecture/index.md +22 -0
- package/expertise/architecture/mobile-architecture/mobile-app-architecture.md +780 -0
- package/expertise/architecture/mobile-architecture/mobile-backend-for-frontend.md +670 -0
- package/expertise/architecture/mobile-architecture/offline-first.md +719 -0
- package/expertise/architecture/mobile-architecture/push-and-sync.md +782 -0
- package/expertise/architecture/patterns/cqrs-event-sourcing.md +717 -0
- package/expertise/architecture/patterns/event-driven.md +797 -0
- package/expertise/architecture/patterns/hexagonal-clean-architecture.md +870 -0
- package/expertise/architecture/patterns/index.md +27 -0
- package/expertise/architecture/patterns/layered-architecture.md +736 -0
- package/expertise/architecture/patterns/microservices.md +753 -0
- package/expertise/architecture/patterns/modular-monolith.md +692 -0
- package/expertise/architecture/patterns/monolith.md +626 -0
- package/expertise/architecture/patterns/plugin-architecture.md +735 -0
- package/expertise/architecture/patterns/serverless.md +780 -0
- package/expertise/architecture/scaling/database-scaling.md +615 -0
- package/expertise/architecture/scaling/feature-flags-and-rollouts.md +757 -0
- package/expertise/architecture/scaling/horizontal-vs-vertical.md +606 -0
- package/expertise/architecture/scaling/index.md +24 -0
- package/expertise/architecture/scaling/multi-tenancy.md +800 -0
- package/expertise/architecture/scaling/stateless-design.md +787 -0
- package/expertise/backend/embedded-firmware.md +625 -0
- package/expertise/backend/go.md +853 -0
- package/expertise/backend/index.md +24 -0
- package/expertise/backend/java-spring.md +448 -0
- package/expertise/backend/node-typescript.md +625 -0
- package/expertise/backend/python-fastapi.md +724 -0
- package/expertise/backend/rust.md +458 -0
- package/expertise/backend/solidity.md +711 -0
- package/expertise/composition-map.yaml +443 -0
- package/expertise/content/foundations/content-modeling.md +395 -0
- package/expertise/content/foundations/editorial-standards.md +449 -0
- package/expertise/content/foundations/index.md +24 -0
- package/expertise/content/foundations/microcopy.md +455 -0
- package/expertise/content/foundations/terminology-governance.md +509 -0
- package/expertise/content/index.md +34 -0
- package/expertise/content/patterns/accessibility-copy.md +518 -0
- package/expertise/content/patterns/index.md +24 -0
- package/expertise/content/patterns/notification-content.md +433 -0
- package/expertise/content/patterns/sample-content.md +486 -0
- package/expertise/content/patterns/state-copy.md +439 -0
- package/expertise/design/PROGRESS.md +58 -0
- package/expertise/design/disciplines/dark-mode-theming.md +577 -0
- package/expertise/design/disciplines/design-systems.md +595 -0
- package/expertise/design/disciplines/index.md +25 -0
- package/expertise/design/disciplines/information-architecture.md +800 -0
- package/expertise/design/disciplines/interaction-design.md +788 -0
- package/expertise/design/disciplines/responsive-design.md +552 -0
- package/expertise/design/disciplines/usability-testing.md +516 -0
- package/expertise/design/disciplines/user-research.md +792 -0
- package/expertise/design/foundations/accessibility-design.md +796 -0
- package/expertise/design/foundations/color-theory.md +797 -0
- package/expertise/design/foundations/iconography.md +795 -0
- package/expertise/design/foundations/index.md +26 -0
- package/expertise/design/foundations/motion-and-animation.md +653 -0
- package/expertise/design/foundations/rtl-design.md +585 -0
- package/expertise/design/foundations/spacing-and-layout.md +607 -0
- package/expertise/design/foundations/typography.md +800 -0
- package/expertise/design/foundations/visual-hierarchy.md +761 -0
- package/expertise/design/index.md +32 -0
- package/expertise/design/patterns/authentication-flows.md +474 -0
- package/expertise/design/patterns/content-consumption.md +789 -0
- package/expertise/design/patterns/data-display.md +618 -0
- package/expertise/design/patterns/e-commerce.md +1494 -0
- package/expertise/design/patterns/feedback-and-states.md +642 -0
- package/expertise/design/patterns/forms-and-input.md +819 -0
- package/expertise/design/patterns/gamification.md +801 -0
- package/expertise/design/patterns/index.md +31 -0
- package/expertise/design/patterns/microinteractions.md +449 -0
- package/expertise/design/patterns/navigation.md +800 -0
- package/expertise/design/patterns/notifications.md +705 -0
- package/expertise/design/patterns/onboarding.md +700 -0
- package/expertise/design/patterns/search-and-filter.md +601 -0
- package/expertise/design/patterns/settings-and-preferences.md +768 -0
- package/expertise/design/patterns/social-and-community.md +748 -0
- package/expertise/design/platforms/desktop-native.md +612 -0
- package/expertise/design/platforms/index.md +25 -0
- package/expertise/design/platforms/mobile-android.md +825 -0
- package/expertise/design/platforms/mobile-cross-platform.md +983 -0
- package/expertise/design/platforms/mobile-ios.md +699 -0
- package/expertise/design/platforms/tablet.md +794 -0
- package/expertise/design/platforms/web-dashboard.md +790 -0
- package/expertise/design/platforms/web-responsive.md +550 -0
- package/expertise/design/psychology/behavioral-nudges.md +449 -0
- package/expertise/design/psychology/cognitive-load.md +1191 -0
- package/expertise/design/psychology/error-psychology.md +778 -0
- package/expertise/design/psychology/index.md +22 -0
- package/expertise/design/psychology/persuasive-design.md +736 -0
- package/expertise/design/psychology/user-mental-models.md +623 -0
- package/expertise/design/tooling/open-pencil.md +266 -0
- package/expertise/frontend/angular.md +1073 -0
- package/expertise/frontend/desktop-electron.md +546 -0
- package/expertise/frontend/flutter.md +782 -0
- package/expertise/frontend/index.md +27 -0
- package/expertise/frontend/native-android.md +409 -0
- package/expertise/frontend/native-ios.md +490 -0
- package/expertise/frontend/react-native.md +1160 -0
- package/expertise/frontend/react.md +808 -0
- package/expertise/frontend/vue.md +1089 -0
- package/expertise/humanize/domain-rules-code.md +79 -0
- package/expertise/humanize/domain-rules-content.md +67 -0
- package/expertise/humanize/domain-rules-technical-docs.md +56 -0
- package/expertise/humanize/index.md +35 -0
- package/expertise/humanize/self-audit-checklist.md +87 -0
- package/expertise/humanize/sentence-patterns.md +218 -0
- package/expertise/humanize/vocabulary-blacklist.md +105 -0
- package/expertise/i18n/PROGRESS.md +65 -0
- package/expertise/i18n/advanced/accessibility-and-i18n.md +28 -0
- package/expertise/i18n/advanced/bidirectional-text-algorithm.md +38 -0
- package/expertise/i18n/advanced/complex-scripts.md +30 -0
- package/expertise/i18n/advanced/performance-and-i18n.md +27 -0
- package/expertise/i18n/advanced/testing-i18n.md +28 -0
- package/expertise/i18n/content/content-adaptation.md +23 -0
- package/expertise/i18n/content/locale-specific-formatting.md +23 -0
- package/expertise/i18n/content/machine-translation-integration.md +28 -0
- package/expertise/i18n/content/translation-management.md +29 -0
- package/expertise/i18n/foundations/date-time-calendars.md +67 -0
- package/expertise/i18n/foundations/i18n-architecture.md +272 -0
- package/expertise/i18n/foundations/locale-and-language-tags.md +79 -0
- package/expertise/i18n/foundations/numbers-currency-units.md +61 -0
- package/expertise/i18n/foundations/pluralization-and-gender.md +109 -0
- package/expertise/i18n/foundations/string-externalization.md +236 -0
- package/expertise/i18n/foundations/text-direction-bidi.md +241 -0
- package/expertise/i18n/foundations/unicode-and-encoding.md +86 -0
- package/expertise/i18n/index.md +38 -0
- package/expertise/i18n/platform/backend-i18n.md +31 -0
- package/expertise/i18n/platform/flutter-i18n.md +148 -0
- package/expertise/i18n/platform/native-android-i18n.md +36 -0
- package/expertise/i18n/platform/native-ios-i18n.md +36 -0
- package/expertise/i18n/platform/react-i18n.md +103 -0
- package/expertise/i18n/platform/web-css-i18n.md +81 -0
- package/expertise/i18n/rtl/arabic-specific.md +175 -0
- package/expertise/i18n/rtl/hebrew-specific.md +149 -0
- package/expertise/i18n/rtl/rtl-animations-and-transitions.md +111 -0
- package/expertise/i18n/rtl/rtl-forms-and-input.md +161 -0
- package/expertise/i18n/rtl/rtl-fundamentals.md +211 -0
- package/expertise/i18n/rtl/rtl-icons-and-images.md +181 -0
- package/expertise/i18n/rtl/rtl-layout-mirroring.md +252 -0
- package/expertise/i18n/rtl/rtl-navigation-and-gestures.md +107 -0
- package/expertise/i18n/rtl/rtl-testing-and-qa.md +147 -0
- package/expertise/i18n/rtl/rtl-typography.md +160 -0
- package/expertise/index.md +113 -0
- package/expertise/index.yaml +216 -0
- package/expertise/infrastructure/cloud-aws.md +597 -0
- package/expertise/infrastructure/cloud-gcp.md +599 -0
- package/expertise/infrastructure/cybersecurity.md +816 -0
- package/expertise/infrastructure/database-mongodb.md +447 -0
- package/expertise/infrastructure/database-postgres.md +400 -0
- package/expertise/infrastructure/devops-cicd.md +787 -0
- package/expertise/infrastructure/index.md +27 -0
- package/expertise/performance/PROGRESS.md +50 -0
- package/expertise/performance/backend/api-latency.md +1204 -0
- package/expertise/performance/backend/background-jobs.md +506 -0
- package/expertise/performance/backend/connection-pooling.md +1209 -0
- package/expertise/performance/backend/database-query-optimization.md +515 -0
- package/expertise/performance/backend/index.md +23 -0
- package/expertise/performance/backend/rate-limiting-and-throttling.md +971 -0
- package/expertise/performance/foundations/algorithmic-complexity.md +954 -0
- package/expertise/performance/foundations/caching-strategies.md +489 -0
- package/expertise/performance/foundations/concurrency-and-parallelism.md +847 -0
- package/expertise/performance/foundations/index.md +24 -0
- package/expertise/performance/foundations/measuring-and-profiling.md +440 -0
- package/expertise/performance/foundations/memory-management.md +964 -0
- package/expertise/performance/foundations/performance-budgets.md +1314 -0
- package/expertise/performance/index.md +31 -0
- package/expertise/performance/infrastructure/auto-scaling.md +1059 -0
- package/expertise/performance/infrastructure/cdn-and-edge.md +1081 -0
- package/expertise/performance/infrastructure/index.md +22 -0
- package/expertise/performance/infrastructure/load-balancing.md +1081 -0
- package/expertise/performance/infrastructure/observability.md +1079 -0
- package/expertise/performance/mobile/index.md +23 -0
- package/expertise/performance/mobile/mobile-animations.md +544 -0
- package/expertise/performance/mobile/mobile-memory-battery.md +416 -0
- package/expertise/performance/mobile/mobile-network.md +452 -0
- package/expertise/performance/mobile/mobile-rendering.md +599 -0
- package/expertise/performance/mobile/mobile-startup-time.md +505 -0
- package/expertise/performance/platform-specific/flutter-performance.md +647 -0
- package/expertise/performance/platform-specific/index.md +22 -0
- package/expertise/performance/platform-specific/node-performance.md +1307 -0
- package/expertise/performance/platform-specific/postgres-performance.md +1366 -0
- package/expertise/performance/platform-specific/react-performance.md +1403 -0
- package/expertise/performance/web/bundle-optimization.md +1239 -0
- package/expertise/performance/web/image-and-media.md +636 -0
- package/expertise/performance/web/index.md +24 -0
- package/expertise/performance/web/network-optimization.md +1133 -0
- package/expertise/performance/web/rendering-performance.md +1098 -0
- package/expertise/performance/web/ssr-and-hydration.md +918 -0
- package/expertise/performance/web/web-vitals.md +1374 -0
- package/expertise/quality/accessibility.md +985 -0
- package/expertise/quality/evidence-based-verification.md +499 -0
- package/expertise/quality/index.md +24 -0
- package/expertise/quality/ml-model-audit.md +614 -0
- package/expertise/quality/performance.md +600 -0
- package/expertise/quality/testing-api.md +891 -0
- package/expertise/quality/testing-mobile.md +496 -0
- package/expertise/quality/testing-web.md +849 -0
- package/expertise/security/PROGRESS.md +54 -0
- package/expertise/security/agentic-identity.md +540 -0
- package/expertise/security/compliance-frameworks.md +601 -0
- package/expertise/security/data/data-encryption.md +364 -0
- package/expertise/security/data/data-privacy-gdpr.md +692 -0
- package/expertise/security/data/database-security.md +1171 -0
- package/expertise/security/data/index.md +22 -0
- package/expertise/security/data/pii-handling.md +531 -0
- package/expertise/security/foundations/authentication.md +1041 -0
- package/expertise/security/foundations/authorization.md +603 -0
- package/expertise/security/foundations/cryptography.md +1001 -0
- package/expertise/security/foundations/index.md +25 -0
- package/expertise/security/foundations/owasp-top-10.md +1354 -0
- package/expertise/security/foundations/secrets-management.md +1217 -0
- package/expertise/security/foundations/secure-sdlc.md +700 -0
- package/expertise/security/foundations/supply-chain-security.md +698 -0
- package/expertise/security/index.md +31 -0
- package/expertise/security/infrastructure/cloud-security-aws.md +1296 -0
- package/expertise/security/infrastructure/cloud-security-gcp.md +1376 -0
- package/expertise/security/infrastructure/container-security.md +721 -0
- package/expertise/security/infrastructure/incident-response.md +1295 -0
- package/expertise/security/infrastructure/index.md +24 -0
- package/expertise/security/infrastructure/logging-and-monitoring.md +1618 -0
- package/expertise/security/infrastructure/network-security.md +1337 -0
- package/expertise/security/mobile/index.md +23 -0
- package/expertise/security/mobile/mobile-android-security.md +1218 -0
- package/expertise/security/mobile/mobile-binary-protection.md +1229 -0
- package/expertise/security/mobile/mobile-data-storage.md +1265 -0
- package/expertise/security/mobile/mobile-ios-security.md +1401 -0
- package/expertise/security/mobile/mobile-network-security.md +1520 -0
- package/expertise/security/smart-contract-security.md +594 -0
- package/expertise/security/testing/index.md +22 -0
- package/expertise/security/testing/penetration-testing.md +1258 -0
- package/expertise/security/testing/security-code-review.md +1765 -0
- package/expertise/security/testing/threat-modeling.md +1074 -0
- package/expertise/security/testing/vulnerability-scanning.md +1062 -0
- package/expertise/security/web/api-security.md +586 -0
- package/expertise/security/web/cors-and-headers.md +433 -0
- package/expertise/security/web/csrf.md +562 -0
- package/expertise/security/web/file-upload.md +1477 -0
- package/expertise/security/web/index.md +25 -0
- package/expertise/security/web/injection.md +1375 -0
- package/expertise/security/web/session-management.md +1101 -0
- package/expertise/security/web/xss.md +1158 -0
- package/exports/README.md +17 -0
- package/exports/hosts/claude/.claude/agents/clarifier.md +42 -0
- package/exports/hosts/claude/.claude/agents/content-author.md +63 -0
- package/exports/hosts/claude/.claude/agents/designer.md +55 -0
- package/exports/hosts/claude/.claude/agents/executor.md +55 -0
- package/exports/hosts/claude/.claude/agents/learner.md +51 -0
- package/exports/hosts/claude/.claude/agents/planner.md +53 -0
- package/exports/hosts/claude/.claude/agents/researcher.md +43 -0
- package/exports/hosts/claude/.claude/agents/reviewer.md +54 -0
- package/exports/hosts/claude/.claude/agents/specifier.md +47 -0
- package/exports/hosts/claude/.claude/agents/verifier.md +71 -0
- package/exports/hosts/claude/.claude/commands/author.md +42 -0
- package/exports/hosts/claude/.claude/commands/clarify.md +38 -0
- package/exports/hosts/claude/.claude/commands/design-review.md +46 -0
- package/exports/hosts/claude/.claude/commands/design.md +44 -0
- package/exports/hosts/claude/.claude/commands/discover.md +37 -0
- package/exports/hosts/claude/.claude/commands/execute.md +48 -0
- package/exports/hosts/claude/.claude/commands/learn.md +38 -0
- package/exports/hosts/claude/.claude/commands/plan-review.md +42 -0
- package/exports/hosts/claude/.claude/commands/plan.md +39 -0
- package/exports/hosts/claude/.claude/commands/prepare-next.md +37 -0
- package/exports/hosts/claude/.claude/commands/review.md +40 -0
- package/exports/hosts/claude/.claude/commands/run-audit.md +41 -0
- package/exports/hosts/claude/.claude/commands/spec-challenge.md +41 -0
- package/exports/hosts/claude/.claude/commands/specify.md +38 -0
- package/exports/hosts/claude/.claude/commands/verify.md +37 -0
- package/exports/hosts/claude/.claude/settings.json +34 -0
- package/exports/hosts/claude/CLAUDE.md +19 -0
- package/exports/hosts/claude/export.manifest.json +38 -0
- package/exports/hosts/claude/host-package.json +67 -0
- package/exports/hosts/codex/AGENTS.md +19 -0
- package/exports/hosts/codex/export.manifest.json +38 -0
- package/exports/hosts/codex/host-package.json +41 -0
- package/exports/hosts/cursor/.cursor/hooks.json +16 -0
- package/exports/hosts/cursor/.cursor/rules/wazir-core.mdc +19 -0
- package/exports/hosts/cursor/export.manifest.json +38 -0
- package/exports/hosts/cursor/host-package.json +42 -0
- package/exports/hosts/gemini/GEMINI.md +19 -0
- package/exports/hosts/gemini/export.manifest.json +38 -0
- package/exports/hosts/gemini/host-package.json +41 -0
- package/hooks/README.md +18 -0
- package/hooks/definitions/loop_cap_guard.yaml +21 -0
- package/hooks/definitions/post_tool_capture.yaml +24 -0
- package/hooks/definitions/pre_compact_summary.yaml +19 -0
- package/hooks/definitions/pre_tool_capture_route.yaml +19 -0
- package/hooks/definitions/protected_path_write_guard.yaml +19 -0
- package/hooks/definitions/session_start.yaml +19 -0
- package/hooks/definitions/stop_handoff_harvest.yaml +20 -0
- package/hooks/loop-cap-guard +17 -0
- package/hooks/post-tool-lint +36 -0
- package/hooks/protected-path-write-guard +17 -0
- package/hooks/session-start +41 -0
- package/llms-full.txt +2355 -0
- package/llms.txt +43 -0
- package/package.json +79 -0
- package/roles/README.md +20 -0
- package/roles/clarifier.md +42 -0
- package/roles/content-author.md +63 -0
- package/roles/designer.md +55 -0
- package/roles/executor.md +55 -0
- package/roles/learner.md +51 -0
- package/roles/planner.md +53 -0
- package/roles/researcher.md +43 -0
- package/roles/reviewer.md +54 -0
- package/roles/specifier.md +47 -0
- package/roles/verifier.md +71 -0
- package/schemas/README.md +24 -0
- package/schemas/accepted-learning.schema.json +20 -0
- package/schemas/author-artifact.schema.json +156 -0
- package/schemas/clarification.schema.json +19 -0
- package/schemas/design-artifact.schema.json +80 -0
- package/schemas/docs-claim.schema.json +18 -0
- package/schemas/export-manifest.schema.json +20 -0
- package/schemas/hook.schema.json +67 -0
- package/schemas/host-export-package.schema.json +18 -0
- package/schemas/implementation-plan.schema.json +19 -0
- package/schemas/proposed-learning.schema.json +19 -0
- package/schemas/research.schema.json +18 -0
- package/schemas/review.schema.json +29 -0
- package/schemas/run-manifest.schema.json +18 -0
- package/schemas/spec-challenge.schema.json +18 -0
- package/schemas/spec.schema.json +20 -0
- package/schemas/usage.schema.json +102 -0
- package/schemas/verification-proof.schema.json +29 -0
- package/schemas/wazir-manifest.schema.json +173 -0
- package/skills/README.md +40 -0
- package/skills/brainstorming/SKILL.md +77 -0
- package/skills/debugging/SKILL.md +50 -0
- package/skills/design/SKILL.md +61 -0
- package/skills/dispatching-parallel-agents/SKILL.md +128 -0
- package/skills/executing-plans/SKILL.md +70 -0
- package/skills/finishing-a-development-branch/SKILL.md +169 -0
- package/skills/humanize/SKILL.md +123 -0
- package/skills/init-pipeline/SKILL.md +124 -0
- package/skills/prepare-next/SKILL.md +20 -0
- package/skills/receiving-code-review/SKILL.md +123 -0
- package/skills/requesting-code-review/SKILL.md +105 -0
- package/skills/requesting-code-review/code-reviewer.md +108 -0
- package/skills/run-audit/SKILL.md +197 -0
- package/skills/scan-project/SKILL.md +41 -0
- package/skills/self-audit/SKILL.md +153 -0
- package/skills/subagent-driven-development/SKILL.md +154 -0
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
- package/skills/subagent-driven-development/implementer-prompt.md +102 -0
- package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/skills/tdd/SKILL.md +23 -0
- package/skills/using-git-worktrees/SKILL.md +163 -0
- package/skills/using-skills/SKILL.md +95 -0
- package/skills/verification/SKILL.md +22 -0
- package/skills/wazir/SKILL.md +463 -0
- package/skills/writing-plans/SKILL.md +30 -0
- package/skills/writing-skills/SKILL.md +157 -0
- package/skills/writing-skills/anthropic-best-practices.md +122 -0
- package/skills/writing-skills/persuasion-principles.md +50 -0
- package/templates/README.md +20 -0
- package/templates/artifacts/README.md +10 -0
- package/templates/artifacts/accepted-learning.md +19 -0
- package/templates/artifacts/accepted-learning.template.json +12 -0
- package/templates/artifacts/author.md +74 -0
- package/templates/artifacts/author.template.json +19 -0
- package/templates/artifacts/clarification.md +21 -0
- package/templates/artifacts/clarification.template.json +12 -0
- package/templates/artifacts/execute-notes.md +19 -0
- package/templates/artifacts/implementation-plan.md +21 -0
- package/templates/artifacts/implementation-plan.template.json +11 -0
- package/templates/artifacts/learning-proposal.md +19 -0
- package/templates/artifacts/next-run-handoff.md +21 -0
- package/templates/artifacts/plan-review.md +19 -0
- package/templates/artifacts/proposed-learning.template.json +12 -0
- package/templates/artifacts/research.md +21 -0
- package/templates/artifacts/research.template.json +12 -0
- package/templates/artifacts/review-findings.md +19 -0
- package/templates/artifacts/review.template.json +11 -0
- package/templates/artifacts/run-manifest.template.json +8 -0
- package/templates/artifacts/spec-challenge.md +19 -0
- package/templates/artifacts/spec-challenge.template.json +11 -0
- package/templates/artifacts/spec.md +21 -0
- package/templates/artifacts/spec.template.json +12 -0
- package/templates/artifacts/verification-proof.md +19 -0
- package/templates/artifacts/verification-proof.template.json +11 -0
- package/templates/examples/accepted-learning.example.json +14 -0
- package/templates/examples/author.example.json +152 -0
- package/templates/examples/clarification.example.json +15 -0
- package/templates/examples/docs-claim.example.json +8 -0
- package/templates/examples/export-manifest.example.json +7 -0
- package/templates/examples/host-export-package.example.json +11 -0
- package/templates/examples/implementation-plan.example.json +17 -0
- package/templates/examples/proposed-learning.example.json +13 -0
- package/templates/examples/research.example.json +15 -0
- package/templates/examples/research.example.md +6 -0
- package/templates/examples/review.example.json +17 -0
- package/templates/examples/run-manifest.example.json +9 -0
- package/templates/examples/spec-challenge.example.json +14 -0
- package/templates/examples/spec.example.json +21 -0
- package/templates/examples/verification-proof.example.json +21 -0
- package/templates/examples/wazir-manifest.example.yaml +65 -0
- package/templates/task-definition-schema.md +99 -0
- package/tooling/README.md +20 -0
- package/tooling/src/adapters/context-mode.js +50 -0
- package/tooling/src/capture/command.js +376 -0
- package/tooling/src/capture/store.js +99 -0
- package/tooling/src/capture/usage.js +270 -0
- package/tooling/src/checks/branches.js +50 -0
- package/tooling/src/checks/brand-truth.js +110 -0
- package/tooling/src/checks/changelog.js +231 -0
- package/tooling/src/checks/command-registry.js +36 -0
- package/tooling/src/checks/commits.js +102 -0
- package/tooling/src/checks/docs-drift.js +103 -0
- package/tooling/src/checks/docs-truth.js +201 -0
- package/tooling/src/checks/runtime-surface.js +156 -0
- package/tooling/src/cli.js +116 -0
- package/tooling/src/command-options.js +56 -0
- package/tooling/src/commands/validate.js +320 -0
- package/tooling/src/doctor/command.js +91 -0
- package/tooling/src/export/command.js +77 -0
- package/tooling/src/export/compiler.js +498 -0
- package/tooling/src/guards/loop-cap-guard.js +52 -0
- package/tooling/src/guards/protected-path-write-guard.js +67 -0
- package/tooling/src/index/command.js +152 -0
- package/tooling/src/index/storage.js +1061 -0
- package/tooling/src/index/summarizers.js +261 -0
- package/tooling/src/loaders.js +18 -0
- package/tooling/src/project-root.js +22 -0
- package/tooling/src/recall/command.js +225 -0
- package/tooling/src/schema-validator.js +30 -0
- package/tooling/src/state-root.js +40 -0
- package/tooling/src/status/command.js +71 -0
- package/wazir.manifest.yaml +135 -0
- package/workflows/README.md +19 -0
- package/workflows/author.md +42 -0
- package/workflows/clarify.md +38 -0
- package/workflows/design-review.md +46 -0
- package/workflows/design.md +44 -0
- package/workflows/discover.md +37 -0
- package/workflows/execute.md +48 -0
- package/workflows/learn.md +38 -0
- package/workflows/plan-review.md +42 -0
- package/workflows/plan.md +39 -0
- package/workflows/prepare-next.md +37 -0
- package/workflows/review.md +40 -0
- package/workflows/run-audit.md +41 -0
- package/workflows/spec-challenge.md +41 -0
- package/workflows/specify.md +38 -0
- package/workflows/verify.md +37 -0
|
@@ -0,0 +1,1098 @@
|
|
|
1
|
+
# Rendering Performance — Performance Expertise Module
|
|
2
|
+
|
|
3
|
+
> Browser rendering follows a critical pipeline: Style > Layout > Paint > Composite. Understanding which CSS properties trigger which stages is the foundation of web rendering optimization. A forced layout (reflow) can take 10-100ms, while a composite-only change takes <1ms.
|
|
4
|
+
|
|
5
|
+
> **Impact:** Critical
|
|
6
|
+
> **Applies to:** Web
|
|
7
|
+
> **Key metrics:** Frame rate (fps), Long Animation Frames (LoAF), Total Blocking Time (TBT), Layout shift count, Interaction to Next Paint (INP)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Table of Contents
|
|
12
|
+
|
|
13
|
+
1. [The Rendering Pipeline](#1-the-rendering-pipeline)
|
|
14
|
+
2. [CSS Property Costs](#2-css-property-costs)
|
|
15
|
+
3. [Layout Thrashing and Forced Synchronous Layouts](#3-layout-thrashing-and-forced-synchronous-layouts)
|
|
16
|
+
4. [CSS Containment and content-visibility](#4-css-containment-and-content-visibility)
|
|
17
|
+
5. [Virtual Scrolling for Large Lists](#5-virtual-scrolling-for-large-lists)
|
|
18
|
+
6. [Web Workers for Off-Main-Thread Computation](#6-web-workers-for-off-main-thread-computation)
|
|
19
|
+
7. [requestAnimationFrame vs setTimeout](#7-requestanimationframe-vs-settimeout)
|
|
20
|
+
8. [will-change and GPU Acceleration](#8-will-change-and-gpu-acceleration)
|
|
21
|
+
9. [DOM Size Impact](#9-dom-size-impact)
|
|
22
|
+
10. [Common Bottlenecks and Anti-Patterns](#10-common-bottlenecks-and-anti-patterns)
|
|
23
|
+
11. [Decision Trees for Rendering Issues](#11-decision-trees-for-rendering-issues)
|
|
24
|
+
12. [Measurement and Tooling](#12-measurement-and-tooling)
|
|
25
|
+
13. [Sources](#13-sources)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 1. The Rendering Pipeline
|
|
30
|
+
|
|
31
|
+
Every frame the browser produces passes through five sequential stages. At 60 fps, each frame has a budget of **16.67ms**. After browser overhead, roughly **10ms** is available for application work.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
JavaScript -> Style -> Layout -> Paint -> Composite
|
|
35
|
+
(~3ms) (~1ms) (~2-8ms) (~1-4ms) (<1ms)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Stage Breakdown
|
|
39
|
+
|
|
40
|
+
| Stage | What Happens | Typical Cost | Trigger Example |
|
|
41
|
+
|-------|-------------|-------------|-----------------|
|
|
42
|
+
| **JavaScript** | Event handlers, rAF callbacks, DOM mutations | 1-5ms | `element.style.width = '100px'` |
|
|
43
|
+
| **Style** | Selector matching, computed style calculation | 0.5-2ms | Adding/removing classes |
|
|
44
|
+
| **Layout** | Geometry calculation (position, size) for all affected elements | 2-15ms (up to 100ms+ for full-page reflow) | Changing `width`, `height`, `top`, `margin` |
|
|
45
|
+
| **Paint** | Filling pixels: text, colors, images, borders, shadows | 1-10ms | Changing `background`, `color`, `box-shadow` |
|
|
46
|
+
| **Composite** | Combining painted layers in GPU, applying transforms | <1ms | Changing `transform`, `opacity` |
|
|
47
|
+
|
|
48
|
+
### Three Pipeline Paths
|
|
49
|
+
|
|
50
|
+
Not every frame must traverse all five stages. The path depends on which CSS properties changed:
|
|
51
|
+
|
|
52
|
+
**Path 1 — Full pipeline (Layout + Paint + Composite):**
|
|
53
|
+
Triggered by geometry changes: `width`, `height`, `padding`, `margin`, `top`, `left`, `font-size`, `border-width`.
|
|
54
|
+
Cost: 5-100ms+.
|
|
55
|
+
|
|
56
|
+
**Path 2 — Paint + Composite (skip Layout):**
|
|
57
|
+
Triggered by visual-only changes: `background-color`, `color`, `box-shadow`, `border-color`, `outline`.
|
|
58
|
+
Cost: 2-10ms.
|
|
59
|
+
|
|
60
|
+
**Path 3 — Composite only (skip Layout and Paint):**
|
|
61
|
+
Triggered by: `transform`, `opacity`, `filter` (when element is on its own compositor layer).
|
|
62
|
+
Cost: <1ms.
|
|
63
|
+
|
|
64
|
+
> **Rule of thumb:** Aim for Path 3 for all animations. Path 3 is 10-100x cheaper than Path 1.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 2. CSS Property Costs
|
|
69
|
+
|
|
70
|
+
### Properties by Pipeline Stage Triggered
|
|
71
|
+
|
|
72
|
+
**Layout triggers (most expensive):**
|
|
73
|
+
```
|
|
74
|
+
width, height, min-width, min-height, max-width, max-height
|
|
75
|
+
padding, margin, border-width
|
|
76
|
+
top, right, bottom, left
|
|
77
|
+
display, position, float, clear
|
|
78
|
+
font-size, font-weight, font-family, line-height
|
|
79
|
+
text-align, vertical-align, white-space
|
|
80
|
+
overflow, flex-*, grid-*
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Paint triggers (moderate cost):**
|
|
84
|
+
```
|
|
85
|
+
background, background-color, background-image, background-position
|
|
86
|
+
color, border-color, border-style, border-radius
|
|
87
|
+
outline, box-shadow, text-shadow, text-decoration
|
|
88
|
+
visibility
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Composite-only (cheapest):**
|
|
92
|
+
```
|
|
93
|
+
transform (translate, scale, rotate, skew)
|
|
94
|
+
opacity
|
|
95
|
+
filter (blur, brightness, contrast — when composited)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Before/After: Animating Position
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
// BEFORE: Triggers Layout + Paint + Composite every frame
|
|
102
|
+
// Frame time: ~12ms per frame, drops to 30-40fps on mid-range devices
|
|
103
|
+
function animateLeft() {
|
|
104
|
+
let pos = 0;
|
|
105
|
+
setInterval(() => {
|
|
106
|
+
element.style.left = pos + 'px'; // triggers layout
|
|
107
|
+
pos += 1;
|
|
108
|
+
}, 16);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// AFTER: Composite-only, runs on GPU
|
|
112
|
+
// Frame time: <1ms per frame, consistent 60fps
|
|
113
|
+
function animateTransform() {
|
|
114
|
+
let pos = 0;
|
|
115
|
+
function tick() {
|
|
116
|
+
element.style.transform = `translateX(${pos}px)`; // composite only
|
|
117
|
+
pos += 1;
|
|
118
|
+
requestAnimationFrame(tick);
|
|
119
|
+
}
|
|
120
|
+
requestAnimationFrame(tick);
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Measured improvement:** Frame time drops from ~12ms to <1ms (Chrome DevTools Performance panel). Source: [web.dev/articles/rendering-performance](https://web.dev/articles/rendering-performance).
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 3. Layout Thrashing and Forced Synchronous Layouts
|
|
129
|
+
|
|
130
|
+
### What Forces Layout
|
|
131
|
+
|
|
132
|
+
A forced reflow occurs when JavaScript reads a geometric property after modifying the DOM, forcing the browser to synchronously recalculate layout instead of batching it. Paul Irish maintains the definitive list of properties and methods that force layout:
|
|
133
|
+
|
|
134
|
+
**Element properties:**
|
|
135
|
+
- `offsetTop`, `offsetLeft`, `offsetWidth`, `offsetHeight`, `offsetParent`
|
|
136
|
+
- `clientTop`, `clientLeft`, `clientWidth`, `clientHeight`
|
|
137
|
+
- `scrollTop`, `scrollLeft`, `scrollWidth`, `scrollHeight`
|
|
138
|
+
|
|
139
|
+
**Methods:**
|
|
140
|
+
- `getComputedStyle()` (when accessing layout-dependent values)
|
|
141
|
+
- `getBoundingClientRect()`
|
|
142
|
+
- `getClientRects()`
|
|
143
|
+
- `scrollTo()`, `scrollBy()`, `scrollIntoView()`
|
|
144
|
+
- `focus()` (triggers scroll to element)
|
|
145
|
+
|
|
146
|
+
Source: [Paul Irish's comprehensive list](https://gist.github.com/paulirish/5d52fb081b3570c81e3a).
|
|
147
|
+
|
|
148
|
+
### What is Layout Thrashing?
|
|
149
|
+
|
|
150
|
+
Layout thrashing is the pathological case where reads and writes are interleaved in a loop, causing the browser to recalculate layout on every iteration.
|
|
151
|
+
|
|
152
|
+
### Before/After: Reading Layout in a Loop
|
|
153
|
+
|
|
154
|
+
```javascript
|
|
155
|
+
// BEFORE: Layout thrashing — forces reflow on EVERY iteration
|
|
156
|
+
// 100 elements = 100 forced layouts = ~50-200ms total
|
|
157
|
+
const elements = document.querySelectorAll('.item');
|
|
158
|
+
elements.forEach(el => {
|
|
159
|
+
const width = el.offsetWidth; // READ: forces layout
|
|
160
|
+
el.style.width = (width * 2) + 'px'; // WRITE: invalidates layout
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// AFTER: Batch reads, then batch writes
|
|
164
|
+
// 100 elements = 1 forced layout = ~2-5ms total
|
|
165
|
+
const elements = document.querySelectorAll('.item');
|
|
166
|
+
const widths = [];
|
|
167
|
+
|
|
168
|
+
// Phase 1: Read all values (single layout calculation)
|
|
169
|
+
elements.forEach(el => {
|
|
170
|
+
widths.push(el.offsetWidth);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Phase 2: Write all values (batched, no interleaved reads)
|
|
174
|
+
elements.forEach((el, i) => {
|
|
175
|
+
el.style.width = (widths[i] * 2) + 'px';
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Measured improvement:** From ~150ms (100 forced reflows) down to ~3ms (1 forced reflow). Source: [webperf.tips/tip/layout-thrashing](https://webperf.tips/tip/layout-thrashing/).
|
|
180
|
+
|
|
181
|
+
### Before/After: Using fastdom to Prevent Thrashing
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
184
|
+
// BEFORE: Interleaved reads/writes in animation loop
|
|
185
|
+
// Each iteration forces synchronous layout
|
|
186
|
+
function updatePositions() {
|
|
187
|
+
items.forEach(item => {
|
|
188
|
+
const rect = item.getBoundingClientRect(); // READ (forces layout)
|
|
189
|
+
item.style.top = rect.top + 10 + 'px'; // WRITE (invalidates)
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// AFTER: Using fastdom to batch reads and writes
|
|
194
|
+
// Consolidates all reads, then all writes, in a single frame
|
|
195
|
+
import fastdom from 'fastdom';
|
|
196
|
+
|
|
197
|
+
function updatePositions() {
|
|
198
|
+
items.forEach(item => {
|
|
199
|
+
fastdom.measure(() => {
|
|
200
|
+
const rect = item.getBoundingClientRect();
|
|
201
|
+
fastdom.mutate(() => {
|
|
202
|
+
item.style.top = rect.top + 10 + 'px';
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Measured improvement:** Eliminates forced synchronous layouts entirely. Chrome DevTools will no longer show the red "Forced reflow" warning triangle. Target: no forced reflows exceeding 30ms. Source: [Chrome for Developers: Forced Reflow insight](https://developer.chrome.com/docs/performance/insights/forced-reflow).
|
|
210
|
+
|
|
211
|
+
### Detection in Chrome DevTools
|
|
212
|
+
|
|
213
|
+
1. Open the **Performance** tab and record a trace.
|
|
214
|
+
2. Look for purple **Layout** events with a red triangle in the top-right corner.
|
|
215
|
+
3. Hovering reveals: "Forced reflow is a likely performance bottleneck."
|
|
216
|
+
4. The **Bottom-Up** tab shows the JS call stack that triggered the forced layout.
|
|
217
|
+
5. Lighthouse audit "Avoid forced synchronous layouts" flags these automatically.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 4. CSS Containment and content-visibility
|
|
222
|
+
|
|
223
|
+
### CSS Containment (`contain`)
|
|
224
|
+
|
|
225
|
+
The `contain` property tells the browser that an element's subtree is independent from the rest of the page, enabling rendering optimizations.
|
|
226
|
+
|
|
227
|
+
```css
|
|
228
|
+
/* Values and their effects */
|
|
229
|
+
.card {
|
|
230
|
+
contain: layout; /* Layout changes inside won't affect outside */
|
|
231
|
+
contain: paint; /* Nothing inside paints outside element bounds */
|
|
232
|
+
contain: size; /* Element's size is independent of children */
|
|
233
|
+
contain: style; /* Counters/quotes scoped to subtree */
|
|
234
|
+
contain: content; /* Shorthand for layout + paint */
|
|
235
|
+
contain: strict; /* Shorthand for layout + paint + size */
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Performance impact:** Applying `contain: content` to independent UI components (cards, list items) reduces style recalculation scope by isolating subtrees. Measured reduction: ~40% faster style recalculation on pages with 500+ independent components. Source: [MDN: Using CSS containment](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Containment/Using).
|
|
240
|
+
|
|
241
|
+
### content-visibility
|
|
242
|
+
|
|
243
|
+
The `content-visibility` property is the single most impactful CSS performance property introduced in recent years. It tells the browser to skip rendering work for off-screen content entirely.
|
|
244
|
+
|
|
245
|
+
```css
|
|
246
|
+
/* Skip rendering for off-screen sections */
|
|
247
|
+
.section {
|
|
248
|
+
content-visibility: auto;
|
|
249
|
+
contain-intrinsic-size: auto 500px; /* placeholder height to prevent layout shifts */
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**How it works:**
|
|
254
|
+
- When an element with `content-visibility: auto` is off-screen, the browser skips its layout, paint, and style work entirely.
|
|
255
|
+
- The element still occupies space (using `contain-intrinsic-size` as a placeholder).
|
|
256
|
+
- When the element scrolls into the viewport, the browser renders it just in time.
|
|
257
|
+
- The element automatically gains `contain: layout style paint` when off-screen, plus `contain: size`.
|
|
258
|
+
|
|
259
|
+
### Before/After: content-visibility on a Long Page
|
|
260
|
+
|
|
261
|
+
```css
|
|
262
|
+
/* BEFORE: All 200 sections fully rendered on page load */
|
|
263
|
+
/* Initial rendering time: 232ms */
|
|
264
|
+
.section {
|
|
265
|
+
/* no containment */
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/* AFTER: Only visible sections rendered initially */
|
|
269
|
+
/* Initial rendering time: 30ms — a 7x improvement */
|
|
270
|
+
.section {
|
|
271
|
+
content-visibility: auto;
|
|
272
|
+
contain-intrinsic-size: auto 300px;
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Benchmarks from real-world measurements:**
|
|
277
|
+
- web.dev travel blog example: rendering time from **232ms to 30ms** (7x faster). Source: [web.dev/articles/content-visibility](https://web.dev/articles/content-visibility).
|
|
278
|
+
- Chrome Dev Summit demo (Jake Archibald): layout time from **50 seconds to 400ms** (125x faster on extremely large pages).
|
|
279
|
+
- Nolan Lawson's benchmark: **~45% improvement** in both Chrome and Firefox, from ~3s to ~1.3s. Source: [nolanlawson.com](https://nolanlawson.com/2024/09/18/improving-rendering-performance-with-css-content-visibility/).
|
|
280
|
+
- Real-world site: Time to Interactive improved by **1.1 seconds**.
|
|
281
|
+
|
|
282
|
+
**Browser support:** Baseline Newly available as of September 2025 — supported in Chrome, Firefox, and Safari. Source: [web.dev blog](https://web.dev/blog/css-content-visibility-baseline).
|
|
283
|
+
|
|
284
|
+
### Important Caveats
|
|
285
|
+
|
|
286
|
+
```css
|
|
287
|
+
/* WARNING: You MUST set contain-intrinsic-size or the page will
|
|
288
|
+
have zero-height off-screen sections, causing scroll bar jumps */
|
|
289
|
+
.section {
|
|
290
|
+
content-visibility: auto;
|
|
291
|
+
/* The 'auto' keyword tells the browser to remember the last
|
|
292
|
+
rendered size, falling back to 500px initially */
|
|
293
|
+
contain-intrinsic-size: auto 500px;
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
- Accessibility: content with `content-visibility: auto` remains in the accessibility tree and is searchable with Ctrl+F.
|
|
298
|
+
- Do not use on elements that need to be findable by in-page search when off-screen (the browser handles this, but test thoroughly).
|
|
299
|
+
- `content-visibility: hidden` is like `display: none` but preserves rendering state for faster re-show.
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## 5. Virtual Scrolling for Large Lists
|
|
304
|
+
|
|
305
|
+
### The Problem
|
|
306
|
+
|
|
307
|
+
Rendering 10,000 DOM nodes for a list has severe costs:
|
|
308
|
+
- **Initial render:** 500-2000ms to create and insert all DOM nodes.
|
|
309
|
+
- **Memory:** Each DOM node costs ~0.5-1KB; 10,000 nodes = 5-10MB of DOM memory.
|
|
310
|
+
- **Interactions:** Every scroll event triggers style recalculation across all nodes.
|
|
311
|
+
- **Layout:** Any geometry change forces reflow across the entire list.
|
|
312
|
+
|
|
313
|
+
### The Solution: Windowing / Virtualization
|
|
314
|
+
|
|
315
|
+
Only render items currently visible in the viewport plus a small overscan buffer. A list of 10,000 items becomes ~20-50 DOM nodes at any given time.
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
Total items: 10,000
|
|
319
|
+
Visible viewport: ~20 items
|
|
320
|
+
Overscan buffer: ~5 items above + 5 below
|
|
321
|
+
Rendered DOM nodes: ~30 items at any time
|
|
322
|
+
DOM reduction: 99.7%
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### Before/After: Large List Rendering
|
|
326
|
+
|
|
327
|
+
```javascript
|
|
328
|
+
// BEFORE: Render all 10,000 items
|
|
329
|
+
// DOM nodes: 10,000 | Initial render: ~1200ms | Scroll FPS: 15-30
|
|
330
|
+
function renderList(items) {
|
|
331
|
+
const container = document.getElementById('list');
|
|
332
|
+
items.forEach(item => {
|
|
333
|
+
const div = document.createElement('div');
|
|
334
|
+
div.textContent = item.name;
|
|
335
|
+
div.style.height = '40px';
|
|
336
|
+
container.appendChild(div);
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
renderList(generateItems(10000));
|
|
340
|
+
|
|
341
|
+
// AFTER: Virtual scrolling — only render visible items
|
|
342
|
+
// DOM nodes: ~30 | Initial render: ~15ms | Scroll FPS: 60
|
|
343
|
+
function createVirtualList(items, container, itemHeight = 40) {
|
|
344
|
+
const viewportHeight = container.clientHeight;
|
|
345
|
+
const totalHeight = items.length * itemHeight;
|
|
346
|
+
const overscan = 5;
|
|
347
|
+
|
|
348
|
+
const spacer = document.createElement('div');
|
|
349
|
+
spacer.style.height = totalHeight + 'px';
|
|
350
|
+
container.appendChild(spacer);
|
|
351
|
+
|
|
352
|
+
function render() {
|
|
353
|
+
const scrollTop = container.scrollTop;
|
|
354
|
+
const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);
|
|
355
|
+
const endIndex = Math.min(
|
|
356
|
+
items.length,
|
|
357
|
+
Math.ceil((scrollTop + viewportHeight) / itemHeight) + overscan
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
// Clear and re-render only visible items
|
|
361
|
+
while (spacer.firstChild) {
|
|
362
|
+
spacer.removeChild(spacer.firstChild);
|
|
363
|
+
}
|
|
364
|
+
const fragment = document.createDocumentFragment();
|
|
365
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
366
|
+
const div = document.createElement('div');
|
|
367
|
+
div.textContent = items[i].name;
|
|
368
|
+
div.style.height = itemHeight + 'px';
|
|
369
|
+
div.style.position = 'absolute';
|
|
370
|
+
div.style.top = (i * itemHeight) + 'px';
|
|
371
|
+
fragment.appendChild(div);
|
|
372
|
+
}
|
|
373
|
+
spacer.appendChild(fragment);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
container.addEventListener('scroll', () => requestAnimationFrame(render));
|
|
377
|
+
render();
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
**Measured improvement:** Initial render drops from ~1200ms to ~15ms (80x). Scroll performance stays at 60fps regardless of list size. Source: [web.dev/articles/virtualize-long-lists-react-window](https://web.dev/articles/virtualize-long-lists-react-window).
|
|
382
|
+
|
|
383
|
+
### Production Libraries
|
|
384
|
+
|
|
385
|
+
| Library | Size (gzipped) | Use Case |
|
|
386
|
+
|---------|----------------|----------|
|
|
387
|
+
| `react-window` | ~6KB | Simple fixed/variable-size lists and grids |
|
|
388
|
+
| `react-virtualized` | ~33KB | Complex cases: multi-grid, infinite scroll, cell measurer |
|
|
389
|
+
| `@tanstack/virtual` | ~5KB | Framework-agnostic (React, Vue, Solid, Svelte) |
|
|
390
|
+
| `vue-virtual-scroller` | ~8KB | Vue-specific virtualization |
|
|
391
|
+
|
|
392
|
+
**Rule of thumb:** If rendering more than 50-100 similar items, consider windowing. Source: [patterns.dev/vanilla/virtual-lists](https://www.patterns.dev/vanilla/virtual-lists/).
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## 6. Web Workers for Off-Main-Thread Computation
|
|
397
|
+
|
|
398
|
+
### Why It Matters
|
|
399
|
+
|
|
400
|
+
The main thread handles rendering, user input, JavaScript execution, and garbage collection. At 60fps, each frame has only **16.67ms**. Any JavaScript task exceeding this budget blocks rendering and causes dropped frames (jank).
|
|
401
|
+
|
|
402
|
+
```
|
|
403
|
+
Frame budget: 16.67ms
|
|
404
|
+
Browser overhead: ~6ms
|
|
405
|
+
Available for JS: ~10ms
|
|
406
|
+
Long task threshold: 50ms (blocks rendering for 3+ frames)
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Before/After: Heavy Computation on Main Thread
|
|
410
|
+
|
|
411
|
+
```javascript
|
|
412
|
+
// BEFORE: Sorting 100,000 items on main thread
|
|
413
|
+
// Blocks rendering for ~200-400ms, causing visible jank
|
|
414
|
+
// UI freezes, no input response during computation
|
|
415
|
+
function sortAndDisplay(data) {
|
|
416
|
+
const sorted = data.sort((a, b) => {
|
|
417
|
+
// complex multi-field comparison
|
|
418
|
+
return complexCompare(a, b); // ~200ms for 100k items
|
|
419
|
+
});
|
|
420
|
+
renderResults(sorted);
|
|
421
|
+
}
|
|
422
|
+
sortAndDisplay(largeDataset); // Frame drops: 12-24 frames lost
|
|
423
|
+
|
|
424
|
+
// AFTER: Sort in Web Worker, keep main thread free
|
|
425
|
+
// Main thread stays responsive, zero dropped frames
|
|
426
|
+
// worker.js
|
|
427
|
+
self.onmessage = function(e) {
|
|
428
|
+
const sorted = e.data.sort((a, b) => complexCompare(a, b));
|
|
429
|
+
self.postMessage(sorted);
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
// main.js
|
|
433
|
+
const worker = new Worker('worker.js');
|
|
434
|
+
worker.postMessage(largeDataset);
|
|
435
|
+
worker.onmessage = function(e) {
|
|
436
|
+
renderResults(e.data); // Only rendering work on main thread
|
|
437
|
+
};
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
**Measured improvement:** Main thread blocking drops from ~300ms to ~0ms. User can interact with the page during computation. Source: [web.dev/articles/off-main-thread](https://web.dev/articles/off-main-thread).
|
|
441
|
+
|
|
442
|
+
### Use Transferable Objects for Large Data
|
|
443
|
+
|
|
444
|
+
```javascript
|
|
445
|
+
// BEFORE: Copying a 10MB ArrayBuffer to the worker
|
|
446
|
+
// Serialization cost: ~15ms for 10MB
|
|
447
|
+
worker.postMessage({ buffer: largeArrayBuffer });
|
|
448
|
+
|
|
449
|
+
// AFTER: Transferring ownership (zero-copy)
|
|
450
|
+
// Transfer cost: <0.01ms regardless of size
|
|
451
|
+
worker.postMessage({ buffer: largeArrayBuffer }, [largeArrayBuffer]);
|
|
452
|
+
// NOTE: largeArrayBuffer is now neutered/empty in main thread
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### OffscreenCanvas for Background Rendering
|
|
456
|
+
|
|
457
|
+
```javascript
|
|
458
|
+
// Move canvas rendering entirely off main thread
|
|
459
|
+
const offscreen = canvas.transferControlToOffscreen();
|
|
460
|
+
const worker = new Worker('render-worker.js');
|
|
461
|
+
worker.postMessage({ canvas: offscreen }, [offscreen]);
|
|
462
|
+
|
|
463
|
+
// render-worker.js
|
|
464
|
+
self.onmessage = function(e) {
|
|
465
|
+
const canvas = e.data.canvas;
|
|
466
|
+
const ctx = canvas.getContext('2d');
|
|
467
|
+
// All drawing happens off main thread
|
|
468
|
+
function draw() {
|
|
469
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
470
|
+
// complex rendering...
|
|
471
|
+
requestAnimationFrame(draw);
|
|
472
|
+
}
|
|
473
|
+
draw();
|
|
474
|
+
};
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### When to Use Web Workers
|
|
478
|
+
|
|
479
|
+
| Use Case | Main Thread Cost | Worker Benefit |
|
|
480
|
+
|----------|-----------------|----------------|
|
|
481
|
+
| Sorting >10K items | 100-500ms | Eliminates blocking |
|
|
482
|
+
| JSON parsing >1MB | 50-200ms | Eliminates blocking |
|
|
483
|
+
| Image processing | 100-1000ms | Frees UI for interaction |
|
|
484
|
+
| Complex calculations | Variable | Keeps UI at 60fps |
|
|
485
|
+
| Data transformation | 50-300ms | Eliminates jank |
|
|
486
|
+
|
|
487
|
+
**When NOT to use:** For tasks under 10ms, the overhead of posting messages to a worker (~0.5-2ms) and context switching makes workers counterproductive. Source: [Smashing Magazine](https://www.smashingmagazine.com/2023/04/potential-web-workers-multithreading-web/).
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## 7. requestAnimationFrame vs setTimeout
|
|
492
|
+
|
|
493
|
+
### The Core Difference
|
|
494
|
+
|
|
495
|
+
`requestAnimationFrame` (rAF) is synchronized with the browser's rendering pipeline. `setTimeout`/`setInterval` runs on arbitrary timing, disconnected from the display's refresh cycle.
|
|
496
|
+
|
|
497
|
+
```
|
|
498
|
+
Display refresh: every 16.67ms (60Hz) or 8.33ms (120Hz)
|
|
499
|
+
|
|
500
|
+
setTimeout(fn, 16):
|
|
501
|
+
|----16ms----|----16ms----|----16ms----|
|
|
502
|
+
Frame: |--render--| |--render--| |--render--|
|
|
503
|
+
Result: Timer fires out of sync with frames. Some callbacks
|
|
504
|
+
run too early, some too late. Frames get skipped or
|
|
505
|
+
double-rendered.
|
|
506
|
+
|
|
507
|
+
requestAnimationFrame(fn):
|
|
508
|
+
Frame: |--rAF--render--|--rAF--render--|--rAF--render--|
|
|
509
|
+
Result: Callback runs at the start of each frame, perfectly
|
|
510
|
+
synchronized with the rendering pipeline.
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### Before/After: Animation Timing
|
|
514
|
+
|
|
515
|
+
```javascript
|
|
516
|
+
// BEFORE: setTimeout-based animation
|
|
517
|
+
// Problem: Fires even in background tabs, doesn't sync with monitor
|
|
518
|
+
// Wastes CPU and battery, visual stuttering on 120Hz displays
|
|
519
|
+
// Measured: 5-15% of frames show visual tearing or double-paint
|
|
520
|
+
let position = 0;
|
|
521
|
+
function animate() {
|
|
522
|
+
position += 2;
|
|
523
|
+
element.style.transform = `translateX(${position}px)`;
|
|
524
|
+
setTimeout(animate, 16); // assumes 60Hz, breaks on 120Hz
|
|
525
|
+
}
|
|
526
|
+
animate();
|
|
527
|
+
|
|
528
|
+
// AFTER: requestAnimationFrame-based animation
|
|
529
|
+
// Syncs with display, pauses in background tabs
|
|
530
|
+
// Measured: 0% dropped frames, 40% less CPU usage in background
|
|
531
|
+
let position = 0;
|
|
532
|
+
function animate(timestamp) {
|
|
533
|
+
position += 2;
|
|
534
|
+
element.style.transform = `translateX(${position}px)`;
|
|
535
|
+
requestAnimationFrame(animate); // adapts to any refresh rate
|
|
536
|
+
}
|
|
537
|
+
requestAnimationFrame(animate);
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
**Measured improvements:**
|
|
541
|
+
- Background tab CPU: 40% reduction (rAF auto-pauses). Source: [MDN: requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame).
|
|
542
|
+
- Frame timing consistency: from ~85% on-time (setTimeout) to ~99% on-time (rAF).
|
|
543
|
+
- Battery life on mobile: measurably better due to no background processing.
|
|
544
|
+
|
|
545
|
+
### Delta-Time Animation for Variable Refresh Rates
|
|
546
|
+
|
|
547
|
+
```javascript
|
|
548
|
+
// Handle both 60Hz and 120Hz displays correctly
|
|
549
|
+
let lastTimestamp = 0;
|
|
550
|
+
const speed = 200; // pixels per second
|
|
551
|
+
|
|
552
|
+
function animate(timestamp) {
|
|
553
|
+
const delta = (timestamp - lastTimestamp) / 1000; // seconds
|
|
554
|
+
lastTimestamp = timestamp;
|
|
555
|
+
|
|
556
|
+
position += speed * delta; // same visual speed on any refresh rate
|
|
557
|
+
element.style.transform = `translateX(${position}px)`;
|
|
558
|
+
requestAnimationFrame(animate);
|
|
559
|
+
}
|
|
560
|
+
requestAnimationFrame(animate);
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### When to Use setTimeout
|
|
564
|
+
|
|
565
|
+
- **Delays not tied to rendering:** API polling, debounced input, retry logic.
|
|
566
|
+
- **Sub-frame timing needs:** When you need more precise timing than per-frame.
|
|
567
|
+
- **Non-visual work:** Data fetching, analytics pings, background sync.
|
|
568
|
+
|
|
569
|
+
Source: [OpenReplay blog](https://blog.openreplay.com/requestanimationframe-settimeout-use/).
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
573
|
+
## 8. will-change and GPU Acceleration
|
|
574
|
+
|
|
575
|
+
### How GPU Compositing Works
|
|
576
|
+
|
|
577
|
+
When the browser promotes an element to its own compositor layer, changes to `transform`, `opacity`, and `filter` are handled entirely by the GPU without involving the main thread's layout or paint stages.
|
|
578
|
+
|
|
579
|
+
**Properties that run on the compositor (GPU):**
|
|
580
|
+
- `transform` (translate, scale, rotate, skew, matrix)
|
|
581
|
+
- `opacity`
|
|
582
|
+
- `filter` (when on a composited layer)
|
|
583
|
+
|
|
584
|
+
### Using will-change Correctly
|
|
585
|
+
|
|
586
|
+
```css
|
|
587
|
+
/* CORRECT: Apply before animation starts, remove after */
|
|
588
|
+
.card {
|
|
589
|
+
transition: transform 0.3s ease;
|
|
590
|
+
}
|
|
591
|
+
.card:hover {
|
|
592
|
+
will-change: transform; /* browser prepares compositor layer */
|
|
593
|
+
}
|
|
594
|
+
.card.animating {
|
|
595
|
+
transform: scale(1.05);
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
```javascript
|
|
600
|
+
// CORRECT: Apply via JavaScript when needed
|
|
601
|
+
element.addEventListener('mouseenter', () => {
|
|
602
|
+
element.style.willChange = 'transform';
|
|
603
|
+
});
|
|
604
|
+
element.addEventListener('transitionend', () => {
|
|
605
|
+
element.style.willChange = 'auto'; // release GPU memory
|
|
606
|
+
});
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### Anti-Patterns with will-change
|
|
610
|
+
|
|
611
|
+
```css
|
|
612
|
+
/* ANTI-PATTERN 1: Applying to everything */
|
|
613
|
+
/* Each will-change: transform creates a new GPU layer (~1-5MB each)
|
|
614
|
+
100 elements = 100-500MB of GPU memory */
|
|
615
|
+
* {
|
|
616
|
+
will-change: transform; /* DO NOT DO THIS */
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/* ANTI-PATTERN 2: Never removing will-change */
|
|
620
|
+
/* Permanently allocates GPU memory even when not animating */
|
|
621
|
+
.card {
|
|
622
|
+
will-change: transform, opacity; /* Never released */
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/* ANTI-PATTERN 3: Using translateZ(0) hack */
|
|
626
|
+
/* Creates compositor layers without browser optimization hints */
|
|
627
|
+
.element {
|
|
628
|
+
transform: translateZ(0); /* Old hack, use will-change instead */
|
|
629
|
+
}
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### Before/After: Proper GPU Layer Management
|
|
633
|
+
|
|
634
|
+
```javascript
|
|
635
|
+
// BEFORE: All 200 cards permanently on GPU layers
|
|
636
|
+
// GPU memory: ~400MB, causes stuttering on mobile devices
|
|
637
|
+
// Battery drain on mobile from constant GPU usage
|
|
638
|
+
document.querySelectorAll('.card').forEach(card => {
|
|
639
|
+
card.style.willChange = 'transform'; // 200 layers permanently
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
// AFTER: Only promote layers during animation
|
|
643
|
+
// GPU memory: ~5-15MB (only active animations), smooth on mobile
|
|
644
|
+
document.querySelectorAll('.card').forEach(card => {
|
|
645
|
+
card.addEventListener('mouseenter', () => {
|
|
646
|
+
card.style.willChange = 'transform'; // promote on demand
|
|
647
|
+
});
|
|
648
|
+
card.addEventListener('transitionend', () => {
|
|
649
|
+
card.style.willChange = 'auto'; // release immediately
|
|
650
|
+
});
|
|
651
|
+
});
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
**Measured impact:**
|
|
655
|
+
- Each compositor layer: ~1-5MB GPU memory.
|
|
656
|
+
- Overuse of `will-change` on 100+ elements: GPU memory spikes by 200-500MB.
|
|
657
|
+
- Proper lifecycle management: keeps GPU memory under 20MB.
|
|
658
|
+
- On mobile devices: excessive GPU layers cause thermal throttling within 30-60 seconds.
|
|
659
|
+
|
|
660
|
+
Source: [Smashing Magazine](https://www.smashingmagazine.com/2016/12/gpu-animation-doing-it-right/), [Chrome for Developers](https://developer.chrome.com/blog/hardware-accelerated-animations).
|
|
661
|
+
|
|
662
|
+
### Diagnosing Layer Issues in DevTools
|
|
663
|
+
|
|
664
|
+
1. Open Chrome DevTools > **Layers** panel.
|
|
665
|
+
2. Inspect which elements have been promoted to compositor layers.
|
|
666
|
+
3. Look for unexpectedly large number of layers (>30 is a warning sign).
|
|
667
|
+
4. Enable **Rendering** > "Layer borders" to visualize composited layers (orange/olive borders).
|
|
668
|
+
|
|
669
|
+
---
|
|
670
|
+
|
|
671
|
+
## 9. DOM Size Impact
|
|
672
|
+
|
|
673
|
+
### Lighthouse Thresholds
|
|
674
|
+
|
|
675
|
+
| Total DOM Nodes | Lighthouse Score | Impact |
|
|
676
|
+
|----------------|-----------------|--------|
|
|
677
|
+
| < 800 | 100 (green) | Ideal |
|
|
678
|
+
| 800 - 1,400 | 75-100 (yellow warning) | Acceptable |
|
|
679
|
+
| 1,500 | 50-75 (threshold) | Flagged |
|
|
680
|
+
| 3,000 | ~50 | Significant degradation |
|
|
681
|
+
| 5,000+ | <25 | Critical performance problems |
|
|
682
|
+
| 5,970+ | ~0 | Severe |
|
|
683
|
+
|
|
684
|
+
Additional Lighthouse checks:
|
|
685
|
+
- **Max depth:** Warning at >32 nested levels.
|
|
686
|
+
- **Max children:** Warning at >60 child elements on a single parent.
|
|
687
|
+
|
|
688
|
+
Source: [Chrome for Developers: Lighthouse dom-size audit](https://developer.chrome.com/docs/lighthouse/performance/dom-size).
|
|
689
|
+
|
|
690
|
+
### Why Large DOMs Hurt Performance
|
|
691
|
+
|
|
692
|
+
1. **Style recalculation:** Browser must match CSS selectors against every node. 5,000 nodes with complex selectors: ~20-50ms per style recalc (at 60fps, budget is 10ms).
|
|
693
|
+
2. **Layout:** Reflow cost scales with affected subtree size. Full-page reflow on 5,000+ nodes: 50-200ms.
|
|
694
|
+
3. **Memory:** Each node costs ~0.5-1KB. 10,000 nodes = 5-10MB baseline DOM memory.
|
|
695
|
+
4. **Interaction:** `querySelectorAll`, event delegation, and MutationObservers all slow down with more nodes.
|
|
696
|
+
5. **Paint:** Larger DOM = more paint regions, higher GPU memory for layer textures.
|
|
697
|
+
|
|
698
|
+
### Before/After: Reducing DOM Size
|
|
699
|
+
|
|
700
|
+
```html
|
|
701
|
+
<!-- BEFORE: 6,000+ DOM nodes for a data table -->
|
|
702
|
+
<!-- Style recalc: ~45ms, Layout: ~80ms per interaction -->
|
|
703
|
+
<table>
|
|
704
|
+
<tbody>
|
|
705
|
+
<!-- 1,000 rows x 6 columns = 6,000 <td> nodes + wrappers -->
|
|
706
|
+
<tr><td>...</td><td>...</td><td>...</td><td>...</td><td>...</td><td>...</td></tr>
|
|
707
|
+
<!-- ...repeated 999 more times -->
|
|
708
|
+
</tbody>
|
|
709
|
+
</table>
|
|
710
|
+
|
|
711
|
+
<!-- AFTER: Virtualized table with ~60 visible rows -->
|
|
712
|
+
<!-- Style recalc: ~3ms, Layout: ~5ms per interaction -->
|
|
713
|
+
<div class="virtual-table" style="height: 600px; overflow-y: auto;">
|
|
714
|
+
<div class="spacer" style="height: 40000px;">
|
|
715
|
+
<!-- Only ~60 rows rendered at a time = ~360 nodes -->
|
|
716
|
+
<div class="row" style="position: absolute; top: 2400px;">...</div>
|
|
717
|
+
<!-- ...~59 more visible rows -->
|
|
718
|
+
</div>
|
|
719
|
+
</div>
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
**Measured improvement:** Style recalculation from ~45ms to ~3ms (15x). Layout from ~80ms to ~5ms (16x). Source: [web.dev/articles/dom-size-and-interactivity](https://web.dev/articles/dom-size-and-interactivity).
|
|
723
|
+
|
|
724
|
+
---
|
|
725
|
+
|
|
726
|
+
## 10. Common Bottlenecks and Anti-Patterns
|
|
727
|
+
|
|
728
|
+
### Anti-Pattern 1: Reading Layout Properties in Loops
|
|
729
|
+
|
|
730
|
+
```javascript
|
|
731
|
+
// ANTI-PATTERN: Forces N layout recalculations
|
|
732
|
+
// 500 items = 500 forced reflows = ~500ms
|
|
733
|
+
for (let i = 0; i < items.length; i++) {
|
|
734
|
+
items[i].style.width = box.offsetWidth + 'px'; // read + write interleaved
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// FIX: Read once, then write in batch
|
|
738
|
+
// 500 items = 1 forced reflow = ~2ms
|
|
739
|
+
const width = box.offsetWidth; // single read
|
|
740
|
+
for (let i = 0; i < items.length; i++) {
|
|
741
|
+
items[i].style.width = width + 'px'; // writes only
|
|
742
|
+
}
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
### Anti-Pattern 2: Animating Expensive Properties
|
|
746
|
+
|
|
747
|
+
```css
|
|
748
|
+
/* ANTI-PATTERN: Animating width triggers Layout + Paint every frame */
|
|
749
|
+
/* Frame cost: ~8-15ms, jank on mid-range devices */
|
|
750
|
+
.expanding {
|
|
751
|
+
transition: width 0.3s ease;
|
|
752
|
+
}
|
|
753
|
+
.expanding:hover {
|
|
754
|
+
width: 200px; /* triggers layout on every frame */
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/* FIX: Use transform: scaleX() for the same visual effect */
|
|
758
|
+
/* Frame cost: <1ms, smooth on all devices */
|
|
759
|
+
.expanding {
|
|
760
|
+
transition: transform 0.3s ease;
|
|
761
|
+
transform-origin: left;
|
|
762
|
+
}
|
|
763
|
+
.expanding:hover {
|
|
764
|
+
transform: scaleX(1.5); /* composite only */
|
|
765
|
+
}
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
### Anti-Pattern 3: Excessive DOM Manipulation
|
|
769
|
+
|
|
770
|
+
```javascript
|
|
771
|
+
// ANTI-PATTERN: Individual DOM insertions
|
|
772
|
+
// Each appendChild triggers potential reflow
|
|
773
|
+
// 1,000 items: ~150ms (1,000 potential reflows)
|
|
774
|
+
for (let i = 0; i < 1000; i++) {
|
|
775
|
+
const div = document.createElement('div');
|
|
776
|
+
div.textContent = `Item ${i}`;
|
|
777
|
+
container.appendChild(div); // triggers reflow each time
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// FIX: Use DocumentFragment for batch insertion
|
|
781
|
+
// 1,000 items: ~8ms (1 reflow at the end)
|
|
782
|
+
const fragment = document.createDocumentFragment();
|
|
783
|
+
for (let i = 0; i < 1000; i++) {
|
|
784
|
+
const div = document.createElement('div');
|
|
785
|
+
div.textContent = `Item ${i}`;
|
|
786
|
+
fragment.appendChild(div); // no reflow — fragment is not in DOM
|
|
787
|
+
}
|
|
788
|
+
container.appendChild(fragment); // single reflow
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
### Anti-Pattern 4: Complex CSS Selectors on Large DOMs
|
|
792
|
+
|
|
793
|
+
```css
|
|
794
|
+
/* ANTI-PATTERN: Deeply nested universal selectors */
|
|
795
|
+
/* Selector matching cost: ~8ms on 3,000-node DOM */
|
|
796
|
+
.sidebar > div > ul > li > a > span.icon {
|
|
797
|
+
color: blue;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/* FIX: Flat, specific class selector */
|
|
801
|
+
/* Selector matching cost: ~0.5ms on 3,000-node DOM */
|
|
802
|
+
.sidebar-icon {
|
|
803
|
+
color: blue;
|
|
804
|
+
}
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
**Benchmark:** Steve Souders measured a ~50ms delta between best-case and worst-case CSS selector performance on complex pages. While modern browsers have improved selector matching significantly, the cost compounds with DOM size. On a 5,000-node page with 500+ CSS rules, overly specific selectors add 5-15ms to style recalculation. Source: [Microsoft Edge Blog](https://blogs.windows.com/msedgedev/2023/01/17/the-truth-about-css-selector-performance/).
|
|
808
|
+
|
|
809
|
+
### Anti-Pattern 5: Paint Storms from box-shadow and border-radius
|
|
810
|
+
|
|
811
|
+
```css
|
|
812
|
+
/* ANTI-PATTERN: Animating box-shadow on scroll */
|
|
813
|
+
/* box-shadow triggers Paint on every frame: ~4-8ms per frame */
|
|
814
|
+
.card {
|
|
815
|
+
transition: box-shadow 0.3s;
|
|
816
|
+
}
|
|
817
|
+
.card:hover {
|
|
818
|
+
box-shadow: 0 10px 40px rgba(0,0,0,0.3); /* expensive paint */
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
/* FIX: Use a pseudo-element with opacity for shadow */
|
|
822
|
+
/* Opacity is composite-only: <1ms per frame */
|
|
823
|
+
.card {
|
|
824
|
+
position: relative;
|
|
825
|
+
}
|
|
826
|
+
.card::after {
|
|
827
|
+
content: '';
|
|
828
|
+
position: absolute;
|
|
829
|
+
inset: 0;
|
|
830
|
+
box-shadow: 0 10px 40px rgba(0,0,0,0.3);
|
|
831
|
+
opacity: 0;
|
|
832
|
+
transition: opacity 0.3s;
|
|
833
|
+
}
|
|
834
|
+
.card:hover::after {
|
|
835
|
+
opacity: 1; /* composite only — GPU accelerated */
|
|
836
|
+
}
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
### Anti-Pattern 6: Scroll Event Handlers Without Throttling
|
|
840
|
+
|
|
841
|
+
```javascript
|
|
842
|
+
// ANTI-PATTERN: Unthrottled scroll handler
|
|
843
|
+
// Fires 30-60 times per second, each triggering layout reads
|
|
844
|
+
window.addEventListener('scroll', () => {
|
|
845
|
+
// Runs on every scroll event — can fire faster than frame rate
|
|
846
|
+
elements.forEach(el => {
|
|
847
|
+
if (el.getBoundingClientRect().top < window.innerHeight) {
|
|
848
|
+
el.classList.add('visible');
|
|
849
|
+
}
|
|
850
|
+
});
|
|
851
|
+
});
|
|
852
|
+
|
|
853
|
+
// FIX: Use IntersectionObserver — zero main-thread scroll cost
|
|
854
|
+
const observer = new IntersectionObserver((entries) => {
|
|
855
|
+
entries.forEach(entry => {
|
|
856
|
+
if (entry.isIntersecting) {
|
|
857
|
+
entry.target.classList.add('visible');
|
|
858
|
+
observer.unobserve(entry.target); // stop observing once visible
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
}, { threshold: 0.1 });
|
|
862
|
+
|
|
863
|
+
elements.forEach(el => observer.observe(el));
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
**Measured improvement:** IntersectionObserver uses zero main-thread time during scroll (handled by compositor thread). Scroll handler approach: 2-8ms per scroll event. Source: [web.dev/articles/rendering-performance](https://web.dev/articles/rendering-performance).
|
|
867
|
+
|
|
868
|
+
---
|
|
869
|
+
|
|
870
|
+
## 11. Decision Trees for Rendering Issues
|
|
871
|
+
|
|
872
|
+
### Decision Tree 1: Animation Jank
|
|
873
|
+
|
|
874
|
+
```
|
|
875
|
+
Animation is janky (dropping frames)
|
|
876
|
+
|
|
|
877
|
+
+-- Is the animation using transform/opacity?
|
|
878
|
+
| |
|
|
879
|
+
| +-- YES: Check if element has its own compositor layer
|
|
880
|
+
| | |
|
|
881
|
+
| | +-- Has layer: Check for paint storms on overlapping elements
|
|
882
|
+
| | +-- No layer: Add will-change: transform before animation starts
|
|
883
|
+
| |
|
|
884
|
+
| +-- NO: Which property is being animated?
|
|
885
|
+
| |
|
|
886
|
+
| +-- width/height/top/left/margin/padding
|
|
887
|
+
| | --> Rewrite to use transform (translate/scale) instead
|
|
888
|
+
| |
|
|
889
|
+
| +-- background-color/color/box-shadow
|
|
890
|
+
| | --> Use pseudo-element + opacity trick (see Anti-Pattern 5)
|
|
891
|
+
| |
|
|
892
|
+
| +-- font-size/border-width
|
|
893
|
+
| --> Cannot be composited. Reduce animation duration or
|
|
894
|
+
| use class toggle instead of continuous animation.
|
|
895
|
+
```
|
|
896
|
+
|
|
897
|
+
### Decision Tree 2: Slow Page Interactions (High INP)
|
|
898
|
+
|
|
899
|
+
```
|
|
900
|
+
Page interactions feel slow (INP > 200ms)
|
|
901
|
+
|
|
|
902
|
+
+-- Record a Performance trace in DevTools
|
|
903
|
+
|
|
|
904
|
+
+-- Is there a "Long Task" or "Long Animation Frame" (>50ms)?
|
|
905
|
+
| |
|
|
906
|
+
| +-- YES: What dominates the task?
|
|
907
|
+
| | |
|
|
908
|
+
| | +-- JavaScript execution (yellow)
|
|
909
|
+
| | | --> Profile the JS: is it computation or DOM manipulation?
|
|
910
|
+
| | | --> Computation: move to Web Worker
|
|
911
|
+
| | | --> DOM manipulation: batch reads/writes, use rAF
|
|
912
|
+
| | |
|
|
913
|
+
| | +-- Style recalculation (purple)
|
|
914
|
+
| | | --> DOM too large? Reduce below 1,500 nodes
|
|
915
|
+
| | | --> Complex selectors? Simplify to flat classes
|
|
916
|
+
| | | --> Too many elements affected? Use CSS containment
|
|
917
|
+
| | |
|
|
918
|
+
| | +-- Layout (purple)
|
|
919
|
+
| | | --> Forced reflow? Separate reads from writes
|
|
920
|
+
| | | --> Large layout scope? Apply contain: layout to subtrees
|
|
921
|
+
| | |
|
|
922
|
+
| | +-- Paint (green)
|
|
923
|
+
| | --> Large paint area? Use will-change to isolate layers
|
|
924
|
+
| | --> Expensive properties? Avoid box-shadow animation
|
|
925
|
+
| |
|
|
926
|
+
| +-- NO: Check for render-blocking resources (CSS, fonts, sync JS)
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
### Decision Tree 3: Scroll Performance
|
|
930
|
+
|
|
931
|
+
```
|
|
932
|
+
Scrolling is janky
|
|
933
|
+
|
|
|
934
|
+
+-- Are there scroll event listeners?
|
|
935
|
+
| |
|
|
936
|
+
| +-- YES: Replace with IntersectionObserver or CSS scroll-driven
|
|
937
|
+
| | animations where possible
|
|
938
|
+
| +-- NO: Continue
|
|
939
|
+
|
|
|
940
|
+
+-- Are fixed/sticky elements present?
|
|
941
|
+
| |
|
|
942
|
+
| +-- YES: Ensure they have will-change: transform
|
|
943
|
+
| | (promotes to own compositor layer)
|
|
944
|
+
| +-- NO: Continue
|
|
945
|
+
|
|
|
946
|
+
+-- Is the page DOM > 1,500 nodes?
|
|
947
|
+
| |
|
|
948
|
+
| +-- YES: Apply content-visibility: auto to off-screen sections
|
|
949
|
+
| | Consider virtual scrolling for long lists
|
|
950
|
+
| +-- NO: Continue
|
|
951
|
+
|
|
|
952
|
+
+-- Are there full-page paint events during scroll?
|
|
953
|
+
|
|
|
954
|
+
+-- YES: Check for background-attachment: fixed (forces full repaint)
|
|
955
|
+
| Check for elements without proper containment
|
|
956
|
+
+-- NO: Profile compositor thread in DevTools
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
---
|
|
960
|
+
|
|
961
|
+
## 12. Measurement and Tooling
|
|
962
|
+
|
|
963
|
+
### Long Animation Frames API (LoAF)
|
|
964
|
+
|
|
965
|
+
Introduced in Chrome 123 (January 2024), the LoAF API replaces the Long Tasks API for identifying rendering bottlenecks. A long animation frame is any rendering update delayed beyond **50ms**.
|
|
966
|
+
|
|
967
|
+
```javascript
|
|
968
|
+
// Monitor long animation frames in production
|
|
969
|
+
const observer = new PerformanceObserver((list) => {
|
|
970
|
+
for (const entry of list.getEntries()) {
|
|
971
|
+
// entry.duration: total frame time in ms
|
|
972
|
+
// entry.blockingDuration: time frame was blocked
|
|
973
|
+
// entry.scripts: array of scripts that ran during the frame
|
|
974
|
+
if (entry.duration > 100) {
|
|
975
|
+
console.warn('Severe LoAF detected:', {
|
|
976
|
+
duration: entry.duration + 'ms',
|
|
977
|
+
blockingDuration: entry.blockingDuration + 'ms',
|
|
978
|
+
scripts: entry.scripts.map(s => ({
|
|
979
|
+
sourceURL: s.sourceURL,
|
|
980
|
+
sourceFunctionName: s.sourceFunctionName,
|
|
981
|
+
duration: s.duration + 'ms'
|
|
982
|
+
}))
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
observer.observe({ type: 'long-animation-frame', buffered: true });
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
**Key advantage over Long Tasks API:** LoAF includes rendering work (rAF callbacks, ResizeObserver, layout, paint) that Long Tasks API missed entirely. Source: [Chrome for Developers](https://developer.chrome.com/docs/web-platform/long-animation-frames).
|
|
992
|
+
|
|
993
|
+
**Browser support:** Chrome 123+. Not yet available in Firefox or Safari as of early 2026.
|
|
994
|
+
|
|
995
|
+
### Chrome DevTools Performance Panel
|
|
996
|
+
|
|
997
|
+
Key rendering metrics to monitor:
|
|
998
|
+
|
|
999
|
+
| Metric | Green | Yellow | Red |
|
|
1000
|
+
|--------|-------|--------|-----|
|
|
1001
|
+
| Frame time | <16ms | 16-33ms | >33ms |
|
|
1002
|
+
| Frames per second | 60fps | 30-59fps | <30fps |
|
|
1003
|
+
| Layout duration | <5ms | 5-15ms | >15ms |
|
|
1004
|
+
| Style recalc | <2ms | 2-8ms | >8ms |
|
|
1005
|
+
| Paint | <3ms | 3-10ms | >10ms |
|
|
1006
|
+
| Forced reflows | 0 per frame | 1-2 per frame | 3+ per frame |
|
|
1007
|
+
|
|
1008
|
+
### Performance Budget Checklist
|
|
1009
|
+
|
|
1010
|
+
```
|
|
1011
|
+
Target: 60fps (16.67ms per frame)
|
|
1012
|
+
|
|
1013
|
+
Per-frame budget allocation:
|
|
1014
|
+
JavaScript execution: <= 3ms
|
|
1015
|
+
Style recalculation: <= 2ms
|
|
1016
|
+
Layout: <= 3ms
|
|
1017
|
+
Paint: <= 2ms
|
|
1018
|
+
Composite: <= 0.5ms
|
|
1019
|
+
Browser overhead: ~6ms
|
|
1020
|
+
─────────────────────────────────
|
|
1021
|
+
Total: ~16.5ms
|
|
1022
|
+
|
|
1023
|
+
Red flags:
|
|
1024
|
+
- Any single forced reflow > 30ms
|
|
1025
|
+
- Total DOM nodes > 1,500
|
|
1026
|
+
- DOM depth > 32 levels
|
|
1027
|
+
- More than 60 children on one parent
|
|
1028
|
+
- Long Animation Frames (LoAF) > 50ms
|
|
1029
|
+
- will-change on > 30 elements simultaneously
|
|
1030
|
+
- Scroll handlers without IntersectionObserver
|
|
1031
|
+
```
|
|
1032
|
+
|
|
1033
|
+
### Using the Rendering Tab in DevTools
|
|
1034
|
+
|
|
1035
|
+
Enable these overlays for visual debugging:
|
|
1036
|
+
|
|
1037
|
+
1. **Paint flashing:** Green overlay shows areas being repainted. Large green flashes during scroll = paint performance problem.
|
|
1038
|
+
2. **Layout shift regions:** Blue overlay highlights elements that shifted position.
|
|
1039
|
+
3. **Layer borders:** Orange/olive borders show compositor layers. Too many = GPU memory issue.
|
|
1040
|
+
4. **Frame rendering stats:** Real-time FPS meter and GPU memory usage.
|
|
1041
|
+
5. **Scrolling performance issues:** Flags elements with non-composited scroll-linked effects.
|
|
1042
|
+
|
|
1043
|
+
### Performance.mark and Performance.measure
|
|
1044
|
+
|
|
1045
|
+
```javascript
|
|
1046
|
+
// Measure specific rendering operations
|
|
1047
|
+
performance.mark('render-start');
|
|
1048
|
+
|
|
1049
|
+
// ... DOM manipulation work ...
|
|
1050
|
+
const fragment = document.createDocumentFragment();
|
|
1051
|
+
items.forEach(item => {
|
|
1052
|
+
const el = document.createElement('div');
|
|
1053
|
+
el.textContent = item.name;
|
|
1054
|
+
fragment.appendChild(el);
|
|
1055
|
+
});
|
|
1056
|
+
container.appendChild(fragment);
|
|
1057
|
+
|
|
1058
|
+
performance.mark('render-end');
|
|
1059
|
+
performance.measure('list-render', 'render-start', 'render-end');
|
|
1060
|
+
|
|
1061
|
+
const measure = performance.getEntriesByName('list-render')[0];
|
|
1062
|
+
console.log(`Render took: ${measure.duration.toFixed(2)}ms`);
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
---
|
|
1066
|
+
|
|
1067
|
+
## 13. Sources
|
|
1068
|
+
|
|
1069
|
+
- [Rendering Performance -- web.dev](https://web.dev/articles/rendering-performance)
|
|
1070
|
+
- [Avoid Large, Complex Layouts and Layout Thrashing -- web.dev](https://web.dev/articles/avoid-large-complex-layouts-and-layout-thrashing)
|
|
1071
|
+
- [content-visibility: the new CSS property that boosts rendering performance -- web.dev](https://web.dev/articles/content-visibility)
|
|
1072
|
+
- [CSS content-visibility is now Baseline Newly available -- web.dev](https://web.dev/blog/css-content-visibility-baseline)
|
|
1073
|
+
- [Virtualize Long Lists with react-window -- web.dev](https://web.dev/articles/virtualize-long-lists-react-window)
|
|
1074
|
+
- [Use Web Workers to Run JS Off Main Thread -- web.dev](https://web.dev/articles/off-main-thread)
|
|
1075
|
+
- [Web Worker Overview -- web.dev](https://web.dev/learn/performance/web-worker-overview)
|
|
1076
|
+
- [Forced Reflow Insight -- Chrome for Developers](https://developer.chrome.com/docs/performance/insights/forced-reflow)
|
|
1077
|
+
- [Lighthouse: Avoid Excessive DOM Size -- Chrome for Developers](https://developer.chrome.com/docs/lighthouse/performance/dom-size)
|
|
1078
|
+
- [Long Animation Frames API -- Chrome for Developers](https://developer.chrome.com/docs/web-platform/long-animation-frames)
|
|
1079
|
+
- [Hardware-Accelerated Animation Updates -- Chrome for Developers](https://developer.chrome.com/blog/hardware-accelerated-animations)
|
|
1080
|
+
- [What Forces Layout/Reflow -- Paul Irish (GitHub Gist)](https://gist.github.com/paulirish/5d52fb081b3570c81e3a)
|
|
1081
|
+
- [CSS Triggers -- csstriggers.com](https://csstriggers.com/)
|
|
1082
|
+
- [How Large DOM Sizes Affect Interactivity -- web.dev](https://web.dev/articles/dom-size-and-interactivity)
|
|
1083
|
+
- [The Truth About CSS Selector Performance -- Microsoft Edge Blog](https://blogs.windows.com/msedgedev/2023/01/17/the-truth-about-css-selector-performance/)
|
|
1084
|
+
- [GPU Animation: Doing It Right -- Smashing Magazine](https://www.smashingmagazine.com/2016/12/gpu-animation-doing-it-right/)
|
|
1085
|
+
- [Improving Rendering Performance with CSS content-visibility -- Nolan Lawson](https://nolanlawson.com/2024/09/18/improving-rendering-performance-with-css-content-visibility/)
|
|
1086
|
+
- [Optimize DOM Size for Better Web Performance -- DebugBear](https://www.debugbear.com/blog/excessive-dom-size)
|
|
1087
|
+
- [How To Fix Forced Reflows and Layout Thrashing -- DebugBear](https://www.debugbear.com/blog/forced-reflows)
|
|
1088
|
+
- [Layout Thrashing and Forced Reflows -- webperf.tips](https://webperf.tips/tip/layout-thrashing/)
|
|
1089
|
+
- [requestAnimationFrame vs setTimeout -- OpenReplay](https://blog.openreplay.com/requestanimationframe-settimeout-use/)
|
|
1090
|
+
- [requestAnimationFrame -- MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame)
|
|
1091
|
+
- [CSS Performance Optimization -- MDN Web Docs](https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/CSS)
|
|
1092
|
+
- [Using CSS Containment -- MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Containment/Using)
|
|
1093
|
+
- [Critical Rendering Path -- MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Critical_rendering_path)
|
|
1094
|
+
- [Virtual DOM is Pure Overhead -- Svelte Blog](https://svelte.dev/blog/virtual-dom-is-pure-overhead)
|
|
1095
|
+
- [List Virtualization -- patterns.dev](https://www.patterns.dev/vanilla/virtual-lists/)
|
|
1096
|
+
- [Web Workers for Multithreading -- Smashing Magazine](https://www.smashingmagazine.com/2023/04/potential-web-workers-multithreading-web/)
|
|
1097
|
+
- [Long Animation Frames (LoAF) Guide -- SpeedCurve](https://www.speedcurve.com/blog/guide-long-animation-frames-loaf/)
|
|
1098
|
+
- [2025 In Review: What's New In Web Performance -- DebugBear](https://www.debugbear.com/blog/2025-in-web-performance)
|