agentleFS
playcanvasplaycanvas/engine/AGENTS.md

engine

AGENTS.md17k starsChanged 11 days agoMITView on GitHub

This document contains rules, conventions, and best practices for AI agents and developers working on the PlayCanvas Engine codebase. PlayCanvas is an open-source WebGL/WebGPU game engine written in JavaScript. It's a performance-critical library used by thousands of developers worldwide. The codebase follows a strict hierarchical structure to maintain clean architecture: Rules: - Lower-level modules cannot import from higher-level modules - Lower-level modules cannot use instances from higher-level modules - Example: core/ cannot import from platform/, scene/, or framework/ - Example:…

Trending

More talk lately.about the whole repository

Dec 2025: 1 mentionJan 2026: 0 mentionsFeb 2026: 2 mentionsMar 2026: 0 mentionsApr 2026: 0 mentionsMay 2026: 1 mentionJun 2026: 1 mentionJul 2026: 1 mentionAug 2026: 1 mentionSep 2026: 1 mentionOct 2026: 10 mentionsNov 2026: 11 mentions
Dec 2025Jun 2026Nov 2026
Mentions a month of the playcanvas/engine repository that our weekly crawl found. There is no adoption data for this file yet.

Who's talking about playcanvas/engine

The biggest 5 of 90 mentions linking to the repository that our crawl found. Each line is their own headline.

See all 90

Talked about on GitHub, YouTube, Bluesky, Hacker News and the web (90 times).

On GitHub · 50

45 more on GitHub

On YouTube · 22

17 more on YouTube

On Bluesky · 13

8 more on Bluesky

On the web · 1

  • Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.

    Of the AGENTS.md files we read, the 31,542 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.

The file

Show its rules and text

We split this AGENTS.md into the rules it gives an agent

