Repository: RSamaium/CanvasEngine Branch: v2 Commit: 5e44e4a42782 Files: 320 Total size: 2.7 MB Directory structure: gitextract_dj33z3ap/ ├── .agents/ │ └── skills/ │ ├── canvasengine/ │ │ ├── SKILL.md │ │ └── agents/ │ │ └── openai.yaml │ └── pixijs/ │ ├── SKILL.md │ └── references/ │ └── index.md ├── .changeset/ │ └── config.json ├── .codex ├── .github/ │ └── workflows/ │ └── ci.yml ├── .gitignore ├── .npmignore ├── README.md ├── __mocks__/ │ └── pixi-viewport.ts ├── docs/ │ ├── .vitepress/ │ │ ├── config.ts │ │ └── theme/ │ │ ├── Layout.vue │ │ ├── components/ │ │ │ ├── CustomHome.vue │ │ │ ├── Playground.vue │ │ │ ├── config.ts │ │ │ └── example.ts │ │ ├── index.ts │ │ └── style.css │ ├── advanced/ │ │ ├── conditional-rendering.md │ │ ├── performance.md │ │ └── without-compiler.md │ ├── api/ │ │ ├── context.md │ │ ├── element.md │ │ └── testing.md │ ├── components/ │ │ ├── _display-object.md │ │ ├── button.md │ │ ├── canvas.md │ │ ├── container.md │ │ ├── dom-container.md │ │ ├── examples/ │ │ │ ├── focus-navigation-dom.js │ │ │ └── polygon-example.js │ │ ├── graphic.md │ │ ├── joystick.md │ │ ├── mesh.md │ │ ├── navigation.md │ │ ├── nine-slice-sprite.md │ │ ├── sprite.md │ │ ├── svg.md │ │ ├── text.md │ │ ├── tiling-sprite.md │ │ ├── video.md │ │ └── viewport.md │ ├── concepts/ │ │ ├── animation.md │ │ ├── child-component.md │ │ ├── context.md │ │ ├── dependencies.md │ │ ├── dynamic-components.md │ │ ├── examples/ │ │ │ └── conditional-rendering.js │ │ ├── lifecycle.md │ │ ├── reactive.md │ │ ├── ref.md │ │ ├── slot.md │ │ ├── styling.md │ │ ├── template-syntax.md │ │ └── trigger.md │ ├── directives/ │ │ ├── controls.md │ │ ├── drag.md │ │ ├── flash.md │ │ ├── shake.md │ │ └── sound.md │ ├── get_started/ │ │ ├── installation.md │ │ ├── readme.md │ │ └── start.md │ ├── index.md │ ├── package.json │ ├── presets/ │ │ ├── _before.md │ │ ├── bar.md │ │ ├── fog-of-war.md │ │ ├── footprints.md │ │ ├── fx.md │ │ ├── loading.md │ │ ├── night-ambiant.md │ │ ├── sprite-shadows.md │ │ ├── tilemap.md │ │ └── weather.md │ └── public/ │ ├── [A]Dirt_pipo.tsx │ ├── [A]Flower_pipo.tsx │ ├── [A]Grass_pipo.tsx │ ├── [A]Wall-Up_pipo.tsx │ ├── [A]WaterFall_pipo.tsx │ ├── [A]Water_pipo.tsx │ ├── [Base]BaseChip_pipo.tsx │ ├── grammar.pegjs │ ├── map.tmx │ ├── simplemap.tmx │ ├── simplemap2.tmx │ └── tileset.tsx ├── package.json ├── packages/ │ ├── compiler/ │ │ ├── grammar.pegjs │ │ ├── grammar2.pegjs │ │ ├── index.ts │ │ ├── package.json │ │ ├── tests/ │ │ │ ├── compiler.spec.ts │ │ │ └── compiler2.spec.ts │ │ ├── tsconfig.json │ │ └── tsup.config.ts │ ├── core/ │ │ ├── index.d.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── components/ │ │ │ │ ├── Button.ts │ │ │ │ ├── Canvas.ts │ │ │ │ ├── Container.ts │ │ │ │ ├── DOMContainer.ts │ │ │ │ ├── DOMElement.ts │ │ │ │ ├── DOMSprite.ts │ │ │ │ ├── DisplayObject.ts │ │ │ │ ├── FocusContainer.ts │ │ │ │ ├── Graphic.ts │ │ │ │ ├── Joystick.ts │ │ │ │ ├── Mesh.ts │ │ │ │ ├── NineSliceSprite.ts │ │ │ │ ├── ParticleEmitter.ts │ │ │ │ ├── Scene.ts │ │ │ │ ├── Sprite.ts │ │ │ │ ├── Text.ts │ │ │ │ ├── TilingSprite.ts │ │ │ │ ├── Video.ts │ │ │ │ ├── Viewport.ts │ │ │ │ ├── index.ts │ │ │ │ └── types/ │ │ │ │ ├── DisplayObject.ts │ │ │ │ ├── MouseEvent.ts │ │ │ │ ├── Spritesheet.ts │ │ │ │ └── index.ts │ │ │ ├── directives/ │ │ │ │ ├── Controls.ts │ │ │ │ ├── ControlsBase.ts │ │ │ │ ├── Drag.ts │ │ │ │ ├── Flash.ts │ │ │ │ ├── FocusNavigation.ts │ │ │ │ ├── FogVisibility.ts │ │ │ │ ├── GamepadControls.ts │ │ │ │ ├── JoystickControls.ts │ │ │ │ ├── KeyboardControls.ts │ │ │ │ ├── Scheduler.ts │ │ │ │ ├── Shake.ts │ │ │ │ ├── Sound.ts │ │ │ │ ├── Transition.ts │ │ │ │ ├── ViewportCull.ts │ │ │ │ ├── ViewportFollow.ts │ │ │ │ └── index.ts │ │ │ ├── engine/ │ │ │ │ ├── FocusManager.ts │ │ │ │ ├── animation.ts │ │ │ │ ├── bootstrap.ts │ │ │ │ ├── directive.ts │ │ │ │ ├── reactive.ts │ │ │ │ ├── signal.ts │ │ │ │ ├── trigger.ts │ │ │ │ └── utils.ts │ │ │ ├── hooks/ │ │ │ │ ├── addContext.ts │ │ │ │ ├── useFocus.ts │ │ │ │ ├── useProps.ts │ │ │ │ └── useRef.ts │ │ │ ├── index.ts │ │ │ ├── types/ │ │ │ │ └── pixi-cull.d.ts │ │ │ └── utils/ │ │ │ ├── Ease.ts │ │ │ ├── GlobalAssetLoader.ts │ │ │ ├── RadialGradient.ts │ │ │ ├── functions.ts │ │ │ └── tabindex.ts │ │ ├── testing/ │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── presets/ │ │ ├── package.json │ │ ├── src/ │ │ │ ├── Bar.ts │ │ │ ├── Button.ts │ │ │ ├── FogOfWar.ts │ │ │ ├── Footprints.ts │ │ │ ├── Loading.ts │ │ │ ├── NightAmbiant.ts │ │ │ ├── Particle.ts │ │ │ ├── SpriteShadows.ts │ │ │ ├── Tilemap/ │ │ │ │ ├── Tile.ts │ │ │ │ ├── TileGroup.ts │ │ │ │ ├── TileLayer.ts │ │ │ │ ├── TileSet.ts │ │ │ │ └── index.ts │ │ │ ├── Weathers/ │ │ │ │ ├── fog.ts │ │ │ │ ├── index.ts │ │ │ │ ├── rain.ts │ │ │ │ └── snow.ts │ │ │ ├── fx/ │ │ │ │ ├── Fx.ts │ │ │ │ ├── index.ts │ │ │ │ ├── presets.ts │ │ │ │ ├── runtime.ts │ │ │ │ ├── textures.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils.ts │ │ │ ├── index.ts │ │ │ └── shaders/ │ │ │ ├── defaultFilter.vert.glsl │ │ │ ├── nightSpot.frag.glsl │ │ │ └── shadowGradient.frag.glsl │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── testing/ │ │ ├── package.json │ │ ├── src/ │ │ │ ├── helpers/ │ │ │ │ ├── createMockComponentInstance.ts │ │ │ │ ├── createMockElement.ts │ │ │ │ └── spyOnElement.ts │ │ │ ├── index.ts │ │ │ └── mocks/ │ │ │ └── pixi-base.ts │ │ ├── tsconfig.json │ │ └── tsup.config.ts │ └── tiled/ │ ├── package.json │ ├── readme.md │ ├── src/ │ │ ├── classes/ │ │ │ ├── Gid.ts │ │ │ ├── Layer.ts │ │ │ ├── Map.ts │ │ │ ├── Object.ts │ │ │ ├── Properties.ts │ │ │ ├── Tile.ts │ │ │ └── Tileset.ts │ │ ├── generate/ │ │ │ ├── tileset.ts │ │ │ └── wangtile.ts │ │ ├── index.ts │ │ ├── parser/ │ │ │ ├── open-file.ts │ │ │ └── parser.ts │ │ ├── types/ │ │ │ ├── Layer.ts │ │ │ ├── Map.ts │ │ │ ├── Objects.ts │ │ │ ├── Text.ts │ │ │ ├── Tile.ts │ │ │ ├── Tileset.ts │ │ │ ├── Types.ts │ │ │ └── WorldMaps.ts │ │ └── utils.ts │ ├── tests/ │ │ ├── class.spec.ts │ │ ├── data.ts │ │ ├── parser.spec.ts │ │ ├── tile-properties.spec.ts │ │ ├── tiledmap-multi-layers.spec.ts │ │ └── tiledmap.spec.ts │ ├── tsconfig.json │ └── vite.config.ts ├── pnpm-workspace.yaml ├── sample/ │ ├── index.html │ ├── package.json │ ├── src/ │ │ ├── app.ce │ │ ├── benchmark.ce │ │ ├── box.ce │ │ ├── child.ce │ │ ├── control.ce │ │ ├── controls-buttons.ce │ │ ├── controls-rect.ce │ │ ├── dependencies.ce │ │ ├── flash.ce │ │ ├── flex.ce │ │ ├── focus-navigation-dom.ce │ │ ├── focus-navigation.ce │ │ ├── fogofwar.ce │ │ ├── footprints.ce │ │ ├── freeze.ce │ │ ├── fx.ce │ │ ├── light.ce │ │ ├── loader-spritesheet.ce │ │ ├── main.ts │ │ ├── preset.ce │ │ ├── shake.ce │ │ ├── sprite-shadows.ce │ │ ├── spritesheet.ce │ │ ├── spritesheet2.ce │ │ ├── test.ce │ │ ├── tiled.ce │ │ ├── viewport.ce │ │ └── weather.ce │ ├── tests/ │ │ ├── README.md │ │ └── example.spec.ts │ ├── tsconfig.json │ ├── vite.config.ts │ └── vitest.config.ts ├── skills-lock.json ├── starter/ │ ├── .gitignore │ ├── components/ │ │ ├── app.ce │ │ └── hello.ce │ ├── index.html │ ├── main.ts │ ├── package.json │ ├── tsconfig.json │ └── vite.config.ts ├── tests/ │ ├── components/ │ │ ├── canvas.spec.ts │ │ ├── component.spec.ts │ │ ├── container.spec.ts │ │ ├── displayobject.spec.ts │ │ ├── domcontainer.spec.ts │ │ ├── domsprite.spec.ts │ │ ├── flex.spec.ts │ │ ├── focus-container-tabindex.spec.ts │ │ ├── focus-container.spec.ts │ │ ├── graphics.spec.ts │ │ ├── mesh.spec.ts │ │ ├── nineslicesprite.spec.ts │ │ ├── particleemitter.spec.ts │ │ ├── scene.spec.ts │ │ ├── sprite.spec.ts │ │ ├── text.spec.ts │ │ ├── tilingsprite.spec.ts │ │ ├── video.spec.ts │ │ └── viewport.spec.ts │ ├── directives/ │ │ ├── drag.spec.ts │ │ ├── flash.spec.ts │ │ └── shake.spec.ts │ ├── engine/ │ │ ├── animation.spec.ts │ │ ├── cond-loop.spec.ts │ │ ├── cond.spec.ts │ │ ├── define-props.spec.ts │ │ ├── dependencies.spec.ts │ │ ├── focus-loop-sharing.spec.ts │ │ ├── freeze.spec.ts │ │ ├── lifecycle.spec.ts │ │ ├── loop-sharing.spec.ts │ │ ├── loop-spread-props.spec.ts │ │ ├── loop.spec.ts │ │ ├── nested-loop.spec.ts │ │ ├── reactive-routing.spec.ts │ │ └── trigger.spec.ts │ ├── presets/ │ │ └── fx.spec.ts │ ├── setup/ │ │ └── canvas.ts │ └── utils/ │ ├── GlobalAssetLoader.spec.ts │ └── tabindex.spec.ts ├── tsconfig.json ├── tsconfig.node.json ├── tsup.config.ts └── vitest.config.ts ================================================ FILE CONTENTS ================================================ ================================================ FILE: .agents/skills/canvasengine/SKILL.md ================================================ --- name: canvasengine description: Work on CanvasEngine projects and .ce components using the official documentation. Use when Codex needs to explain, create, review, or modify CanvasEngine code, especially files ending in .ce, CanvasEngine reactivity with signals, computed, and effect, template directives such as @if and @for, component script/template/style structure, or CanvasEngine-specific syntax that mixes ideas from React, Vue, and Angular. --- # CanvasEngine Project ## Documentation First Before answering or editing CanvasEngine code, fetch and read the current documentation index: ```bash curl -L https://canvasengine.net/llms.txt ``` If `curl` is unavailable, use an equivalent command or tool (`wget`, browser/web fetch, or another HTTP client). If network access is blocked, say that the current documentation could not be fetched and proceed only from local code plus any already available docs. Use `llms.txt` as a table of contents: 1. Read the summary and section list. 2. Identify the Markdown documentation URLs relevant to the user request. 3. Fetch the relevant `.md` pages with `curl -L ` or an equivalent tool. 4. Base implementation and explanations on those pages, not on assumptions from React, Vue, Angular, or PixiJS. 5. Mention the specific docs or examples consulted when the answer depends on them. ## Project Model Treat CanvasEngine components as `.ce` files with: - a script block for state, imports, functions, signals, `computed`, and `effect` - component content/template markup - an optional CSS style block Prefer existing project conventions for file layout, imports, naming, and component composition. Inspect nearby `.ce` files before adding new patterns. ## Reactivity CanvasEngine reactivity is centered on signals plus `computed` and `effect`. Use the documentation to confirm exact APIs before writing code. Do not assume that signal usage is identical to Solid, Angular, Vue, React, or another framework. Important template rules: - In a template, `` means bind the `x` variable from the script scope. `x` may be a signal or a plain value. Do not interpret this as a boolean-only JSX prop. - For reactive conditions, pass the signal/reference to the directive: use `@if (show)`, not `@if (show())`. - For reactive loops, pass the signal/reference to the directive in the same spirit: use `@for` with the reactive source itself rather than eagerly calling or unwrapping it, unless the official docs for the exact case say otherwise. - Keep signal reads/writes consistent with the documented CanvasEngine syntax for the context: script code and template code may differ. ## Implementation Checklist When modifying a CanvasEngine project: 1. Fetch `llms.txt` and the relevant Markdown docs. 2. Inspect local examples with `rg --files -g '*.ce'` and read nearby components. 3. Preserve `.ce` component structure: script, content/template, optional style. 4. Use CanvasEngine primitives and directives instead of importing framework habits from React/Vue/Angular. 5. Verify shorthand bindings, reactive `@if`, and reactive `@for` syntax before finishing. 6. Run the project’s relevant checks or at least a focused syntax/type check when available. ================================================ FILE: .agents/skills/canvasengine/agents/openai.yaml ================================================ interface: display_name: "CanvasEngine" short_description: "Guide projets CanvasEngine et fichiers .ce" default_prompt: "Use $canvasengine to implement or explain a CanvasEngine .ce component with the official docs." ================================================ FILE: .agents/skills/pixijs/SKILL.md ================================================ --- name: pixijs description: "Use this skill first for ANY PixiJS v8 task; it routes to the right specialized skill for the job. Covers the full PixiJS surface: Application setup, the scene graph (Container, Sprite, Graphics, Text, Mesh, ParticleContainer, DOMContainer, GifSprite), rendering (WebGL/WebGPU/Canvas, render loop, custom shaders, filters, blend modes), assets, events, color, math, ticker, accessibility, performance, environments, migration from v7, and project scaffolding. Triggers on: pixi, pixi.js, pixijs, PixiJS, v8, Application, app.init, Sprite, Container, Graphics, Text, Mesh, ParticleContainer, DOMContainer, GifSprite, Assets, Ticker, renderer, WebGL, WebGPU, scene graph, filter, shader, blend mode, texture, BitmapText, create-pixi, how do I draw, how do I render, how do I animate in pixi." license: MIT --- Entry point for the PixiJS v8 skill collection. PixiJS is the fastest library available for the web, working across all devices and allowing you to create rich, interactive graphics and cross-platform applications using WebGL, WebGPU, and Canvas as a fallback. ## How to use this skill 1. Find the specialized skill in the router below that best matches the task. 2. Load that skill's `SKILL.md` and follow its guidance. 3. If no sub-skill fits (the task references a specific class, function, option, or API surface not listed below), **WebFetch `https://pixijs.download/release/docs/llms.txt`**. That file is the auto-generated, always-current index of the full PixiJS API and guides. Each entry links to a `.html.md` page you can WebFetch for the detailed content. For the long-form description and trigger keywords of every skill, see [references/index.md](references/index.md). ## Skill router ### Foundations | Skill | Load when... | |---|---| | [pixijs-application](../pixijs-application/SKILL.md) | Creating or configuring a PixiJS `Application`, calling `app.init()`, accessing `app.stage`/`renderer`/`canvas`/`screen`, resize/ticker plugins, `app.destroy()`. | | [pixijs-core-concepts](../pixijs-core-concepts/SKILL.md) | Understanding the renderer pipeline, choosing WebGL/WebGPU/Canvas, render loop internals, systems and pipes. | | [pixijs-create](../pixijs-create/SKILL.md) | Scaffolding a new project with the `create-pixi` CLI (bundler-vite, creation-web, framework-react templates). | | [pixijs-environments](../pixijs-environments/SKILL.md) | Running PixiJS in Web Workers, Node/SSR, or strict-CSP contexts (`DOMAdapter`, `WebWorkerAdapter`, `pixi.js/unsafe-eval`). | | [pixijs-migration-v8](../pixijs-migration-v8/SKILL.md) | Upgrading from v7 to v8 or fixing v7 patterns (`beginFill`/`endFill`, `@pixi/*` packages, `BaseTexture`, `DisplayObject`). | | [pixijs-scene-core-concepts](../pixijs-scene-core-concepts/SKILL.md) | Understanding the scene graph as a whole: containers vs leaves, transforms, render order, masking, `RenderLayer`. | ### Scene Objects | Skill | Load when... | |---|---| | [pixijs-scene-container](../pixijs-scene-container/SKILL.md) | Working with `Container`: `addChild`/`removeChild`, transforms, `zIndex`, bounds, `toGlobal`/`toLocal`, `destroy`. | | [pixijs-scene-sprite](../pixijs-scene-sprite/SKILL.md) | Drawing images: `Sprite`, `AnimatedSprite`, `NineSliceSprite`, `TilingSprite`. | | [pixijs-scene-graphics](../pixijs-scene-graphics/SKILL.md) | Drawing vector shapes or paths: `Graphics`, `GraphicsContext`, `fill`/`stroke`, `FillGradient`, SVG. | | [pixijs-scene-text](../pixijs-scene-text/SKILL.md) | Rendering text: `Text`, `BitmapText`, `HTMLText`, `SplitText`, `TextStyle`. | | [pixijs-scene-mesh](../pixijs-scene-mesh/SKILL.md) | Custom geometry: `Mesh`, `MeshSimple`, `MeshPlane`, `MeshRope`, `PerspectiveMesh`. | | [pixijs-scene-particle-container](../pixijs-scene-particle-container/SKILL.md) | Rendering thousands of lightweight sprites: `ParticleContainer`, `Particle`, `dynamicProperties`. | | [pixijs-scene-dom-container](../pixijs-scene-dom-container/SKILL.md) | Overlaying HTML elements on the canvas: `DOMContainer`, `pixi.js/dom`. | | [pixijs-scene-gif](../pixijs-scene-gif/SKILL.md) | Displaying animated GIFs: `GifSprite`, `GifSource`, `pixi.js/gif`. | ### Utilities | Skill | Load when... | |---|---| | [pixijs-assets](../pixijs-assets/SKILL.md) | Loading resources: `Assets.init`, `Assets.load`, bundles, manifests, spritesheets, caching. | | [pixijs-color](../pixijs-color/SKILL.md) | Creating or converting colors: `Color` class, hex/rgb/hsl, `tint`, `premultiply`. | | [pixijs-events](../pixijs-events/SKILL.md) | Handling pointer/mouse/touch/wheel input: `eventMode`, `FederatedEvent`, `hitArea`, `cursor`, drag. | | [pixijs-math](../pixijs-math/SKILL.md) | Points, vectors, matrices, shapes, hit testing: `Point`, `Matrix`, `Rectangle`, `toGlobal`/`toLocal`. | | [pixijs-ticker](../pixijs-ticker/SKILL.md) | Per-frame logic or controlling the render loop: `Ticker`, `deltaTime`, `UPDATE_PRIORITY`, `maxFPS`. | ### Advanced | Skill | Load when... | |---|---| | [pixijs-accessibility](../pixijs-accessibility/SKILL.md) | Screen reader or keyboard navigation: `AccessibilitySystem`, `accessibleTitle`, `tabIndex`. | | [pixijs-blend-modes](../pixijs-blend-modes/SKILL.md) | Compositing with blend modes: `add`, `multiply`, `screen`, `overlay`, `pixi.js/advanced-blend-modes`. | | [pixijs-custom-rendering](../pixijs-custom-rendering/SKILL.md) | Writing custom shaders, uniforms, or batchers: `Shader.from`, `GlProgram`/`GpuProgram`, `UniformGroup`, custom `Filter`. | | [pixijs-filters](../pixijs-filters/SKILL.md) | Applying visual effects: `BlurFilter`, `ColorMatrixFilter`, `DisplacementFilter`, `Filter.from`, `pixi-filters`. | | [pixijs-performance](../pixijs-performance/SKILL.md) | Profiling or optimizing FPS, draw calls, GPU memory: culling, `GCSystem`, `cacheAsTexture`, object pooling. | ## Fallback: canonical PixiJS docs If the task references a class, function, option, or API surface not covered by any sub-skill above, **WebFetch `https://pixijs.download/release/docs/llms.txt`**. It's the auto-generated index of the full PixiJS API and guides, regenerated on every release. Each entry links to a `.html.md` page you can WebFetch for the detailed content. Use this fallback whenever the router table doesn't point at an obvious match. ================================================ FILE: .agents/skills/pixijs/references/index.md ================================================ # PixiJS Skills: Full Index Detailed routing table for the PixiJS v8 skill collection. Each entry lists the skill's full description and the trigger keywords that should match it. For a scannable short-form table, see the parent `SKILL.md`. ## Foundations ### pixijs-application Create and configure a PixiJS v8 `Application`. Covers `new Application()` + async `app.init()` options (width, height, background, antialias, resolution, autoDensity, preference, resizeTo, autoStart, sharedTicker, canvas), `app.stage`/`renderer`/`canvas`/`screen` access, `ResizePlugin`, `TickerPlugin`, and `app.destroy()`. **Triggers:** Application, app.init, app.stage, app.renderer, app.canvas, app.screen, ApplicationOptions, resizeTo, preference, autoStart, sharedTicker, app.destroy. ### pixijs-core-concepts How PixiJS v8 renders frames: the systems-and-pipes renderer, the render loop, and how the library adapts to different environments. Covers `WebGLRenderer`/`WebGPURenderer`/`CanvasRenderer` selection, `renderer.render()` pipeline, environment detection, and pointers to per-topic deep dives. **Triggers:** renderer, WebGL, WebGPU, Canvas, render loop, render pipeline, systems, environments, autoDetectRenderer. ### pixijs-create Scaffold a new PixiJS v8 project with the `create-pixi` CLI. Covers npm/yarn/pnpm/bun create commands, interactive vs non-interactive flows, available template presets (bundler-vite, bundler-webpack, bundler-esbuild, bundler-import-map, creation-web, framework-react, extension-default), Node version requirements, and post-scaffold dev flow. **Triggers:** create pixi.js, npm create, scaffold, template, bundler-vite, bundler-webpack, creation-web, framework-react, new project, getting started. ### pixijs-environments Run PixiJS v8 outside a standard browser: Web Workers, `OffscreenCanvas`, Node/SSR, or CSP-restricted contexts. Covers `DOMAdapter.set`, `BrowserAdapter`, `WebWorkerAdapter`, custom `Adapter` interface, `pixi.js/unsafe-eval` for strict CSP. **Triggers:** DOMAdapter, BrowserAdapter, WebWorkerAdapter, Web Worker, OffscreenCanvas, Node, headless, SSR, CSP, unsafe-eval, Adapter. ### pixijs-migration-v8 Upgrade a PixiJS project from v7 to v8 or diagnose broken v7 code after an upgrade. Covers async `app.init`, single `pixi.js` package (deprecated `@pixi/*` sub-packages), `Graphics` shape-then-fill, `BaseTexture` -> `TextureSource`, shader/uniform rework, `ParticleContainer`+`Particle`, constructor options objects, `DisplayObject` removal, `settings`/`utils` removal, `Ticker` signature, events rewrite. **Triggers:** migrate v7, v8 breaking changes, @pixi/ import, DisplayObject, beginFill, endFill, cacheAsBitmap, BaseTexture, deprecated. ### pixijs-scene-core-concepts The PixiJS v8 scene graph as a whole: how containers, leaves, transforms, and render order fit together. Covers leaf vs container distinction, local/world coordinates, culling, render groups, sortable children, masking, `RenderLayer`, and which leaf skill covers which display object. **Triggers:** scene graph, display list, Container, Sprite, Graphics, Text, Mesh, ParticleContainer, DOMContainer, GifSprite, masking, render group, RenderLayer, world transform. ## Scene Objects ### pixijs-scene-container Group, position, or transform display objects. Covers `Container` constructor options (`isRenderGroup`, `sortableChildren`, `boundsArea`), `addChild`/`removeChild`/`addChildAt`/`swapChildren`/`setChildIndex`, `position`/`scale`/`rotation`/`pivot`/`skew`/`alpha`/`tint`, `getBounds`/`getGlobalPosition`/`toLocal`/`toGlobal`, `zIndex` sorting, `cullable`, `destroy`. **Triggers:** Container, addChild, removeChild, addChildAt, swapChildren, sortableChildren, zIndex, position, scale, rotation, pivot, getBounds, toGlobal, toLocal, destroy. ### pixijs-scene-dom-container Overlay HTML elements on the PixiJS v8 canvas. Covers `DOMContainer` with `element`, `anchor`, and scene-graph-driven CSS transforms, the `pixi.js/dom` side-effect import, `DOMPipe` registration, visibility sync, pointer-events handling. **Triggers:** DOMContainer, pixi.js/dom, DOMPipe, HTML overlay, input on canvas, iframe overlay, DOMContainerOptions, element, anchor. ### pixijs-scene-gif Display animated GIFs. Covers the `pixi.js/gif` side-effect import, `Assets.load` returning a `GifSource`, `GifSprite` playback (`play`/`stop`/`currentFrame`/`animationSpeed`), `autoPlay`/`loop` options, `onComplete`/`onLoop`/`onFrameChange` callbacks, `GifSource` sharing, `clone`, `destroy`. **Triggers:** GifSprite, GifSource, pixi.js/gif, animationSpeed, currentFrame, autoPlay, onComplete, onFrameChange. ### pixijs-scene-graphics Draw vector shapes and paths. Covers the `Graphics` shape-then-fill API (`rect`/`circle`/`ellipse`/`poly`/`roundRect`/`star`), path methods (`moveTo`/`lineTo`/`bezierCurveTo`/`arc`), `fill`/`stroke`/`cut`, `FillGradient`, `FillPattern`, `GraphicsContext` sharing, SVG markup. **Triggers:** Graphics, GraphicsContext, rect, circle, poly, roundRect, fill, stroke, cut, FillGradient, FillPattern, moveTo, bezierCurveTo, svg. ### pixijs-scene-mesh Render custom geometry. Covers `Mesh` with `MeshGeometry` (positions, uvs, indices, topology), `MeshSimple` for per-frame vertex animation, `MeshPlane` for subdivided deformation, `MeshRope` for path-following textures, `PerspectiveMesh` for 2.5D corners. **Triggers:** Mesh, MeshGeometry, MeshSimple, MeshPlane, MeshRope, PerspectiveMesh, positions, uvs, indices, topology, setCorners. ### pixijs-scene-particle-container Render thousands of lightweight sprites. Covers `ParticleContainer` with `Particle` instances, `addParticle`/`removeParticle`, `particleChildren` array, `dynamicProperties` (vertex, position, rotation, uvs, color), `boundsArea`, `roundPixels`, `update`. **Triggers:** ParticleContainer, Particle, IParticle, addParticle, particleChildren, dynamicProperties, boundsArea, particle effects. ### pixijs-scene-sprite Draw images. Covers `Sprite` with `anchor`/`tint`/`texture`, `AnimatedSprite` for frame animation, `NineSliceSprite` for resizable UI panels, `TilingSprite` for scrolling/repeating backgrounds. **Triggers:** Sprite, AnimatedSprite, NineSliceSprite, TilingSprite, Sprite.from, anchor, tint, tilePosition, animationSpeed, gotoAndPlay, leftWidth, topHeight. ### pixijs-scene-text Render text. Covers `Text` for canvas-quality styled labels, `BitmapText` for cheap per-frame updates via glyph atlas, `HTMLText` for HTML/CSS markup via SVG, `SplitText` and `SplitBitmapText` for per-character animation, `TextStyle`, `tagStyles`. **Triggers:** Text, BitmapText, HTMLText, SplitText, SplitBitmapText, TextStyle, HTMLTextStyle, BitmapFont.install, tagStyles, fontFamily, wordWrap. ## Utilities ### pixijs-assets Load and manage resources. Covers `Assets.init`, `Assets.load`/`add`/`unload`, bundles, manifests, background loading, `onProgress`, caching, spritesheets, compressed textures, SVG as texture or Graphics, resolution detection. **Triggers:** Assets, Assets.load, Assets.init, loadBundle, manifest, backgroundLoad, Spritesheet, Cache, LoadOptions, unload. ### pixijs-color Create, convert, or manipulate colors. Covers `Color` class input formats (hex, CSS names, RGB/HSL objects, arrays, `Uint8Array`), conversion methods (`toHex`, `toNumber`, `toArray`, `toRgba`), component access, `setAlpha`/`multiply`/`premultiply`, `Color.shared` singleton. **Triggers:** Color, ColorSource, hex, rgb, hsl, tint, premultiply, Color.shared, color conversion. ### pixijs-events Handle pointer, mouse, touch, or wheel input. Covers `eventMode` (none, passive, auto, static, dynamic), `FederatedEvent` types, propagation and capture phase, `hitArea`, `interactiveChildren`, `cursor` and `cursorStyles`, global move events for drag, `eventFeatures` config. **Triggers:** eventMode, FederatedPointerEvent, pointerdown, click, tap, globalpointermove, drag, hitArea, cursor, stopPropagation. ### pixijs-math Coordinates, vectors, matrices, shapes, and hit testing. Covers `Point`/`ObservablePoint`, `Matrix` (2D affine, decompose, apply), shapes (`Rectangle`, `Circle`, `Ellipse`, `Polygon`, `RoundedRectangle`, `Triangle`), `toGlobal`/`toLocal`, `PointData` types, `DEG_TO_RAD`, and `pixi.js/math-extras` vector helpers. **Triggers:** Point, ObservablePoint, Matrix, Rectangle, Circle, Polygon, toGlobal, toLocal, hitArea, math-extras, DEG_TO_RAD, PointData. ### pixijs-ticker Run per-frame logic or control the render loop. Covers `Ticker.add`/`addOnce`/`remove`, `deltaTime` vs `deltaMS` vs `elapsedMS`, `UPDATE_PRIORITY` ordering, `maxFPS`/`minFPS` capping, speed scaling, `Ticker.shared` vs new instances, per-object `onRender` hook, manual rendering. **Triggers:** Ticker, UPDATE_PRIORITY, deltaTime, deltaMS, elapsedMS, onRender, app.ticker, maxFPS, minFPS, Ticker.shared. ## Advanced ### pixijs-accessibility Add screen reader and keyboard navigation to PixiJS v8 apps. Covers `AccessibilitySystem` options (`enabledByDefault`, `debug`, `activateOnTab`, `deactivateOnMouseMove`), per-container accessibility properties, shadow DOM overlay, mobile touch-hook activation. **Triggers:** accessibility, a11y, screen reader, ARIA, keyboard navigation, tab order, AccessibilitySystem, accessibleTitle, accessibleHint, tabIndex, accessibleChildren. ### pixijs-blend-modes Composite display objects with blend modes. Covers standard modes (`normal`, `add`, `multiply`, `screen`, `erase`, `min`, `max`), advanced modes via `pixi.js/advanced-blend-modes` (`color-burn`, `overlay`, `hard-light`, etc.), batch-friendly ordering. **Triggers:** blendMode, additive, multiply, screen, overlay, color-burn, color-dodge, advanced-blend-modes, glow, erase. ### pixijs-custom-rendering Write custom shaders, uniforms, or batchers. Covers `Shader.from({gl, gpu, resources})`, `GlProgram`/`GpuProgram`, `UniformGroup` with typed uniforms (`f32`, `vec2`, `mat4x4`), UBO mode, textures as resources, custom `Filter`, custom `Batcher` via extensions. **Triggers:** Shader, GlProgram, GpuProgram, UniformGroup, Batcher, Filter, GLSL, WGSL, UBO, uniform, custom shader. ### pixijs-filters Apply visual effects to containers via the filter pipeline. Covers built-in filters (`AlphaFilter`, `BlurFilter`, `ColorMatrixFilter`, `DisplacementFilter`, `NoiseFilter`), custom `Filter.from()` with GLSL/WGSL, options (`resolution`, `padding`, `antialias`, `blendRequired`), `filterArea` optimization, `pixi-filters` community package. **Triggers:** filters, BlurFilter, ColorMatrixFilter, DisplacementFilter, NoiseFilter, Filter.from, GLSL filter, pixi-filters, filterArea. ### pixijs-performance Profile or optimize a PixiJS v8 app for FPS, draw calls, or GPU memory. Covers destroy patterns (`cacheAsTexture(false)`, `releaseGlobalResources`), `GCSystem` and `TextureGCSystem`, `PrepareSystem`, object pooling, batching rules, `BitmapText` for dynamic text, culling (`Culler`, `CullerPlugin`, `cullable`, `cullArea`), resolution/antialias tradeoffs. **Triggers:** FPS, jank, draw calls, batching, object pool, GCSystem, PrepareSystem, Culler, cacheAsTexture, memory leak, destroy patterns. ================================================ FILE: .changeset/config.json ================================================ { "$schema": "https://unpkg.com/@changesets/config@3.0.1/schema.json", "changelog": "@changesets/cli/changelog", "commit": false, "fixed": [], "linked": [], "access": "restricted", "baseBranch": "v2", "updateInternalDependencies": "patch", "ignore": [] } ================================================ FILE: .codex ================================================ ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: push: branches: - "*" paths-ignore: - "docs/**" pull_request: branches: - "*" paths-ignore: - "docs/**" jobs: tests: runs-on: ubuntu-22.04 strategy: matrix: node-version: [20] steps: - uses: actions/checkout@v4 - name: Install pnpm uses: pnpm/action-setup@v4 with: version: 9 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: "pnpm" - name: Install dependencies run: pnpm install --no-frozen-lockfile - name: Build run: pnpm build - name: Run Tests run: pnpm test deploy: needs: tests runs-on: ubuntu-22.04 if: github.ref == 'refs/heads/v2' steps: - uses: actions/checkout@v4 - name: Install pnpm uses: pnpm/action-setup@v4 with: version: 9 - name: Use Node.js uses: actions/setup-node@v4 with: node-version: 20 cache: "pnpm" - name: Install dependencies run: pnpm install --no-frozen-lockfile - name: Build run: pnpm build - name: 📣 Create Release Pull Request or Publish to npm id: changesets uses: changesets/action@v1 with: title: "chore(release): version packages 🦋" publish: pnpm publish:packages version: pnpm version:packages commit: "chore(release): version packages 🦋 [skip ci]" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Update Starter Package Versions run: | CORE_VERSION=$(jq -r '.version' packages/core/package.json) jq --arg version "$CORE_VERSION" '.dependencies.canvasengine = $version | .devDependencies["@canvasengine/compiler"] = $version' starter/package.json > starter/package.tmp.json mv starter/package.tmp.json starter/package.json shell: bash - name: Commit Changes run: | git add starter/package.json git commit -m "chore(release): update starter package version to $CORE_VERSION" git push shell: bash ================================================ FILE: .gitignore ================================================ # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* node_modules dist dist-ssr *.local # Editor directories and files .vscode/* !.vscode/extensions.json .idea .DS_Store *.suo *.ntvs* *.njsproj *.sln *.sw? lib cache .vitepress/dist .vitepress/cache coverage sample/public ================================================ FILE: .npmignore ================================================ tests template sample public docs .vitepress node_modules starter .github .cursorrules logo.png compiler ================================================ FILE: README.md ================================================ # CanvasEngine - A reactive HTML5 Canvas management library built on top of PixiJS and Vite ![CanvasEngine](docs/public/logo.png) CanvasEngine is a reactive HTML5 Canvas management library built on top of PixiJS and Vite. It provides a component-oriented approach to canvas rendering, similar to modern frontend frameworks. Features: - Reactive components - Use flex in Canvas ! - Easy Animation system - Keyboard, Gamepad et Virtual Joystick - Tiled Map Editor integration - Particle Emitter - Audio System ## Installation ```bash npx degit RSamaium/CanvasEngine/starter my-project cd my-project npm install npm run dev # and go to localhost:5173 ``` ## Documentation https://canvasengine.net ## Example: ```html ``` ## Contributing Before, install `pnpm` and run the following command: ```bash git clone https://github.com/RSamaium/CanvasEngine.git cd CanvasEngine pnpm install pnpm run dev # to build the libraries ``` To run the sample project: ```bash pnpm run dev:sample ``` ### Build Documentation/Website ``` cd docs pnpm install pnpm run dev ``` ### Release ```bash pnpm run release ``` > Choose the version you want to release Push the release branch to the remote repository ```bash git push origin v2 ``` ================================================ FILE: __mocks__/pixi-viewport.ts ================================================ import { vi } from "vitest"; import { Viewport as PixiViewport } from 'pixi-viewport'; export class Viewport extends PixiViewport { drag = vi.fn().mockReturnThis(); wheel = vi.fn().mockReturnThis(); clamp = vi.fn().mockReturnThis(); decelerate = vi.fn().mockReturnThis(); pinch = vi.fn().mockReturnThis(); on = vi.fn().mockReturnThis(); update = vi.fn().mockReturnThis(); screenWidth = 0; screenHeight = 0; worldWidth = 0; worldHeight = 0; options: any = { events: {} }; // Initialize options input: any = { wheelFunction: vi.fn() }; // Mock input property } ================================================ FILE: docs/.vitepress/config.ts ================================================ import { defineConfig } from 'vitepress'; import llmstxt from 'vitepress-plugin-llms' const guideMenu = [ { text: "Quick Start", collapsed: false, items: [ { text: "Installation", link: "/get_started/installation", }, { text: "Start", link: "/get_started/start", } ], }, { text: "Concepts", collapsed: false, items: [ { text: "Template Syntax", link: "/concepts/template-syntax", }, { text: "Reactivity", link: "/concepts/reactive", }, { text: "Child Component", link: "/concepts/child-component", }, { text: "Trigger", link: "/concepts/trigger", }, { text: "Lifecycle", link: "/concepts/lifecycle", }, { text: "Dependencies", link: "/concepts/dependencies", }, { text: "Slot", link: "/concepts/slot", }, { text: "Dynamic Components", link: "/concepts/dynamic-components", }, { text: "Primitive Animation", link: "/concepts/animation", }, { text: "Styling", link: "/concepts/styling", } ], }, { text: "Components", collapsed: false, items: [ { text: "Canvas", link: "/components/canvas", }, { text: "Container", link: "/components/container", }, { text: "Graphics", link: "/components/graphic", }, { text: "Svg", link: "/components/svg", }, { text: "Text", link: "/components/text", }, { text: "Button", link: "/components/button", }, { text: "Sprite", link: "/components/sprite", }, { text: "NineSliceSprite", link: "/components/nine-slice-sprite", }, { text: "Viewport", link: "/components/viewport", }, { text: "TilingSprite", link: "/components/tiling-sprite", }, { text: "Video", link: "/components/video", }, { text: "Mesh", link: "/components/mesh", }, { text: "DOMContainer", link: "/components/dom-container", }, { text: "Navigation", link: "/components/navigation", }, { text: "Joystick", link: "/components/joystick", } ], }, { text: "Directives", collapsed: false, items: [ { text: "Controls", link: "/directives/controls", }, { text: "Drag", link: "/directives/drag", }, { text: "Sound", link: "/directives/sound", }, { text: "Flash", link: "/directives/flash", }, { text: "Shake", link: "/directives/shake", } ], }, { text: "Presets Components", collapsed: false, items: [ { text: "Bar", link: "/presets/bar", }, { text: "Loading", link: "/presets/loading", }, { text: "Tilemap", link: "/presets/tilemap", }, { text: "Weather", link: "/presets/weather", }, { text: "NightAmbiant", link: "/presets/night-ambiant", }, { text: "Footprints", link: "/presets/footprints", }, { text: "Fx", link: "/presets/fx", } ], }, { text: "API", collapsed: false, items: [ { text: "Element Object", link: "/api/element", }, { text: "Context", link: "/api/context", }, { text: "Testing", link: "/api/testing", }, { text: "Use without Compiler", link: "/advanced/without-compiler", } ], }, ]; export default defineConfig({ title: "Canvas Engine Documentation", description: "Reactive Canvas Framework", ignoreDeadLinks: true, themeConfig: { search: { provider: "local", }, repo: "https://github.com/RSamaium/CanvasEngine", nav: [ { text: "Home", link: "https://canvasengine.net", }, { text: "Guide", link: "/guide/get-started", }, ], sidebar: { "/": guideMenu, "/guide/": guideMenu, "/components/": guideMenu, "/directives/": guideMenu, }, }, vite: { plugins: [llmstxt()] }, }) ================================================ FILE: docs/.vitepress/theme/Layout.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/CustomHome.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/Playground.vue ================================================ ================================================ FILE: docs/.vitepress/theme/components/config.ts ================================================ const isDev = typeof window !== 'undefined' && window.location.hostname === 'localhost' /** * Configuration map for external dependencies * Ensures all CanvasEngine exports from the compiler are always available */ export const dependencyConfig = { 'canvasengine': { globalName: 'CanvasEngine', url: isDev ? 'http://localhost:3000/packages/core/dist/index.global.js' : 'https://cdn.jsdelivr.net/npm/canvasengine@latest/dist/index.global.js' }, '@canvasengine/presets': { globalName: 'CanvasEnginePresets', url: isDev ? 'http://localhost:3000/packages/presets/dist/index.global.js' : 'https://cdn.jsdelivr.net/npm/@canvasengine/presets@latest/dist/index.global.js' }, 'pixi.js': { globalName: 'PIXI', url: 'https://cdn.jsdelivr.net/npm/pixi.js@latest/dist/pixi.min.js' } } /** * List of primitive components that should always be available * Matches the PRIMITIVE_COMPONENTS from the compiler */ export const PRIMITIVE_COMPONENTS = [ "Canvas", "Sprite", "Text", "Viewport", "Graphics", "Container", "ImageMap", "NineSliceSprite", "Rect", "Circle", "Ellipse", "Triangle", "TilingSprite", "svg", "Video", "Mesh", "Svg", "DOMContainer", "DOMElement", "Button", "Joystick", "FocusContainer" ] /** * Core functions that should always be available * Matches the required imports from the compiler */ export const CORE_FUNCTIONS = [ "h", "computed", "cond", "loop", "useProps", "useDefineProps", "bootstrapCanvas" ] ================================================ FILE: docs/.vitepress/theme/components/example.ts ================================================ interface Example { title: string; description: string; files: Record; } const examples: Example[] = [{ title: 'Hello World', description: 'A simple example of how to use CanvasEngine', files: { "app.ce": ` `, "hello.ce": ``, }, }, { title: 'Reactivity', description: 'Example of using reactivity in CanvasEngine', files: { "app.ce": ` `, }, }, { title: 'With loop and condition syntax', description: 'Example of using loop and condition syntax in CanvasEngine', files: { "app.ce": ` @if (show) { @for ((color,index) of colors) { } } `, }, }, { title: 'Drag and Drop', description: 'Example of using drag and drop in CanvasEngine', files: { "app.ce": ` `, }, }, { title: 'Sprite Animation', description: 'Example of using sprite animation in CanvasEngine', files: { "app.ce": ` `, }, }, // { // title: 'Joystick', // description: 'Example of using joystick in CanvasEngine', // files: { // "app.ce": ` // // // // // // // `, // }, // }, { title: 'Sprite Animation and controls', description: 'Example of using sprite animation and controls in CanvasEngine. Use the arrow keys to move the sprite.', files: { "app.ce": ` `, "spritesheet.js": ` export const spritesheet = (framesWidth, framesHeight, frameStand = 1) => { if (framesWidth <= frameStand) { frameStand = framesWidth - 1 } const frameY = direction => { const gap = Math.max(4 - framesHeight, 0) return { 'down': 0, 'left': Math.max(0, 1 - gap), 'right': Math.max(0, 2 - gap), 'up': Math.max(0, 3 - gap) }[direction] } const stand = (direction) => [{ time: 0, frameX: frameStand, frameY: frameY(direction) }] const walk = direction => { const array = [] const durationFrame = 10 for (let i = 0; i < framesWidth; i++) { array.push({ time: i * durationFrame, frameX: i, frameY: frameY(direction) }) } array.push({ time: array[array.length - 1].time + durationFrame }) return array } return { textures: { 'stand': { animations: ({direction}) => [stand(direction)] }, 'walk': { animations: ({direction}) => [walk(direction)] } }, framesHeight, framesWidth } } ` }, }, { title: 'Tiled Map', description: 'Example of using a Tiled map in CanvasEngine', files: { "app.ce": ` } /> `, }, }, { title: 'DOM with form', description: 'Example of using a Tiled map in CanvasEngine', files: { "app.ce": `

