diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..3920bcd3127 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,41 @@ +# This file normalizes line endings stored in the repo to LF (Unix/Git). +# Contributors are still able to use their native line endings locally. +# More info here: https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings + +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files to be normalized on checkin +# and converted back to native line endings on checkout. +*.js text +*.json text +*.mjs text +*.cjs text +*.jsx text +*.ts text +*.txt text +*.tsx text +*.md text +*.html text +*.gltf text +*.glsl text +*.css text +*.mustache text +*.obj text +*.atlas text +*.yaml text +*.babelrc text + +# Denote all files that are truly binary and should therefore not be modified. +*.png binary +*.jpg binary +*.glb binary +*.fbx binary +*.wasm binary +*.basis binary +*.bin binary +*.dds binary +*.drc binary +*.mp3 binary +*.mp4 binary +*.gz binary diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 55129c0e681..db0e9c736da 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,14 +1,59 @@ -# CONTRIBUTING +# Contributing to the PlayCanvas Engine -# HOW TO CONTRIBUTE +Welcome! We're excited that you want to contribute to PlayCanvas. This guide will help you get started, whether you're fixing a typo or adding a major feature. + +## Table of Contents +- [Quick Start](#quick-start) +- [Development Setup](#development-setup) +- [How to Contribute](#how-to-contribute) +- [Testing Your Changes](#testing-your-changes) +- [Submitting Pull Requests](#submitting-pull-requests) +- [Need Help?](#need-help) +- [Coding Standards](#coding-standards) + +## Quick Start + +For **simple bug fixes or documentation updates**: + +1. Fork the repository +2. Create a branch: `git checkout -b fix-issue-123` +3. Make your changes +4. Run tests: `npm test` +5. Submit a pull request + +For **larger changes or new features**, please read the full guidelines below and consider opening an issue first to discuss your approach. + +## Development Setup + +1. **Fork and clone** the repository: + ```bash + git clone https://github.com/YOUR_USERNAME/engine.git + cd engine + ``` + +2. **Install dependencies**: + ```bash + npm install + ``` + +3. **Run tests** to ensure everything works: + ```bash + npm test + ``` + +4. **Build the engine** (optional, for testing): + ```bash + npm run build + ``` + +## How to Contribute 1. Looking for ideas? Check out ["good first PR"](https://github.com/playcanvas/engine/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+PR%22) label. 2. Or start a conversation in [Issues](https://github.com/playcanvas/engine/issues) to get help and advice from community on PR ideas. 3. Read the coding standards below. 4. Keep PR simple and focused - one PR per feature. 5. Make a Pull Request. -6. Complete the [Contributor License Agreement](https://docs.google.com/a/playcanvas.com/forms/d/1Ih69zQfJG-QDLIEpHr6CsaAs6fPORNOVnMv5nuo0cjk/viewform). -7. Happy Days! 🎉 +6. Happy Days! 🎉 #### Tips @@ -18,11 +63,58 @@ If you are looking for ideas what to work on, head to [Issues](https://github.co Try to keep PR focused on a single feature, small PR's are easier to review and will get merged faster. Too large PR's are better be broken into smaller ones so they can be merged and tested on its own. -# CODING STANDARDS +## Testing Your Changes + +PlayCanvas uses [Mocha](https://mochajs.org/) and [Chai](https://www.chaijs.com/) for unit testing. -## General +### Running Tests +```bash +# Run all tests +npm test -Our coding standards are derived from the [Google JavaScript Coding Standards](https://google.github.io/styleguide/javascriptguide.xml) which are based on ES5 (ECMA2009). Also we have a whitelist of modern JavaScript features (ES6+), explicitly listed below. +# Run tests with coverage report +npm run test:coverage +``` + +### Writing Tests +- **Add tests for new features** - Write unit tests that prove your feature works +- **Update existing tests** - Modify tests when changing existing behavior +- **Test browser compatibility** - Ensure your changes work across target browsers +- **Test with examples** - Check that relevant examples still work + +### Test Guidelines +- Place test files in the `test/` directory mirroring the source structure +- Use `.test.mjs` extension for test files +- Follow the existing test patterns and naming conventions +- See [test/README.md](test/README.md) for detailed testing documentation + +## Submitting Pull Requests + +1. **Create a focused PR** - One feature or fix per pull request +2. **Write a clear description** - Explain what changes and why +3. **Reference issues** - Link to related issues with "Fixes #123" +4. **Test thoroughly** - Ensure tests pass and no regressions +5. **Follow code standards** - See detailed guidelines below +6. **Be patient** - Reviews take time, especially for complex changes + +### Git Workflow +- Create feature branches from `main`: `git checkout -b feature-name` +- Use clear commit messages describing what changed +- Keep commits focused and atomic when possible +- Rebase/squash if requested during review + +## Need Help? + +- **Questions about contributing?** Open a [Discussion](https://github.com/playcanvas/engine/discussions) +- **Found a bug?** Check existing [Issues](https://github.com/playcanvas/engine/issues) first +- **Want to chat?** Visit the [PlayCanvas Forum](http://forum.playcanvas.com/) +- **Looking for ideas?** Check ["good first PR"](https://github.com/playcanvas/engine/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+PR%22) issues + +## Coding Standards + +### General + +Our coding standards are derived from established JavaScript best practices. We support modern JavaScript features (ES6+) as listed below, targeting current browser versions. ### Keep it simple @@ -44,8 +136,10 @@ You may use the following JavaScript language features in the engine codebase: * [Default parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters) * [Modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) * [Optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) -* [Static keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static) +* [`static` keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static) * [Template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) +* [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) +* [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) ### Opening braces should be on the same line as the statement @@ -57,7 +151,7 @@ function inc() { } ``` -Also use the following style for 'if' statements: +Also use the following style for `if` statements: ```javascript if (test) { // do something @@ -156,7 +250,7 @@ for (let i = 0; i < items.length; i++) { } ``` -## Naming +### Naming ### Capitalization @@ -173,12 +267,30 @@ let mixedCase = 1; // Function are usually variables so should be mixedCase // (unless they are class constructors) let myFunction = function () { }; +let myFunction = () => { }; // Constants should be ALL_CAPITALS separated by underscores. // Note, ES5 doesn't support constants, // so this is just convention. const THIS_IS_CONSTANT = "well, kind of"; +// Enum constants follow similar rules as normal constants. In general, +// the enum consists of the type, and its values. +// In other languages, this is implemented as +// enum CubeFace { +// PosX: 0, +// PosY: 1 +// } +// Due to the lack of native enum support by JavaScript, the enums are +// represented by constants. The constant name contains the enum name without +// the underscores, followed by the values with optional underscores as +// needed to improve the readability. This is one possible implementation: +const CUBEFACE_POSX = 0; +const CUBEFACE_POSY = 1; +// and this is also acceptable +const CUBEFACE_POS_X = 0; +const CUBEFACE_POS_Y = 1; + // Private variables should start with a leading underscore. // Note, you should attempt to make private variables actually private using // a closure. @@ -258,7 +370,7 @@ function foo(a, b) { ``` -## Privacy +### Privacy ### Make variables private if used only internally @@ -278,7 +390,7 @@ let foo = new Item(); foo._a += "?"; // not good ``` -## Object Member Iteration +### Object Member Iteration The hasOwnProperty() function should be used when iterating over an object's members. This is to avoid accidentally picking up unintended members that may have been added to the object's prototype. For example: @@ -291,7 +403,7 @@ for (let key in values) { } ``` -## Source files +### Source files ### Filenames should contain only class name @@ -304,9 +416,9 @@ asset-registry.js graph-node.js ``` -## Namespaces and Classes (ES6) +### Namespaces and Classes (ES6) -The entire PlayCanvas API must be declared under the ```pc``` namespace. This is handled by build script, so ES6 notation of `import`/`export` should be used. The vast majority of the PlayCanvas codebase is made up of `class` definitions. These have the following structure (which should be adhered to): +The entire PlayCanvas API must be declared under the `pc` namespace. This is handled by build script, so ES6 notation of `import`/`export` should be used. The vast majority of the PlayCanvas codebase is made up of `class` definitions. These have the following structure (which should be adhered to): ```javascript class Class { @@ -328,7 +440,7 @@ class SubClass extends Class { } someFunc(x) { - // if method is overriden + // if method is overridden // this is the way to call parent class method super.someFunc(x); } diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8c8a1febbaa..9e07b6ea4cc 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,9 @@ +## Description +Brief description of what this PR does. + Fixes # -I confirm I have read the [contributing guidelines](https://github.com/playcanvas/engine/blob/master/.github/CONTRIBUTING.md) and signed the [Contributor License Agreement](https://docs.google.com/a/playcanvas.com/forms/d/1Ih69zQfJG-QDLIEpHr6CsaAs6fPORNOVnMv5nuo0cjk/viewform). +## Checklist +- [ ] I have read the [contributing guidelines](https://github.com/playcanvas/engine/blob/master/.github/CONTRIBUTING.md) +- [ ] My code follows the project's coding standards +- [ ] This PR focuses on a single change diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 386ca986bc1..00000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "npm" - # Look for `package.json` and `lock` files in the `root` directory - directory: "/" - # Check the npm registry for updates every day (weekdays) - schedule: - interval: "monthly" - - - package-ecosystem: "github-actions" - directory: "/" - # Look for `package.json` and `lock` files in the `root` directory - schedule: - interval: "monthly" diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 00000000000..0f161aec6a7 --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ], + "packageRules": [ + { + "matchManagers": [ + "npm" + ], + "groupName": "all npm dependencies", + "schedule": [ + "on monday at 10:00am" + ] + }, + { + "matchDepTypes": [ + "devDependencies" + ], + "rangeStrategy": "pin" + }, + { + "matchDepTypes": [ + "dependencies" + ], + "rangeStrategy": "widen" + }, + { + "matchPackageNames": [ + "monaco-editor" + ], + "matchFileNames": [ + "examples/package.json" + ], + "enabled": false + }, + { + "matchPackageNames": [ + "eslint" + ], + "allowedVersions": "<10.0.0" + } + ], + "ignorePaths": [ + ".nvmrc" + ] +} diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml new file mode 100644 index 00000000000..b2e365c6f13 --- /dev/null +++ b/.github/workflows/beta.yml @@ -0,0 +1,57 @@ +name: Beta + +on: + workflow_dispatch: + inputs: + force: + description: "Force release even if no changes detected" + type: boolean + default: false + +permissions: + contents: write + +jobs: + beta: + runs-on: ubuntu-latest + if: github.repository == 'playcanvas/engine' && github.ref_name == 'main' + steps: + - name: Generate app token + id: app-token + uses: actions/create-github-app-token@v3 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_KEY }} + + - name: Check out code + uses: actions/checkout@v6 + with: + fetch-depth: 0 + token: ${{ steps.app-token.outputs.token }} + + - name: Configure Git User + run: | + git config --global user.email "playcanvas[bot]@users.noreply.github.com" + git config --global user.name "PlayCanvas [bot]" + shell: bash + + - name: Check for changes + if: github.event.inputs.force == 'false' + run: | + last_tag=$(git describe --tags --abbrev=0) + if ! git diff --quiet --exit-code $last_tag; then + echo "Changes found since v$last_tag" + else + echo "No changes detected since v$last_tag" + exit 1 + fi + + - name: Bump version + run: | + npm version prerelease --preid=beta + + - name: Push version + run: | + git push origin HEAD:${{ github.ref_name }} + git push origin --tags + shell: bash diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aef965d7ec0..ae7797936fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,72 +1,151 @@ name: CI on: + workflow_dispatch: push: - branches: [ master ] + branches: [main] pull_request: - branches: [ master ] + branches: [main] + +concurrency: + group: ci-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read jobs: build: name: Build runs-on: ubuntu-latest + timeout-minutes: 10 steps: - - name: Checkout code - uses: actions/checkout@v2 - - name: Setup Node.js 12.x - uses: actions/setup-node@v2.4.0 - with: - node-version: 12.x - - name: Install dependencies - run: npm ci - - name: Build PlayCanvas - run: npm run build + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Node.js 22.x + uses: actions/setup-node@v6 + with: + node-version: 24.x + cache: "npm" + + - name: Install dependencies + run: npm clean-install --progress=false --no-fund + + - name: Build PlayCanvas + run: npm run build + + - name: Run Publint + run: npm run publint + + docs: + name: Docs + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Node.js 22.x + uses: actions/setup-node@v6 + with: + node-version: 24.x + cache: "npm" + + - name: Install dependencies + run: npm clean-install --progress=false --no-fund + + - name: Build API reference manual + run: npm run docs lint: name: Lint runs-on: ubuntu-latest + timeout-minutes: 10 steps: - - name: Checkout code - uses: actions/checkout@v2 - - name: Setup Node.js 12.x - uses: actions/setup-node@v2.4.0 - with: - node-version: 12.x - - name: Install dependencies - run: npm ci - - name: Run ESLint - run: npm run lint - - typescript-definitions: - name: Typescript Definitions + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Node.js 22.x + uses: actions/setup-node@v6 + with: + node-version: 24.x + cache: "npm" + + - name: Install dependencies + run: npm clean-install --progress=false --no-fund + + - name: Run ESLint + run: npm run lint + + - name: Run ESLint on examples + working-directory: ./examples + run: | + npm clean-install --progress=false --no-fund + npm run lint + + typescript-declarations: + name: TypeScript Declarations runs-on: ubuntu-latest + timeout-minutes: 10 steps: - - name: Checkout code - uses: actions/checkout@v2 - - name: Setup Node.js 12.x - uses: actions/setup-node@v2.4.0 - with: - node-version: 12.x - - name: Install dependencies - run: npm ci - - name: Build Typescript definitions - run: npm run test:tsd + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Node.js 22.x + uses: actions/setup-node@v6 + with: + node-version: 24.x + cache: "npm" + + - name: Install dependencies + run: npm clean-install --progress=false --no-fund + + - name: Build TypeScript declarations + run: npm run build:types + + - name: Compile TypeScript declarations + run: npm run test:types unit-test: name: Unit Test runs-on: ubuntu-latest + timeout-minutes: 10 steps: - - name: Checkout code - uses: actions/checkout@v2 - - name: Setup Node.js 12.x - uses: actions/setup-node@v2.4.0 - with: - node-version: 12.x - - name: Install dependencies - run: npm ci - - name: Build PlayCanvas (ES5-only) - run: npm run build:es5 - - name: Install X virtual framebuffer - run: sudo apt-get install xvfb - - name: Run unit tests - run: xvfb-run --auto-servernum npm run test + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Node.js 22.x + uses: actions/setup-node@v6 + with: + node-version: 24.x + cache: "npm" + + - name: Install dependencies + run: npm clean-install --progress=false --no-fund + + - name: Run unit tests + run: npm test + + build-examples: + name: Build Examples Browser + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Node.js 22.x + uses: actions/setup-node@v6 + with: + node-version: 24.x + cache: "npm" + + - name: Install dependencies + run: npm clean-install --progress=false --no-fund + + - name: Build Examples Browser + working-directory: ./examples + run: | + npm clean-install --progress=false --no-fund + npm run build diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 666132e9a32..00000000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,71 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ master ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ master ] - schedule: - - cron: '28 18 * * 3' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'javascript' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000000..c0723965d7b --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,62 @@ +name: Publish + +on: + push: + tags: + - "v[0-9]+.[0-9]+.[0-9]+" + - "v[0-9]+.[0-9]+.[0-9]+-preview.[0-9]+" + - "v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+" + +jobs: + publish: + name: Publish + runs-on: ubuntu-latest + if: ${{ github.repository_owner == 'playcanvas' }} + permissions: + contents: read + id-token: write + steps: + - name: Check out code + uses: actions/checkout@v6 + + - name: Set up Node.js 24.x + uses: actions/setup-node@v6 + with: + node-version: 24.x + cache: "npm" + registry-url: "https://registry.npmjs.org/" + + - name: Parse tag name + run: | + TAG_NAME=${GITHUB_REF#refs/tags/} + echo "TAG=${TAG_NAME}" >> $GITHUB_ENV + echo "VERSION=${TAG_NAME/v/}" >> $GITHUB_ENV + + - name: Install Dependencies + run: npm install + + - name: Build PlayCanvas + run: npm run build + + - name: Run Publint + run: npm run publint + + - name: Publish to npm + run: | + if [[ "${{ env.TAG }}" =~ "preview" ]]; then + tag=preview + elif [[ "${{ env.TAG }}" =~ "beta" ]]; then + tag=beta + else + tag=latest + fi + npm publish --tag $tag --provenance + + - name: Write version + run: echo "${{ env.VERSION }}" > version.txt + + - name: Upload version + uses: actions/upload-artifact@v7 + with: + name: version + path: version.txt diff --git a/.github/workflows/upload.yml b/.github/workflows/upload.yml new file mode 100644 index 00000000000..be02207170c --- /dev/null +++ b/.github/workflows/upload.yml @@ -0,0 +1,39 @@ +name: Upload + +on: + workflow_dispatch: + workflow_run: + workflows: ["Publish"] + types: + - completed + +jobs: + upload: + runs-on: ubuntu-latest + if: github.repository_owner == 'playcanvas' && (github.event_name == 'workflow_dispatch' && startsWith(github.ref, 'refs/tags/') || (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')) + steps: + - name: Download version + if: github.event_name == 'workflow_run' + uses: actions/download-artifact@v8 + with: + name: version + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + + - name: Read version + if: github.event_name == 'workflow_run' + run: echo "VERSION=$(cat version.txt)" >> $GITHUB_ENV + + - name: Parse tag name + if: github.event_name == 'workflow_dispatch' + run: | + TAG_NAME=${GITHUB_REF#refs/tags/} + echo "VERSION=${TAG_NAME/v/}" >> $GITHUB_ENV + + - name: Upload to code.playcanvas.com + run: | + if ! curl -fsS -X POST -H "Content-Type: application/json" \ + -d '{ "engineVersion": "${{ env.VERSION }}" }' ${{ secrets.PUBLISH_ENDPOINT }}; then + echo "Failed to publish to code.playcanvas.com" + exit 1 + fi diff --git a/.gitignore b/.gitignore index ebc034b381a..63cf3d3e923 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,20 @@ *.DS_Store -/build -/docs -node_modules/ +.cursor .idea/ .vscode/ -npm-debug.log -.java-version -release.py -examples/node_modules +build +tree*.*.html +coverage +docs examples/dist +examples/node_modules +node_modules +npm-debug.log +types +stats.html +.npmrc +examples/.npmrc +.prettierrc +# Added by Snap Cursor Rules extension +.cursor/rules/cursor-rules-debug.log +.cursor/rules/remote diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000000..3c032078a4a --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +18 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000000..3a3090772d2 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,342 @@ +# 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.0.0 +- **Build System**: Rollup +- **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 +- **Build output**: Generated files go in `build/` (never edit these directly) +- **Examples**: Live in `examples/src/examples/` +- **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: + ```javascript + /** + * 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` +- 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: + ```javascript + /** + * @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) +- **Test structure**: + ```javascript + 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` + +### 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()`, `deprecated()`, `log()`, `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 + ```javascript + // 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 (except `src/polyfill/`) +- **WebGL 2.0 minimum**: WebGL 1.0 is not supported +- **WebGPU support**: Must maintain compatibility with WebGPU API + +## Common Patterns + +### 15. Object Creation + +```javascript +// 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 + +```javascript +// 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 + +- Examples go in `examples/src/examples/` +- Follow existing example structure (see other `.example.mjs` files) +- Include descriptive comments +- Keep examples simple and focused on one feature + +### 22. 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 + +- **API Reference**: https://api.playcanvas.com/engine/ +- **User Manual**: https://developer.playcanvas.com/user-manual/engine/ +- **Developer Site**: https://github.com/playcanvas/developer-site + - For large features, ask to add documentation to the User Manual + - Manual pages are Markdown files in the `docs/` directory +- **Examples**: https://playcanvas.github.io +- **Forum**: https://forum.playcanvas.com +- **Discord**: https://discord.gg/RSaMRzg +- **GitHub Issues**: https://github.com/playcanvas/engine/issues + +## 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. + diff --git a/LICENSE b/LICENSE index 41bbbfac990..7f478db6d47 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011-2021 PlayCanvas Ltd. +Copyright (c) 2011-2026 PlayCanvas Ltd. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README-ja.md b/README-ja.md new file mode 100644 index 00000000000..26afb86417f --- /dev/null +++ b/README-ja.md @@ -0,0 +1,141 @@ +# PlayCanvas Engine + +[![NPM Version](https://img.shields.io/npm/v/playcanvas)](https://www.npmjs.com/package/playcanvas) +[![NPM Downloads](https://img.shields.io/npm/dw/playcanvas)](https://npmtrends.com/playcanvas) +[![License](https://img.shields.io/npm/l/playcanvas)](https://github.com/playcanvas/engine/blob/main/LICENSE) +[![Discord](https://img.shields.io/badge/Discord-5865F2?style=flat&logo=discord&logoColor=white&color=black)](https://discord.gg/RSaMRzg) +[![Reddit](https://img.shields.io/badge/Reddit-FF4500?style=flat&logo=reddit&logoColor=white&color=black)](https://www.reddit.com/r/PlayCanvas) +[![X](https://img.shields.io/badge/X-000000?style=flat&logo=x&logoColor=white&color=black)](https://x.com/intent/follow?screen_name=playcanvas) + +| [ユーザーマニュアル](https://developer.playcanvas.com/user-manual/engine/) | [APIリファレンス](https://api.playcanvas.com/engine/) | [例](https://playcanvas.github.io) | [ブログ](https://blog.playcanvas.com) | [フォーラム](https://forum.playcanvas.com) | + +PlayCanvasは、WebGL2とWebGPU上に構築されたオープンソースのゲームエンジンです。あらゆるブラウザ、あらゆるデバイスで動作するインタラクティブな3Dアプリ、ゲーム、ビジュアライゼーションを作成できます。 + +[English](https://github.com/playcanvas/engine/blob/dev/README.md) +[中文](https://github.com/playcanvas/engine/blob/dev/README-zh.md) +[日本語](https://github.com/playcanvas/engine/blob/dev/README-ja.md) +[한글](https://github.com/playcanvas/engine/blob/dev/README-kr.md) + +## インストール + +```sh +npm install playcanvas +``` + +または、[`create-playcanvas`](https://github.com/playcanvas/create-playcanvas) で数秒でプロジェクトを作成: + +```sh +npm create playcanvas@latest +``` + +## 使用方法 + +シンプルなHello Worldの例です - 回転するキューブ! + +```js +import { + Application, + Color, + Entity, + FILLMODE_FILL_WINDOW, + RESOLUTION_AUTO +} from 'playcanvas'; + +const canvas = document.createElement('canvas'); +document.body.appendChild(canvas); + +const app = new Application(canvas); + +// fill the available space at full resolution +app.setCanvasFillMode(FILLMODE_FILL_WINDOW); +app.setCanvasResolution(RESOLUTION_AUTO); + +// ensure canvas is resized when window changes size +window.addEventListener('resize', () => app.resizeCanvas()); + +// create box entity +const box = new Entity('cube'); +box.addComponent('render', { + type: 'box' +}); +app.root.addChild(box); + +// create camera entity +const camera = new Entity('camera'); +camera.addComponent('camera', { + clearColor: new Color(0.1, 0.2, 0.3) +}); +app.root.addChild(camera); +camera.setPosition(0, 0, 3); + +// create directional light entity +const light = new Entity('light'); +light.addComponent('light'); +app.root.addChild(light); +light.setEulerAngles(45, 0, 0); + +// rotate the box according to the delta time since the last frame +app.on('update', dt => box.rotate(10 * dt, 20 * dt, 30 * dt)); + +app.start(); +``` + +このコードを自分で試すには[CodePen](https://codepen.io/playcanvas/pen/NPbxMj)をクリックします。 + +PlayCanvas Engine をベースにしたローカル開発環境の設定に関する完全ガイドは[こちら](https://developer.playcanvas.com/user-manual/engine/standalone/)で見つけることができます。 + +## 機能 + +PlayCanvasはフル機能のゲームエンジンです。 + +* 🧊 **グラフィックス** - WebGL2とWebGPUで構築された高度な2D + 3Dグラフィックスエンジン +* 💠 **ガウシアンスプラッティング** - [3Dガウシアンスプラット](https://developer.playcanvas.com/user-manual/graphics/gaussian-splatting/)のロードとレンダリングをネイティブサポート +* 🥽 **XR** - [WebXR](https://developer.playcanvas.com/user-manual/xr/)による没入型ARおよびVR体験のビルトインサポート +* ⚛️ **物理** - 3Dリジッドボディ物理エンジン [ammo.js](https://github.com/kripken/ammo.js) +* 🏃 **アニメーション** - キャラクターやシーンに対する強力なステートベースのアニメーション +* 🎮 **インプット** - マウス、キーボード、タッチ、ゲームパッドのAPI +* 🔊 **サウンド** - Web Audio APIを利用した3D位置情報サウンド +* 📦 **アセット** - [glTF 2.0](https://www.khronos.org/gltf/)、[Draco](https://google.github.io/draco/)、[Basis](https://github.com/BinomialLLC/basis_universal) の圧縮技術を利用した非同期型ストリーミングシステム +* 📜 **スクリプト** - TypeScriptとJavaScriptをサポート + +## エコシステム + +お好みの方法でPlayCanvasを使って開発: + +| パッケージ | 説明 | +| --------- | ---- | +| [`playcanvas`](https://www.npmjs.com/package/playcanvas) | コアエンジン(このページ) | +| [`@playcanvas/react`](https://www.npmjs.com/package/@playcanvas/react) | PlayCanvas用Reactレンダラー | +| [`@playcanvas/web-components`](https://www.npmjs.com/package/@playcanvas/web-components) | カスタム要素による宣言的3D | +| [`create-playcanvas`](https://www.npmjs.com/package/create-playcanvas) | プロジェクトスキャフォールディングCLI | +| [PlayCanvasエディター](https://github.com/playcanvas/editor) | ブラウザベースのビジュアルエディター | + +## ショーケース + +PlayCanvasエンジンを使って[多くのゲームやアプリ](https://github.com/playcanvas/awesome-playcanvas)が公開されています。ここではその一部をご紹介します。 + +[![Seemore](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14705/319531/O4J4VU-image-25.jpg)](https://playcanv.as/p/MflWvdTW/) [![After The Flood](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14928/440410/98554E-image-25.jpg)](https://playcanv.as/p/44MRmJRU/) [![Casino](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14928/349824/U88HJQ-image-25.jpg)](https://playcanv.as/p/LpmXGUe6/) +[![Swooop](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/4763/TKYXB8-image-25.jpg)](https://playcanv.as/p/JtL2iqIH/) [![Master Archer](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/415995/10A5A9-image-25.jpg)](https://playcanv.as/p/JERg21J8/) [![Gaussian Splat Statues](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/1224723/266D9C-image-25.jpg)](https://playcanv.as/p/cLkf99ZV/) +[![Car](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/347824/7ULQ3Y-image-25.jpg)](https://playcanv.as/p/RqJJ9oU9/) [![Star-Lord](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/333626/BGQN9H-image-25.jpg)](https://playcanv.as/p/SA7hVBLt/) [![Global Illumination](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/4373/625081/6AB32D-image-25.jpg)](https://playcanv.as/p/ZV4PW6wr/) + +他のゲームは[PlayCanvasのウェブサイト](https://playcanvas.com/explore)で見ることができます。 + +## 利用実績 + +PlayCanvasは、ビデオゲーム、広告、ビジュアライゼーションの分野で大手企業に採用されています。 +**Animech, Arm, BMW, Disney, Facebook, Famobi, Funday Factory, IGT, King, Miniclip, Leapfrog, Mojiworks, Mozilla, Nickelodeon, Nordeus, NOWWA, PikPok, PlaySide Studios, Polaris, Product Madness, Samsung, Snap, Spry Fox, Zeptolab, Zynga** + +## ビルドの手順 + +[Node.js 18+](https://nodejs.org)がインストールされていることを確認します。次に、必要なNode.jsの依存関係をすべてインストールします。 + +```sh +npm install +``` + +これで、様々なオプションでビルドを実行できるようになりました。 + +| コマンド | 説明 | 出力先 | +| ------- | ---- | ----- | +| `npm run build` | すべてのエンジンビルドターゲットと型宣言をビルドする | `build` | +| `npm run docs` | エンジンの[APIリファレンスドキュメント](https://api.playcanvas.com/engine/)をビルドする | `docs` | diff --git a/README-kr.md b/README-kr.md new file mode 100644 index 00000000000..5b2fe3b36db --- /dev/null +++ b/README-kr.md @@ -0,0 +1,141 @@ +# PlayCanvas Engine + +[![NPM Version](https://img.shields.io/npm/v/playcanvas)](https://www.npmjs.com/package/playcanvas) +[![NPM Downloads](https://img.shields.io/npm/dw/playcanvas)](https://npmtrends.com/playcanvas) +[![License](https://img.shields.io/npm/l/playcanvas)](https://github.com/playcanvas/engine/blob/main/LICENSE) +[![Discord](https://img.shields.io/badge/Discord-5865F2?style=flat&logo=discord&logoColor=white&color=black)](https://discord.gg/RSaMRzg) +[![Reddit](https://img.shields.io/badge/Reddit-FF4500?style=flat&logo=reddit&logoColor=white&color=black)](https://www.reddit.com/r/PlayCanvas) +[![X](https://img.shields.io/badge/X-000000?style=flat&logo=x&logoColor=white&color=black)](https://x.com/intent/follow?screen_name=playcanvas) + +| [사용자 매뉴얼](https://developer.playcanvas.com/user-manual/engine/) | [API 레퍼런스](https://api.playcanvas.com/engine/) | [예제](https://playcanvas.github.io) | [블로그](https://blog.playcanvas.com) | [포럼](https://forum.playcanvas.com) | + +PlayCanvas는 WebGL2와 WebGPU 기반의 오픈소스 게임 엔진입니다. 모든 브라우저, 모든 디바이스에서 실행되는 인터랙티브 3D 앱, 게임 및 시각화를 만들 수 있습니다. + +[English](https://github.com/playcanvas/engine/blob/dev/README.md) +[中文](https://github.com/playcanvas/engine/blob/dev/README-zh.md) +[日本語](https://github.com/playcanvas/engine/blob/dev/README-ja.md) +[한글](https://github.com/playcanvas/engine/blob/dev/README-kr.md) + +## 설치 + +```sh +npm install playcanvas +``` + +또는 [`create-playcanvas`](https://github.com/playcanvas/create-playcanvas)로 몇 초 만에 프로젝트를 생성할 수 있습니다: + +```sh +npm create playcanvas@latest +``` + +## 사용방법 + +여기에 아주 간단한 Hello World의 예가 있습니다 - 회전하는 큐브! + +```js +import { + Application, + Color, + Entity, + FILLMODE_FILL_WINDOW, + RESOLUTION_AUTO +} from 'playcanvas'; + +const canvas = document.createElement('canvas'); +document.body.appendChild(canvas); + +const app = new Application(canvas); + +// fill the available space at full resolution +app.setCanvasFillMode(FILLMODE_FILL_WINDOW); +app.setCanvasResolution(RESOLUTION_AUTO); + +// ensure canvas is resized when window changes size +window.addEventListener('resize', () => app.resizeCanvas()); + +// create box entity +const box = new Entity('cube'); +box.addComponent('render', { + type: 'box' +}); +app.root.addChild(box); + +// create camera entity +const camera = new Entity('camera'); +camera.addComponent('camera', { + clearColor: new Color(0.1, 0.2, 0.3) +}); +app.root.addChild(camera); +camera.setPosition(0, 0, 3); + +// create directional light entity +const light = new Entity('light'); +light.addComponent('light'); +app.root.addChild(light); +light.setEulerAngles(45, 0, 0); + +// rotate the box according to the delta time since the last frame +app.on('update', dt => box.rotate(10 * dt, 20 * dt, 30 * dt)); + +app.start(); +``` + +이 코드를 직접 시도하려면 [CodePen](https://codepen.io/playcanvas/pen/NPbxMj)를 클릭하세요. + +PlayCanvas 엔진을 기반으로 하는 로컬 개발 환경 설정에 대한 전체 가이드는 [여기](https://developer.playcanvas.com/user-manual/engine/standalone/)에서 찾을 수 있습니다. + +## 특징 + +PlayCanvas는 완전한 기능의 게임 엔진입니다. + +* 🧊 **그래픽** - WebGL2와 WebGPU로 구축된 고도의 2D+3D 그래픽 엔진 +* 💠 **가우시안 스플래팅** - [3D 가우시안 스플랫](https://developer.playcanvas.com/user-manual/graphics/gaussian-splatting/) 로딩 및 렌더링 기본 지원 +* 🥽 **XR** - [WebXR](https://developer.playcanvas.com/user-manual/xr/)을 통한 몰입형 AR 및 VR 경험 기본 지원 +* ⚛️ **물리** - 3D 리지드 바디 물리 엔진 [ammo.js](https://github.com/kripken/ammo.js) +* 🏃 **애니메이션** - 캐릭터나 장면에 대한 강력한 스테이트 기반 애니메이션 +* 🎮 **입력** - 마우스, 키보드, 터치, 게임패드 API +* 🔊 **사운드** - Web Audio API를 이용한 3D 위치정보 사운드 +* 📦 **에셋** - [glTF 2.0](https://www.khronos.org/gltf/), [Draco](https://google.github.io/draco/), [Basis](https://github.com/BinomialLLC/basis_universal) 압축 기술을 이용한 비동기형 스트리밍 시스템 +* 📜 **스크립트** - TypeScript와 JavaScript 지원 + +## 에코시스템 + +원하는 방식으로 PlayCanvas를 사용하여 개발하세요: + +| 패키지 | 설명 | +| ------ | ---- | +| [`playcanvas`](https://www.npmjs.com/package/playcanvas) | 코어 엔진 (현재 페이지) | +| [`@playcanvas/react`](https://www.npmjs.com/package/@playcanvas/react) | PlayCanvas용 React 렌더러 | +| [`@playcanvas/web-components`](https://www.npmjs.com/package/@playcanvas/web-components) | 커스텀 엘리먼트를 통한 선언적 3D | +| [`create-playcanvas`](https://www.npmjs.com/package/create-playcanvas) | 프로젝트 스캐폴딩 CLI | +| [PlayCanvas 에디터](https://github.com/playcanvas/editor) | 브라우저 기반 비주얼 에디터 | + +## 프로젝트 쇼케이스 + +PlayCanvas 엔진을 사용하여 [많은 게임과 앱](https://github.com/playcanvas/awesome-playcanvas)이 공개되어 있습니다. 다음은 그 일부를 소개하겠습니다. + +[![Seemore](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14705/319531/O4J4VU-image-25.jpg)](https://playcanv.as/p/MflWvdTW/) [![After The Flood](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14928/440410/98554E-image-25.jpg)](https://playcanv.as/p/44MRmJRU/) [![Casino](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14928/349824/U88HJQ-image-25.jpg)](https://playcanv.as/p/LpmXGUe6/) +[![Swooop](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/4763/TKYXB8-image-25.jpg)](https://playcanv.as/p/JtL2iqIH/) [![dev Archer](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/415995/10A5A9-image-25.jpg)](https://playcanv.as/p/JERg21J8/) [![Gaussian Splat Statues](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/1224723/266D9C-image-25.jpg)](https://playcanv.as/p/cLkf99ZV/) +[![Car](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/347824/7ULQ3Y-image-25.jpg)](https://playcanv.as/p/RqJJ9oU9/) [![Star-Lord](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/333626/BGQN9H-image-25.jpg)](https://playcanv.as/p/SA7hVBLt/) [![Global Illumination](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/4373/625081/6AB32D-image-25.jpg)](https://playcanv.as/p/ZV4PW6wr/) + +다른 게임은 [PlayCanvas 웹사이트](https://playcanvas.com/explore)에서 볼 수 있습니다. + +## 이용 실적 + +PlayCanvas는 비디오 게임, 광고, 시각화 분야에서 대기업에 채용되고 있습니다. +**Animech, Arm, BMW, Disney, Facebook, Famobi, Funday Factory, IGT, King, Miniclip, Leapfrog, Mojiworks, Mozilla, Nickelodeon, Nordeus, NOWWA, PikPok, PlaySide Studios, Polaris, Product Madness, Samsung, Snap, Spry Fox, Zeptolab, Zynga** + +## 빌드 순서 + +[Node.js 18+](https://nodejs.org)가 설치되어 있는지 확인합니다. 그 다음 필요한 Node.js 종속성을 모두 설치합니다. + +```sh +npm install +``` + +이제 다양한 빌드 옵션을 실행할 수 있습니다. + +| 명령어 | 설명 | 출력 위치 | +| ----- | ---- | ------- | +| `npm run build` | 모든 엔진 빌드 대상과 타입 선언을 빌드합니다 | `build` | +| `npm run docs` | 엔진 [API 참조 문서](https://api.playcanvas.com/engine/)를 빌드합니다 | `docs` | diff --git a/README-zh.md b/README-zh.md index 17a74291d03..a84e45c2c48 100644 --- a/README-zh.md +++ b/README-zh.md @@ -1,186 +1,141 @@ -
+# PlayCanvas Engine - +[![NPM Version](https://img.shields.io/npm/v/playcanvas)](https://www.npmjs.com/package/playcanvas) +[![NPM Downloads](https://img.shields.io/npm/dw/playcanvas)](https://npmtrends.com/playcanvas) +[![License](https://img.shields.io/npm/l/playcanvas)](https://github.com/playcanvas/engine/blob/main/LICENSE) +[![Discord](https://img.shields.io/badge/Discord-5865F2?style=flat&logo=discord&logoColor=white&color=black)](https://discord.gg/RSaMRzg) +[![Reddit](https://img.shields.io/badge/Reddit-FF4500?style=flat&logo=reddit&logoColor=white&color=black)](https://www.reddit.com/r/PlayCanvas) +[![X](https://img.shields.io/badge/X-000000?style=flat&logo=x&logoColor=white&color=black)](https://x.com/intent/follow?screen_name=playcanvas) -# PlayCanvas WebGL 游戏引擎 -[开发者站点](https://developer.playcanvas.com) | [例子](https://playcanvas.github.io) | [论坛](https://forum.playcanvas.com) | [博客](https://blog.playcanvas.com) +| [用户手册](https://developer.playcanvas.com/user-manual/engine/) | [API 参考](https://api.playcanvas.com/engine/) | [例子](https://playcanvas.github.io) | [博客](https://blog.playcanvas.com) | [论坛](https://forum.playcanvas.com) | -PlayCanvas 是一款使用 HTML5 和 WebGL 技术运行游戏以及其他 3D 内容的开源游戏引擎,PlayCanvas 以其独特的性能实现了在任何手机移动端和桌面浏览器端均可以流畅运行。 +PlayCanvas 是一款基于 WebGL2 和 WebGPU 构建的开源游戏引擎。使用它可以创建在任何浏览器和任何设备上运行的交互式 3D 应用、游戏和可视化内容。 -[![NPM version][npm-badge]][npm-url] -[![Minzipped size][minzip-badge]][minzip-url] -[![Average time to resolve an issue][resolution-badge]][isitmaintained-url] -[![Percentage of issues still open][open-issues-badge]][isitmaintained-url] -[![Twitter][twitter-badge]][twitter-url] +[English](https://github.com/playcanvas/engine/blob/dev/README.md) +[中文](https://github.com/playcanvas/engine/blob/dev/README-zh.md) +[日本語](https://github.com/playcanvas/engine/blob/dev/README-ja.md) +[한글](https://github.com/playcanvas/engine/blob/dev/README-kr.md) -[English](https://github.com/playcanvas/engine/blob/master/README.md) -[中文](https://github.com/playcanvas/engine/blob/master/README-zh.md) +## 安装 -## 项目展示 +```sh +npm install playcanvas +``` -许多团队已经成功地使用了 PlayCanvas 引擎开发并发布了游戏和应用。以下是一些项目案例: +或者使用 [`create-playcanvas`](https://github.com/playcanvas/create-playcanvas) 快速创建一个完整项目: -[![Seemore](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14705/319531/O4J4VU-image-25.jpg)](https://playcanv.as/p/MflWvdTW/) [![After The Flood](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14928/440410/98554E-image-25.jpg)](https://playcanv.as/p/44MRmJRU/) [![Casino](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14928/349824/U88HJQ-image-25.jpg)](https://playcanv.as/p/LpmXGUe6/) -[![Swooop](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/4763/TKYXB8-image-25.jpg)](https://playcanv.as/p/JtL2iqIH/) [![Master Archer](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/415995/10A5A9-image-25.jpg)](https://playcanv.as/p/JERg21J8/) [![Flappy Bird](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/8/375389/23PRTL-image-25.jpg)](https://playcanv.as/p/2OlkUaxF/) -[![Car](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/347824/7ULQ3Y-image-25.jpg)](https://playcanv.as/p/RqJJ9oU9/) [![Star-Lord](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/333626/BGQN9H-image-25.jpg)](https://playcanv.as/p/SA7hVBLt/) [![Global Illumination](http://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/4373/625081/6AB32D-image-25.jpg)](https://playcanv.as/p/ZV4PW6wr/) +```sh +npm create playcanvas@latest +``` -点击此链接查看更多案例: [PlayCanvas website](https://playcanvas.com/explore). +## 如何使用 -
+以下为一个简单的使用案例 - 实现一个旋转的立方体! -## 我们的客户 +```js +import { + Application, + Color, + Entity, + FILLMODE_FILL_WINDOW, + RESOLUTION_AUTO +} from 'playcanvas'; + +const canvas = document.createElement('canvas'); +document.body.appendChild(canvas); + +const app = new Application(canvas); + +// 在全屏模式下填满可用空间 +app.setCanvasFillMode(FILLMODE_FILL_WINDOW); +app.setCanvasResolution(RESOLUTION_AUTO); + +// 确保在窗口尺寸变化同时画布也同时改变其大小 +window.addEventListener('resize', () => app.resizeCanvas()); + +// 创建一个立方体 +const box = new Entity('cube'); +box.addComponent('render', { + type: 'box' +}); +app.root.addChild(box); + +// 创建一个摄像头 +const camera = new Entity('camera'); +camera.addComponent('camera', { + clearColor: new Color(0.1, 0.2, 0.3) +}); +app.root.addChild(camera); +camera.setPosition(0, 0, 3); + +// 创建一个指向灯 +const light = new Entity('light'); +light.addComponent('light'); +app.root.addChild(light); +light.setEulerAngles(45, 0, 0); + +// 根据立方体的时间增量旋转立方体 +app.on('update', dt => box.rotate(10 * dt, 20 * dt, 30 * dt)); + +app.start(); +``` -许多行业龙头公司在不同领域(广告,电子游戏以及产品可视化等)均适用了 PlayCanvas: +想要自己动手试试?点击 [CodePen](https://codepen.io/playcanvas/pen/NPbxMj). -**Animech, Arm, Disney, Facebook, IGT, King, Miniclip, Leapfrog, Mozilla, Nickelodeon, Nordeus, PikPok, PlaySide Studios, Polaris, Product Madness, Samsung, Snap, Spry Fox, Zeptolab, Zynga** +基于 PlayCanvas 引擎设置本地开发环境的完整指南可以在[这里](https://developer.playcanvas.com/user-manual/engine/standalone/)找到。 ## 特点 PlayCanvas 是一款优秀的全功能游戏引擎。 -- 🧊 **图形** - 基于 WebGL1&2 的超前 2D + 3D 图形引擎 -- 🏃 **动画** - 基于状态的强大动画功能,有效展现动画角色和随机场景属性 +- 🧊 **图形** - 基于 WebGL2 和 WebGPU 的超前 2D + 3D 图形引擎 +- 💠 **高斯泼溅** - 原生支持加载和渲染 [3D 高斯泼溅](https://developer.playcanvas.com/user-manual/graphics/gaussian-splatting/) +- 🥽 **XR** - 通过 [WebXR](https://developer.playcanvas.com/user-manual/xr/) 内置支持沉浸式 AR 和 VR 体验 - ⚛️ **物理** - 一体化的 3D 刚体物理引擎 [ammo.js](https://github.com/kripken/ammo.js) -- 🎮 **输入** - 支持鼠标,键盘,触控,游戏控制器以及众多 VR 控制器 API +- 🏃 **动画** - 基于状态的强大动画功能,有效展现动画角色和随机场景属性 +- 🎮 **输入** - 支持鼠标、键盘、触控和游戏控制器 API - 🔊 **声音** - 基于 Web Audio API 的 3D 音效 - 📦 **资源** - 使用 [glTF 2.0](https://www.khronos.org/gltf/), [Draco](https://google.github.io/draco/) 以及 [Basis](https://github.com/BinomialLLC/basis_universal) 的异步流媒体系统 -- 📜 **代码** - 支持 Typescript 以及 JavaScript - -## 如何使用 - -以下为一个简单的使用案例 - 实现一个旋转的立方体! +- 📜 **代码** - 支持 TypeScript 以及 JavaScript -```html - - - - - PlayCanvas Hello Cube - - - - - - - - - -``` - -想要自己动手试试?点击 [CodePen](https://codepen.io/playcanvas/pen/NPbxMj). - -## 如何搭建项目 +## 生态系统 -确保已安装 [Node.js](https://nodejs.org) ,并安装 Node.js 相关依赖组件。 +以你喜欢的方式使用 PlayCanvas 进行开发: - npm install +| 包 | 描述 | +| --- | ---- | +| [`playcanvas`](https://www.npmjs.com/package/playcanvas) | 核心引擎(当前页面) | +| [`@playcanvas/react`](https://www.npmjs.com/package/@playcanvas/react) | PlayCanvas 的 React 渲染器 | +| [`@playcanvas/web-components`](https://www.npmjs.com/package/@playcanvas/web-components) | 通过自定义元素实现声明式 3D | +| [`create-playcanvas`](https://www.npmjs.com/package/create-playcanvas) | 项目脚手架 CLI | +| [PlayCanvas 编辑器](https://github.com/playcanvas/editor) | 基于浏览器的可视化编辑器 | -现在您就可以运行不同的搭建选项了: - -| Command | Description | Outputs | -| ----------------- | ----------------------------------------- | -------------------------------- | -| `npm run build` | Build release, debug and profiler engines | `build\playcanvas[.dbg/.prf].js` | -| `npm run tsd` | Build engine Typescript bindings | `build\playcanvas.d.ts` | -| `npm run docs` | Build engine [API reference docs][docs] | `docs` | - -您也可以使用 PlayCanvas 的预搭建版本 - -最新的开发版本: - -- https://code.playcanvas.com/playcanvas-latest.js -- https://code.playcanvas.com/playcanvas-latest.min.js - -最新的稳定版本: - -- https://code.playcanvas.com/playcanvas-stable.js -- https://code.playcanvas.com/playcanvas-stable.min.js - -特定引擎版本: - -- https://code.playcanvas.com/playcanvas-1.38.4.js -- https://code.playcanvas.com/playcanvas-1.38.4.min.js - -### 生成 Source Maps - -您可以在任何构建指令之后添加 `-- -m` 来生成 Source map 更好更方便地对引擎进行调试和排错: - - npm run build -- -m - -此条指令将会将结果输出到 `build/output/playcanvas.js.map` +## 项目展示 -提示:在生成 source map 过程中,系统会忽略预处理器以防止其对过程产生影响。这意味着在生成 source map 的过程中,所有 debug 和 profiling 代码将会被包含在引擎构建中。 +许多团队已经成功地使用了 PlayCanvas 引擎开发并发布了游戏和应用。以下是一些项目案例: -## 如何测试 +[![Seemore](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14705/319531/O4J4VU-image-25.jpg)](https://playcanv.as/p/MflWvdTW/) [![After The Flood](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14928/440410/98554E-image-25.jpg)](https://playcanv.as/p/44MRmJRU/) [![Casino](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14928/349824/U88HJQ-image-25.jpg)](https://playcanv.as/p/LpmXGUe6/) +[![Swooop](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/4763/TKYXB8-image-25.jpg)](https://playcanv.as/p/JtL2iqIH/) [![Master Archer](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/415995/10A5A9-image-25.jpg)](https://playcanv.as/p/JERg21J8/) [![Gaussian Splat Statues](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/1224723/266D9C-image-25.jpg)](https://playcanv.as/p/cLkf99ZV/) +[![Car](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/347824/7ULQ3Y-image-25.jpg)](https://playcanv.as/p/RqJJ9oU9/) [![Star-Lord](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/333626/BGQN9H-image-25.jpg)](https://playcanv.as/p/SA7hVBLt/) [![Global Illumination](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/4373/625081/6AB32D-image-25.jpg)](https://playcanv.as/p/ZV4PW6wr/) -PlayCanvas 使用 Karma 进行单元测试。您可以使用如下两种方式进行测试: +点击此链接查看更多案例: [PlayCanvas website](https://playcanvas.com/explore). -| Command | Description | -| -------------------- | ------------------------------------------------------------------------------------ | -| `npm run test` | Runs unit tests on a built `playcanvas.js` | -| `npm run test:watch` | Re-runs unit tests when changes are detected - open http://localhost:9876/debug.html | +## 我们的客户 -## PlayCanvas 平台 +许多行业龙头公司在不同领域(广告,电子游戏以及产品可视化等)均使用了 PlayCanvas: +**Animech, Arm, BMW, Disney, Facebook, Famobi, Funday Factory, IGT, King, Miniclip, Leapfrog, Mojiworks, Mozilla, Nickelodeon, Nordeus, NOWWA, PikPok, PlaySide Studios, Polaris, Product Madness, Samsung, Snap, Spry Fox, Zeptolab, Zynga** -PlayCanvas 引擎是一款可以基于浏览器的用于制作游戏以及 3D 可视化的开源引擎。除此之外,我们还开发了[PlayCanvas 开发平台](https://playcanvas.com/), 为我们的用户提供了可视化编辑器,资源管理,代码编辑,代码托管以及发布等服务。 +## 如何搭建项目 -[![Editor](https://github.com/playcanvas/editor/blob/master/images/editor.png?raw=true)](https://github.com/playcanvas/editor) +确保已安装 [Node.js 18+](https://nodejs.org) ,并安装 Node.js 相关依赖组件。 -## License +```sh +npm install +``` -The PlayCanvas Engine is released under the [MIT](https://opensource.org/licenses/MIT) license. See LICENSE file. +现在您就可以运行不同的搭建选项了: -[npm-badge]: https://img.shields.io/npm/v/playcanvas -[npm-url]: https://www.npmjs.com/package/playcanvas -[minzip-badge]: https://img.shields.io/bundlephobia/minzip/playcanvas -[minzip-url]: https://bundlephobia.com/result?p=playcanvas -[resolution-badge]: http://isitmaintained.com/badge/resolution/playcanvas/engine.svg -[open-issues-badge]: http://isitmaintained.com/badge/open/playcanvas/engine.svg -[isitmaintained-url]: http://isitmaintained.com/project/playcanvas/engine -[twitter-badge]: https://img.shields.io/twitter/follow/playcanvas.svg?style=social&label=Follow -[twitter-url]: https://twitter.com/intent/follow?screen_name=playcanvas -[docs]: https://developer.playcanvas.com/en/api/ +| 命令 | 描述 | 输出到 | +| ---- | ---- | ----- | +| `npm run build` | 构建所有引擎构建目标和类型声明 | `build` | +| `npm run docs` | 构建引擎[API参考文档](https://api.playcanvas.com/engine/) | `docs` | diff --git a/README.md b/README.md index cedca1890eb..4d7e15224a7 100644 --- a/README.md +++ b/README.md @@ -1,183 +1,141 @@ -
+# PlayCanvas Engine - +[![NPM Version](https://img.shields.io/npm/v/playcanvas)](https://www.npmjs.com/package/playcanvas) +[![NPM Downloads](https://img.shields.io/npm/dw/playcanvas)](https://npmtrends.com/playcanvas) +[![License](https://img.shields.io/npm/l/playcanvas)](https://github.com/playcanvas/engine/blob/main/LICENSE) +[![Discord](https://img.shields.io/badge/Discord-5865F2?style=flat&logo=discord&logoColor=white&color=black)](https://discord.gg/RSaMRzg) +[![Reddit](https://img.shields.io/badge/Reddit-FF4500?style=flat&logo=reddit&logoColor=white&color=black)](https://www.reddit.com/r/PlayCanvas) +[![X](https://img.shields.io/badge/X-000000?style=flat&logo=x&logoColor=white&color=black)](https://x.com/intent/follow?screen_name=playcanvas) -# PlayCanvas WebGL Game Engine -[Docs](https://developer.playcanvas.com) | [Examples](https://playcanvas.github.io) | [Forum](https://forum.playcanvas.com) | [Blog](https://blog.playcanvas.com) +| [User Manual](https://developer.playcanvas.com/user-manual/engine/) | [API Reference](https://api.playcanvas.com/engine/) | [Examples](https://playcanvas.github.io) | [Blog](https://blog.playcanvas.com) | [Forum](https://forum.playcanvas.com) | -PlayCanvas is an open-source game engine. It uses HTML5 and WebGL to run games and other interactive 3D content in any mobile or desktop browser. +PlayCanvas is an open-source game engine built on WebGL2 and WebGPU. Use it to create interactive 3D apps, games and visualizations that run in any browser on any device. -[![NPM version][npm-badge]][npm-url] -[![Minzipped size][minzip-badge]][minzip-url] -[![Average time to resolve an issue][resolution-badge]][isitmaintained-url] -[![Percentage of issues still open][open-issues-badge]][isitmaintained-url] -[![Twitter][twitter-badge]][twitter-url] +[English](https://github.com/playcanvas/engine/blob/dev/README.md) +[中文](https://github.com/playcanvas/engine/blob/dev/README-zh.md) +[日本語](https://github.com/playcanvas/engine/blob/dev/README-ja.md) +[한글](https://github.com/playcanvas/engine/blob/dev/README-kr.md) -[English](https://github.com/playcanvas/engine/blob/master/README.md) -[中文](https://github.com/playcanvas/engine/blob/master/README-zh.md) +## Install -## Project Showcase - -[Many games and apps](https://github.com/playcanvas/awesome-playcanvas#awesome-playcanvas- -) have been published using the PlayCanvas engine. Here is a small selection: - -[![Seemore](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14705/319531/O4J4VU-image-25.jpg)](https://playcanv.as/p/MflWvdTW/) [![After The Flood](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14928/440410/98554E-image-25.jpg)](https://playcanv.as/p/44MRmJRU/) [![Casino](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14928/349824/U88HJQ-image-25.jpg)](https://playcanv.as/p/LpmXGUe6/) -[![Swooop](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/4763/TKYXB8-image-25.jpg)](https://playcanv.as/p/JtL2iqIH/) [![Master Archer](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/415995/10A5A9-image-25.jpg)](https://playcanv.as/p/JERg21J8/) [![Flappy Bird](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/8/375389/23PRTL-image-25.jpg)](https://playcanv.as/p/2OlkUaxF/) -[![Car](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/347824/7ULQ3Y-image-25.jpg)](https://playcanv.as/p/RqJJ9oU9/) [![Star-Lord](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/333626/BGQN9H-image-25.jpg)](https://playcanv.as/p/SA7hVBLt/) [![Global Illumination](http://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/4373/625081/6AB32D-image-25.jpg)](https://playcanv.as/p/ZV4PW6wr/ ) - - - -You can see more games on the [PlayCanvas website](https://playcanvas.com/explore). - -
- -## Users - -PlayCanvas is used by leading companies in video games, advertising and visualization such as: -**Animech, Arm, BMW, Disney, Facebook, Famobi, Funday Factory, IGT, King, Miniclip, Leapfrog, Mojiworks, Mozilla, Nickelodeon, Nordeus, NOWWA, PikPok, PlaySide Studios, Polaris, Product Madness, Samsung, Snap, Spry Fox, Zeptolab, Zynga** - -## Features +```sh +npm install playcanvas +``` -PlayCanvas is a fully featured game engine. +Or scaffold a full project in seconds with [`create-playcanvas`](https://github.com/playcanvas/create-playcanvas): -* 🧊 **Graphics** - Advanced 2D + 3D graphics engine built on WebGL 1 & 2. -* 🏃 **Animation** - Powerful state-based animations for characters and arbitrary scene properties -* ⚛️ **Physics** - Full integration with 3D rigid-body physics engine [ammo.js](https://github.com/kripken/ammo.js) -* 🎮 **Input** - Mouse, keyboard, touch, gamepad and VR controller APIs -* 🔊 **Sound** - 3D positional sounds built on the Web Audio API -* 📦 **Assets** - Asynchronous streaming system built on [glTF 2.0](https://www.khronos.org/gltf/), [Draco](https://google.github.io/draco/) and [Basis](https://github.com/BinomialLLC/basis_universal) compression -* 📜 **Scripts** - Write game behaviors in Typescript or JavaScript +```sh +npm create playcanvas@latest +``` ## Usage Here's a super-simple Hello World example - a spinning cube! -```html - - - - - PlayCanvas Hello Cube - - - - - - - - - +```js +import { + Application, + Color, + Entity, + FILLMODE_FILL_WINDOW, + RESOLUTION_AUTO +} from 'playcanvas'; + +const canvas = document.createElement('canvas'); +document.body.appendChild(canvas); + +const app = new Application(canvas); + +// fill the available space at full resolution +app.setCanvasFillMode(FILLMODE_FILL_WINDOW); +app.setCanvasResolution(RESOLUTION_AUTO); + +// ensure canvas is resized when window changes size +window.addEventListener('resize', () => app.resizeCanvas()); + +// create box entity +const box = new Entity('cube'); +box.addComponent('render', { + type: 'box' +}); +app.root.addChild(box); + +// create camera entity +const camera = new Entity('camera'); +camera.addComponent('camera', { + clearColor: new Color(0.1, 0.2, 0.3) +}); +app.root.addChild(camera); +camera.setPosition(0, 0, 3); + +// create directional light entity +const light = new Entity('light'); +light.addComponent('light'); +app.root.addChild(light); +light.setEulerAngles(45, 0, 0); + +// rotate the box according to the delta time since the last frame +app.on('update', dt => box.rotate(10 * dt, 20 * dt, 30 * dt)); + +app.start(); ``` Want to play with the code yourself? Edit it on [CodePen](https://codepen.io/playcanvas/pen/NPbxMj). -## How to build +A full guide to setting up a local development environment based on the PlayCanvas Engine can be found [here](https://developer.playcanvas.com/user-manual/engine/standalone/). -Ensure you have [Node.js](https://nodejs.org) installed. Then, install all of the required Node.js dependencies: - - npm install - -Now you can run various build options: - -| Command | Description | Outputs | -|------------------------|-------------------------------------------|----------------------------------| -| `npm run build` | Build release, debug and profiler engines | `build\playcanvas[.dbg/.prf].js` | -| `npm run tsd` | Build engine Typescript bindings | `build\playcanvas.d.ts` | -| `npm run docs` | Build engine [API reference docs][docs] | `docs` | - -Pre-built versions of the engine are also available. - -Latest development release (head revision of master branch): - -* https://code.playcanvas.com/playcanvas-latest.js -* https://code.playcanvas.com/playcanvas-latest.min.js - -Latest stable release: +## Features -* https://code.playcanvas.com/playcanvas-stable.js -* https://code.playcanvas.com/playcanvas-stable.min.js +PlayCanvas is a fully-featured game engine. -Specific engine versions: +* 🧊 **Graphics** - Advanced 2D + 3D graphics engine built on WebGL2 & WebGPU +* 💠 **Gaussian Splatting** - First-class support for loading and rendering [3D Gaussian Splats](https://developer.playcanvas.com/user-manual/graphics/gaussian-splatting/) +* 🥽 **XR** - Built-in support for immersive AR and VR experiences via [WebXR](https://developer.playcanvas.com/user-manual/xr/) +* ⚛️ **Physics** - Full integration with 3D rigid-body physics engine [ammo.js](https://github.com/kripken/ammo.js) +* 🏃 **Animation** - Powerful state-based animations for characters and arbitrary scene properties +* 🎮 **Input** - Mouse, keyboard, touch and gamepad APIs +* 🔊 **Sound** - 3D positional sounds built on the Web Audio API +* 📦 **Assets** - Asynchronous streaming system built on [glTF 2.0](https://www.khronos.org/gltf/), [Draco](https://google.github.io/draco/) and [Basis](https://github.com/BinomialLLC/basis_universal) compression +* 📜 **Scripts** - Write game behaviors in TypeScript or JavaScript -* https://code.playcanvas.com/playcanvas-1.38.4.js -* https://code.playcanvas.com/playcanvas-1.38.4.min.js +## Ecosystem -### Generate Source Maps +Build with PlayCanvas your way: -To build the source map to allow for easier engine debugging, you can add `-- -m` to any engine build command. For example: +| Package | Description | +| ------- | ----------- | +| [`playcanvas`](https://www.npmjs.com/package/playcanvas) | Core engine (you are here) | +| [`@playcanvas/react`](https://www.npmjs.com/package/@playcanvas/react) | React renderer for PlayCanvas | +| [`@playcanvas/web-components`](https://www.npmjs.com/package/@playcanvas/web-components) | Declarative 3D via Custom Elements | +| [`create-playcanvas`](https://www.npmjs.com/package/create-playcanvas) | Project scaffolding CLI | +| [PlayCanvas Editor](https://github.com/playcanvas/editor) | Browser-based visual editor | - npm run build -- -m +## Project Showcase -This will output to `build/output/playcanvas.js.map` +[Many games and apps](https://github.com/playcanvas/awesome-playcanvas) have been published using the PlayCanvas engine. Here is a small selection: -Note: The preprocessor is ignored when generating the source map as it breaks the mapping. This means that all debug and profiling code is included in the engine build when generating the source map. +[![Seemore](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14705/319531/O4J4VU-image-25.jpg)](https://playcanv.as/p/MflWvdTW/) [![After The Flood](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14928/440410/98554E-image-25.jpg)](https://playcanv.as/p/44MRmJRU/) [![Casino](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/14928/349824/U88HJQ-image-25.jpg)](https://playcanv.as/p/LpmXGUe6/) +[![Swooop](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/4763/TKYXB8-image-25.jpg)](https://playcanv.as/p/JtL2iqIH/) [![dev Archer](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/415995/10A5A9-image-25.jpg)](https://playcanv.as/p/JERg21J8/) [![Gaussian Splat Statues](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/1224723/266D9C-image-25.jpg)](https://playcanv.as/p/cLkf99ZV/) +[![Car](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/347824/7ULQ3Y-image-25.jpg)](https://playcanv.as/p/RqJJ9oU9/) [![Star-Lord](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/12/333626/BGQN9H-image-25.jpg)](https://playcanv.as/p/SA7hVBLt/) [![Global Illumination](https://s3-eu-west-1.amazonaws.com/images.playcanvas.com/projects/4373/625081/6AB32D-image-25.jpg)](https://playcanv.as/p/ZV4PW6wr/ ) -## How to run tests +You can see more games on the [PlayCanvas website](https://playcanvas.com/explore). -PlayCanvas uses of Karma for unit testing. There are two ways of running the tests: +## Users -| Command | Description | -|------------------------|---------------------------------------------------------------------------------------| -| `npm run test` | Runs unit tests on a built `playcanvas.js` | -| `npm run test:watch` | Re-runs unit tests when changes are detected - open http://localhost:9876/debug.html | +PlayCanvas is used by leading companies in video games, advertising and visualization such as: +**Animech, Arm, BMW, Disney, Facebook, Famobi, Funday Factory, IGT, King, Miniclip, Leapfrog, Mojiworks, Mozilla, Nickelodeon, Nordeus, NOWWA, PikPok, PlaySide Studios, Polaris, Product Madness, Samsung, Snap, Spry Fox, Zeptolab, Zynga** -## PlayCanvas Editor +## How to build -The PlayCanvas Engine is an open source engine which you can use to create HTML5 apps/games. In addition to the engine, we also make the [PlayCanvas Editor](https://playcanvas.com/): +Ensure you have [Node.js 18+](https://nodejs.org) installed. Then, install all of the required Node.js dependencies: -[![Editor](https://github.com/playcanvas/editor/blob/master/images/editor.png?raw=true)](https://github.com/playcanvas/editor) +```sh +npm install +``` -For Editor related bugs and issues, please refer to the [Editor's repo](https://github.com/playcanvas/editor). +Now you can run various build options: -[npm-badge]: https://img.shields.io/npm/v/playcanvas -[npm-url]: https://www.npmjs.com/package/playcanvas -[minzip-badge]: https://img.shields.io/bundlephobia/minzip/playcanvas -[minzip-url]: https://bundlephobia.com/result?p=playcanvas -[resolution-badge]: http://isitmaintained.com/badge/resolution/playcanvas/engine.svg -[open-issues-badge]: http://isitmaintained.com/badge/open/playcanvas/engine.svg -[isitmaintained-url]: http://isitmaintained.com/project/playcanvas/engine -[twitter-badge]: https://img.shields.io/twitter/follow/playcanvas.svg?style=social&label=Follow -[twitter-url]: https://twitter.com/intent/follow?screen_name=playcanvas -[docs]: https://developer.playcanvas.com/en/api/ +| Command | Description | Outputs To | +| ------- | ----------- | ---------- | +| `npm run build` | Build all engine flavors and type declarations | `build` | +| `npm run docs` | Build engine [API reference docs](https://api.playcanvas.com/engine/) | `docs` | diff --git a/build.mjs b/build.mjs new file mode 100644 index 00000000000..e7e88ad56d6 --- /dev/null +++ b/build.mjs @@ -0,0 +1,45 @@ +/** + * Build helper scripts + * Usage: node build.mjs [options] -- [rollup options] + * + * Options: + * target[:][:][:] - Specify the target + * - moduleFormat (esm, umd) + * - buildType (release, debug, profiler, min) + * - bundleState (unbundled, bundled) + * Example: target:esm:release:bundled + * + * treemap - Enable treemap build visualization (release only). + * treenet - Enable treenet build visualization (release only). + * treesun - Enable treesun build visualization (release only). + * treeflame - Enable treeflame build visualization (release only). + */ + +import { execSync } from 'child_process'; + +const args = process.argv.slice(2); + +const ENV_START_MATCHES = [ + 'target', + 'treemap', + 'treenet', + 'treesun', + 'treeflame' +]; + +const env = []; +for (let i = 0; i < args.length; i++) { + if (ENV_START_MATCHES.some(match => args[i].startsWith(match)) && args[i - 1] !== '--environment') { + env.push(`--environment ${args[i]}`); + args.splice(i, 1); + i--; + continue; + } +} + +const cmd = `rollup -c ${args.join(' ')} ${env.join(' ')}`; +try { + execSync(cmd, { stdio: 'inherit' }); +} catch (e) { + console.error(e.message); +} diff --git a/conf-api.json b/conf-api.json deleted file mode 100644 index 8853241f160..00000000000 --- a/conf-api.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "plugins": [ - "plugins/markdown" - ], - "recurseDepth": 10, - "source": { - "include": ["src"], - "includePattern": ".+\\.js(doc|x)?$", - "excludePattern": "(^|\\/|\\\\)_" - }, - "sourceType": "module", - "tags": { - "allowUnknownTags": true, - "dictionaries": ["jsdoc","closure"] - }, - "templates": { - "cleverLinks": false, - "monospaceLinks": false - }, - "opts": { - "destination": "docs", - "encoding": "utf8", - "recurse": true, - "template": "./node_modules/@playcanvas/jsdoc-template" - } -} \ No newline at end of file diff --git a/conf-tsd.json b/conf-tsd.json deleted file mode 100644 index b9ce3c2bb14..00000000000 --- a/conf-tsd.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "source": { - "include": ["src"] - }, - "opts": { - "destination": "build", - "outFile": "playcanvas.d.ts", - "recurse": true, - "template": "node_modules/tsd-jsdoc/dist" - } -} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000000..8e59750a10c --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,70 @@ +import playcanvasConfig from '@playcanvas/eslint-config'; +import globals from 'globals'; + +// Extract or preserve existing JSDoc tags +const jsdocRule = playcanvasConfig.find( + config => config.rules && config.rules['jsdoc/check-tag-names'] +); +const existingTags = jsdocRule?.rules['jsdoc/check-tag-names'][1]?.definedTags || []; + +export default [ + ...playcanvasConfig, + { + files: ['**/*.js', '**/*.mjs'], + languageOptions: { + ecmaVersion: 2022, + sourceType: 'module', + globals: { + ...globals.browser, + ...globals.mocha, + ...globals.node, + 'Ammo': 'readonly', + 'earcut': 'readonly', + 'opentype': 'readonly', + 'pc': 'readonly', + 'TWEEN': 'readonly', + 'twgsl': 'readonly', + 'webkitAudioContext': 'readonly' + } + }, + rules: { + 'import/order': 'off', + 'jsdoc/check-tag-names': [ + 'error', + { + // custom mjs script tags to not error on, add them to those from parent config + definedTags: [...new Set([...existingTags, 'range', 'step', 'precision'])] + } + ] + } + }, + { + files: ['scripts/**/*.js'], + rules: { + 'no-var': 'off' + } + }, + { + files: ['scripts/**/*.mjs'], + rules: { + 'jsdoc/no-defaults': 'off', // Attributes use default values + 'import/no-unresolved': 'off' // PlayCanvas is not installed for scripts + } + }, + { + files: ['test/**/*.mjs'], + rules: { + 'import/order': 'error', + 'no-unused-expressions': 'off', + 'prefer-arrow-callback': 'off' // Mocha uses function callbacks + } + }, + { + ignores: [ + 'examples/lib/*', + 'scripts/textmesh/*.min.js', + 'src/polyfill/*', + 'scripts/spine/*' + ] + } +]; diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 00000000000..6de0845310c --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,5 @@ +# Prettier config +.prettierrc + +# Cache directory +cache \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index c5f193e5216..6ece9a36d9f 100644 --- a/examples/README.md +++ b/examples/README.md @@ -6,118 +6,169 @@ A selection of simple examples to get you up and running See them running live -## Local development +## Local examples browser development +This section covers how to locally develop the examples browser application. For information on how to develop individual examples please see the following section. + Ensure you have Node.js installed. Then, install all of the required Node.js dependencies: ``` npm install ``` -Now run the following two commands in two separate terminals: +Now run the following command: ``` -npm run build:watch +npm run develop ``` -and +Visit the url mentioned in your terminal to view the examples browser. + +You can also run the examples browser with a specific version of the engine by running the following command: + ``` -npm run serve +ENGINE_PATH=../build/playcanvas.mjs npm run develop ``` -Visit [http://localhost:5000]() to view the examples browser. -To create the side bar thumbnails run the following script: +Where `../build/playcanvas.mjs` is the path to the ESM version of the engine. + +Or directly from the source: + ``` -npm run thumbnails +ENGINE_PATH=../src/index.js npm run develop ``` -### Local engine development -By default, the local build uses whichever version of PlayCanvas is listed in the package.json file. If you'd like to use the locally built version of PlayCanvas in the engines build directory you can replace the `npm run build:watch` script above with `npm run local` or `npm run local:dbg` for the debug version. +## Creating an example -By default, example code is executed as an anonymous function in the browser (in order to support live code editing). However this limits the usefulness of debugging tools as the callstack for the example code is obscured. To run examples with a full callstack, allowing line by line debugging of an example, you can use the debug path for each example. Where `/#/misc/hello-world` becomes `/#/debug/misc/hello-world`. A full list of debug paths can be found at [http://localhost:5000/debug-directory](). +The available examples are written as classes in JavaScript under the paths `./src/examples//.example.mjs`. +To create a new example you can copy any of the existing examples as a template. -## Creating an example +Each example consists of two modules to define its behavior: -The available examples are written as classes in TypeScript under the paths `./src/examples/\/\.tsx. -To create a new example you can copy any of the existing examples as a template and update its path. +### `.example.mjs` -Each example extends the `Example` parent class and can implement three methods to define its functionality: +```js +import * as pc from 'playcanvas'; -### `example` function -```tsx -import * as pc from 'playcanvas/build/playcanvas.js'; -example(canvas: HTMLCanvasElement) { - const app = new pc.Application(canvas, {}); -} -``` -This is the only function that's required to run an example. The code defined in this function is executed each time the example play button is pressed. It takes the example's canvas element as its first argument and usually begins by creating a new PlayCanvas application using that canvas. - -### `load` function -You can define a set of PlayCanvas assets to load into your application using this function. The function should return a set of Loader React components: -```tsx -import React from 'react'; -import { AssetLoader } from '../../app/helpers/loader'; -load() { - return <> - - - <>; -} +const canvas = /** @type {HTMLCanvasElement} */ (document.getElementById('application-canvas')); +window.focus(); + +const app = new pc.Application(canvas, {}); + +export { app }; ``` -As assets are loaded using React, be sure to import React into any example that is loading assets. -Assets and scripts present in the `./assets` and `../scripts` directories will be available to examples under the `static/` path. -Each asset you load will be made available to the `example` function you write as the second parameter and will already be in the loaded state. -```tsx -example(canvas: HTMLCanvasElement, assets: { statue: pc.Asset, firstPersonCamScript: pc.Asset }) { - const app = new pc.Application(canvas, {}); - // this will log true - console.log(assets.statue.loaded); -} +This is the only file that's required to run an example. The code defined in this function is executed each time the example play button is pressed. It takes the example's canvas element from the DOM and usually begins by creating a new PlayCanvas `Application` or `AppBase` using that canvas. + +Examples can also contain comments which allow you to define the default configuration for your examples as well as overrides to particular settings such as `deviceType`. Check the possible values to set in `ExampleConfig` in `scripts/utils.mjs` file for the full list. + +```js +// @config DESCRIPTION This is a description +// @config HIDDEN +// @config ENGINE performance +// @config NO_DEVICE_SELECTOR +// @config NO_MINISTATS +// @config WEBGPU_DISABLED +// @config WEBGL_DISABLED +import * as pc from 'playcanvas'; +... ``` -Be sure to correctly define the type of the assets parameter to list each asset you're loading into the example. +You can load external scripts into an example using the `loadES5` function as follows: -You can also load external scripts into an example using the `ScriptLoader` React component as follows: -```tsx -import React from 'react'; -import { ScriptLoader } from '../../app/helpers/loader'; -load() { - return <> - - <>; -} +```js +import { loadES5 } from 'examples/utils'; + +const CORE = await loadES5('https://cdn.jsdelivr.net/npm/@loaders.gl/core@2.3.6/dist/dist.min.js'); +const DRACO = await loadES5('https://cdn.jsdelivr.net/npm/@loaders.gl/draco@2.3.6/dist/dist.min.js'); ``` -Each script will be made available as a parameter of the example function as an esModule using the name it was given and therefore any scripts should be defined in the examples function signature as follows: -```tsx -example(canvas: HTMLCanvasElement, TWEEN: any) { - const app = new pc.Application(canvas, {}); - console.log(TWEEN); -} + +However, depending on external URL's is maybe not what you want as it breaks your examples once your internet connection is gone - you can simply import modules directly as follows: + +```js +import confetti from "https://esm.sh/canvas-confetti@1.6.0" ``` -### `controls` function -This function allows you to define a set of PCUI based interface which can be used to display stats from your example or provide users with a way of controlling the example. -```tsx -import Button from '@playcanvas/pcui/Button/component'; -controls(data: any) { - return <> -