49 rules. About 0 are common, 30 are distinctive, and 19 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈30

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 19

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  • could be automatic: a setting could enforce it
  1. Very specific:

    Follow ESLint rules: Always run npm run lint before committing

    line 21
  2. Distinctive:

    Important: Only fix lint issues in code you are actively modifying or creating

    line 22
  3. Distinctive:

    Do not fix pre-existing lint issues in unrelated code unless specifically asked

    line 23
  4. Distinctive:

    Use JSDoc comments: All public APIs must have comprehensive JSDoc documentation

    line 25
  5. Distinctive:

    Module imports: Use ES6 import/export syntax

    line 26
  6. Very specific:

    Source files: All engine source code goes in src/

    line 34
  7. Very specific:

    Use kebab-case for file names (e.g., graphics-device.js for GraphicsDevice class)

    line 46
  8. Distinctive:

    If a class is renamed, the file should be renamed to match

    line 47
  9. Distinctive:

    When in doubt, ask before breaking the hierarchy

    line 67
  10. Very specific:

    Link related APIs: Use @see tags to cross-reference

    line 90
  11. Very specific:

    Mark deprecations: Use @deprecated with migration instructions

    line 91
  12. Very specific:

    Run npm run build:types to generate .d.ts files

    line 96
  13. Very specific:

    Test types with npm run test:types.

    line 97
  14. Distinctive:

    Use proper JSDoc type annotations:

    line 98
  15. Very specific:

    Type-only imports: Use @import for types referenced in JSDoc comments

    line 103
  16. Distinctive:

    Place at the top of the file in a JSDoc comment block

    line 105
  17. Distinctive:

    Test naming: Use descriptive names that explain what is being tested

    line 119
  18. Distinctive:

    Use abstraction layers: Don't call WebGL/WebGPU APIs directly in high-level code

    line 145
  19. Very specific:

    When adding public API methods to GraphicsDevice, add stub implementations to NullGraphicsDevice

    line 150
  20. Distinctive:

    Add console warning in development builds

    line 161
  21. Distinctive:

    Keep deprecated code for at least one major version

    line 162
  22. Distinctive:

    Consider removing jsdocs completely

    line 163
  23. Very specific:

    Source is in src/: Never edit files in build/ directory

    line 168
  24. Very specific:

    Never add module-scope side effects (top-level calls, prototype patches, registry writes, window access).

    line 174
  25. Distinctive:

    Minimal dependencies: Avoid adding new dependencies unless absolutely necessary

    line 181
  26. Very specific:

    Debug class: Use Debug class (src/core/debug.js) for logging and assertions

    line 186
  27. Distinctive:

    Important: All Debug methods are stripped out in production builds

    line 188
  28. Very specific:

    Use *Once() variants to avoid spam in loops or frequent calls

    line 189
  29. Distinctive:

    Don't use Debug in hot paths - even in debug builds, excessive logging impacts performance

    line 190
  30. Distinctive:

    Avoid very obvious comments: Don't state what the code clearly does

    line 202
  31. Distinctive:

    Clear commit messages: Use conventional commits format

    line 206
  32. Very specific:

    No generated files: Don't commit files in build/ directory

    line 215
  33. Distinctive:

    WebGPU support: Must maintain compatibility with WebGPU API

    line 222
  34. Distinctive:

    Always address the root cause of issues rather than implementing workarounds that hide or suppress problems:

    line 271
  35. Distinctive:

    Identify the root cause: When you encounter an error or unexpected behavior, investigate why it's happening

    line 273
  36. Distinctive:

    Don't mask symptoms: Avoid solutions that simply hide errors or suppress warnings without fixing the underlying issue

    line 274
  37. Distinctive:

    Fix at the source: When you identify the root cause, fix it where the problem originates, not where it manifests

    line 275
  38. Very specific:

    Don't use var: Use const or let (except in legacy scripts/ directory)

    line 281
  39. Distinctive:

    Don't bypass abstractions: Use the platform API, not direct WebGL/WebGPU calls

    line 286
  40. Very specific:

    Lint your changes: Run npm run lint

    line 302
  41. Very specific:

    Follow existing example structure (see other example.mjs files)

    line 310
  42. Distinctive:

    Keep examples simple and focused on one feature

    line 312
  43. Very specific:

    Import the engine constants and resolve the strings via lookup maps where the script applies them (see scripts/esm/camera-frame.mjs for the …

    line 321
  44. Distinctive:

    Keep accepting raw numeric values (pass them through unchanged) so existing attribute data continues to work

    line 323
  45. Distinctive:

    Format as a single code block: Always deliver PR descriptions wrapped in triple backticks for easy copy/paste

    line 328
  46. Very specific:

    Only document public APIs: Do not list functionality tagged with @ignore, @protected, or @private as these are internal implementation …

    line 339
  47. Distinctive:

    Look at similar existing code in the codebase

    line 356
  48. Distinctive:

    Check the ESLint configuration

    line 357
  49. Distinctive:

    If unclear or multiple valid approaches exist, ask instead of picking a possibly incorrect solution

    line 359

≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
AGENTS.md

Agent Guidelines for PlayCanvas Engine

This document contains rules, conventions, and best practices for AI agents and developers working on the PlayCanvas Engine codebase.

Project Overview

PlayCanvas is an open-source WebGL/WebGPU game engine written in JavaScript. It's a performance-critical library used by thousands of developers worldwide.

  • Language: JavaScript (ES2022) with JSDoc for TypeScript type definitions
  • Module System: ES Modules
  • Node Version: >=18.3.0 (see engines in package.json)
  • Build System: esbuild for the JavaScript bundles (build.mjs); TypeScript plus Rollup (rollup-plugin-dts) for the bundled .d.ts
  • Testing: Mocha + Chai + Sinon
  • Linting: ESLint with @playcanvas/eslint-config
  • License: MIT

General Code Rules

1. Code Style and Formatting

  • Follow ESLint rules: Always run npm run lint before committing
    • Important: Only fix lint issues in code you are actively modifying or creating
    • Do not fix pre-existing lint issues in unrelated code unless specifically asked
    • Focus on ensuring new and refactored code is lint-free
  • Use JSDoc comments: All public APIs must have comprehensive JSDoc documentation
  • Module imports: Use ES6 import/export syntax
  • Naming conventions:
    • Classes: PascalCase (e.g., GraphicsDevice, Entity)
    • Functions/methods: camelCase (e.g., createShader, setPosition)
    • Constants: UPPER_SNAKE_CASE (e.g., PIXELFORMAT_RGBA8)

2. File Organization

  • Source files: All engine source code goes in src/
  • Directory structure:
    • src/core/ - Core utilities and data structures
    • src/platform/ - Platform-specific code (graphics, audio, input)
    • src/scene/ - Scene graph, rendering, materials, shaders
    • src/framework/ - High-level components and application framework
    • src/extras/ - Optional extras and utilities
    • src/deprecated/ - Side-effect-free aliases for deprecated APIs (see section 9)
  • Build output: Generated files go in build/ (never edit these directly)
  • Examples: Live in examples/src/examples/<category>/<example>/, one folder per example
  • Tests: Unit tests go in test/ with .mjs extension
  • File naming: Module file names should match the main class they contain
    • Use kebab-case for file names (e.g., graphics-device.js for GraphicsDevice class)
    • If a class is renamed, the file should be renamed to match
    • Multiple related classes can share a file if they're tightly coupled

Module Dependency Hierarchy

The codebase follows a strict hierarchical structure to maintain clean architecture:

core → platform → scene → framework

Rules:

  • Lower-level modules cannot import from higher-level modules
  • Lower-level modules cannot use instances from higher-level modules
  • Example: core/ cannot import from platform/, scene/, or framework/
  • Example: scene/ cannot import from framework/

Known Exception:

  • CameraComponent (from framework/) is currently used in multiple places at the scene/ level
  • Do not introduce new exceptions unless explicitly requested and confirmed
  • When in doubt, ask before breaking the hierarchy

This hierarchy ensures:

  • Clean separation of concerns
  • Prevents circular dependencies
  • Makes the codebase more maintainable and testable

3. Documentation Standards

  • JSDoc is mandatory for all public APIs:
    /**
     * Brief description of the function.
     *
     * @param {string} name - Parameter description.
     * @param {number} [optional=0] - Optional parameter with default.
     * @returns {boolean} Return value description.
     * @example
     * const result = myFunction('test', 5);
     */
  • Include examples for complex APIs
  • Document side effects: Mention if a function modifies state
  • Link related APIs: Use @see tags to cross-reference
  • Mark deprecations: Use @deprecated with migration instructions

4. TypeScript Definitions

  • JSDoc comments are used to generate TypeScript definitions
  • Run npm run build:types to generate .d.ts files
  • 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
  • Use proper JSDoc type annotations:
    • @type {TypeName} for variables
    • @param {TypeName} paramName for parameters
    • @returns {TypeName} for return values
    • Support for generics, unions, and complex types
  • Type-only imports: Use @import for types referenced in JSDoc comments
    • These imports are only for type information, not runtime code
    • Place at the top of the file in a JSDoc comment block
    • Example:
      /**
       * @import { Texture } from './texture.js'
       * @import { Shader } from './shader.js'
       */
    • These help TypeScript understand types without adding runtime dependencies

5. Testing

  • Write tests for all new features and bug fixes if instructed
  • Test location: test/ directory, organized by module
  • Test naming: Use descriptive names that explain what is being tested
  • Run tests: npm test (or npm run test:coverage for coverage)
  • Bundle tests: test/bundles/ checks the built bundles (exports, tree shaking, live bindings). Run npm run build first, then npm run test:build
  • Test structure:
    describe('ClassName', function () {
        describe('#methodName', function () {
            it('should do something specific', function () {
                // Test implementation
            });
        });
    });

6. Performance Considerations

This is a performance-critical engine. Always consider:

  • Avoid allocations in hot paths: Reuse objects, use object pools
  • Minimize function calls: Inline critical code when necessary
  • Cache property access: Store frequently accessed properties in local variables
  • Use typed arrays: For numeric data (Float32Array, Uint8Array, etc.)

7. Graphics API Considerations

  • Multi-backend support: Code must work with both WebGL2 and WebGPU
  • Use abstraction layers: Don't call WebGL/WebGPU APIs directly in high-level code
  • Shader code: Maintain both GLSL and WGSL versions
    • GLSL: src/scene/shader-lib/glsl/
    • WGSL: src/scene/shader-lib/wgsl/
  • NullGraphicsDevice: A dummy graphics device for headless/testing scenarios
    • When adding public API methods to GraphicsDevice, add stub implementations to NullGraphicsDevice
    • Stub methods should be empty or return safe default values to avoid crashes
    • This ensures the engine can run without a real graphics backend for testing/server-side use

Project-Specific Rules

8. API Stability and Deprecation

  • Backward compatibility matters: Breaking changes require major version bump
  • Deprecation process:
    1. Mark API as @deprecated with alternatives
    2. Add console warning in development builds
    3. Keep deprecated code for at least one major version
    4. Consider removing jsdocs completely
  • Never remove public APIs without proper deprecation cycle

9. Build System

  • Source is in src/: Never edit files in build/ directory
  • Module exports: Main exports defined in src/index.js
  • 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
  • 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
  • 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
  • Tree shaking: package.json declares "sideEffects": false, so consumers' bundlers drop every module they don't import from. Therefore:
    • Never add module-scope side effects (top-level calls, prototype patches, registry writes, window access). Do registration inside constructors or functions
    • Deprecated constant aliases and helper functions go in src/deprecated/deprecated.js, which must stay free of module-scope side effects
    • 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
    • test/bundles/treeshake.test.mjs guards both rules

10. Dependencies

  • Minimal dependencies: Avoid adding new dependencies unless absolutely necessary
  • Types only: @types/* and @webgpu/types are the main dependencies

11. Error Handling

  • Debug class: Use Debug class (src/core/debug.js) for logging and assertions
    • Methods include: assert(), warn(), warnOnce(), error(), errorOnce(), deprecated(), removed(), log(), logOnce(), trace()
    • Important: All Debug methods are stripped out in production builds
    • Use *Once() variants to avoid spam in loops or frequent calls
    • Don't use Debug in hot paths - even in debug builds, excessive logging impacts performance
  • DebugHelper class: Helper methods for debugging (also stripped in production)
    • setName(), setLabel(), setDestroyed() for marking objects

12. Code Comments

  • Explain "why" not "what": Code should be self-documenting, but comments help with quick understanding
  • Complex algorithms: Explain the approach and any non-obvious optimizations
  • TODOs: Include issue reference or context
    // TODO: Optimize this when texture streaming is implemented (#1234)
  • Avoid very obvious comments: Don't state what the code clearly does

13. Commit and PR Guidelines

  • Clear commit messages: Use conventional commits format
    • feat: Add feature description
    • fix: Bug fix description
    • perf: Performance improvement description
    • docs: Documentation update
    • refactor: Code refactoring
    • test: Test updates
  • Reference issues: Include issue number in commit message in format 'Fixed #1234'
  • Small, focused commits: Each commit should be a logical unit
  • No generated files: Don't commit files in build/ directory

14. Browser Compatibility

  • Modern browsers only: ES6+ features are allowed
  • No polyfills in engine: Users can add their own if needed
  • WebGL 2.0 minimum: WebGL 1.0 is not supported
  • WebGPU support: Must maintain compatibility with WebGPU API

Common Patterns

15. Object Creation

// Prefer class syntax with TypeScript-like property declarations
class MyClass {
    /**
     * @type {GraphicsDevice}
     */
    device;

    /**
     * @type {string}
     */
    name;

    constructor(device, options = {}) {
        this.device = device;
        this.name = options.name ?? 'default';
    }

    destroy() {
        // Clean up resources
        this.device = null;
    }
}

