Commits
# New 1st Party Plugin System
This allows deep configuration of the excalibur subsystems by providing lifecycle hooks/interception points at every critical juncture to boot the engine. Right now we are mainly focused on renderer/asset type plugins so this initial stab leans in that direction.
1. **Engine construction** — `onEnginePreConfig` → (flags frozen) → `onEnginePostConfig`
2. **Engine start** — `onLoad` → (resources loaded) → `onLoadComplete`
3. **Engine initialize** — `onEnginePreInitialize` → `onEnginePostInitialize`
4. **Graphics context construction** — `onGraphicsPreConfig` → `onGraphicsPostConfig`
5. **Graphics context init** — `onGraphicsPreInitialize` → `onGraphicsPostInitialize`
6. **Scene initialize** — `onScenePreInitialize` → `onScenePostInitialize`
7. **Scene activate** — `onScenePreActivate` → `onScenePostActivate`
8. **Scene deactivate** — `onScenePreDeactivate` → `onScenePostDeactivate`
9. **Graphics context lost/restored** — `onGraphicsContextLost` → `onGraphicsContextRestored`
10. **Engine dispose** — `dispose`
This is a long time coming, TS6 upgrade to all the things AND a new typedoc plugin fork. I decided to abandon the astro port, the more effort I put into it the more I realized it'd be a TON of work to match the features we already have and I didn't want to step backwards in functionality
* TS6 IS A THING!!!
* API Doc Plugin Fork has been paired down to just our needs and updated to the latest TypeDoc
* https://github.com/excaliburjs/docusaurus-plugin-typedoc-api
* Build a small custom remark plugin that translates to the API docs paths based on TypeDoc cli generation in `npm run api:generate`
* Docusaurus link checking will now break the build to keep our docs from accumulating dead links
* Invalid TypeDoc will now break the build as well
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* fix: double screen resize
* fix lint
* fix tests
* update mock
* fix lint
x/y scale were transposed which caused things to break subtly when scale was non-uniform
The wikipedia https://en.wikipedia.org/wiki/Transformation_matrix#affine-transformations
* Add some defense to Resource loading failures with a better error message
* Add some defense to Gif resources
There isn't an issue for this one, but discussed in Discord.
## Changes
This PR overhauls the playground to:
* Have a stronger webapp look and feel, similar to codepen, etc
* Display logs within the playground
* Introduce a framework to minimise subtle state bugs
## Tech choice
As discussed in Discord, Erik mentioned using what makes me "happy and productive" - which is React. Even for non-React devs, I hope it is relatively easy to trace the data flow - there is no over the top state management like redux, etc.
## UI
The look and feel is heavily inspired by @jyoung4242 IDE work.
The zinc and purple color scales are from Tailwind v4
## General layout
### Editor
<img width="3326" height="2558" alt="CleanShot 2026-06-19 at 21 38 28@2x" src="https://github.com/user-attachments/assets/16e581da-fd9f-41c8-bfbb-6c73f4236ccd" />
### Assets
I'm not 100% on this; it's better than current (which is non-existent) but I will do another pass on this later.
<img width="3326" height="2558" alt="CleanShot 2026-06-19 at 21 38 59@2x" src="https://github.com/user-attachments/assets/786a906a-1b31-4953-ac3a-7650b26924d8" />
### Console
Supports 3x colors via `console.log`, `console.info`, and `console.warn`.
<img width="3326" height="2558" alt="CleanShot 2026-06-19 at 21 40 01@2x" src="https://github.com/user-attachments/assets/be6ec2f5-cfc3-4f76-976f-a253904887c3" />
## Embedded
The same embedded search params are applied. It will look like the following when embedded in the docs:
<img width="3160" height="2538" alt="CleanShot 2026-06-17 at 23 08 27@2x" src="https://github.com/user-attachments/assets/40bd49da-cfcd-49bb-af57-23556e34ef1e" />
---
## Deployments
The following `.env` will need to part of the deployment of the playground:
```properties
VITE_PLAYGROUND_PATH='./playground'
VITE_HIJACK_LOGS=true
```
**Note:** I couldn't find the actual deployment steps in `.github` for the playground. And I don't think its built during a PR?
---
## Basic accessibility
The monaco editor traps focus (possibly a future fix?), but all other elements have focus state and the template modal has proper focus trap (thanks to baseui)
### Toolbar button focus
<img width="926" height="136" alt="CleanShot 2026-06-19 at 21 48 28@2x" src="https://github.com/user-attachments/assets/2a84d539-a8d2-44fb-9602-904a7cfeaf75" />
### Toolbar switch focus
<img width="926" height="136" alt="CleanShot 2026-06-19 at 21 48 38@2x" src="https://github.com/user-attachments/assets/9be08073-4807-462a-9c98-e85c27822941" />
### Modal button focus (3rd button)
<img width="1036" height="1058" alt="CleanShot 2026-06-19 at 21 48 53@2x" src="https://github.com/user-attachments/assets/5441ad26-7302-4b4c-875a-3c586ec6957d" />
---
## Misc
* I've kept light mode, but it's not great - if anyone has a good light theme we could slot in that matches the overall feel let me know
* The dark theme is based on mookie's ide editor
* There are more `useEffect`'s then I would normally want, however, a lot of this is imperative in nature
---
## Disclaimer
No AI clankers used for this PR _except_ for converting the dark mode json to the light mode json.
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
HSL CSS color strings were incorrect :facepalm: fixed up to spec
small bug: color.screen never worked :facepalm:
added some defense to components
This PR fixes Uniform Array vs Uniform Block (packed struct) confusion
- #3360 accidentally broke this
- Went ahead to dug into any other missing gl types we should add
- Did some lite refactoring to make things a little easier to maintain and more performant
# Fix NineSliceStretch.Tile clipping behavior
## Description
Fixes issue #3777 where `NineSliceStretch.Tile` mode was squashing partial tiles instead of clipping them to fit the destination space properly.
## Problem
When using `NineSliceStretch.Tile` mode, the last partial tile would be distorted to fit the remaining space rather than being clipped. This behavior did not match the documented behavior: "takes input slice and paints it across the entirety of the output dimensions in a repeating texture fashion that will not distort the source image at all, but may not fit properly in the destination space, leaving a potentially partial drawing of the texture remaining."
**Expected behavior:** Tiles should repeat without distortion, with partial tiles at edges being clipped.
**Actual behavior:** Partial tiles were being stretched/squashed to fit the space.
## Solution
Modified the `_drawTile` method in `src/engine/graphics/nine-slice.ts` to properly apply clipping when drawing tiled sections. When `NineSliceStretch.Tile` is used, the source dimensions (`srcW` and `srcH`) now correctly reflect the calculated `tempSize` instead of always using the full `targetCanvas` dimensions.
The fix ensures that:
- When horizontally tiling, the source width uses `tempSize` for horizontal calculations
- When vertically tiling, the source height uses `tempSize` for vertical calculations
- This allows the canvas clipping to properly handle partial tiles at the edges
## Testing
Verified with checkerboard pattern tiling to confirm tiles are no longer distorted when they don't fit evenly into the destination space.
## Related Issues
Closes #3777
closes https://github.com/excaliburjs/Excalibur/issues/3468
Forces cleared actions to stop properly, including sequences, and handle repeating
## Changes:
- Upgrade to latest vitest
- Post image diffs on failure!
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Small tweak to the pause component, makes it no longer a required component, but an excluded one. This makes it harder to forget to configure pause correctly, and it's faster because there is no last minute pause decision during system eval.
update docs + defaults actor canPause=true screenElement canPause=false
fixes: #3748
## Changes:
- Switches out renderer to correct one, oversight from renderer refactoring
- Removes mem allocations in the hot particle draw loop
* fix: Enhance pointer event handling by adding coordPlane check for graphics tracking, also added world to screen space conversion on pointer event check
* convert to c-style loop
* speed madness
* fix c-style-loop
* back out bounding box types
* revert
* remove commented code
---------
Co-authored-by: Erik Onarheim <erik.onarheim@gmail.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
# New 1st Party Plugin System
This allows deep configuration of the excalibur subsystems by providing lifecycle hooks/interception points at every critical juncture to boot the engine. Right now we are mainly focused on renderer/asset type plugins so this initial stab leans in that direction.
1. **Engine construction** — `onEnginePreConfig` → (flags frozen) → `onEnginePostConfig`
2. **Engine start** — `onLoad` → (resources loaded) → `onLoadComplete`
3. **Engine initialize** — `onEnginePreInitialize` → `onEnginePostInitialize`
4. **Graphics context construction** — `onGraphicsPreConfig` → `onGraphicsPostConfig`
5. **Graphics context init** — `onGraphicsPreInitialize` → `onGraphicsPostInitialize`
6. **Scene initialize** — `onScenePreInitialize` → `onScenePostInitialize`
7. **Scene activate** — `onScenePreActivate` → `onScenePostActivate`
8. **Scene deactivate** — `onScenePreDeactivate` → `onScenePostDeactivate`
9. **Graphics context lost/restored** — `onGraphicsContextLost` → `onGraphicsContextRestored`
10. **Engine dispose** — `dispose`
This is a long time coming, TS6 upgrade to all the things AND a new typedoc plugin fork. I decided to abandon the astro port, the more effort I put into it the more I realized it'd be a TON of work to match the features we already have and I didn't want to step backwards in functionality
* TS6 IS A THING!!!
* API Doc Plugin Fork has been paired down to just our needs and updated to the latest TypeDoc
* https://github.com/excaliburjs/docusaurus-plugin-typedoc-api
* Build a small custom remark plugin that translates to the API docs paths based on TypeDoc cli generation in `npm run api:generate`
* Docusaurus link checking will now break the build to keep our docs from accumulating dead links
* Invalid TypeDoc will now break the build as well
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
There isn't an issue for this one, but discussed in Discord.
## Changes
This PR overhauls the playground to:
* Have a stronger webapp look and feel, similar to codepen, etc
* Display logs within the playground
* Introduce a framework to minimise subtle state bugs
## Tech choice
As discussed in Discord, Erik mentioned using what makes me "happy and productive" - which is React. Even for non-React devs, I hope it is relatively easy to trace the data flow - there is no over the top state management like redux, etc.
## UI
The look and feel is heavily inspired by @jyoung4242 IDE work.
The zinc and purple color scales are from Tailwind v4
## General layout
### Editor
<img width="3326" height="2558" alt="CleanShot 2026-06-19 at 21 38 28@2x" src="https://github.com/user-attachments/assets/16e581da-fd9f-41c8-bfbb-6c73f4236ccd" />
### Assets
I'm not 100% on this; it's better than current (which is non-existent) but I will do another pass on this later.
<img width="3326" height="2558" alt="CleanShot 2026-06-19 at 21 38 59@2x" src="https://github.com/user-attachments/assets/786a906a-1b31-4953-ac3a-7650b26924d8" />
### Console
Supports 3x colors via `console.log`, `console.info`, and `console.warn`.
<img width="3326" height="2558" alt="CleanShot 2026-06-19 at 21 40 01@2x" src="https://github.com/user-attachments/assets/be6ec2f5-cfc3-4f76-976f-a253904887c3" />
## Embedded
The same embedded search params are applied. It will look like the following when embedded in the docs:
<img width="3160" height="2538" alt="CleanShot 2026-06-17 at 23 08 27@2x" src="https://github.com/user-attachments/assets/40bd49da-cfcd-49bb-af57-23556e34ef1e" />
---
## Deployments
The following `.env` will need to part of the deployment of the playground:
```properties
VITE_PLAYGROUND_PATH='./playground'
VITE_HIJACK_LOGS=true
```
**Note:** I couldn't find the actual deployment steps in `.github` for the playground. And I don't think its built during a PR?
---
## Basic accessibility
The monaco editor traps focus (possibly a future fix?), but all other elements have focus state and the template modal has proper focus trap (thanks to baseui)
### Toolbar button focus
<img width="926" height="136" alt="CleanShot 2026-06-19 at 21 48 28@2x" src="https://github.com/user-attachments/assets/2a84d539-a8d2-44fb-9602-904a7cfeaf75" />
### Toolbar switch focus
<img width="926" height="136" alt="CleanShot 2026-06-19 at 21 48 38@2x" src="https://github.com/user-attachments/assets/9be08073-4807-462a-9c98-e85c27822941" />
### Modal button focus (3rd button)
<img width="1036" height="1058" alt="CleanShot 2026-06-19 at 21 48 53@2x" src="https://github.com/user-attachments/assets/5441ad26-7302-4b4c-875a-3c586ec6957d" />
---
## Misc
* I've kept light mode, but it's not great - if anyone has a good light theme we could slot in that matches the overall feel let me know
* The dark theme is based on mookie's ide editor
* There are more `useEffect`'s then I would normally want, however, a lot of this is imperative in nature
---
## Disclaimer
No AI clankers used for this PR _except_ for converting the dark mode json to the light mode json.
# Fix NineSliceStretch.Tile clipping behavior
## Description
Fixes issue #3777 where `NineSliceStretch.Tile` mode was squashing partial tiles instead of clipping them to fit the destination space properly.
## Problem
When using `NineSliceStretch.Tile` mode, the last partial tile would be distorted to fit the remaining space rather than being clipped. This behavior did not match the documented behavior: "takes input slice and paints it across the entirety of the output dimensions in a repeating texture fashion that will not distort the source image at all, but may not fit properly in the destination space, leaving a potentially partial drawing of the texture remaining."
**Expected behavior:** Tiles should repeat without distortion, with partial tiles at edges being clipped.
**Actual behavior:** Partial tiles were being stretched/squashed to fit the space.
## Solution
Modified the `_drawTile` method in `src/engine/graphics/nine-slice.ts` to properly apply clipping when drawing tiled sections. When `NineSliceStretch.Tile` is used, the source dimensions (`srcW` and `srcH`) now correctly reflect the calculated `tempSize` instead of always using the full `targetCanvas` dimensions.
The fix ensures that:
- When horizontally tiling, the source width uses `tempSize` for horizontal calculations
- When vertically tiling, the source height uses `tempSize` for vertical calculations
- This allows the canvas clipping to properly handle partial tiles at the edges
## Testing
Verified with checkerboard pattern tiling to confirm tiles are no longer distorted when they don't fit evenly into the destination space.
## Related Issues
Closes #3777
Small tweak to the pause component, makes it no longer a required component, but an excluded one. This makes it harder to forget to configure pause correctly, and it's faster because there is no last minute pause decision during system eval.
update docs + defaults actor canPause=true screenElement canPause=false
* fix: Enhance pointer event handling by adding coordPlane check for graphics tracking, also added world to screen space conversion on pointer event check
* convert to c-style loop
* speed madness
* fix c-style-loop
* back out bounding box types
* revert
* remove commented code
---------
Co-authored-by: Erik Onarheim <erik.onarheim@gmail.com>