{text}

`, }, }, { title: 'Animated signal', description: 'Example of using an animated signal in CanvasEngine. Click the rect to move it.', files: { "app.ce": ` `, }, }, { title: 'Joystick', description: 'Example of using a joystick in CanvasEngine. Use the joystick to move the rect.', files: { "app.ce": ` `, }, }, { title: 'Flash Effect', description: 'Example of using flash effects in CanvasEngine. Click the rectangles to see different flash types.', files: { "app.ce": ` alphaFlashTrigger.start()} /> tintFlashTrigger.start()} /> bothFlashTrigger.start()} /> multiCycleFlashTrigger.start()} /> `, }, }, { title: 'Shake Effect', description: 'Example of using shake effects in CanvasEngine. Click the rectangles to see different shake configurations.', files: { "app.ce": ` basicShakeTrigger.start()} /> horizontalShakeTrigger.start()} /> verticalShakeTrigger.start()} /> intenseShakeTrigger.start()} /> `, }, }, ]; export default examples; ================================================ FILE: docs/.vitepress/theme/index.ts ================================================ import DefaultTheme from "vitepress/theme"; import CustomHome from "./components/CustomHome.vue"; import Playground from "./components/Playground.vue"; import Layout from "./Layout.vue"; import "./style.css"; export default { ...DefaultTheme, Layout, enhanceApp(ctx) { DefaultTheme.enhanceApp(ctx); ctx.app.component('CustomHome', CustomHome); ctx.app.component('Playground', Playground); }, }; ================================================ FILE: docs/.vitepress/theme/style.css ================================================ /* Custom theme styles */ :root { --vp-c-brand: #646cff; --vp-c-brand-light: #747bff; --vp-c-brand-lighter: #9499ff; --vp-c-brand-lightest: #bcc0ff; --vp-c-brand-dark: #535bf2; --vp-c-brand-darker: #454ce1; --vp-c-brand-dimm: rgba(100, 108, 255, 0.08); } /* Hide default layout for custom home */ .custom-layout .VPContent { padding: 0 !important; } /* Smooth scrolling */ html { scroll-behavior: smooth; } /* Custom scrollbar */ ::-webkit-scrollbar { width: 8px; } ::-webkit-scrollbar-track { background: var(--vp-c-bg-soft); } ::-webkit-scrollbar-thumb { background: var(--vp-c-brand); border-radius: 4px; } ::-webkit-scrollbar-thumb:hover { background: var(--vp-c-brand-dark); } ================================================ FILE: docs/advanced/conditional-rendering.md ================================================ # Conditional Rendering The `cond()` function allows you to conditionally render elements based on reactive signals or static boolean values. It supports if/else if/else patterns for complex conditional logic. ## Basic Usage ### Simple Condition ```typescript import { cond, signal, h, Text } from 'canvasengine'; const isVisible = signal(true); const conditionalText = cond( isVisible, () => h(Text, { text: 'I am visible!' }) ); ``` ### With Else ```typescript const conditionalText = cond( isVisible, () => h(Text, { text: 'Visible' }), () => h(Text, { text: 'Hidden' }) // else case ); ``` ## Advanced Usage ### Multiple Conditions (else if) ```typescript const status = signal('loading'); const statusDisplay = cond( () => status() === 'loading', () => h(Text, { text: 'Loading...', color: 'yellow' }), [() => status() === 'error', () => h(Text, { text: 'Error!', color: 'red' })], // else if [() => status() === 'success', () => h(Text, { text: 'Success!', color: 'green' })], // else if () => h(Text, { text: 'Unknown status', color: 'gray' }) // else ); ``` ### Grade System Example ```typescript const score = signal(85); const gradeDisplay = cond( () => score() >= 90, () => h(Text, { text: 'A+', color: 'gold' }), [() => score() >= 80, () => h(Text, { text: 'A', color: 'green' })], [() => score() >= 70, () => h(Text, { text: 'B', color: 'blue' })], [() => score() >= 60, () => h(Text, { text: 'C', color: 'orange' })], () => h(Text, { text: 'F', color: 'red' }) // else ); ``` ## Condition Types The `cond()` function accepts three types of conditions: 1. **Signals**: Reactive values that trigger re-evaluation when changed 2. **Static booleans**: Simple true/false values 3. **Functions**: Functions that return boolean values (automatically converted to computed signals) ### Examples ```typescript // Signal condition const showElement = signal(true); cond(showElement, () => h(Text, { text: 'Signal condition' })); // Static boolean condition cond(true, () => h(Text, { text: 'Static condition' })); // Function condition (reactive) const user = signal({ role: 'admin' }); cond( () => user().role === 'admin', () => h(Text, { text: 'Admin panel' }) ); ``` ## Reactivity All conditions are reactive. When any signal used in the conditions changes, the `cond()` function automatically re-evaluates and updates the rendered element: ```typescript const userRole = signal('guest'); const navigation = cond( () => userRole() === 'admin', () => h(Container, { children: [ h(Text, { text: 'Admin Dashboard' }), h(Text, { text: 'User Management' }), h(Text, { text: 'Settings' }) ]}), [() => userRole() === 'user', () => h(Container, { children: [ h(Text, { text: 'Dashboard' }), h(Text, { text: 'Profile' }) ]})], () => h(Text, { text: 'Please log in' }) // guest ); // Changing the role will automatically update the UI userRole.set('admin'); // Shows admin navigation userRole.set('user'); // Shows user navigation userRole.set('guest'); // Shows login message ``` ## Performance - **Lazy evaluation**: Only the matching condition's element is created - **Automatic cleanup**: Previous elements are properly destroyed when conditions change - **Optimized updates**: Elements are only updated when the matching condition actually changes ## Best Practices 1. **Order matters**: Conditions are evaluated in order, the first `true` condition wins 2. **Use functions for complex logic**: Convert complex boolean expressions to functions for better reactivity 3. **Provide fallbacks**: Always consider adding an `else` case for unexpected states 4. **Keep conditions simple**: Complex logic should be extracted to computed signals or functions ```typescript // Good: Simple, readable conditions const theme = signal('dark'); cond( () => theme() === 'dark', () => h(Text, { text: 'Dark mode', color: 'white' }), () => h(Text, { text: 'Light mode', color: 'black' }) ); // Better: Extract complex logic const isDarkMode = computed(() => { const currentTheme = theme(); const userPreference = getUserPreference(); const systemPreference = getSystemPreference(); return currentTheme === 'dark' || (currentTheme === 'auto' && (userPreference === 'dark' || systemPreference === 'dark')); }); cond( isDarkMode, () => h(Text, { text: 'Dark mode', color: 'white' }), () => h(Text, { text: 'Light mode', color: 'black' }) ); ``` ================================================ FILE: docs/advanced/performance.md ================================================ # Performance Optimization Guide When building games or visualizations with many elements (1000+), performance becomes critical. This guide covers best practices for optimizing CanvasEngine applications. ## Understanding the Reactive System Cost CanvasEngine uses a reactive system based on signals. Each signal creates: - An RxJS subscription - Change detection overhead - Component update callbacks **Rule of thumb**: Minimize the number of signals, especially for properties that change frequently. ### Signal Count Impact | Elements | Signals/Element | Total Signals | Estimated Cost | |----------|-----------------|---------------|----------------| | 100 | 5 | 500 | Low | | 1000 | 5 | 5,000 | Medium | | 5000 | 5 | 25,000 | High | | 5000 | 2 | 10,000 | Medium | ## Optimization Strategies ### 1. Reduce Signal Granularity Instead of creating signals for every property, only use signals for properties that need reactive updates from external sources. **Before (expensive)**: ```javascript // 5 signals per element = 25,000 signals for 5000 elements function generateItems(count) { return Array.from({ length: count }, (_, i) => ({ x: signal(i * 10), y: signal(i * 10), rotation: signal(0), // Animated - DON'T use signal! alpha: signal(1), // Animated - DON'T use signal! scale: signal(1), // Animated - DON'T use signal! })); } ``` **After (optimized)**: ```javascript // 2 signals per element = 10,000 signals for 5000 elements function generateItems(count) { return Array.from({ length: count }, (_, i) => ({ x: signal(i * 10), // Position needs signals for loop y: signal(i * 10), rotationSpeed: Math.random() * 0.1, // Plain value alphaBase: 0.5 + Math.random() * 0.5, // Plain value scaleBase: 0.8 + Math.random() * 0.4, // Plain value })); } ``` ### 2. Imperative Animation in tick() For animations, update Pixi objects directly instead of going through signals: ```html ``` ### 3. Incremental Collection Updates When adding/removing elements, avoid resetting the entire collection: **Before (expensive)**: ```javascript // This triggers a full reset - destroys and recreates ALL elements items.set(generateItems(newCount)); ``` **After (optimized)**: ```javascript effect(() => { const targetCount = elementCount(); const currentItems = items(); const currentCount = currentItems.length; if (targetCount > currentCount) { // Add only new elements const newItems = [...currentItems]; for (let i = currentCount; i < targetCount; i++) { newItems.push(createItem(i)); } items.set(newItems); } else if (targetCount < currentCount) { // Remove from end - avoids full recreation items.set(currentItems.slice(0, targetCount)); } }); ``` ### 4. Frame Throttling For non-critical updates, skip frames: ```javascript tick((tickValue) => { // Update every 2nd frame (30 FPS effective) if (tickValue.frame % 2 !== 0) return; // Or every 3rd frame (20 FPS effective) if (tickValue.frame % 3 !== 0) return; // Animation logic }); ``` ### 5. Level of Detail (LOD) Reduce visual complexity based on element count: ```javascript tick((tickValue, element) => { const count = items().length; const sprites = getSprites(element); sprites.forEach((sprite, i) => { // Always animate rotation (cheap) sprite.rotation += items()[i].rotationSpeed; // Animate alpha only below 5000 elements if (count < 5000) { sprite.alpha = 0.5 + Math.sin(tickValue.frame * 0.02) * 0.5; } // Animate scale only below 2000 elements if (count < 2000) { const scale = 1 + Math.sin(tickValue.frame * 0.01) * 0.2; sprite.scale.set(scale); } }); }); ``` ### 6. Viewport Culling Use the `viewportCull` directive to hide off-screen elements: ```html @for (item of items) { } ``` ## Complete Optimized Example ```html @for (item of items) { } ``` ## Performance Checklist - [ ] Minimize signals per element (2-3 max for large collections) - [ ] Use imperative updates in `tick()` for animations - [ ] Implement incremental add/remove for collections - [ ] Add frame throttling for non-critical updates - [ ] Implement LOD for very large element counts - [ ] Enable viewport culling for scrollable worlds - [ ] Profile with browser DevTools to identify bottlenecks ## Benchmark Run the benchmark in `sample/src/benchmark.ce` to test different optimization modes: ```bash cd sample npm run dev ``` Press `1-4` to switch between optimization modes and observe FPS differences. ================================================ FILE: docs/advanced/without-compiler.md ================================================ # Using CanvasEngine Without the Compiler CanvasEngine provides a powerful template syntax that gets compiled to JavaScript functions. However, you can also use CanvasEngine directly without the compiler by using the core functions: `h`, `loop`, and `cond` from the `canvasengine` package. This approach gives you more control and can be useful for: - Dynamic template generation - Integration with existing build systems - Learning how the compiler works under the hood - Performance-critical applications where you want to avoid compilation overhead ## Core Functions ### `h(component, props?, children?)` Creates a component instance. This is the equivalent of JSX elements. ### `loop(iterable, callback)` Renders a list of items. This is the equivalent of `@for` loops. ### `cond(condition, callback)` Conditionally renders content. This is the equivalent of `@if` statements. ## Components ### Basic Component Instead of writing: ```html ``` Use: ```javascript h('Canvas') ``` ### Component with Properties Instead of writing: ```html ``` Use: ```javascript h('Canvas', { width: '800', height: '600' }) ``` ### Dynamic Properties Instead of writing: ```html ``` Use: ```javascript h('Canvas', { width: screenWidth, height: screenHeight }) ``` ### Computed Properties For reactive expressions, instead of writing: ```html ``` Use: ```javascript h('Canvas', { width: computed(() => x() * 2) }) ``` ### Complex Computed Properties For multiple reactive variables: ```html ``` Use: ```javascript h('Canvas', { width: computed(() => x() * 2 * y()) }) ``` ### Object Properties Instead of writing: ```html ``` Use: ```javascript h('Sprite', { sheet: { definition, playing: "stand", params: { direction: "right" }, onFinish } }) ``` ### Array Properties Instead of writing: ```html ``` Use: ```javascript h('Canvas', { positions: computed(() => [x(), 20]) }) ``` ### Event Handlers Instead of writing: ```html ``` Use: ```javascript h('Sprite', { click: handleClick }) ``` ### Inline Event Handlers Instead of writing: ```html console.log('clicked')} /> ``` Use: ```javascript h('Sprite', { click: () => console.log('clicked') }) ``` ### Spread Operator Instead of writing: ```html ``` Use: ```javascript h('Canvas', props) ``` ### Component as Property Instead of writing: ```html } /> ``` Use: ```javascript h('Canvas', { child: h('Sprite') }) ``` ### Function Returning Component Instead of writing: ```html } /> ``` Use: ```javascript h('Canvas', { child: () => h('Sprite') }) ``` ## Children ### Single Child Instead of writing: ```html ``` Use: ```javascript h('Canvas', null, h('Sprite')) ``` ### Multiple Children Instead of writing: ```html ``` Use: ```javascript h('Canvas', null, [ h('Sprite'), h('Text') ]) ``` ## Loops ### Basic Loop Instead of writing: ```html @for (sprite of sprites) { } ``` Use: ```javascript loop(sprites, sprite => h('Sprite')) ``` ### Loop with Properties Instead of writing: ```html @for (sprite of sprites) { } ``` Use: ```javascript loop(sprites, sprite => h('Sprite', { x: sprite.x, y: sprite.y })) ``` ### Loop with Index Instead of writing: ```html @for ((sprite, index) of sprites) { } ``` Use: ```javascript loop(sprites, (sprite, index) => h('Sprite', { key: index })) ``` ### Loop with Object Property Instead of writing: ```html @for (sprite of sprites.items) { } ``` Use: ```javascript loop(sprites.items, sprite => h('Sprite')) ``` ### Loop with Function Call Instead of writing: ```html @for (sprite of getSprites()) { } ``` Use: ```javascript loop(getSprites(), sprite => h('Sprite')) ``` ### Nested Loops Instead of writing: ```html @for (sprite of sprites) { @for (other of others) { } } ``` Use: ```javascript loop(sprites, sprite => loop(others, other => h('Sprite')) ) ``` ### Loop in Component Instead of writing: ```html @for (sprite of sprites) { } ``` Use: ```javascript h('Canvas', null, loop(sprites, sprite => h('Sprite'))) ``` ## Conditions ### Basic Condition Instead of writing: ```html @if (sprite) { } ``` Use: ```javascript cond(sprite, () => h('Sprite')) ``` ### Property-based Condition Instead of writing: ```html @if (sprite.visible) { } ``` Use: ```javascript cond(sprite.visible, () => h('Sprite')) ``` ### Function-based Condition Instead of writing: ```html @if (isVisible()) { } ``` Use: ```javascript cond(isVisible(), () => h('Sprite')) ``` ### Complex Conditions Instead of writing: ```html @if (!sprite && other) { } ``` Use: ```javascript cond(computed(() => !sprite() && other()), () => h('Sprite')) ``` ### Multiple Conditions Instead of writing: ```html @if (sprite) { } @if (other) { } ``` Use: ```javascript [ cond(sprite, () => h('Sprite')), cond(other, () => h('Text')) ] ``` ### Nested Conditions Instead of writing: ```html @if (sprite.visible) { @if (deep) { } } ``` Use: ```javascript cond(sprite.visible, () => cond(deep, () => h('Sprite')) ) ``` ### Condition with Multiple Elements Instead of writing: ```html @if (sprite.visible) { } ``` Use: ```javascript cond(sprite.visible, () => [ h('Sprite'), h('Text') ]) ``` ## Combining Loops and Conditions ### Condition in Loop Instead of writing: ```html @for (sprite of sprites) { @if (sprite.visible) { } } ``` Use: ```javascript h('Canvas', null, loop(sprites, sprite => cond(sprite.visible, () => h('Sprite')) ) ) ``` ### Multiple Loops Instead of writing: ```html @for (sprite of sprites) { } @for (other of others) { } ``` Use: ```javascript h('Canvas', null, [ loop(sprites, sprite => h('Sprite')), loop(others, other => h('Text')) ]) ``` ## Complete Example Here's a complete example showing how to build a complex component without the compiler: ```javascript import { h, loop, cond, computed } from 'canvasengine'; function GameScene({ sprites, enemies, showUI }) { return h('Canvas', { width: 800, height: 600 }, [ // Background h('Sprite', { texture: 'background' }), // Player sprites loop(sprites, sprite => cond(sprite.visible, () => h('Sprite', { x: sprite.x, y: sprite.y, texture: sprite.texture, click: () => sprite.onClick() }) ) ), // Enemies loop(enemies, (enemy, index) => h('Sprite', { key: index, x: computed(() => enemy.x() + 10), y: computed(() => enemy.y() + 10), texture: enemy.texture, tint: enemy.isHit ? 0xff0000 : 0xffffff }) ), // UI overlay cond(showUI, () => h('Container', null, [ h('Text', { text: 'Score: 100', x: 10, y: 10 }), h('Text', { text: 'Lives: 3', x: 10, y: 30 }) ]) ) ]); } ``` This approach gives you the full power of CanvasEngine while maintaining complete control over your component structure and logic. ================================================ FILE: docs/api/context.md ================================================ # Context The context is an object that is automatically provided to all components in the component tree. It contains shared resources and utilities that are available throughout your application. ## Available Properties The context object contains the following properties: | Name | Type | Description | |------|------|-------------| | `app` | `() => Application \| null` | Function that returns the PixiJS Application instance. Returns `null` until the canvas is rendered. | | `canvasSize` | `Signal<{ width: number, height: number }>` | Signal containing the current width and height of the canvas. Updates automatically when the canvas is resized. | | `globalLoader` | `GlobalAssetLoader` | Global asset loader instance that tracks loading progress of all assets across the component tree. See [GlobalAssetLoader documentation](/components/sprite.html#global-asset-loader) for more details. | | `tick` | `Signal` | Signal containing the ticker information. Updates on each frame with timing and frame data. See [Tick interface](#tick-interface) below. | | `rootElement` | `Element` | The root Canvas element. See [Element documentation](./element.md) for more details. | ## Tick Interface The `tick` signal contains the following properties: | Property | Type | Description | |----------|------|-------------| | `timestamp` | `number` | Current timestamp in milliseconds | | `deltaTime` | `number` | Time elapsed since the last frame in milliseconds | | `frame` | `number` | Current frame number | | `deltaRatio` | `number` | Ratio of deltaTime to the target frame time (useful for frame-independent animations) | ## Accessing Context You can access the context through the `element.props.context` property in any component: ```html ``` ## Examples ### Using Canvas Size for Responsive Layouts ```html ``` ### Tracking Asset Loading Progress ```html ``` ### Using Tick for Frame-Independent Animations ```html ``` ### Accessing PixiJS Application ```html ``` ================================================ FILE: docs/api/element.md ================================================ # Element Interface The Element interface represents a component in the framework. It contains all the necessary properties and methods to manage a component's lifecycle, props, effects, and relationships. ## Properties and Methods | Name | Type | Description | |------|------|-------------| | `tag` | `string` | The HTML tag name or component name | | `props` | `Props` | The component's properties/attributes | | `componentInstance` | `T` | The instance of the component. It is the PixiJS instance | | `propObservables` | `NestedSignalObjects \| undefined` | Observable objects for reactive properties | | `parent` | `Element \| null` | Reference to the parent element. Null if it's a root element | | `context` | `{ [key: string]: any }` | Optional context object for sharing data between components | | `directives` | `{ [key: string]: Directive }` | Map of directives applied to the element | | `destroy` | `() => void` | Cleanup method called when the element is being destroyed | | `isFrozen` | `boolean` | Indicates whether the element is currently frozen (read-only) ## Examples ### Get the tag name ```html ``` ### Get the children components: ```html ``` ### Get context ```html ``` ### Get the reactive props ```html ``` ### Get directives You can access directive instances through the `directives` property. Each directive is stored with its attribute name as the key. ```html ``` ## Freeze System The `freeze` prop allows you to completely freeze an element, preventing all updates, controls, and events. When an element is frozen: - **Reactive updates are blocked**: No `onUpdate` calls are made when signal values change - **Controls are blocked**: All input controls (keyboard, gamepad, joystick) are stopped - **Events are blocked**: Event handlers (click, mousedown, etc.) are not executed The `freeze` prop accepts either a `boolean` or `Signal`, allowing you to toggle the freeze state dynamically. ### Basic Usage ```html ``` ### Example: Dynamic Freeze ```html y.set(y() - 10) } }} click={() => { console.log('Sprite clicked!') }} /> ``` ### Example: Blocking Updates When frozen, reactive property updates are completely blocked: ```html ``` ### Example: Blocking Controls When frozen, all controls are automatically stopped: ```html { console.log('Moving...'); // Won't execute when frozen } } }} /> ``` ### Example: Blocking Events When frozen, event handlers are not executed: ```html { console.log('Clicked!'); // Won't execute when frozen }} mousedown={() => { console.log('Mouse down!'); // Won't execute when frozen }} /> ``` ### Checking Freeze State You can check if an element is frozen using the `isElementFrozen` helper function: ```html ``` Or access the `isFrozen` property directly: ```html ``` ================================================ FILE: docs/api/testing.md ================================================ # Testing Package The `@canvasengine/testing` package provides comprehensive testing utilities and mocks for CanvasEngine. It allows you to test your CanvasEngine components without requiring a full PixiJS environment or jsdom setup. ## Installation ```bash npm install @canvasengine/testing --save-dev ``` or with pnpm: ```bash pnpm add @canvasengine/testing --save-dev ``` ## Overview The testing package includes: - **PixiJS Mocks**: Complete mocks for all PixiJS classes used in CanvasEngine (Container, Sprite, Text, Application, etc.) - **Element Helpers**: Utilities to create mock elements with spyable `componentInstance` - **Spy Utilities**: Helpers to easily spy on element properties and methods ## PixiJS Mocks The package provides mocks for all major PixiJS classes: - `MockContainer` - Mock for PixiJS Container - `MockSprite` - Mock for PixiJS Sprite - `MockText` - Mock for PixiJS Text - `MockGraphics` - Mock for PixiJS Graphics - `MockMesh` - Mock for PixiJS Mesh - `MockTilingSprite` - Mock for PixiJS TilingSprite - `MockNineSlicePlane` - Mock for PixiJS NineSlicePlane - `MockDOMElement` - Mock for PixiJS DOMElement - `MockDOMContainer` - Mock for PixiJS DOMContainer - `MockApplication` - Mock for PixiJS Application - `MockTexture` - Mock for PixiJS Texture - `MockRectangle` - Mock for PixiJS Rectangle - `MockObservablePoint` - Mock for PixiJS ObservablePoint - `MockVideoResource` - Mock for PixiJS VideoResource All mocks include: - Essential properties (x, y, width, height, alpha, visible, rotation, etc.) - Methods mocked with `vi.fn()` for easy spying - Event support (on, off, emit) - Child management for Container-based mocks ### Using PixiJS Mocks ```typescript import { MockContainer, MockSprite } from '@canvasengine/testing'; // Create a mock container const container = new MockContainer(); container.x = 100; container.y = 50; container.width = 200; container.height = 150; // Create a mock sprite const sprite = new MockSprite(); sprite.x = 10; sprite.y = 10; // Add sprite to container container.addChild(sprite); // Spy on methods import { vi } from 'vitest'; const addChildSpy = vi.spyOn(container, 'addChild'); container.addChild(new MockContainer()); expect(addChildSpy).toHaveBeenCalled(); ``` ## Creating Mock Elements The `createMockElement` helper creates a complete mock Element with all required properties. ### Basic Usage ```typescript import { createMockElement } from '@canvasengine/testing'; // Create a basic element with default mock const element = createMockElement('Container', { x: 100, y: 50 }); expect(element.tag).toBe('Container'); expect(element.props.x).toBe(100); expect(element.componentInstance.x).toBe(100); ``` ### With Custom ComponentInstance ```typescript import { createMockElement, MockSprite } from '@canvasengine/testing'; // Create an element with custom componentInstance const customInstance = new MockSprite(); const spriteElement = createMockElement('Sprite', { image: 'hero.png', x: 200, y: 100 }, customInstance); expect(spriteElement.componentInstance).toBe(customInstance); expect(spriteElement.componentInstance.x).toBe(200); ``` ### Accessing componentInstance The `componentInstance` property contains the mock PixiJS instance, which you can spy upon: ```typescript import { createMockElement } from '@canvasengine/testing'; import { vi } from 'vitest'; const element = createMockElement('Container', { x: 100 }); // Access the componentInstance const instance = element.componentInstance; expect(instance.x).toBe(100); // Spy on properties or methods const xSpy = vi.spyOn(instance, 'x', 'get'); const addChildSpy = vi.spyOn(instance, 'addChild'); ``` ## Spying on Elements The `spyOnElement` helper makes it easy to spy on element properties and methods. ### Spying on a Single Property ```typescript import { createMockElement, spyOnElement } from '@canvasengine/testing'; const element = createMockElement('Container', { x: 100 }); // Spy on a property const spy = spyOnElement(element, 'x'); element.componentInstance.x = 200; // Note: For property setters, you may need to use vi.spyOn directly // depending on your testing needs ``` ### Spying on Methods ```typescript import { createMockElement, spyOnElement } from '@canvasengine/testing'; const element = createMockElement('Container'); // Spy on a method const addChildSpy = spyOnElement(element, 'addChild'); element.componentInstance.addChild(new MockContainer()); expect(addChildSpy).toHaveBeenCalled(); ``` ### Spying on Multiple Properties ```typescript import { createMockElement, spyOnElementMultiple } from '@canvasengine/testing'; const element = createMockElement('Container'); // Spy on multiple methods at once const spies = spyOnElementMultiple(element, ['addChild', 'removeChild', 'destroy']); element.componentInstance.addChild(new MockContainer()); element.componentInstance.removeChild(element.componentInstance.children[0]); element.componentInstance.destroy(); expect(spies.addChild).toHaveBeenCalled(); expect(spies.removeChild).toHaveBeenCalled(); expect(spies.destroy).toHaveBeenCalled(); ``` ## Creating Mock Component Instances The `createMockComponentInstance` helper creates appropriate mock instances based on component type: ```typescript import { createMockComponentInstance } from '@canvasengine/testing'; const containerInstance = createMockComponentInstance('Container'); const spriteInstance = createMockComponentInstance('Sprite'); const textInstance = createMockComponentInstance('Text'); ``` ## Common Use Cases ### Testing Component Logic ```typescript import { describe, test, expect, vi } from 'vitest'; import { createMockElement, spyOnElement } from '@canvasengine/testing'; describe('MyComponent', () => { test('should update position', () => { const element = createMockElement('Container', { x: 0, y: 0 }); // Your component logic that updates position element.componentInstance.x = 100; element.componentInstance.y = 50; expect(element.componentInstance.x).toBe(100); expect(element.componentInstance.y).toBe(50); }); test('should add children', () => { const parent = createMockElement('Container'); const child = createMockElement('Sprite'); const addChildSpy = spyOnElement(parent, 'addChild'); parent.componentInstance.addChild(child.componentInstance); expect(addChildSpy).toHaveBeenCalledWith(child.componentInstance); expect(parent.componentInstance.children).toContain(child.componentInstance); }); }); ``` ### Testing Directives ```typescript import { describe, test, expect } from 'vitest'; import { createMockElement } from '@canvasengine/testing'; describe('MyDirective', () => { test('should apply directive to element', () => { const element = createMockElement('Sprite', { x: 100, y: 100 }); // Apply your directive // directive.onInit(element); // Test directive behavior // expect(element.directives.myDirective).toBeDefined(); }); }); ``` ### Testing Event Handlers ```typescript import { describe, test, expect } from 'vitest'; import { createMockElement } from '@canvasengine/testing'; describe('Event Handling', () => { test('should handle click events', () => { const element = createMockElement('Sprite'); const clickHandler = vi.fn(); element.componentInstance.on('click', clickHandler); element.componentInstance.emit('click', { x: 100, y: 100 }); expect(clickHandler).toHaveBeenCalledWith({ x: 100, y: 100 }); }); }); ``` ## Migration from Manual Mocks If you're currently creating manual mocks in your tests, you can migrate to use `@canvasengine/testing`: ### Before ```typescript // Manual mock class MockContainer { x = 0; y = 0; children = []; addChild() {} } const element = { tag: 'Container', props: { x: 100 }, componentInstance: new MockContainer(), // ... other properties }; ``` ### After ```typescript import { createMockElement } from '@canvasengine/testing'; const element = createMockElement('Container', { x: 100 }); // All properties are automatically set up ``` ## Best Practices 1. **Use createMockElement for Elements**: Always use `createMockElement` when you need an Element in tests. It ensures all required properties are present. 2. **Spy on componentInstance**: Use `spyOnElement` to spy on the PixiJS instance methods and properties. 3. **Use Appropriate Mocks**: Use the specific mock class (MockSprite, MockText, etc.) when you need a particular PixiJS class. 4. **Test Behavior, Not Implementation**: Focus on testing the behavior of your components rather than internal PixiJS implementation details. 5. **Clean Up**: The mocks are lightweight and don't require cleanup, but if you're using spies, remember to clear them between tests if needed. ## TypeScript Support The package is fully typed and provides TypeScript definitions for all mocks and helpers. You'll get full autocomplete and type checking in your tests. ```typescript import { createMockElement, Element, ComponentInstance } from '@canvasengine/testing'; const element: Element = createMockElement('Container'); ``` ## Using Mocks with bootstrapCanvas The `bootstrapCanvas` function supports component registration configuration, allowing you to use mocks for testing. ### mockComponents The `mockComponents` object provides a mapping of all CanvasEngine component names to their corresponding mock classes. You can import it from `@canvasengine/testing`: ```typescript import { mockComponents } from '@canvasengine/testing'; ``` ### Registering All Mocks To register all components as mocks: ```typescript import { bootstrapCanvas } from 'canvasengine'; import { mockComponents } from '@canvasengine/testing'; await bootstrapCanvas(rootElement, MyComponent, { components: mockComponents, autoRegister: false // Only register the specified (mocked) components }); ``` ### Registering Specific Mocks To register only specific components as mocks while keeping others as real components: ```typescript import { bootstrapCanvas } from 'canvasengine'; import { MockSprite, MockContainer, mockComponents } from '@canvasengine/testing'; await bootstrapCanvas(rootElement, MyComponent, { components: { Sprite: MockSprite, Container: MockContainer, // Other components will be registered normally }, autoRegister: true // Register all default components, then override with mocks }); ``` ### Overriding Specific Components To register all default components but override specific ones with mocks: ```typescript import { bootstrapCanvas } from 'canvasengine'; import { MockSprite } from '@canvasengine/testing'; await bootstrapCanvas(rootElement, MyComponent, { components: { Sprite: MockSprite // Replace Sprite with mock, keep others as real }, autoRegister: true // Register all default components first }); ``` ### Available Mock Components The `mockComponents` object includes mappings for: - `Canvas` → `MockContainer` - `Container` → `MockContainer` - `Sprite` → `MockSprite` - `Text` → `MockText` - `Graphics`, `Rect`, `Circle`, `Ellipse`, `Triangle`, `Svg` → `MockGraphics` - `Mesh` → `MockMesh` - `TilingSprite` → `MockTilingSprite` - `NineSliceSprite` → `MockNineSlicePlane` - `DOMContainer` → `MockDOMContainer` - `DOMElement` → `MockDOMElement` - `Viewport` → `MockContainer` - `ParticlesEmitter` → `MockContainer` You can access individual mocks directly: ```typescript import { MockContainer, MockSprite, MockText, MockGraphics, MockMesh, MockTilingSprite, MockNineSlicePlane, MockDOMElement, MockDOMContainer, mockComponents } from '@canvasengine/testing'; ``` ## API Reference ### mockComponents ```typescript const mockComponents: { readonly Canvas: typeof MockContainer; readonly Container: typeof MockContainer; readonly Sprite: typeof MockSprite; readonly Text: typeof MockText; readonly Graphics: typeof MockGraphics; readonly Rect: typeof MockGraphics; readonly Circle: typeof MockGraphics; readonly Ellipse: typeof MockGraphics; readonly Triangle: typeof MockGraphics; readonly Svg: typeof MockGraphics; readonly Mesh: typeof MockMesh; readonly TilingSprite: typeof MockTilingSprite; readonly NineSliceSprite: typeof MockNineSlicePlane; readonly DOMContainer: typeof MockDOMContainer; readonly DOMElement: typeof MockDOMElement; readonly Viewport: typeof MockContainer; readonly ParticlesEmitter: typeof MockContainer; } ``` Mapping of CanvasEngine component names to their corresponding mock classes. Can be used directly with `bootstrapCanvas()`. ### createMockElement ```typescript function createMockElement( tag: string, props?: Props, componentInstance?: T ): Element ``` Creates a mock Element with all required properties. ### createMockComponentInstance ```typescript function createMockComponentInstance(componentType: string): ComponentInstance ``` Creates a mock ComponentInstance based on the component type. ### spyOnElement ```typescript function spyOnElement( element: Element, property: keyof T | string ): ReturnType ``` Creates a spy on a property or method of an element's componentInstance. ### spyOnElementMultiple ```typescript function spyOnElementMultiple( element: Element, properties: (keyof T | string)[] ): Record> ``` Creates spies on multiple properties or methods at once. ================================================ FILE: docs/components/_display-object.md ================================================ ## Common Properties | Property | Type | Description | |----------------|---------------------|-----------------------------------------------------------------------------| | x | number | X-coordinate position of the display object. | | y | number | Y-coordinate position of the display object. | | width | number | Width of the display object. | | height | number | Height of the display object. | | scale | object | Scale of the display object. | | anchor | object | Anchor point of the display object. | | skew | object | Skew of the display object. | | tint | number | Tint color of the display object. | | rotation | number | Rotation of the display object in radians. | | angle | number | Rotation of the display object in degrees. | | zIndex | number | Z-index of the display object. | | roundPixels | boolean | Whether to round pixel values. | | cursor | string | Cursor style when hovering over the display object. | | visible | boolean | Visibility of the display object. | | alpha | number | Alpha transparency of the display object. | | pivot | object | Pivot point of the display object. | | filters | array | Filters applied to the display object. | | maskOf | Element | Element that this display object masks. | | blendMode | string | Blend mode for rendering. | | filterArea | object | Filter area for rendering. | ## Layout Properties Pour obtenir la documentation complète et détaillée sur toutes les propriétés de mise en page, consultez la documentation officielle de [PixiJS Layout](https://layout.pixijs.io/). ### Sizing and Dimensions | Property | Type | Description | |----------------|---------------------|-----------------------------------------------------------------------------| | width | number/string | Width of the display object. Accepts pixels or percentage (e.g. '50%'). | | height | number/string | Height of the display object. Accepts pixels or percentage (e.g. '50%'). | | minWidth | number/string | Minimum width the object can shrink to. | | minHeight | number/string | Minimum height the object can shrink to. | | maxWidth | number/string | Maximum width the object can expand to. | | maxHeight | number/string | Maximum height the object can expand to. | | aspectRatio | number | Ratio between width and height (e.g. 1.5 for 3:2 ratio). | ### Flex Layout | Property | Type | Description | |----------------|---------------------|-----------------------------------------------------------------------------| | flexDirection | string | Direction of flex items. Values: 'row', 'column', 'row-reverse', 'column-reverse'. | | flexWrap | string | Whether items wrap. Values: 'wrap', 'nowrap', 'wrap-reverse'. | | justifyContent | string | Alignment along main axis. Values: 'flex-start', 'flex-end', 'center', 'space-between', 'space-around'. | | alignItems | string | Alignment along cross axis. Values: 'flex-start', 'flex-end', 'center', 'stretch', 'baseline'. | | alignContent | string | Alignment of lines with multiple items. Values: 'flex-start', 'flex-end', 'center', 'stretch', 'space-between', 'space-around'. | | alignSelf | string | Override of parent's alignItems for specific item. | | flexGrow | number | Grow factor of item relative to other items. | | flexShrink | number | Shrink factor of item relative to other items. | | flexBasis | number/string | Initial size of item before flex growing/shrinking. | | gap | number/object | Gap between items. | | rowGap | number | Gap between rows. | | columnGap | number | Gap between columns. | ### Positioning | Property | Type | Description | |----------------|---------------------|-----------------------------------------------------------------------------| | positionType | string | Type of positioning. Values: 'relative', 'absolute', 'static'. | | top | number/string | Distance from the top edge. | | right | number/string | Distance from the right edge. | | bottom | number/string | Distance from the bottom edge. | | left | number/string | Distance from the left edge. | ### Spacing, Margins and Borders | Property | Type | Description | |----------------|---------------------|-----------------------------------------------------------------------------| | margin | number/array | Space outside border box. Can be single value or array for different sides. | | padding | number/array | Space inside border box. Can be single value or array for different sides. | | border | number/array | Border width. Can be single value or array for different sides. | ### Object Fitting and Alignment | Property | Type | Description | |----------------|---------------------|-----------------------------------------------------------------------------| | objectFit | string | How object is resized to fit layout box. Values: 'contain', 'cover', 'fill', 'none', 'scale-down'. | | objectPosition | string | Anchor point of object inside layout box. E.g. 'center', 'top left'. | | transformOrigin| string | Pivot point for rotation and scaling of layout box. | ## Shadow | Property | Type | Description | |----------------|---------------------|-----------------------------------------------------------------------------| | blur | number | Blur strength. | | color | number | Color of the shadow. | | offset | object | Offset of the shadow. | | quality | number | Quality of the shadow. | # Hook before destroy ```html @if (bool) { } ``` ================================================ FILE: docs/components/button.md ================================================ # Button The Button component provides an interactive button with visual feedback for different states (normal, hover, pressed, disabled). It supports both sprite-based and graphics-based rendering approaches. ## Basic Usage ```html ``` ### Button with Multiple Elements ```html ``` When `children` are provided, they take priority over the `text` property. ## Custom Background You can provide a custom background component: ```html ``` ``` ## TypeScript Types ```typescript interface ButtonStyle { backgroundColor?: { normal?: string; hover?: string; pressed?: string; disabled?: string; }; border?: { color?: string; width?: number; radius?: number; }; text?: { color?: string; fontSize?: number; fontFamily?: string; }; textures?: { normal?: string; hover?: string; pressed?: string; disabled?: string; }; } interface ButtonProps { text?: string; disabled?: boolean; click?: (event: FederatedPointerEvent) => void; hoverEnter?: (event: FederatedPointerEvent) => void; hoverLeave?: (event: FederatedPointerEvent) => void; pressDown?: (event: FederatedPointerEvent) => void; pressUp?: (event: FederatedPointerEvent) => void; style?: ButtonStyle; width?: number; height?: number; x?: number; y?: number; alpha?: number; visible?: boolean; cursor?: string; controls?: ControlsDirective | JoystickControls; controlName?: string; shape?: 'rect' | 'circle' | 'ellipse'; background?: Element | ComponentFunction; children?: Element[]; } ``` ================================================ FILE: docs/components/canvas.md ================================================ # Use Canvas component It's the starting point for all the other components. Common example: ```html ``` ### options You can use all properties from [PixiJS Canvas Renderer](https://pixijs.download/release/docs/rendering.html#autoDetectRenderer) ================================================ FILE: docs/components/container.md ================================================ # Use Container component Common example: ```html ``` Example with x and y: ```html ``` ================================================ FILE: docs/components/dom-container.md ================================================ # DOMContainer Component The `DOMContainer` component provides a bridge between the canvas rendering system and traditional DOM manipulation. It allows you to render standard DOM elements within your canvas application while maintaining proper transform hierarchy and visibility. This component is especially useful for rendering form elements like ``, `