16. Resource Management

// Always provide destroy() method for objects holding resources
class Resource {
    constructor() {
        this._resource = createResource();
    }

    destroy() {
        this._resource?.destroy();
        this._resource = null;
    }
}

17. Root Cause Analysis

Always address the root cause of issues rather than implementing workarounds that hide or suppress problems:

  • Identify the root cause: When you encounter an error or unexpected behavior, investigate why it's happening
  • Don't mask symptoms: Avoid solutions that simply hide errors or suppress warnings without fixing the underlying issue
  • Fix at the source: When you identify the root cause, fix it where the problem originates, not where it manifests

Things to Avoid

18. Anti-Patterns

  • Don't use var: Use const or let (except in legacy scripts/ directory)
  • Avoid any types: Be specific in JSDoc type annotations
  • No global state: Everything should be instance-based
    • Exception: Module-scope variables for local optimization are allowed (e.g., reusable Mat4 instances)
    • These must never be exported and should only be used within the module
  • Don't bypass abstractions: Use the platform API, not direct WebGL/WebGPU calls
  • Don't suppress linter warnings: Fix the underlying issue

19. Performance Anti-Patterns

  • No allocations in render loop: Pre-allocate and reuse if feasible
  • Don't use try/catch in hot paths: It prevents optimizations
  • No string concatenation in loops: Build arrays and join
  • Don't create functions in loops: Define functions outside

