{"owner":"playcanvas","repo":"engine","hasSkills":true,"totalSkillsCount":2,"totalTokensCount":4003,"categories":["root-instruction","cursor-rule"],"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md",".cursorrules (anti-overengineering.mdc)"],"skills":{"AGENTS.md":"# Agent Guidelines for PlayCanvas Engine\n\nThis document contains rules, conventions, and best practices for AI agents and developers working on the PlayCanvas Engine codebase.\n\n## Project Overview\n\nPlayCanvas is an open-source WebGL/WebGPU game engine written in JavaScript. It's a performance-critical library used by thousands of developers worldwide.\n\n- **Language**: JavaScript (ES2022) with JSDoc for TypeScript type definitions\n- **Module System**: ES Modules\n- **Node Version**: >=18.3.0 (see `engines` in `package.json`)\n- **Build System**: esbuild for the JavaScript bundles (`build.mjs`); TypeScript plus Rollup (`rollup-plugin-dts`) for the bundled `.d.ts`\n- **Testing**: Mocha + Chai + Sinon\n- **Linting**: ESLint with @playcanvas/eslint-config\n- **License**: MIT\n\n## General Code Rules\n\n### 1. Code Style and Formatting\n\n- **Follow ESLint rules**: Always run `npm run lint` before committing\n  - **Important**: Only fix lint issues in code you are actively modifying or creating\n  - Do not fix pre-existing lint issues in unrelated code unless specifically asked\n  - Focus on ensuring new and refactored code is lint-free\n- **Use JSDoc comments**: All public APIs must have comprehensive JSDoc documentation\n- **Module imports**: Use ES6 import/export syntax\n- **Naming conventions**:\n  - Classes: PascalCase (e.g., `GraphicsDevice`, `Entity`)\n  - Functions/methods: camelCase (e.g., `createShader`, `setPosition`)\n  - Constants: UPPER_SNAKE_CASE (e.g., `PIXELFORMAT_RGBA8`)\n\n### 2. File Organization\n\n- **Source files**: All engine source code goes in `src/`\n- **Directory structure**:\n  - `src/core/` - Core utilities and data structures\n  - `src/platform/` - Platform-specific code (graphics, audio, input)\n  - `src/scene/` - Scene graph, rendering, materials, shaders\n  - `src/framework/` - High-level components and application framework\n  - `src/extras/` - Optional extras and utilities\n  - `src/deprecated/` - Side-effect-free aliases for deprecated APIs (see section 9)\n- **Build output**: Generated files go in `build/` (never edit these directly)\n- **Examples**: Live in `examples/src/examples/`\n- **Tests**: Unit tests go in `test/` with `.mjs` extension\n- **File naming**: Module file names should match the main class they contain\n  - Use kebab-case for file names (e.g., `graphics-device.js` for `GraphicsDevice` class)\n  - If a class is renamed, the file should be renamed to match\n  - Multiple related classes can share a file if they're tightly coupled\n\n#### Module Dependency Hierarchy\n\nThe codebase follows a strict hierarchical structure to maintain clean architecture:\n\n```\ncore → platform → scene → framework\n```\n\n**Rules**:\n- Lower-level modules **cannot import** from higher-level modules\n- Lower-level modules **cannot use instances** from higher-level modules\n- Example: `core/` cannot import from `platform/`, `scene/`, or `framework/`\n- Example: `scene/` cannot import from `framework/`\n\n**Known Exception**:\n- `CameraComponent` (from `framework/`) is currently used in multiple places at the `scene/` level\n- **Do not introduce new exceptions** unless explicitly requested and confirmed\n- When in doubt, ask before breaking the hierarchy\n\nThis hierarchy ensures:\n- Clean separation of concerns\n- Prevents circular dependencies\n- Makes the codebase more maintainable and testable\n\n### 3. Documentation Standards\n\n- **JSDoc is mandatory** for all public APIs:\n  ```javascript\n  /**\n   * Brief description of the function.\n   *\n   * @param {string} name - Parameter description.\n   * @param {number} [optional=0] - Optional parameter with default.\n   * @returns {boolean} Return value description.\n   * @example\n   * const result = myFunction('test', 5);\n   */\n  ```\n- **Include examples** for complex APIs\n- **Document side effects**: Mention if a function modifies state\n- **Link related APIs**: Use `@see` tags to cross-reference\n- **Mark deprecations**: Use `@deprecated` with migration instructions\n\n### 4. TypeScript Definitions\n\n- JSDoc comments are used to generate TypeScript definitions\n- Run `npm run build:types` to generate `.d.ts` files\n- Test types with `npm run test:types`. This compiles the bundled declarations and the consumer-side type tests in `test/type-tests`, which check inference and augmentation against `build/playcanvas.d.ts`\n- Use proper JSDoc type annotations:\n  - `@type {TypeName}` for variables\n  - `@param {TypeName} paramName` for parameters\n  - `@returns {TypeName}` for return values\n  - Support for generics, unions, and complex types\n- **Type-only imports**: Use `@import` for types referenced in JSDoc comments\n  - These imports are only for type information, not runtime code\n  - Place at the top of the file in a JSDoc comment block\n  - Example:\n    ```javascript\n    /**\n     * @import { Texture } from './texture.js'\n     * @import { Shader } from './shader.js'\n     */\n    ```\n  - These help TypeScript understand types without adding runtime dependencies\n\n### 5. Testing\n\n- **Write tests** for all new features and bug fixes if instructed\n- **Test location**: `test/` directory, organized by module\n- **Test naming**: Use descriptive names that explain what is being tested\n- **Run tests**: `npm test` (or `npm run test:coverage` for coverage)\n- **Bundle tests**: `test/bundles/` checks the built bundles (exports, tree shaking, live bindings). Run `npm run build` first, then `npm run test:build`\n- **Test structure**:\n  ```javascript\n  describe('ClassName', function () {\n      describe('#methodName', function () {\n          it('should do something specific', function () {\n              // Test implementation\n          });\n      });\n  });\n  ```\n\n### 6. Performance Considerations\n\nThis is a **performance-critical** engine. Always consider:\n\n- **Avoid allocations in hot paths**: Reuse objects, use object pools\n- **Minimize function calls**: Inline critical code when necessary\n- **Cache property access**: Store frequently accessed properties in local variables\n- **Use typed arrays**: For numeric data (Float32Array, Uint8Array, etc.)\n\n### 7. Graphics API Considerations\n\n- **Multi-backend support**: Code must work with both WebGL2 and WebGPU\n- **Use abstraction layers**: Don't call WebGL/WebGPU APIs directly in high-level code\n- **Shader code**: Maintain both GLSL and WGSL versions\n  - GLSL: `src/scene/shader-lib/glsl/`\n  - WGSL: `src/scene/shader-lib/wgsl/`\n- **NullGraphicsDevice**: A dummy graphics device for headless/testing scenarios\n  - When adding public API methods to `GraphicsDevice`, add stub implementations to `NullGraphicsDevice`\n  - Stub methods should be empty or return safe default values to avoid crashes\n  - This ensures the engine can run without a real graphics backend for testing/server-side use\n\n## Project-Specific Rules\n\n### 8. API Stability and Deprecation\n\n- **Backward compatibility matters**: Breaking changes require major version bump\n- **Deprecation process**:\n  1. Mark API as `@deprecated` with alternatives\n  2. Add console warning in development builds\n  3. Keep deprecated code for at least one major version\n  4. Consider removing jsdocs completely\n- **Never remove public APIs** without proper deprecation cycle\n\n### 9. Build System\n\n- **Source is in `src/`**: Never edit files in `build/` directory\n- **Module exports**: Main exports defined in `src/index.js`\n- **Bundler**: `build.mjs` drives esbuild (`utils/esbuild-build-target.mjs`). Each build type (`rel`, `dbg`, `prf`, `min`) is emitted as a UMD bundle (`build/playcanvas*.js`) and an ESM bundle (`build/playcanvas*.mjs`). The `rel`, `dbg` and `prf` ESM builds also emit an unbundled module tree (`build/playcanvas/src/`, `build/playcanvas.dbg/src/`, `build/playcanvas.prf/src/`), which is what `import 'playcanvas'` resolves to\n- **Type declarations**: `npm run build:types` runs `tsc` over the JSDoc, patches the output with `utils/plugins/rollup-types-fixup.mjs` (hand-declared `StandardMaterial` accessors, optional `ScriptType` lifecycle methods, and the `AssetMap` typedef rewritten into an augmentable interface) and bundles it with Rollup (`rollup-plugin-dts`) into `build/playcanvas.d.ts`\n- **Debug stripping**: the `Debug`, `DebugHelper`, `DebugGraphics` and `WebgpuDebug` calls listed in `STRIP_FUNCTIONS` (`utils/esbuild-build-target.mjs`) are removed from every build except `dbg`. `// #if _DEBUG` blocks survive only in `dbg`; `// #if _PROFILER` blocks survive in `dbg` and `prf`\n- **Tree shaking**: `package.json` declares `\"sideEffects\": false`, so consumers' bundlers drop every module they don't import from. Therefore:\n  - Never add module-scope side effects (top-level calls, prototype patches, registry writes, `window` access). Do registration inside constructors or functions\n  - Deprecated constant aliases and helper functions go in `src/deprecated/deprecated.js`, which must stay free of module-scope side effects\n  - Deprecated prototype shims (e.g. `Object.defineProperty(Foo.prototype, ...)`) go at the bottom of the module that defines the class, so they ship only when that class does\n  - `test/bundles/treeshake.test.mjs` guards both rules\n\n### 10. Dependencies\n\n- **Minimal dependencies**: Avoid adding new dependencies unless absolutely necessary\n- **Types only**: `@types/*` and `@webgpu/types` are the main dependencies\n\n### 11. Error Handling\n\n- **Debug class**: Use `Debug` class (`src/core/debug.js`) for logging and assertions\n  - Methods include: `assert()`, `warn()`, `warnOnce()`, `error()`, `errorOnce()`, `deprecated()`, `removed()`, `log()`, `logOnce()`, `trace()`\n  - **Important**: All Debug methods are stripped out in production builds\n  - Use `*Once()` variants to avoid spam in loops or frequent calls\n  - Don't use Debug in hot paths - even in debug builds, excessive logging impacts performance\n- **DebugHelper class**: Helper methods for debugging (also stripped in production)\n  - `setName()`, `setLabel()`, `setDestroyed()` for marking objects\n\n### 12. Code Comments\n\n- **Explain \"why\" not \"what\"**: Code should be self-documenting, but comments help with quick understanding\n- **Complex algorithms**: Explain the approach and any non-obvious optimizations\n- **TODOs**: Include issue reference or context\n  ```javascript\n  // TODO: Optimize this when texture streaming is implemented (#1234)\n  ```\n- **Avoid very obvious comments**: Don't state what the code clearly does\n\n### 13. Commit and PR Guidelines\n\n- **Clear commit messages**: Use conventional commits format\n  - `feat: Add feature description`\n  - `fix: Bug fix description`\n  - `perf: Performance improvement description`\n  - `docs: Documentation update`\n  - `refactor: Code refactoring`\n  - `test: Test updates`\n- **Reference issues**: Include issue number in commit message in format 'Fixed #1234'\n- **Small, focused commits**: Each commit should be a logical unit\n- **No generated files**: Don't commit files in `build/` directory\n\n### 14. Browser Compatibility\n\n- **Modern browsers only**: ES6+ features are allowed\n- **No polyfills in engine**: Users can add their own if needed\n- **WebGL 2.0 minimum**: WebGL 1.0 is not supported\n- **WebGPU support**: Must maintain compatibility with WebGPU API\n\n## Common Patterns\n\n### 15. Object Creation\n\n```javascript\n// Prefer class syntax with TypeScript-like property declarations\nclass MyClass {\n    /**\n     * @type {GraphicsDevice}\n     */\n    device;\n\n    /**\n     * @type {string}\n     */\n    name;\n\n    constructor(device, options = {}) {\n        this.device = device;\n        this.name = options.name ?? 'default';\n    }\n\n    destroy() {\n        // Clean up resources\n        this.device = null;\n    }\n}\n```\n\n### 16. Resource Management\n\n```javascript\n// Always provide destroy() method for objects holding resources\nclass Resource {\n    constructor() {\n        this._resource = createResource();\n    }\n\n    destroy() {\n        this._resource?.destroy();\n        this._resource = null;\n    }\n}\n```\n\n### 17. Root Cause Analysis\n\nAlways address the root cause of issues rather than implementing workarounds that hide or suppress problems:\n\n- **Identify the root cause**: When you encounter an error or unexpected behavior, investigate why it's happening\n- **Don't mask symptoms**: Avoid solutions that simply hide errors or suppress warnings without fixing the underlying issue\n- **Fix at the source**: When you identify the root cause, fix it where the problem originates, not where it manifests\n\n## Things to Avoid\n\n### 18. Anti-Patterns\n\n- **Don't use `var`**: Use `const` or `let` (except in legacy `scripts/` directory)\n- **Avoid `any` types**: Be specific in JSDoc type annotations\n- **No global state**: Everything should be instance-based\n  - Exception: Module-scope variables for local optimization are allowed (e.g., reusable Mat4 instances)\n  - These must never be exported and should only be used within the module\n- **Don't bypass abstractions**: Use the platform API, not direct WebGL/WebGPU calls\n- **Don't suppress linter warnings**: Fix the underlying issue\n\n### 19. Performance Anti-Patterns\n\n- **No allocations in render loop**: Pre-allocate and reuse if feasible\n- **Don't use `try/catch` in hot paths**: It prevents optimizations\n- **No string concatenation in loops**: Build arrays and join\n- **Don't create functions in loops**: Define functions outside\n\n## AI Agent-Specific Guidelines\n\n### 20. When Making Changes\n\n- **Read existing code first**: Understand the context and patterns\n- **Follow existing style**: Match the style of surrounding code\n- **Lint your changes**: Run `npm run lint`\n- **Update documentation**: Modify JSDoc comments when changing APIs\n- **Consider performance**: This is a real-time engine, every microsecond counts\n- **Check both WebGL and WebGPU**: Changes may affect both backends\n\n### 21. When Creating Examples\n\n- Examples go in `examples/src/examples/`\n- Follow existing example structure (see other `.example.mjs` files)\n- Include descriptive comments\n- Keep examples simple and focused on one feature\n\n### 22. When Authoring Scripts\n\n- Reusable scripts live in `scripts/esm/` and expose their configuration as script attributes\n- **Attribute enums must use readable string values**: declare them as `@enum {string}` with\n  human-readable values (e.g., `LINEAR: 'linear'`), never as raw numeric engine constants\n  - Numeric constant values (e.g., `PIXELFORMAT_RGBA16F = 12`) are implementation details that\n    can change between releases and make attribute data unreadable (`\"renderFormat\": 12`)\n  - Import the engine constants and resolve the strings via lookup maps where the script applies\n    them (see `scripts/esm/camera-frame.mjs` for the pattern)\n  - Keep accepting raw numeric values (pass them through unchanged) so existing attribute data\n    continues to work\n\n### 23. When Writing PR Descriptions\n\n- **Format as a single code block**: Always deliver PR descriptions wrapped in triple backticks for easy copy/paste\n- **Structure**:\n  - Brief title and overview\n  - Bullet points for functionality changes\n  - Technical details section (if relevant)\n  - **Clearly list all public API changes** with before/after code examples\n  - List updated examples (if applicable)\n  - Performance considerations (if relevant)\n- **Focus on user-facing changes**: What developers using the engine will see/use\n- **Be concise but complete**: Include all breaking changes and new APIs\n- **Avoid excessive detail**: Group related changes together, don't list every tiny implementation detail or internal refactoring\n- **Only document public APIs**: Do not list functionality tagged with `@ignore`, `@protected`, or `@private` as these are internal implementation details\n\n## Resources\n\n- **API Reference**: https://api.playcanvas.com/engine/\n- **User Manual**: https://developer.playcanvas.com/user-manual/engine/\n- **Developer Site**: https://github.com/playcanvas/developer-site\n  - For large features, ask to add documentation to the User Manual\n  - Manual pages are Markdown files in the `docs/` directory\n- **Examples**: https://playcanvas.github.io\n- **Forum**: https://forum.playcanvas.com\n- **Discord**: https://discord.gg/RSaMRzg\n- **GitHub Issues**: https://github.com/playcanvas/engine/issues\n\n## Questions?\n\nWhen in doubt:\n1. Look at similar existing code in the codebase\n2. Check the ESLint configuration\n3. Review recent commits for patterns\n4. If unclear or multiple valid approaches exist, ask instead of picking a possibly incorrect solution\n\n---\n\n**Remember**: This is a library used by thousands of developers. Quality, performance, and stability are paramount. When in doubt, prefer conservative, well-tested changes over clever optimizations.\n\n",".cursorrules (anti-overengineering.mdc)":"# Anti-Over-Engineering\n\nOnly change what was asked. Simplest solution first. When unsure, ask.\n\nDo not modify unrequested code, add abstractions without a concrete need, import unnecessary dependencies, rewrite entire files for small changes, or add error handling for impossible scenarios.\n\nBefore delivery: verify you only changed requested code, check for simpler approaches, confirm no unrequested files were touched."},"files":{"AGENTS.md":"# Agent Guidelines for PlayCanvas Engine\n\nThis document contains rules, conventions, and best practices for AI agents and developers working on the PlayCanvas Engine codebase.\n\n## Project Overview\n\nPlayCanvas is an open-source WebGL/WebGPU game engine written in JavaScript. It's a performance-critical library used by thousands of developers worldwide.\n\n- **Language**: JavaScript (ES2022) with JSDoc for TypeScript type definitions\n- **Module System**: ES Modules\n- **Node Version**: >=18.3.0 (see `engines` in `package.json`)\n- **Build System**: esbuild for the JavaScript bundles (`build.mjs`); TypeScript plus Rollup (`rollup-plugin-dts`) for the bundled `.d.ts`\n- **Testing**: Mocha + Chai + Sinon\n- **Linting**: ESLint with @playcanvas/eslint-config\n- **License**: MIT\n\n## General Code Rules\n\n### 1. Code Style and Formatting\n\n- **Follow ESLint rules**: Always run `npm run lint` before committing\n  - **Important**: Only fix lint issues in code you are actively modifying or creating\n  - Do not fix pre-existing lint issues in unrelated code unless specifically asked\n  - Focus on ensuring new and refactored code is lint-free\n- **Use JSDoc comments**: All public APIs must have comprehensive JSDoc documentation\n- **Module imports**: Use ES6 import/export syntax\n- **Naming conventions**:\n  - Classes: PascalCase (e.g., `GraphicsDevice`, `Entity`)\n  - Functions/methods: camelCase (e.g., `createShader`, `setPosition`)\n  - Constants: UPPER_SNAKE_CASE (e.g., `PIXELFORMAT_RGBA8`)\n\n### 2. File Organization\n\n- **Source files**: All engine source code goes in `src/`\n- **Directory structure**:\n  - `src/core/` - Core utilities and data structures\n  - `src/platform/` - Platform-specific code (graphics, audio, input)\n  - `src/scene/` - Scene graph, rendering, materials, shaders\n  - `src/framework/` - High-level components and application framework\n  - `src/extras/` - Optional extras and utilities\n  - `src/deprecated/` - Side-effect-free aliases for deprecated APIs (see section 9)\n- **Build output**: Generated files go in `build/` (never edit these directly)\n- **Examples**: Live in `examples/src/examples/`\n- **Tests**: Unit tests go in `test/` with `.mjs` extension\n- **File naming**: Module file names should match the main class they contain\n  - Use kebab-case for file names (e.g., `graphics-device.js` for `GraphicsDevice` class)\n  - If a class is renamed, the file should be renamed to match\n  - Multiple related classes can share a file if they're tightly coupled\n\n#### Module Dependency Hierarchy\n\nThe codebase follows a strict hierarchical structure to maintain clean architecture:\n\n```\ncore → platform → scene → framework\n```\n\n**Rules**:\n- Lower-level modules **cannot import** from higher-level modules\n- Lower-level modules **cannot use instances** from higher-level modules\n- Example: `core/` cannot import from `platform/`, `scene/`, or `framework/`\n- Example: `scene/` cannot import from `framework/`\n\n**Known Exception**:\n- `CameraComponent` (from `framework/`) is currently used in multiple places at the `scene/` level\n- **Do not introduce new exceptions** unless explicitly requested and confirmed\n- When in doubt, ask before breaking the hierarchy\n\nThis hierarchy ensures:\n- Clean separation of concerns\n- Prevents circular dependencies\n- Makes the codebase more maintainable and testable\n\n### 3. Documentation Standards\n\n- **JSDoc is mandatory** for all public APIs:\n  ```javascript\n  /**\n   * Brief description of the function.\n   *\n   * @param {string} name - Parameter description.\n   * @param {number} [optional=0] - Optional parameter with default.\n   * @returns {boolean} Return value description.\n   * @example\n   * const result = myFunction('test', 5);\n   */\n  ```\n- **Include examples** for complex APIs\n- **Document side effects**: Mention if a function modifies state\n- **Link related APIs**: Use `@see` tags to cross-reference\n- **Mark deprecations**: Use `@deprecated` with migration instructions\n\n### 4. TypeScript Definitions\n\n- JSDoc comments are used to generate TypeScript definitions\n- Run `npm run build:types` to generate `.d.ts` files\n- Test types with `npm run test:types`. This compiles the bundled declarations and the consumer-side type tests in `test/type-tests`, which check inference and augmentation against `build/playcanvas.d.ts`\n- Use proper JSDoc type annotations:\n  - `@type {TypeName}` for variables\n  - `@param {TypeName} paramName` for parameters\n  - `@returns {TypeName}` for return values\n  - Support for generics, unions, and complex types\n- **Type-only imports**: Use `@import` for types referenced in JSDoc comments\n  - These imports are only for type information, not runtime code\n  - Place at the top of the file in a JSDoc comment block\n  - Example:\n    ```javascript\n    /**\n     * @import { Texture } from './texture.js'\n     * @import { Shader } from './shader.js'\n     */\n    ```\n  - These help TypeScript understand types without adding runtime dependencies\n\n### 5. Testing\n\n- **Write tests** for all new features and bug fixes if instructed\n- **Test location**: `test/` directory, organized by module\n- **Test naming**: Use descriptive names that explain what is being tested\n- **Run tests**: `npm test` (or `npm run test:coverage` for coverage)\n- **Bundle tests**: `test/bundles/` checks the built bundles (exports, tree shaking, live bindings). Run `npm run build` first, then `npm run test:build`\n- **Test structure**:\n  ```javascript\n  describe('ClassName', function () {\n      describe('#methodName', function () {\n          it('should do something specific', function () {\n              // Test implementation\n          });\n      });\n  });\n  ```\n\n### 6. Performance Considerations\n\nThis is a **performance-critical** engine. Always consider:\n\n- **Avoid allocations in hot paths**: Reuse objects, use object pools\n- **Minimize function calls**: Inline critical code when necessary\n- **Cache property access**: Store frequently accessed properties in local variables\n- **Use typed arrays**: For numeric data (Float32Array, Uint8Array, etc.)\n\n### 7. Graphics API Considerations\n\n- **Multi-backend support**: Code must work with both WebGL2 and WebGPU\n- **Use abstraction layers**: Don't call WebGL/WebGPU APIs directly in high-level code\n- **Shader code**: Maintain both GLSL and WGSL versions\n  - GLSL: `src/scene/shader-lib/glsl/`\n  - WGSL: `src/scene/shader-lib/wgsl/`\n- **NullGraphicsDevice**: A dummy graphics device for headless/testing scenarios\n  - When adding public API methods to `GraphicsDevice`, add stub implementations to `NullGraphicsDevice`\n  - Stub methods should be empty or return safe default values to avoid crashes\n  - This ensures the engine can run without a real graphics backend for testing/server-side use\n\n## Project-Specific Rules\n\n### 8. API Stability and Deprecation\n\n- **Backward compatibility matters**: Breaking changes require major version bump\n- **Deprecation process**:\n  1. Mark API as `@deprecated` with alternatives\n  2. Add console warning in development builds\n  3. Keep deprecated code for at least one major version\n  4. Consider removing jsdocs completely\n- **Never remove public APIs** without proper deprecation cycle\n\n### 9. Build System\n\n- **Source is in `src/`**: Never edit files in `build/` directory\n- **Module exports**: Main exports defined in `src/index.js`\n- **Bundler**: `build.mjs` drives esbuild (`utils/esbuild-build-target.mjs`). Each build type (`rel`, `dbg`, `prf`, `min`) is emitted as a UMD bundle (`build/playcanvas*.js`) and an ESM bundle (`build/playcanvas*.mjs`). The `rel`, `dbg` and `prf` ESM builds also emit an unbundled module tree (`build/playcanvas/src/`, `build/playcanvas.dbg/src/`, `build/playcanvas.prf/src/`), which is what `import 'playcanvas'` resolves to\n- **Type declarations**: `npm run build:types` runs `tsc` over the JSDoc, patches the output with `utils/plugins/rollup-types-fixup.mjs` (hand-declared `StandardMaterial` accessors, optional `ScriptType` lifecycle methods, and the `AssetMap` typedef rewritten into an augmentable interface) and bundles it with Rollup (`rollup-plugin-dts`) into `build/playcanvas.d.ts`\n- **Debug stripping**: the `Debug`, `DebugHelper`, `DebugGraphics` and `WebgpuDebug` calls listed in `STRIP_FUNCTIONS` (`utils/esbuild-build-target.mjs`) are removed from every build except `dbg`. `// #if _DEBUG` blocks survive only in `dbg`; `// #if _PROFILER` blocks survive in `dbg` and `prf`\n- **Tree shaking**: `package.json` declares `\"sideEffects\": false`, so consumers' bundlers drop every module they don't import from. Therefore:\n  - Never add module-scope side effects (top-level calls, prototype patches, registry writes, `window` access). Do registration inside constructors or functions\n  - Deprecated constant aliases and helper functions go in `src/deprecated/deprecated.js`, which must stay free of module-scope side effects\n  - Deprecated prototype shims (e.g. `Object.defineProperty(Foo.prototype, ...)`) go at the bottom of the module that defines the class, so they ship only when that class does\n  - `test/bundles/treeshake.test.mjs` guards both rules\n\n### 10. Dependencies\n\n- **Minimal dependencies**: Avoid adding new dependencies unless absolutely necessary\n- **Types only**: `@types/*` and `@webgpu/types` are the main dependencies\n\n### 11. Error Handling\n\n- **Debug class**: Use `Debug` class (`src/core/debug.js`) for logging and assertions\n  - Methods include: `assert()`, `warn()`, `warnOnce()`, `error()`, `errorOnce()`, `deprecated()`, `removed()`, `log()`, `logOnce()`, `trace()`\n  - **Important**: All Debug methods are stripped out in production builds\n  - Use `*Once()` variants to avoid spam in loops or frequent calls\n  - Don't use Debug in hot paths - even in debug builds, excessive logging impacts performance\n- **DebugHelper class**: Helper methods for debugging (also stripped in production)\n  - `setName()`, `setLabel()`, `setDestroyed()` for marking objects\n\n### 12. Code Comments\n\n- **Explain \"why\" not \"what\"**: Code should be self-documenting, but comments help with quick understanding\n- **Complex algorithms**: Explain the approach and any non-obvious optimizations\n- **TODOs**: Include issue reference or context\n  ```javascript\n  // TODO: Optimize this when texture streaming is implemented (#1234)\n  ```\n- **Avoid very obvious comments**: Don't state what the code clearly does\n\n### 13. Commit and PR Guidelines\n\n- **Clear commit messages**: Use conventional commits format\n  - `feat: Add feature description`\n  - `fix: Bug fix description`\n  - `perf: Performance improvement description`\n  - `docs: Documentation update`\n  - `refactor: Code refactoring`\n  - `test: Test updates`\n- **Reference issues**: Include issue number in commit message in format 'Fixed #1234'\n- **Small, focused commits**: Each commit should be a logical unit\n- **No generated files**: Don't commit files in `build/` directory\n\n### 14. Browser Compatibility\n\n- **Modern browsers only**: ES6+ features are allowed\n- **No polyfills in engine**: Users can add their own if needed\n- **WebGL 2.0 minimum**: WebGL 1.0 is not supported\n- **WebGPU support**: Must maintain compatibility with WebGPU API\n\n## Common Patterns\n\n### 15. Object Creation\n\n```javascript\n// Prefer class syntax with TypeScript-like property declarations\nclass MyClass {\n    /**\n     * @type {GraphicsDevice}\n     */\n    device;\n\n    /**\n     * @type {string}\n     */\n    name;\n\n    constructor(device, options = {}) {\n        this.device = device;\n        this.name = options.name ?? 'default';\n    }\n\n    destroy() {\n        // Clean up resources\n        this.device = null;\n    }\n}\n```\n\n### 16. Resource Management\n\n```javascript\n// Always provide destroy() method for objects holding resources\nclass Resource {\n    constructor() {\n        this._resource = createResource();\n    }\n\n    destroy() {\n        this._resource?.destroy();\n        this._resource = null;\n    }\n}\n```\n\n### 17. Root Cause Analysis\n\nAlways address the root cause of issues rather than implementing workarounds that hide or suppress problems:\n\n- **Identify the root cause**: When you encounter an error or unexpected behavior, investigate why it's happening\n- **Don't mask symptoms**: Avoid solutions that simply hide errors or suppress warnings without fixing the underlying issue\n- **Fix at the source**: When you identify the root cause, fix it where the problem originates, not where it manifests\n\n## Things to Avoid\n\n### 18. Anti-Patterns\n\n- **Don't use `var`**: Use `const` or `let` (except in legacy `scripts/` directory)\n- **Avoid `any` types**: Be specific in JSDoc type annotations\n- **No global state**: Everything should be instance-based\n  - Exception: Module-scope variables for local optimization are allowed (e.g., reusable Mat4 instances)\n  - These must never be exported and should only be used within the module\n- **Don't bypass abstractions**: Use the platform API, not direct WebGL/WebGPU calls\n- **Don't suppress linter warnings**: Fix the underlying issue\n\n### 19. Performance Anti-Patterns\n\n- **No allocations in render loop**: Pre-allocate and reuse if feasible\n- **Don't use `try/catch` in hot paths**: It prevents optimizations\n- **No string concatenation in loops**: Build arrays and join\n- **Don't create functions in loops**: Define functions outside\n\n## AI Agent-Specific Guidelines\n\n### 20. When Making Changes\n\n- **Read existing code first**: Understand the context and patterns\n- **Follow existing style**: Match the style of surrounding code\n- **Lint your changes**: Run `npm run lint`\n- **Update documentation**: Modify JSDoc comments when changing APIs\n- **Consider performance**: This is a real-time engine, every microsecond counts\n- **Check both WebGL and WebGPU**: Changes may affect both backends\n\n### 21. When Creating Examples\n\n- Examples go in `examples/src/examples/`\n- Follow existing example structure (see other `.example.mjs` files)\n- Include descriptive comments\n- Keep examples simple and focused on one feature\n\n### 22. When Authoring Scripts\n\n- Reusable scripts live in `scripts/esm/` and expose their configuration as script attributes\n- **Attribute enums must use readable string values**: declare them as `@enum {string}` with\n  human-readable values (e.g., `LINEAR: 'linear'`), never as raw numeric engine constants\n  - Numeric constant values (e.g., `PIXELFORMAT_RGBA16F = 12`) are implementation details that\n    can change between releases and make attribute data unreadable (`\"renderFormat\": 12`)\n  - Import the engine constants and resolve the strings via lookup maps where the script applies\n    them (see `scripts/esm/camera-frame.mjs` for the pattern)\n  - Keep accepting raw numeric values (pass them through unchanged) so existing attribute data\n    continues to work\n\n### 23. When Writing PR Descriptions\n\n- **Format as a single code block**: Always deliver PR descriptions wrapped in triple backticks for easy copy/paste\n- **Structure**:\n  - Brief title and overview\n  - Bullet points for functionality changes\n  - Technical details section (if relevant)\n  - **Clearly list all public API changes** with before/after code examples\n  - List updated examples (if applicable)\n  - Performance considerations (if relevant)\n- **Focus on user-facing changes**: What developers using the engine will see/use\n- **Be concise but complete**: Include all breaking changes and new APIs\n- **Avoid excessive detail**: Group related changes together, don't list every tiny implementation detail or internal refactoring\n- **Only document public APIs**: Do not list functionality tagged with `@ignore`, `@protected`, or `@private` as these are internal implementation details\n\n## Resources\n\n- **API Reference**: https://api.playcanvas.com/engine/\n- **User Manual**: https://developer.playcanvas.com/user-manual/engine/\n- **Developer Site**: https://github.com/playcanvas/developer-site\n  - For large features, ask to add documentation to the User Manual\n  - Manual pages are Markdown files in the `docs/` directory\n- **Examples**: https://playcanvas.github.io\n- **Forum**: https://forum.playcanvas.com\n- **Discord**: https://discord.gg/RSaMRzg\n- **GitHub Issues**: https://github.com/playcanvas/engine/issues\n\n## Questions?\n\nWhen in doubt:\n1. Look at similar existing code in the codebase\n2. Check the ESLint configuration\n3. Review recent commits for patterns\n4. If unclear or multiple valid approaches exist, ask instead of picking a possibly incorrect solution\n\n---\n\n**Remember**: This is a library used by thousands of developers. Quality, performance, and stability are paramount. When in doubt, prefer conservative, well-tested changes over clever optimizations.\n\n",".cursorrules (anti-overengineering.mdc)":"# Anti-Over-Engineering\n\nOnly change what was asked. Simplest solution first. When unsure, ask.\n\nDo not modify unrequested code, add abstractions without a concrete need, import unnecessary dependencies, rewrite entire files for small changes, or add error handling for impossible scenarios.\n\nBefore delivery: verify you only changed requested code, check for simpler approaches, confirm no unrequested files were touched."},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/playcanvas/engine/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Agent Guidelines for PlayCanvas Engine\n\nThis document contains rules, conventions, and best practices for AI agents and developers working on the PlayCanvas Engine codebase.\n\n## Project Overview\n\nPlayCanvas is an open-source WebGL/WebGPU game engine written in JavaScript. It's a performance-critical library used by thousands of developers worldwide.\n\n- **Language**: JavaScript (ES2022) with JSDoc for TypeScript type definitions\n- **Module System**: ES Modules\n- **Node Version**: >=18.3.0 (see `engines` in `package.json`)\n- **Build System**: esbuild for the JavaScript bundles (`build.mjs`); TypeScript plus Rollup (`rollup-plugin-dts`) for the bundled `.d.ts`\n- **Testing**: Mocha + Chai + Sinon\n- **Linting**: ESLint with @playcanvas/eslint-config\n- **License**: MIT\n\n## General Code Rules\n\n### 1. Code Style and Formatting\n\n- **Follow ESLint rules**: Always run `npm run lint` before committing\n  - **Important**: Only fix lint issues in code you are actively modifying or creating\n  - Do not fix pre-existing lint issues in unrelated code unless specifically asked\n  - Focus on ensuring new and refactored code is lint-free\n- **Use JSDoc comments**: All public APIs must have comprehensive JSDoc documentation\n- **Module imports**: Use ES6 import/export syntax\n- **Naming conventions**:\n  - Classes: PascalCase (e.g., `GraphicsDevice`, `Entity`)\n  - Functions/methods: camelCase (e.g., `createShader`, `setPosition`)\n  - Constants: UPPER_SNAKE_CASE (e.g., `PIXELFORMAT_RGBA8`)\n\n### 2. File Organization\n\n- **Source files**: All engine source code goes in `src/`\n- **Directory structure**:\n  - `src/core/` - Core utilities and data structures\n  - `src/platform/` - Platform-specific code (graphics, audio, input)\n  - `src/scene/` - Scene graph, rendering, materials, shaders\n  - `src/framework/` - High-level components and application framework\n  - `src/extras/` - Optional extras and utilities\n  - `src/deprecated/` - Side-effect-free aliases for deprecated APIs (see section 9)\n- **Build output**: Generated files go in `build/` (never edit these directly)\n- **Examples**: Live in `examples/src/examples/`\n- **Tests**: Unit tests go in `test/` with `.mjs` extension\n- **File naming**: Module file names should match the main class they contain\n  - Use kebab-case for file names (e.g., `graphics-device.js` for `GraphicsDevice` class)\n  - If a class is renamed, the file should be renamed to match\n  - Multiple related classes can share a file if they're tightly coupled\n\n#### Module Dependency Hierarchy\n\nThe codebase follows a strict hierarchical structure to maintain clean architecture:\n\n```\ncore → platform → scene → framework\n```\n\n**Rules**:\n- Lower-level modules **cannot import** from higher-level modules\n- Lower-level modules **cannot use instances** from higher-level modules\n- Example: `core/` cannot import from `platform/`, `scene/`, or `framework/`\n- Example: `scene/` cannot import from `framework/`\n\n**Known Exception**:\n- `CameraComponent` (from `framework/`) is currently used in multiple places at the `scene/` level\n- **Do not introduce new exceptions** unless explicitly requested and confirmed\n- When in doubt, ask before breaking the hierarchy\n\nThis hierarchy ensures:\n- Clean separation of concerns\n- Prevents circular dependencies\n- Makes the codebase more maintainable and testable\n\n### 3. Documentation Standards\n\n- **JSDoc is mandatory** for all public APIs:\n  ```javascript\n  /**\n   * Brief description of the function.\n   *\n   * @param {string} name - Parameter description.\n   * @param {number} [optional=0] - Optional parameter with default.\n   * @returns {boolean} Return value description.\n   * @example\n   * const result = myFunction('test', 5);\n   */\n  ```\n- **Include examples** for complex APIs\n- **Document side effects**: Mention if a function modifies state\n- **Link related APIs**: Use `@see` tags to cross-reference\n- **Mark deprecations**: Use `@deprecated` with migration instructions\n\n### 4. TypeScript Definitions\n\n- JSDoc comments are used to generate TypeScript definitions\n- Run `npm run build:types` to generate `.d.ts` files\n- Test types with `npm run test:types`. This compiles the bundled declarations and the consumer-side type tests in `test/type-tests`, which check inference and augmentation against `build/playcanvas.d.ts`\n- Use proper JSDoc type annotations:\n  - `@type {TypeName}` for variables\n  - `@param {TypeName} paramName` for parameters\n  - `@returns {TypeName}` for return values\n  - Support for generics, unions, and complex types\n- **Type-only imports**: Use `@import` for types referenced in JSDoc comments\n  - These imports are only for type information, not runtime code\n  - Place at the top of the file in a JSDoc comment block\n  - Example:\n    ```javascript\n    /**\n     * @import { Texture } from './texture.js'\n     * @import { Shader } from './shader.js'\n     */\n    ```\n  - These help TypeScript understand types without adding runtime dependencies\n\n### 5. Testing\n\n- **Write tests** for all new features and bug fixes if instructed\n- **Test location**: `test/` directory, organized by module\n- **Test naming**: Use descriptive names that explain what is being tested\n- **Run tests**: `npm test` (or `npm run test:coverage` for coverage)\n- **Bundle tests**: `test/bundles/` checks the built bundles (exports, tree shaking, live bindings). Run `npm run build` first, then `npm run test:build`\n- **Test structure**:\n  ```javascript\n  describe('ClassName', function () {\n      describe('#methodName', function () {\n          it('should do something specific', function () {\n              // Test implementation\n          });\n      });\n  });\n  ```\n\n### 6. Performance Considerations\n\nThis is a **performance-critical** engine. Always consider:\n\n- **Avoid allocations in hot paths**: Reuse objects, use object pools\n- **Minimize function calls**: Inline critical code when necessary\n- **Cache property access**: Store frequently accessed properties in local variables\n- **Use typed arrays**: For numeric data (Float32Array, Uint8Array, etc.)\n\n### 7. Graphics API Considerations\n\n- **Multi-backend support**: Code must work with both WebGL2 and WebGPU\n- **Use abstraction layers**: Don't call WebGL/WebGPU APIs directly in high-level code\n- **Shader code**: Maintain both GLSL and WGSL versions\n  - GLSL: `src/scene/shader-lib/glsl/`\n  - WGSL: `src/scene/shader-lib/wgsl/`\n- **NullGraphicsDevice**: A dummy graphics device for headless/testing scenarios\n  - When adding public API methods to `GraphicsDevice`, add stub implementations to `NullGraphicsDevice`\n  - Stub methods should be empty or return safe default values to avoid crashes\n  - This ensures the engine can run without a real graphics backend for testing/server-side use\n\n## Project-Specific Rules\n\n### 8. API Stability and Deprecation\n\n- **Backward compatibility matters**: Breaking changes require major version bump\n- **Deprecation process**:\n  1. Mark API as `@deprecated` with alternatives\n  2. Add console warning in development builds\n  3. Keep deprecated code for at least one major version\n  4. Consider removing jsdocs completely\n- **Never remove public APIs** without proper deprecation cycle\n\n### 9. Build System\n\n- **Source is in `src/`**: Never edit files in `build/` directory\n- **Module exports**: Main exports defined in `src/index.js`\n- **Bundler**: `build.mjs` drives esbuild (`utils/esbuild-build-target.mjs`). Each build type (`rel`, `dbg`, `prf`, `min`) is emitted as a UMD bundle (`build/playcanvas*.js`) and an ESM bundle (`build/playcanvas*.mjs`). The `rel`, `dbg` and `prf` ESM builds also emit an unbundled module tree (`build/playcanvas/src/`, `build/playcanvas.dbg/src/`, `build/playcanvas.prf/src/`), which is what `import 'playcanvas'` resolves to\n- **Type declarations**: `npm run build:types` runs `tsc` over the JSDoc, patches the output with `utils/plugins/rollup-types-fixup.mjs` (hand-declared `StandardMaterial` accessors, optional `ScriptType` lifecycle methods, and the `AssetMap` typedef rewritten into an augmentable interface) and bundles it with Rollup (`rollup-plugin-dts`) into `build/playcanvas.d.ts`\n- **Debug stripping**: the `Debug`, `DebugHelper`, `DebugGraphics` and `WebgpuDebug` calls listed in `STRIP_FUNCTIONS` (`utils/esbuild-build-target.mjs`) are removed from every build except `dbg`. `// #if _DEBUG` blocks survive only in `dbg`; `// #if _PROFILER` blocks survive in `dbg` and `prf`\n- **Tree shaking**: `package.json` declares `\"sideEffects\": false`, so consumers' bundlers drop every module they don't import from. Therefore:\n  - Never add module-scope side effects (top-level calls, prototype patches, registry writes, `window` access). Do registration inside constructors or functions\n  - Deprecated constant aliases and helper functions go in `src/deprecated/deprecated.js`, which must stay free of module-scope side effects\n  - Deprecated prototype shims (e.g. `Object.defineProperty(Foo.prototype, ...)`) go at the bottom of the module that defines the class, so they ship only when that class does\n  - `test/bundles/treeshake.test.mjs` guards both rules\n\n### 10. Dependencies\n\n- **Minimal dependencies**: Avoid adding new dependencies unless absolutely necessary\n- **Types only**: `@types/*` and `@webgpu/types` are the main dependencies\n\n### 11. Error Handling\n\n- **Debug class**: Use `Debug` class (`src/core/debug.js`) for logging and assertions\n  - Methods include: `assert()`, `warn()`, `warnOnce()`, `error()`, `errorOnce()`, `deprecated()`, `removed()`, `log()`, `logOnce()`, `trace()`\n  - **Important**: All Debug methods are stripped out in production builds\n  - Use `*Once()` variants to avoid spam in loops or frequent calls\n  - Don't use Debug in hot paths - even in debug builds, excessive logging impacts performance\n- **DebugHelper class**: Helper methods for debugging (also stripped in production)\n  - `setName()`, `setLabel()`, `setDestroyed()` for marking objects\n\n### 12. Code Comments\n\n- **Explain \"why\" not \"what\"**: Code should be self-documenting, but comments help with quick understanding\n- **Complex algorithms**: Explain the approach and any non-obvious optimizations\n- **TODOs**: Include issue reference or context\n  ```javascript\n  // TODO: Optimize this when texture streaming is implemented (#1234)\n  ```\n- **Avoid very obvious comments**: Don't state what the code clearly does\n\n### 13. Commit and PR Guidelines\n\n- **Clear commit messages**: Use conventional commits format\n  - `feat: Add feature description`\n  - `fix: Bug fix description`\n  - `perf: Performance improvement description`\n  - `docs: Documentation update`\n  - `refactor: Code refactoring`\n  - `test: Test updates`\n- **Reference issues**: Include issue number in commit message in format 'Fixed #1234'\n- **Small, focused commits**: Each commit should be a logical unit\n- **No generated files**: Don't commit files in `build/` directory\n\n### 14. Browser Compatibility\n\n- **Modern browsers only**: ES6+ features are allowed\n- **No polyfills in engine**: Users can add their own if needed\n- **WebGL 2.0 minimum**: WebGL 1.0 is not supported\n- **WebGPU support**: Must maintain compatibility with WebGPU API\n\n## Common Patterns\n\n### 15. Object Creation\n\n```javascript\n// Prefer class syntax with TypeScript-like property declarations\nclass MyClass {\n    /**\n     * @type {GraphicsDevice}\n     */\n    device;\n\n    /**\n     * @type {string}\n     */\n    name;\n\n    constructor(device, options = {}) {\n        this.device = device;\n        this.name = options.name ?? 'default';\n    }\n\n    destroy() {\n        // Clean up resources\n        this.device = null;\n    }\n}\n```\n\n### 16. Resource Management\n\n```javascript\n// Always provide destroy() method for objects holding resources\nclass Resource {\n    constructor() {\n        this._resource = createResource();\n    }\n\n    destroy() {\n        this._resource?.destroy();\n        this._resource = null;\n    }\n}\n```\n\n### 17. Root Cause Analysis\n\nAlways address the root cause of issues rather than implementing workarounds that hide or suppress problems:\n\n- **Identify the root cause**: When you encounter an error or unexpected behavior, investigate why it's happening\n- **Don't mask symptoms**: Avoid solutions that simply hide errors or suppress warnings without fixing the underlying issue\n- **Fix at the source**: When you identify the root cause, fix it where the problem originates, not where it manifests\n\n## Things to Avoid\n\n### 18. Anti-Patterns\n\n- **Don't use `var`**: Use `const` or `let` (except in legacy `scripts/` directory)\n- **Avoid `any` types**: Be specific in JSDoc type annotations\n- **No global state**: Everything should be instance-based\n  - Exception: Module-scope variables for local optimization are allowed (e.g., reusable Mat4 instances)\n  - These must never be exported and should only be used within the module\n- **Don't bypass abstractions**: Use the platform API, not direct WebGL/WebGPU calls\n- **Don't suppress linter warnings**: Fix the underlying issue\n\n### 19. Performance Anti-Patterns\n\n- **No allocations in render loop**: Pre-allocate and reuse if feasible\n- **Don't use `try/catch` in hot paths**: It prevents optimizations\n- **No string concatenation in loops**: Build arrays and join\n- **Don't create functions in loops**: Define functions outside\n\n## AI Agent-Specific Guidelines\n\n### 20. When Making Changes\n\n- **Read existing code first**: Understand the context and patterns\n- **Follow existing style**: Match the style of surrounding code\n- **Lint your changes**: Run `npm run lint`\n- **Update documentation**: Modify JSDoc comments when changing APIs\n- **Consider performance**: This is a real-time engine, every microsecond counts\n- **Check both WebGL and WebGPU**: Changes may affect both backends\n\n### 21. When Creating Examples\n\n- Examples go in `examples/src/examples/`\n- Follow existing example structure (see other `.example.mjs` files)\n- Include descriptive comments\n- Keep examples simple and focused on one feature\n\n### 22. When Authoring Scripts\n\n- Reusable scripts live in `scripts/esm/` and expose their configuration as script attributes\n- **Attribute enums must use readable string values**: declare them as `@enum {string}` with\n  human-readable values (e.g., `LINEAR: 'linear'`), never as raw numeric engine constants\n  - Numeric constant values (e.g., `PIXELFORMAT_RGBA16F = 12`) are implementation details that\n    can change between releases and make attribute data unreadable (`\"renderFormat\": 12`)\n  - Import the engine constants and resolve the strings via lookup maps where the script applies\n    them (see `scripts/esm/camera-frame.mjs` for the pattern)\n  - Keep accepting raw numeric values (pass them through unchanged) so existing attribute data\n    continues to work\n\n### 23. When Writing PR Descriptions\n\n- **Format as a single code block**: Always deliver PR descriptions wrapped in triple backticks for easy copy/paste\n- **Structure**:\n  - Brief title and overview\n  - Bullet points for functionality changes\n  - Technical details section (if relevant)\n  - **Clearly list all public API changes** with before/after code examples\n  - List updated examples (if applicable)\n  - Performance considerations (if relevant)\n- **Focus on user-facing changes**: What developers using the engine will see/use\n- **Be concise but complete**: Include all breaking changes and new APIs\n- **Avoid excessive detail**: Group related changes together, don't list every tiny implementation detail or internal refactoring\n- **Only document public APIs**: Do not list functionality tagged with `@ignore`, `@protected`, or `@private` as these are internal implementation details\n\n## Resources\n\n- **API Reference**: https://api.playcanvas.com/engine/\n- **User Manual**: https://developer.playcanvas.com/user-manual/engine/\n- **Developer Site**: https://github.com/playcanvas/developer-site\n  - For large features, ask to add documentation to the User Manual\n  - Manual pages are Markdown files in the `docs/` directory\n- **Examples**: https://playcanvas.github.io\n- **Forum**: https://forum.playcanvas.com\n- **Discord**: https://discord.gg/RSaMRzg\n- **GitHub Issues**: https://github.com/playcanvas/engine/issues\n\n## Questions?\n\nWhen in doubt:\n1. Look at similar existing code in the codebase\n2. Check the ESLint configuration\n3. Review recent commits for patterns\n4. If unclear or multiple valid approaches exist, ask instead of picking a possibly incorrect solution\n\n---\n\n**Remember**: This is a library used by thousands of developers. Quality, performance, and stability are paramount. When in doubt, prefer conservative, well-tested changes over clever optimizations.\n\n","isInternal":false,"tokens":3884,"sizeBytes":16594},{"name":".cursorrules","path":".cursorrules (anti-overengineering.mdc)","rawUrl":"https://raw.githubusercontent.com/PatrickJS/awesome-cursorrules/main/rules/anti-overengineering.mdc","title":"Prevent AI over-engineering by keeping changes scoped, simple, and directly tied to the user's request","category":"cursor-rule","format":"markdown","content":"# Anti-Over-Engineering\n\nOnly change what was asked. Simplest solution first. When unsure, ask.\n\nDo not modify unrequested code, add abstractions without a concrete need, import unnecessary dependencies, rewrite entire files for small changes, or add error handling for impossible scenarios.\n\nBefore delivery: verify you only changed requested code, check for simpler approaches, confirm no unrequested files were touched.","frontmatter":{"description":"Prevent AI over-engineering by keeping changes scoped, simple, and directly tied to the user's request","globs":["**/*"],"alwaysApply":false},"tokens":119,"sizeBytes":422}],"systemPromptSnippet":"<yakaai_skills repo=\"playcanvas/engine\">\n<!-- File: AGENTS.md (Tokens: ~3884 | Category: root-instruction) -->\n# Agent Guidelines for PlayCanvas Engine\n\nThis document contains rules, conventions, and best practices for AI agents and developers working on the PlayCanvas Engine codebase.\n\n## Project Overview\n\nPlayCanvas is an open-source WebGL/WebGPU game engine written in JavaScript. It's a performance-critical library used by thousands of developers worldwide.\n\n- **Language**: JavaScript (ES2022) with JSDoc for TypeScript type definitions\n- **Module System**: ES Modules\n- **Node Version**: >=18.3.0 (see `engines` in `package.json`)\n- **Build System**: esbuild for the JavaScript bundles (`build.mjs`); TypeScript plus Rollup (`rollup-plugin-dts`) for the bundled `.d.ts`\n- **Testing**: Mocha + Chai + Sinon\n- **Linting**: ESLint with @playcanvas/eslint-config\n- **License**: MIT\n\n## General Code Rules\n\n### 1. Code Style and Formatting\n\n- **Follow ESLint rules**: Always run `npm run lint` before committing\n  - **Important**: Only fix lint issues in code you are actively modifying or creating\n  - Do not fix pre-existing lint issues in unrelated code unless specifically asked\n  - Focus on ensuring new and refactored code is lint-free\n- **Use JSDoc comments**: All public APIs must have comprehensive JSDoc documentation\n- **Module imports**: Use ES6 import/export syntax\n- **Naming conventions**:\n  - Classes: PascalCase (e.g., `GraphicsDevice`, `Entity`)\n  - Functions/methods: camelCase (e.g., `createShader`, `setPosition`)\n  - Constants: UPPER_SNAKE_CASE (e.g., `PIXELFORMAT_RGBA8`)\n\n### 2. File Organization\n\n- **Source files**: All engine source code goes in `src/`\n- **Directory structure**:\n  - `src/core/` - Core utilities and data structures\n  - `src/platform/` - Platform-specific code (graphics, audio, input)\n  - `src/scene/` - Scene graph, rendering, materials, shaders\n  - `src/framework/` - High-level components and application framework\n  - `src/extras/` - Optional extras and utilities\n  - `src/deprecated/` - Side-effect-free aliases for deprecated APIs (see section 9)\n- **Build output**: Generated files go in `build/` (never edit these directly)\n- **Examples**: Live in `examples/src/examples/`\n- **Tests**: Unit tests go in `test/` with `.mjs` extension\n- **File naming**: Module file names should match the main class they contain\n  - Use kebab-case for file names (e.g., `graphics-device.js` for `GraphicsDevice` class)\n  - If a class is renamed, the file should be renamed to match\n  - Multiple related classes can share a file if they're tightly coupled\n\n#### Module Dependency Hierarchy\n\nThe codebase follows a strict hierarchical structure to maintain clean architecture:\n\n```\ncore → platform → scene → framework\n```\n\n**Rules**:\n- Lower-level modules **cannot import** from higher-level modules\n- Lower-level modules **cannot use instances** from higher-level modules\n- Example: `core/` cannot import from `platform/`, `scene/`, or `framework/`\n- Example: `scene/` cannot import from `framework/`\n\n**Known Exception**:\n- `CameraComponent` (from `framework/`) is currently used in multiple places at the `scene/` level\n- **Do not introduce new exceptions** unless explicitly requested and confirmed\n- When in doubt, ask before breaking the hierarchy\n\nThis hierarchy ensures:\n- Clean separation of concerns\n- Prevents circular dependencies\n- Makes the codebase more maintainable and testable\n\n### 3. Documentation Standards\n\n- **JSDoc is mandatory** for all public APIs:\n  ```javascript\n  /**\n   * Brief description of the function.\n   *\n   * @param {string} name - Parameter description.\n   * @param {number} [optional=0] - Optional parameter with default.\n   * @returns {boolean} Return value description.\n   * @example\n   * const result = myFunction('test', 5);\n   */\n  ```\n- **Include examples** for complex APIs\n- **Document side effects**: Mention if a function modifies state\n- **Link related APIs**: Use `@see` tags to cross-reference\n- **Mark deprecations**: Use `@deprecated` with migration instructions\n\n### 4. TypeScript Definitions\n\n- JSDoc comments are used to generate TypeScript definitions\n- Run `npm run build:types` to generate `.d.ts` files\n- Test types with `npm run test:types`. This compiles the bundled declarations and the consumer-side type tests in `test/type-tests`, which check inference and augmentation against `build/playcanvas.d.ts`\n- Use proper JSDoc type annotations:\n  - `@type {TypeName}` for variables\n  - `@param {TypeName} paramName` for parameters\n  - `@returns {TypeName}` for return values\n  - Support for generics, unions, and complex types\n- **Type-only imports**: Use `@import` for types referenced in JSDoc comments\n  - These imports are only for type information, not runtime code\n  - Place at the top of the file in a JSDoc comment block\n  - Example:\n    ```javascript\n    /**\n     * @import { Texture } from './texture.js'\n     * @import { Shader } from './shader.js'\n     */\n    ```\n  - These help TypeScript understand types without adding runtime dependencies\n\n### 5. Testing\n\n- **Write tests** for all new features and bug fixes if instructed\n- **Test location**: `test/` directory, organized by module\n- **Test naming**: Use descriptive names that explain what is being tested\n- **Run tests**: `npm test` (or `npm run test:coverage` for coverage)\n- **Bundle tests**: `test/bundles/` checks the built bundles (exports, tree shaking, live bindings). Run `npm run build` first, then `npm run test:build`\n- **Test structure**:\n  ```javascript\n  describe('ClassName', function () {\n      describe('#methodName', function () {\n          it('should do something specific', function () {\n              // Test implementation\n          });\n      });\n  });\n  ```\n\n### 6. Performance Considerations\n\nThis is a **performance-critical** engine. Always consider:\n\n- **Avoid allocations in hot paths**: Reuse objects, use object pools\n- **Minimize function calls**: Inline critical code when necessary\n- **Cache property access**: Store frequently accessed properties in local variables\n- **Use typed arrays**: For numeric data (Float32Array, Uint8Array, etc.)\n\n### 7. Graphics API Considerations\n\n- **Multi-backend support**: Code must work with both WebGL2 and WebGPU\n- **Use abstraction layers**: Don't call WebGL/WebGPU APIs directly in high-level code\n- **Shader code**: Maintain both GLSL and WGSL versions\n  - GLSL: `src/scene/shader-lib/glsl/`\n  - WGSL: `src/scene/shader-lib/wgsl/`\n- **NullGraphicsDevice**: A dummy graphics device for headless/testing scenarios\n  - When adding public API methods to `GraphicsDevice`, add stub implementations to `NullGraphicsDevice`\n  - Stub methods should be empty or return safe default values to avoid crashes\n  - This ensures the engine can run without a real graphics backend for testing/server-side use\n\n## Project-Specific Rules\n\n### 8. API Stability and Deprecation\n\n- **Backward compatibility matters**: Breaking changes require major version bump\n- **Deprecation process**:\n  1. Mark API as `@deprecated` with alternatives\n  2. Add console warning in development builds\n  3. Keep deprecated code for at least one major version\n  4. Consider removing jsdocs completely\n- **Never remove public APIs** without proper deprecation cycle\n\n### 9. Build System\n\n- **Source is in `src/`**: Never edit files in `build/` directory\n- **Module exports**: Main exports defined in `src/index.js`\n- **Bundler**: `build.mjs` drives esbuild (`utils/esbuild-build-target.mjs`). Each build type (`rel`, `dbg`, `prf`, `min`) is emitted as a UMD bundle (`build/playcanvas*.js`) and an ESM bundle (`build/playcanvas*.mjs`). The `rel`, `dbg` and `prf` ESM builds also emit an unbundled module tree (`build/playcanvas/src/`, `build/playcanvas.dbg/src/`, `build/playcanvas.prf/src/`), which is what `import 'playcanvas'` resolves to\n- **Type declarations**: `npm run build:types` runs `tsc` over the JSDoc, patches the output with `utils/plugins/rollup-types-fixup.mjs` (hand-declared `StandardMaterial` accessors, optional `ScriptType` lifecycle methods, and the `AssetMap` typedef rewritten into an augmentable interface) and bundles it with Rollup (`rollup-plugin-dts`) into `build/playcanvas.d.ts`\n- **Debug stripping**: the `Debug`, `DebugHelper`, `DebugGraphics` and `WebgpuDebug` calls listed in `STRIP_FUNCTIONS` (`utils/esbuild-build-target.mjs`) are removed from every build except `dbg`. `// #if _DEBUG` blocks survive only in `dbg`; `// #if _PROFILER` blocks survive in `dbg` and `prf`\n- **Tree shaking**: `package.json` declares `\"sideEffects\": false`, so consumers' bundlers drop every module they don't import from. Therefore:\n  - Never add module-scope side effects (top-level calls, prototype patches, registry writes, `window` access). Do registration inside constructors or functions\n  - Deprecated constant aliases and helper functions go in `src/deprecated/deprecated.js`, which must stay free of module-scope side effects\n  - Deprecated prototype shims (e.g. `Object.defineProperty(Foo.prototype, ...)`) go at the bottom of the module that defines the class, so they ship only when that class does\n  - `test/bundles/treeshake.test.mjs` guards both rules\n\n### 10. Dependencies\n\n- **Minimal dependencies**: Avoid adding new dependencies unless absolutely necessary\n- **Types only**: `@types/*` and `@webgpu/types` are the main dependencies\n\n### 11. Error Handling\n\n- **Debug class**: Use `Debug` class (`src/core/debug.js`) for logging and assertions\n  - Methods include: `assert()`, `warn()`, `warnOnce()`, `error()`, `errorOnce()`, `deprecated()`, `removed()`, `log()`, `logOnce()`, `trace()`\n  - **Important**: All Debug methods are stripped out in production builds\n  - Use `*Once()` variants to avoid spam in loops or frequent calls\n  - Don't use Debug in hot paths - even in debug builds, excessive logging impacts performance\n- **DebugHelper class**: Helper methods for debugging (also stripped in production)\n  - `setName()`, `setLabel()`, `setDestroyed()` for marking objects\n\n### 12. Code Comments\n\n- **Explain \"why\" not \"what\"**: Code should be self-documenting, but comments help with quick understanding\n- **Complex algorithms**: Explain the approach and any non-obvious optimizations\n- **TODOs**: Include issue reference or context\n  ```javascript\n  // TODO: Optimize this when texture streaming is implemented (#1234)\n  ```\n- **Avoid very obvious comments**: Don't state what the code clearly does\n\n### 13. Commit and PR Guidelines\n\n- **Clear commit messages**: Use conventional commits format\n  - `feat: Add feature description`\n  - `fix: Bug fix description`\n  - `perf: Performance improvement description`\n  - `docs: Documentation update`\n  - `refactor: Code refactoring`\n  - `test: Test updates`\n- **Reference issues**: Include issue number in commit message in format 'Fixed #1234'\n- **Small, focused commits**: Each commit should be a logical unit\n- **No generated files**: Don't commit files in `build/` directory\n\n### 14. Browser Compatibility\n\n- **Modern browsers only**: ES6+ features are allowed\n- **No polyfills in engine**: Users can add their own if needed\n- **WebGL 2.0 minimum**: WebGL 1.0 is not supported\n- **WebGPU support**: Must maintain compatibility with WebGPU API\n\n## Common Patterns\n\n### 15. Object Creation\n\n```javascript\n// Prefer class syntax with TypeScript-like property declarations\nclass MyClass {\n    /**\n     * @type {GraphicsDevice}\n     */\n    device;\n\n    /**\n     * @type {string}\n     */\n    name;\n\n    constructor(device, options = {}) {\n        this.device = device;\n        this.name = options.name ?? 'default';\n    }\n\n    destroy() {\n        // Clean up resources\n        this.device = null;\n    }\n}\n```\n\n### 16. Resource Management\n\n```javascript\n// Always provide destroy() method for objects holding resources\nclass Resource {\n    constructor() {\n        this._resource = createResource();\n    }\n\n    destroy() {\n        this._resource?.destroy();\n        this._resource = null;\n    }\n}\n```\n\n### 17. Root Cause Analysis\n\nAlways address the root cause of issues rather than implementing workarounds that hide or suppress problems:\n\n- **Identify the root cause**: When you encounter an error or unexpected behavior, investigate why it's happening\n- **Don't mask symptoms**: Avoid solutions that simply hide errors or suppress warnings without fixing the underlying issue\n- **Fix at the source**: When you identify the root cause, fix it where the problem originates, not where it manifests\n\n## Things to Avoid\n\n### 18. Anti-Patterns\n\n- **Don't use `var`**: Use `const` or `let` (except in legacy `scripts/` directory)\n- **Avoid `any` types**: Be specific in JSDoc type annotations\n- **No global state**: Everything should be instance-based\n  - Exception: Module-scope variables for local optimization are allowed (e.g., reusable Mat4 instances)\n  - These must never be exported and should only be used within the module\n- **Don't bypass abstractions**: Use the platform API, not direct WebGL/WebGPU calls\n- **Don't suppress linter warnings**: Fix the underlying issue\n\n### 19. Performance Anti-Patterns\n\n- **No allocations in render loop**: Pre-allocate and reuse if feasible\n- **Don't use `try/catch` in hot paths**: It prevents optimizations\n- **No string concatenation in loops**: Build arrays and join\n- **Don't create functions in loops**: Define functions outside\n\n## AI Agent-Specific Guidelines\n\n### 20. When Making Changes\n\n- **Read existing code first**: Understand the context and patterns\n- **Follow existing style**: Match the style of surrounding code\n- **Lint your changes**: Run `npm run lint`\n- **Update documentation**: Modify JSDoc comments when changing APIs\n- **Consider performance**: This is a real-time engine, every microsecond counts\n- **Check both WebGL and WebGPU**: Changes may affect both backends\n\n### 21. When Creating Examples\n\n- Examples go in `examples/src/examples/`\n- Follow existing example structure (see other `.example.mjs` files)\n- Include descriptive comments\n- Keep examples simple and focused on one feature\n\n### 22. When Authoring Scripts\n\n- Reusable scripts live in `scripts/esm/` and expose their configuration as script attributes\n- **Attribute enums must use readable string values**: declare them as `@enum {string}` with\n  human-readable values (e.g., `LINEAR: 'linear'`), never as raw numeric engine constants\n  - Numeric constant values (e.g., `PIXELFORMAT_RGBA16F = 12`) are implementation details that\n    can change between releases and make attribute data unreadable (`\"renderFormat\": 12`)\n  - Import the engine constants and resolve the strings via lookup maps where the script applies\n    them (see `scripts/esm/camera-frame.mjs` for the pattern)\n  - Keep accepting raw numeric values (pass them through unchanged) so existing attribute data\n    continues to work\n\n### 23. When Writing PR Descriptions\n\n- **Format as a single code block**: Always deliver PR descriptions wrapped in triple backticks for easy copy/paste\n- **Structure**:\n  - Brief title and overview\n  - Bullet points for functionality changes\n  - Technical details section (if relevant)\n  - **Clearly list all public API changes** with before/after code examples\n  - List updated examples (if applicable)\n  - Performance considerations (if relevant)\n- **Focus on user-facing changes**: What developers using the engine will see/use\n- **Be concise but complete**: Include all breaking changes and new APIs\n- **Avoid excessive detail**: Group related changes together, don't list every tiny implementation detail or internal refactoring\n- **Only document public APIs**: Do not list functionality tagged with `@ignore`, `@protected`, or `@private` as these are internal implementation details\n\n## Resources\n\n- **API Reference**: https://api.playcanvas.com/engine/\n- **User Manual**: https://developer.playcanvas.com/user-manual/engine/\n- **Developer Site**: https://github.com/playcanvas/developer-site\n  - For large features, ask to add documentation to the User Manual\n  - Manual pages are Markdown files in the `docs/` directory\n- **Examples**: https://playcanvas.github.io\n- **Forum**: https://forum.playcanvas.com\n- **Discord**: https://discord.gg/RSaMRzg\n- **GitHub Issues**: https://github.com/playcanvas/engine/issues\n\n## Questions?\n\nWhen in doubt:\n1. Look at similar existing code in the codebase\n2. Check the ESLint configuration\n3. Review recent commits for patterns\n4. If unclear or multiple valid approaches exist, ask instead of picking a possibly incorrect solution\n\n---\n\n**Remember**: This is a library used by thousands of developers. Quality, performance, and stability are paramount. When in doubt, prefer conservative, well-tested changes over clever optimizations.\n\n<!-- File: .cursorrules (anti-overengineering.mdc) (Tokens: ~119 | Category: cursor-rule) -->\n# Anti-Over-Engineering\n\nOnly change what was asked. Simplest solution first. When unsure, ask.\n\nDo not modify unrequested code, add abstractions without a concrete need, import unnecessary dependencies, rewrite entire files for small changes, or add error handling for impossible scenarios.\n\nBefore delivery: verify you only changed requested code, check for simpler approaches, confirm no unrequested files were touched.\n</yakaai_skills>"}