Skip to content

Commit

Permalink
Examples Overhaul (#6060)
Browse files Browse the repository at this point in the history
* separated out template example html to file

* removed temporary comment

* Added comment to explain template replacements

* setup barebones examples module

* removed examples-new testing; app.html (unused)

* moved files around for better organization

* checked in thumbnails to have defaults

* removed unused enableHotReload file

* Removed unused importmap file

* renamed directory and generate standalone files to more descriptive names and commented scripts

* fixed watching standalone files

* removed example data generation and embedded into helper

* removed log in example-data helper

* object cleanup in example data

* removed options.js; moved assetPath inside app folder

* replaced all thumbnails from png to webp

* fixed monaco dark issue

* change github link to use main branch

* renamed pathes to paths

* fixed path rename in example template

* removed unused example data object

* removed unused import in standalone generation

* put sharing html files into single subfolder instead of combining folder structure with other dist elements

* removed unused polyfill functions

* fixed getDeviceType

* split up floating functions into utils, extracted polyfill function, simplified engine setting, handled event cleanup in menu

* removed unused polyfill files

* updated event types to use CustomEvent

* made events consistent and made handlers private methods

* moved components into subfolder

* renamed components to use uppercase (convention)

* minor refactor for object

* fixed ready scope issue

* changed separate methods for events into fire method handler

* updated stats to use single event for setting state; added back delay for code editor resize

* cleaned up iframe code

* moved example and controls to body of html (prep for module import); added clean script

* fixed issue with controls showing up with no content

* cleaned up case conversion

* extracted metadata from examples into separate file

* extracted all examples path searching into a single file

* included loadES5 in utils module when loaded

* added first version of metadata building for examples

* calculated default example files inside sidebar class

* updated formatting and naming for scripts

* refactor for async standalone html

* fixed import bug on windows

* modified metadata generation to derive info from directory over import resolution

* removed index files

* examples loaded in from module

* fixed tween loading issue

* put es5 lib loading into example (temporary) and removed tween library

* removed import map (temporary); entire module script loaded

* remove unused imports injection

* removed umused es5lbis injection

* added blob cleanup on unload

* extracted pcx from args since its in global scope

* hoisted class props to top of file

* reverted include pcx in examples and put fire into utils

* removed global paths to use static locations

* moved canvas to inside each example

* removed unused canvas element in example template

* removed generating empty module

* added class config to metadata

* prebuild config for each example and pass in as module

* cleaned up examples config

* changed exporting of example classes format to all be the same

* removed each example class and replaced with exports for controls and example

* remove examples args; put data in window scope and getDeviceType in utils

* extracted ministats info into separate module

* Cleaned up app starting

* fixed types for example ministats module

* in process of separating controls and example functions into separate files

* finished split of examples and controls into separate files

* Updated controls build to use module style

* Changed default controls for each example

* refactor to use local setType in gizmo example

* added import pc to top of controls file (fixes linting)

* Removed example function and eslint fix attempt for all examples

* eslint fix attempt for all examples

* fixed all examples to use single quotes

* Updated examples only module names

* added canvas check to each example

* fixed error restart for example

* Disabled regenerating controls every change to code editor

* updated monaco editor

* formatted and removed unused vars in components

* added placeholder object for files for module import

* remove files object from global scope

* added files module comment

* added syntax highlighting to shaders

* fixed focusing in gizmo example

* reverted monaco update

* fixed pathing issue

* renamed assetPaths to paths

* renaming components to uppercase

* fixed pathing issue with double slash

* updated getDeviceType to deviceType

* moved observer to module; created loader class for example; fixed multi app hot reload error

* inserted observer into examples

* moved loader to separate file and cleaned up exposing attributes and functions

* fixed abstracting requestedFiles event fire

* removed temporary thumbnail files

* Update examples/iframe/files.mjs

Co-authored-by: Will Eastcott <will@playcanvas.com>

* removed unnecessary ts-ignore

* added config files for each example

* fixed config path type and added in build standalone

* cleaned up glsl code in example config

* removed old examples.config.mjs

* cleaned up metadata path

* removed empty controls files and used template instead

* fixed thumbnail generation and use kebab case in all cases

* updated typing to use custom event interface

* updated readme for examples to include new documentation

* fixed config setting to index default prop in standalone-html

* replaced umd observer with mjs version

* removed mapping for internal modules; removed documentation in readme

* fixed spacing in loader

* updated playcanvas to use es6 build over es5

* updated extras to use module build

* added pcx import to misc examples

* fixed webgpu hot restart error; fixed reclick on example error

* linting fix in sidebar

* changed wgsl example format to new system

* converted wgsl to use new system

* added wgsl syntax highlighting and updated glsl highlight

* refactored themes and languages into monaco folder

* added thumbnails for wgsl shader

* added hidden functionality back when generating metadata

---------

Co-authored-by: Will Eastcott <will@playcanvas.com>
  • Loading branch information
kpal81xd and willeastcott authored Feb 21, 2024
1 parent 80144e0 commit ea502fc
Show file tree
Hide file tree
Showing 702 changed files with 30,113 additions and 29,601 deletions.
5 changes: 5 additions & 0 deletions examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Prettier config
.prettierrc

# Cache directory
cache
92 changes: 58 additions & 34 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,64 +33,59 @@ Or directly from the source:
ENGINE_PATH=../src/index.js npm run develop
```

To create the side bar thumbnails run the following script:
```
npm run build:thumbnails
```

Please note that the examples app requires a built version of the engine to be present in the engine repo within the `../build` folder. If you haven't already done so, run `npm install` followed by `npm run build` in the engine repo.

As Monaco is supporting IntelliSense via type definitions files, you will also need to build the type definitions in the engine repo with `npm run build:types`.

## Creating an example

The available examples are written as classes in JavaScript under the paths `./src/examples/\<categoryName\>/\<exampleName>.mjs.
To create a new example you can copy any of the existing examples as a template and update its path.
The available examples are written as classes in JavaScript under the paths `./src/examples/<category>/<exampleName>`.
To create a new example you can copy any of the existing examples as a template.

Each example can implement two methods to define its functionality:
Each example consists of three modules to define its behavior:

### `example` function
### `example.mjs`

```js
import * as pc from 'playcanvas';
/**
* @param {import('../../../app/example.mjs').ExampleOptions} options - The example options.
* @returns {Promise<pc.AppBase>} The example application.
*/
async function example({ canvas, deviceType, assetPath, scriptsPath }) {
const app = new pc.Application(canvas, {});

const canvas = document.getElementById('application-canvas');
if (!(canvas instanceof HTMLCanvasElement)) {
throw new Error('No canvas found');
}

const app = new pc.Application(canvas, {});

export { app };
```

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 from the options and usually begins by creating a new PlayCanvas `Application` or `AppBase` using that canvas.
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.

You can load external scripts into an example using the `loadES5` function as follows:

```js
import { loadES5 } from '../../loadES5.mjs';
async function example({ canvas, deviceType, files, assetPath, glslangPath, twgslPath }) {
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');
console.log({ CORE, DRACO })
}
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');
```

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 install a NPM package and use it instead aswell:
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 * as TWEEN from '@tweenjs/tween.js';
import confetti from "https://esm.sh/canvas-confetti@1.6.0"
```

### `controls` function
### `controls.mjs`

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.
This file 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.

```js
/**
* @param {import('../../app/example.mjs').ControlOptions} options - The options.
* @param {import('../../../app/Example.mjs').ControlOptions} options - The options.
* @returns {JSX.Element} The returned JSX Element.
*/
function controls({ observer, ReactPCUI, React, jsx, fragment }) {
export function controls({ observer, ReactPCUI, React, jsx, fragment }) {
const { Button } = ReactPCUI;
return fragment(
jsx(Button, {
Expand All @@ -105,13 +100,33 @@ function controls({ observer, ReactPCUI, React, jsx, fragment }) {

The controls function takes a [pcui observer](https://playcanvas.github.io/pcui/data-binding/using-observers/) as its parameter and returns a set of PCUI components. Check this [link](https://playcanvas.github.io/pcui/examples/todo/) for an example of how to create and use PCUI.

The data observer used in the `controls` function will be made available as a property in the example function:
The data observer used in the `controls` function will be made available as an import `@examples/observer` to use in the example file:

```js
example({ canvas, assets, data }) {
const app = new pc.Application(canvas, {});
console.log(data.get('flash'));
}
import { data } from '@examples/observer';

console.log(data.get('flash'));
```

### `config.mjs`

This file allows you to define the default configuration for your examples as well as overrides to particular settings such as `deviceType` and additional files (e.g. vertex and fragment shaders). Check the config options `ExampleConfig` in `types.mjs` file.

```js
/**
* @type {import('../../../../types.mjs').ExampleConfig}
*/
export default {
WEBGPU_ENABLED: true,
FILES: {
"shader.vert": /* glsl */`
// vertex shader
`
"shader.frag": /* glsl */`
// fragment shader
`
}
};
```

### Testing your example
Expand All @@ -122,6 +137,15 @@ You can view the full collection of example iframes by visiting [http://localhos
### Debug and performance engine development
By default, the examples app uses the local version of the playcanvas engine located at `../build/playcanvas.js`. If you'd like to test the examples browser with the debug or performance versions of the engine instead, you can run `npm run watch:debug` or `npm run watch:profiler` commands.

## Example Modules

The example script allows you to import examples only modules that interact with the environment such as the device selector and controls. These are listed below:

- `@examples/config` - The example config defined in `./src/examples/<category>/<exampleName>/config.mjs`.
- `@examples/utils` - Contains utilities functions such as `loadES5`. The full list of functions can be found in `./iframe/utils.mjs`.
- `@examples/observer` - The observer object `data`.
- `@examples/files` - The reatime file contents of all files used in the example (includes `FILES` property from `config.mjs`).

## Deployment

1) **Build the latest engine** by running the following in the `/engine` directory:
Expand All @@ -138,7 +162,7 @@ npm run build
npm run serve
```

3) **Generate thumbnails** This step will create the thumbnails directory for the browser and may take a while depending on the number of new examples or if this is first time it has been run locally.
3) **Generate thumbnails (Case-by-case basis)** This step will create the thumbnails directory for the browser. This only needs to be run if the examples thumbnails are updated or new examples are added.
```
npm run build:thumbnails
```
Expand Down
Loading

0 comments on commit ea502fc

Please sign in to comment.