AI Agent-Specific Guidelines

20. When Making Changes

  • Read existing code first: Understand the context and patterns
  • Follow existing style: Match the style of surrounding code
  • Lint your changes: Run npm run lint
  • Update documentation: Modify JSDoc comments when changing APIs
  • Consider performance: This is a real-time engine, every microsecond counts
  • Check both WebGL and WebGPU: Changes may affect both backends

21. When Creating Examples

  • Each example is a folder, examples/src/examples/<category>/<example>/, holding example.mjs, optional controls.jsx, any other files it imports, and its thumbnail-large.webp / thumbnail-small.webp
  • Follow existing example structure (see other example.mjs files)
  • Include descriptive comments
  • Keep examples simple and focused on one feature

22. When Authoring Scripts

  • Reusable scripts live in scripts/esm/ and expose their configuration as script attributes
  • Attribute enums must use readable string values: declare them as @enum {string} with human-readable values (e.g., LINEAR: 'linear'), never as raw numeric engine constants
    • Numeric constant values (e.g., PIXELFORMAT_RGBA16F = 12) are implementation details that can change between releases and make attribute data unreadable ("renderFormat": 12)
    • Import the engine constants and resolve the strings via lookup maps where the script applies them (see scripts/esm/camera-frame.mjs for the pattern)
    • Keep accepting raw numeric values (pass them through unchanged) so existing attribute data continues to work

23. When Writing PR Descriptions

  • Format as a single code block: Always deliver PR descriptions wrapped in triple backticks for easy copy/paste
  • Structure:
    • Brief title and overview
    • Bullet points for functionality changes
    • Technical details section (if relevant)
    • Clearly list all public API changes with before/after code examples
    • List updated examples (if applicable)
    • Performance considerations (if relevant)
  • Focus on user-facing changes: What developers using the engine will see/use
  • Be concise but complete: Include all breaking changes and new APIs
  • Avoid excessive detail: Group related changes together, don't list every tiny implementation detail or internal refactoring
  • Only document public APIs: Do not list functionality tagged with @ignore, @protected, or @private as these are internal implementation details

Resources

Questions?

When in doubt:

  1. Look at similar existing code in the codebase
  2. Check the ESLint configuration
  3. Review recent commits for patterns
  4. If unclear or multiple valid approaches exist, ask instead of picking a possibly incorrect solution

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.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.