Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
build/
node_modules/
src/build/
static/
5 changes: 5 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"printWidth": 120,
"tabWidth": 4,
"trailingComma": "es5"
}
60 changes: 60 additions & 0 deletions azure-pipelines.compiled-demos.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
trigger:
branches:
include:
- master
paths:
include:
- azure-pipelines.compiled-demos.yml
- .prettierignore
- .prettierrc.json
- docs/compiled-demos.md
- eslint.config.mjs
- package.json
- package-lock.json
- scripts/demos/**
- src/compiledDemos/**
- static/Demos/**
- static/Scenes/**
- tsconfig.demos.json
- vite.demos.config.mjs

pr:
branches:
include:
- master
paths:
include:
- azure-pipelines.compiled-demos.yml
- .prettierignore
- .prettierrc.json
- docs/compiled-demos.md
- eslint.config.mjs
- package.json
- package-lock.json
- scripts/demos/**
- src/compiledDemos/**
- static/Demos/**
- static/Scenes/**
- tsconfig.demos.json
- vite.demos.config.mjs

pool:
vmImage: ubuntu-latest

steps:
- task: NodeTool@0
displayName: Use Node.js 20
inputs:
versionSpec: 20.x

- script: npm ci
displayName: Install dependencies

- script: npx playwright install --with-deps chromium
displayName: Install Playwright Chromium

- script: npm run build
displayName: Build site and compiled demos

- script: npm run demos:ci
displayName: Lint, typecheck, and render-check compiled demos
61 changes: 61 additions & 0 deletions docs/compiled-demo-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Compiled Demo Migration Inventory

This tracks the move from legacy static demos under `static/Demos/` to compiled demos under `src/compiledDemos/`. Each migration should keep the public URL stable at `/Demos/<Demo>/`, expose source with `/Demos/<Demo>/source/`, and pass the compiled demo CI checks.

## Status Key

- `done`: Ported to `src/compiledDemos`, registered in `manifest.json`, and covered by render checks.
- `covered`: Scenario is already exercised by another compiled demo and should not consume a current migration wave slot.
- `unusable`: The legacy/online demo no longer renders correctly and should not be ported until the source demo is repaired or replaced.
- `wave-1`: Simple single-canvas demo selected for the current migration wave.
- `candidate`: Not migrated yet, likely suitable for a later wave after inspection.
- `special`: Needs extra handling such as workers, vendored bundles, service workers, generated app bundles, WebGPU, physics, GUI, or complex external assets.

## Current Status

| Demo | Status | Notes |
| --- | --- | --- |
| AssetsManager | done | AssetsManager mesh, text, and binary tasks using local legacy demo assets. |
| Boom | done | First compiled demo; includes click interaction render check. |
| Lines | done | Thin animated line rendering; custom low colored-sample threshold. |
| Heightmap | done | Texture and heightmap asset loading. |
| Offscreen | done | Custom worker bootstrap; render check validates both canvases. |
| Fog | done | Animated simple geometry and exponential fog. |
| Bump | done | Simple texture material using an existing shared normal map asset. |
| FlightHelmet | covered | Flight Helmet asset loading is already exercised by the compiled Offscreen demo; standalone legacy page is left out of this wave. |
| GLTF | done | glTF binary asset loading from the deployed legacy `/assets/` path. |
| GLTF1CesiumMan | unusable | Legacy and online demo do not render; excluded from the compiled registry until the source demo is repaired or replaced. |
| GLTFMeshPrimitiveAttributeTest | done | Multiple remote glTF assets plus generated normal attribute coverage. |
| GLTFNormals | done | Multiple remote glTF assets covering normals/tangents variants. |
| Lights | done | Multiple dynamic lights and shared skybox assets. |
| Particles | done | CPU particle systems plus mirror render target texture. |
| Fresnel | done | Fresnel material parameters, shared skybox assets, and lens flares. |
| Shadows | done | Directional lights, shadow generators, and legacy grass texture. |
| PointLightShadowMap | done | Point light shadow generator with torus knot scene. |
| Refraction | done | Reflection probe refraction with built-in bump/fresnel/IOR controls. |
| Ribbons | done | Dynamic ribbon geometry with volumetric light scattering post-process coverage. |
| VolumetricLightScattering | done | Local skull scene asset with volumetric light scattering billboard and texture coverage. |
| Yeti | done | Remote animated glTF asset with loader animation options, default environment, and textured snow particles. |

## Next Waves

| Wave | Demos | Main Risk To Prove |
| --- | --- | --- |
| Asset and loader follow-up | Mansion, Sponza, TheCar | Larger model load times, local scene payloads, animation/UI dependencies, service workers, shadows, and optimizer behavior. TheCar currently needs investigation because its scene readiness can stall render validation. |
| Render/effects follow-up | Polygon | Polygon needs an explicit `earcut` dependency decision before porting. |
| Materials and render pipeline demos | CellShading, FireMaterial, Fur, GlowLayer, PBR, PBRGlossy, PBRGlossyBloom, PBRRough, WaterMaterial, DOF, DefaultRenderingPipeline, MotionBlur, PPBloom, PPConvolution, PPRef, SSAO, SSAO2, StandardRenderingPipeline | Extra Babylon packages, shader/material side effects, post-process scene components. |
| Interaction and tooling demos | ActionBuilder, Actions, Charting, CustomShader, Decals, DragNDrop, Facets, Highlights, Lens, LookAt, Octree, Procedural, Simplification, VertexData, Views | Picking, pointer events, custom shaders, scene tools, and user interaction checks. |
| Animation, skeleton, and morph demos | Bones, Dancers, Dancing CSG, HillValley, HillValleyVR, InstancedBones, Instances, Instances2, LOD, MorphTargets, V8 | Skeletons, animation loops, instancing, LOD behavior, and render-check stability. |
| Physics and advanced systems | AdvancedShadows, CSG, Cloth, CustomRenderTarget, DisplacementMap, ExtrudePolygon, Multimaterial, Particles2, Physics, Planet, Ruins, SelfShadowing, SoftShadows, SPS, SPSCollisions, Starfield, Tunnel, Viper | Physics engines, generated geometry, custom render targets, particles, and advanced scene components. |
| Special app-style demos | Amp360Video, AnimatedGif, AudioAnalyser, AudioAnalyzer, ChibiRex, Distraction, Espilit, FatObjects, Flat2009, GlowingEspilit, Heart, Ink, MansionVR, ProductPage, RefProbe, Retail, SpaceDeK, Spaceship, SponzaDynamicShadows, Train, UTD, VideoProcessing, WCafe, WebGPU | Vendored bundles, multi-page apps, workers/service workers, audio/video, VR, WebGPU, or nonstandard build/runtime flows. |

## Per-Demo Checklist

1. Inspect the legacy `index.html`, `demo.js`, scene file, and local assets.
2. Create `src/compiledDemos/<Demo>/index.html`, `main.ts`, and `scene.ts` unless the demo needs a custom bootstrap.
3. Prefer `shared/demoRunner.ts` for single-canvas demos.
4. Replace `BABYLON.*` globals with named ESM imports and add side-effect imports for prototype-augmented APIs.
5. Keep asset URLs rooted at stable public paths such as `/Scenes/...` when possible.
6. Register the demo in `src/compiledDemos/manifest.json` with source files and render-check thresholds.
7. Run `npm run demos:format:write`, `npm run build`, and `npm run demos:ci`.
8. Commit one demo or small coherent batch at a time.
171 changes: 171 additions & 0 deletions docs/compiled-demos.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# Compiled Demos Architecture

The legacy demos under `static/Demos/` are copied directly into `build/` and load Babylon from the UMD CDN. Compiled demos live under `src/compiledDemos/`, import `@babylonjs/core` and sibling packages as ES modules, and are bundled with Vite.

The migration tracker lives in `docs/compiled-demo-migration.md`.

## Goals

- Keep existing demo URLs stable, for example `/Demos/Boom/`.
- Migrate one demo at a time without disturbing demos that still live in `static/Demos/`.
- Make new demos easy to add with a small source folder and one manifest entry.
- Check that compiled demos typecheck, bundle, load in a browser, create a scene, and render a nonblank canvas.

## Build Flow

1. `npm run site:build` runs the existing Eleventy build and copies `static/` to `build/`.
2. `npm run demos:build` runs Vite with `vite.demos.config.mjs` and generates source pages.
3. `npm run build` runs both steps in order, producing the full deployable site output.
4. Vite writes compiled demo pages into `build/Demos/<slug>/`, overlaying only the migrated demos listed in `src/compiledDemos/manifest.json`.
5. Unmigrated demos continue to come from `static/Demos/`.

This keeps the site and demo build steps available separately while making the default `build` script produce the final combined output.

For local preview, run `npm run demos:serve`. This builds the site, overlays the compiled demos, and serves the final `build/` output with Vite preview.

## Source Layout

```text
src/compiledDemos/
manifest.json
shared/
demoRunner.ts
AssetsManager/
index.html
main.ts
scene.ts
Boom/
index.html
main.ts
scene.ts
Bump/
index.html
main.ts
scene.ts
Fog/
index.html
main.ts
scene.ts
Fresnel/
index.html
main.ts
scene.ts
GLTF/
index.html
main.ts
scene.ts
GLTFMeshPrimitiveAttributeTest/
index.html
main.ts
scene.ts
GLTFNormals/
index.html
main.ts
scene.ts
Lines/
index.html
main.ts
scene.ts
Lights/
index.html
main.ts
scene.ts
Ribbons/
index.html
main.ts
scene.ts
VolumetricLightScattering/
index.html
main.ts
scene.ts
Yeti/
index.html
main.ts
scene.ts
Heightmap/
index.html
main.ts
scene.ts
Offscreen/
index.html
main.ts
scene.ts
worker.ts
PointLightShadowMap/
index.html
main.ts
scene.ts
Particles/
index.html
main.ts
scene.ts
Refraction/
index.html
main.ts
scene.ts
Shadows/
index.html
main.ts
scene.ts
```

Each demo folder owns its HTML shell and TypeScript entry. Shared browser bootstrapping lives in `shared/demoRunner.ts`, which creates the engine, starts the render loop, wires common controls, and exposes `window.__babylonDemoReady` for CI.

Each demo page should include a small source link at the bottom of the viewport:

```html
<a id="sourceLink" href="./source/">Source</a>
```

`npm run demos:build` generates `/Demos/<slug>/source/` from the files listed in `manifest.json`, so the site can show the exact TypeScript source for each compiled demo.

## Adding A Demo

1. Create `src/compiledDemos/<Slug>/index.html`, `main.ts`, and `scene.ts`.
2. Export a scene factory from `scene.ts`:

```ts
export function createScene(engine: Engine, canvas: HTMLCanvasElement): Scene {
// create and return a Babylon scene
}
```

3. Call the shared runner from `main.ts`:

```ts
import { runDemo } from "../shared/demoRunner";
import { createScene } from "./scene";

runDemo({ createScene });
```

4. Add the demo to `src/compiledDemos/manifest.json`.
5. Add `sourceFiles` for the files that should appear on the source page.
6. Run `npm run demos:format:write` if needed, then `npm run build && npm run demos:ci`.

## Render Checks

`npm run demos:check` serves the `build/` directory locally, opens each compiled demo with Playwright Chromium, waits for `window.__babylonDemoReady`, screenshots the canvas, samples pixels with Sharp, and fails if the canvas is blank or browser errors were reported.

The initial check is intentionally a health check. It proves the demo compiles and renders. Individual demos can add `renderCheck.interaction` entries for important first-screen behavior; Boom uses this to click the canvas and verify the rendered output changes after the sign explodes. Screenshot baselines can be added later once the migration has enough coverage to justify the extra maintenance.

Demos with more than one canvas can set `renderCheck.minimumCanvasCount` and `renderCheck.canvasSelector`. The Offscreen demo uses this to verify both the main-thread canvas and worker OffscreenCanvas render nonblank frames.

## Linting And Formatting

Compiled demo source is linted with ESLint and formatted with Prettier. The checks are intentionally scoped to the new compiled demo pipeline, not the legacy `static/` demo tree.

- `npm run demos:lint` checks TypeScript demo source and demo build scripts.
- `npm run demos:format` verifies formatting for compiled demo source, config, and docs.
- `npm run demos:format:write` applies the configured formatting.

## CI

`azure-pipelines.compiled-demos.yml` is intentionally separate from the existing build CI. It runs `npm run build` first, which produces the site with compiled demos, and then runs `npm run demos:ci` to lint, format-check, typecheck, and render-check the compiled demos. If the main build pipeline can publish a build artifact later, this pipeline can be changed to consume that artifact instead of rebuilding the site.

## Migration Notes

- Custom scene-factory demos usually map cleanly from `BABYLON.*` globals to named ES module imports from `@babylonjs/core`.
- Demos that currently load `.babylon`, `.glb`, GUI, materials, loaders, or inspector packages should import the matching side-effect modules in their compiled entry.
- Keep asset URLs rooted at existing public paths such as `/Scenes/...` when assets are already served from `static/`.
- Once a compiled demo is stable, the old `static/Demos/<Slug>/` sources can be removed in a separate cleanup PR.
38 changes: 38 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";

export default [
{
ignores: ["build/**", "node_modules/**", "src/build/**", "static/**"],
},
js.configs.recommended,
...tseslint.configs.recommended,
{
files: ["scripts/demos/**/*.mjs", "vite.demos.config.mjs", "eslint.config.mjs"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
globals: { ...globals.node, ...globals.browser },
},
},
{
files: ["src/compiledDemos/**/*.ts"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
globals: globals.browser,
},
rules: {
"no-undef": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
},
],
},
},
];
Loading