@guinetik/gcanvas 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/release.yaml +70 -0
- package/.jshintrc +4 -0
- package/.vscode/settings.json +22 -0
- package/CLAUDE.md +310 -0
- package/blackhole.jpg +0 -0
- package/demo.png +0 -0
- package/demos/CNAME +1 -0
- package/demos/animations.html +31 -0
- package/demos/basic.html +38 -0
- package/demos/baskara.html +31 -0
- package/demos/bezier.html +35 -0
- package/demos/beziersignature.html +29 -0
- package/demos/blackhole.html +28 -0
- package/demos/blob.html +35 -0
- package/demos/demos.css +289 -0
- package/demos/easing.html +28 -0
- package/demos/events.html +195 -0
- package/demos/fluent.html +647 -0
- package/demos/fractals.html +36 -0
- package/demos/genart.html +26 -0
- package/demos/gendream.html +26 -0
- package/demos/group.html +36 -0
- package/demos/home.html +587 -0
- package/demos/index.html +364 -0
- package/demos/isometric.html +34 -0
- package/demos/js/animations.js +452 -0
- package/demos/js/basic.js +204 -0
- package/demos/js/baskara.js +751 -0
- package/demos/js/bezier.js +692 -0
- package/demos/js/beziersignature.js +241 -0
- package/demos/js/blackhole/accretiondisk.obj.js +379 -0
- package/demos/js/blackhole/blackhole.obj.js +318 -0
- package/demos/js/blackhole/index.js +409 -0
- package/demos/js/blackhole/particle.js +56 -0
- package/demos/js/blackhole/starfield.obj.js +218 -0
- package/demos/js/blob.js +2263 -0
- package/demos/js/easing.js +477 -0
- package/demos/js/fluent.js +183 -0
- package/demos/js/fractals.js +931 -0
- package/demos/js/fractalworker.js +93 -0
- package/demos/js/genart.js +268 -0
- package/demos/js/gendream.js +209 -0
- package/demos/js/group.js +140 -0
- package/demos/js/info-toggle.js +25 -0
- package/demos/js/isometric.js +863 -0
- package/demos/js/kerr.js +1556 -0
- package/demos/js/lavalamp.js +590 -0
- package/demos/js/layout.js +354 -0
- package/demos/js/mondrian.js +285 -0
- package/demos/js/opacity.js +275 -0
- package/demos/js/painter.js +484 -0
- package/demos/js/particles-showcase.js +514 -0
- package/demos/js/particles.js +299 -0
- package/demos/js/patterns.js +397 -0
- package/demos/js/penrose/artifact.js +69 -0
- package/demos/js/penrose/blackhole.js +121 -0
- package/demos/js/penrose/constants.js +73 -0
- package/demos/js/penrose/game.js +943 -0
- package/demos/js/penrose/lore.js +278 -0
- package/demos/js/penrose/penrosescene.js +892 -0
- package/demos/js/penrose/ship.js +216 -0
- package/demos/js/penrose/sounds.js +211 -0
- package/demos/js/penrose/voidparticle.js +55 -0
- package/demos/js/penrose/voidscene.js +258 -0
- package/demos/js/penrose/voidship.js +144 -0
- package/demos/js/penrose/wormhole.js +46 -0
- package/demos/js/pipeline.js +555 -0
- package/demos/js/scene.js +304 -0
- package/demos/js/scenes.js +320 -0
- package/demos/js/schrodinger.js +410 -0
- package/demos/js/schwarzschild.js +1023 -0
- package/demos/js/shapes.js +628 -0
- package/demos/js/space/alien.js +171 -0
- package/demos/js/space/boom.js +98 -0
- package/demos/js/space/boss.js +353 -0
- package/demos/js/space/buff.js +73 -0
- package/demos/js/space/bullet.js +102 -0
- package/demos/js/space/constants.js +85 -0
- package/demos/js/space/game.js +1884 -0
- package/demos/js/space/hud.js +112 -0
- package/demos/js/space/laserbeam.js +179 -0
- package/demos/js/space/lightning.js +277 -0
- package/demos/js/space/minion.js +192 -0
- package/demos/js/space/missile.js +212 -0
- package/demos/js/space/player.js +430 -0
- package/demos/js/space/powerup.js +90 -0
- package/demos/js/space/starfield.js +58 -0
- package/demos/js/space/starpower.js +90 -0
- package/demos/js/spacetime.js +559 -0
- package/demos/js/svgtween.js +204 -0
- package/demos/js/tde/accretiondisk.js +418 -0
- package/demos/js/tde/blackhole.js +219 -0
- package/demos/js/tde/blackholescene.js +209 -0
- package/demos/js/tde/config.js +59 -0
- package/demos/js/tde/index.js +695 -0
- package/demos/js/tde/jets.js +290 -0
- package/demos/js/tde/lensedstarfield.js +147 -0
- package/demos/js/tde/tdestar.js +317 -0
- package/demos/js/tde/tidalstream.js +356 -0
- package/demos/js/tde_old/blackhole.obj.js +354 -0
- package/demos/js/tde_old/debris.obj.js +791 -0
- package/demos/js/tde_old/flare.obj.js +239 -0
- package/demos/js/tde_old/index.js +448 -0
- package/demos/js/tde_old/star.obj.js +812 -0
- package/demos/js/tiles.js +312 -0
- package/demos/js/tweendemo.js +79 -0
- package/demos/js/visibility.js +102 -0
- package/demos/kerr.html +28 -0
- package/demos/lavalamp.html +27 -0
- package/demos/layouts.html +37 -0
- package/demos/logo.svg +4 -0
- package/demos/loop.html +84 -0
- package/demos/mondrian.html +32 -0
- package/demos/og_image.png +0 -0
- package/demos/opacity.html +36 -0
- package/demos/painter.html +39 -0
- package/demos/particles-showcase.html +28 -0
- package/demos/particles.html +24 -0
- package/demos/patterns.html +33 -0
- package/demos/penrose-game.html +31 -0
- package/demos/pipeline.html +737 -0
- package/demos/scene.html +33 -0
- package/demos/scenes.html +96 -0
- package/demos/schrodinger.html +27 -0
- package/demos/schwarzschild.html +27 -0
- package/demos/shapes.html +16 -0
- package/demos/space.html +85 -0
- package/demos/spacetime.html +27 -0
- package/demos/svgtween.html +29 -0
- package/demos/tde.html +28 -0
- package/demos/tiles.html +28 -0
- package/demos/transforms.html +400 -0
- package/demos/tween.html +45 -0
- package/demos/visibility.html +33 -0
- package/disk_example.png +0 -0
- package/docs/README.md +222 -0
- package/docs/concepts/architecture-overview.md +204 -0
- package/docs/concepts/lifecycle.md +255 -0
- package/docs/concepts/rendering-pipeline.md +279 -0
- package/docs/concepts/tde-zorder.md +106 -0
- package/docs/concepts/two-layer-architecture.md +229 -0
- package/docs/getting-started/first-game.md +354 -0
- package/docs/getting-started/hello-world.md +269 -0
- package/docs/getting-started/installation.md +157 -0
- package/docs/modules/collision/README.md +453 -0
- package/docs/modules/fluent/README.md +1075 -0
- package/docs/modules/game/README.md +303 -0
- package/docs/modules/isometric-camera.md +210 -0
- package/docs/modules/isometric.md +275 -0
- package/docs/modules/painter/README.md +328 -0
- package/docs/modules/particle/README.md +559 -0
- package/docs/modules/shapes/README.md +221 -0
- package/docs/modules/shapes/base/euclidian.md +123 -0
- package/docs/modules/shapes/base/geometry2d.md +204 -0
- package/docs/modules/shapes/base/renderable.md +215 -0
- package/docs/modules/shapes/base/shape.md +262 -0
- package/docs/modules/shapes/base/transformable.md +243 -0
- package/docs/modules/shapes/hierarchy.md +218 -0
- package/docs/modules/state/README.md +577 -0
- package/docs/modules/util/README.md +99 -0
- package/docs/modules/util/camera3d.md +412 -0
- package/docs/modules/util/scene3d.md +395 -0
- package/index.html +17 -0
- package/jsdoc.json +50 -0
- package/package.json +55 -0
- package/readme.md +599 -0
- package/scripts/build-demo.js +69 -0
- package/scripts/bundle4llm.js +276 -0
- package/scripts/clearconsole.js +48 -0
- package/src/collision/collision-system.js +332 -0
- package/src/collision/collision.js +303 -0
- package/src/collision/index.js +10 -0
- package/src/fluent/fluent-game.js +430 -0
- package/src/fluent/fluent-go.js +1060 -0
- package/src/fluent/fluent-layer.js +152 -0
- package/src/fluent/fluent-scene.js +291 -0
- package/src/fluent/index.js +98 -0
- package/src/fluent/sketch.js +380 -0
- package/src/game/game.js +467 -0
- package/src/game/index.js +49 -0
- package/src/game/objects/go.js +220 -0
- package/src/game/objects/imagego.js +30 -0
- package/src/game/objects/index.js +54 -0
- package/src/game/objects/isometric-scene.js +260 -0
- package/src/game/objects/layoutscene.js +549 -0
- package/src/game/objects/scene.js +175 -0
- package/src/game/objects/scene3d.js +118 -0
- package/src/game/objects/text.js +221 -0
- package/src/game/objects/wrapper.js +232 -0
- package/src/game/pipeline.js +243 -0
- package/src/game/ui/button.js +396 -0
- package/src/game/ui/cursor.js +93 -0
- package/src/game/ui/fps.js +91 -0
- package/src/game/ui/index.js +5 -0
- package/src/game/ui/togglebutton.js +93 -0
- package/src/game/ui/tooltip.js +249 -0
- package/src/index.js +25 -0
- package/src/io/events.js +20 -0
- package/src/io/index.js +86 -0
- package/src/io/input.js +70 -0
- package/src/io/keys.js +152 -0
- package/src/io/mouse.js +61 -0
- package/src/io/touch.js +39 -0
- package/src/logger/debugtab.js +138 -0
- package/src/logger/index.js +3 -0
- package/src/logger/loggable.js +47 -0
- package/src/logger/logger.js +113 -0
- package/src/math/complex.js +37 -0
- package/src/math/constants.js +1 -0
- package/src/math/fractal.js +1271 -0
- package/src/math/gr.js +201 -0
- package/src/math/heat.js +202 -0
- package/src/math/index.js +12 -0
- package/src/math/noise.js +433 -0
- package/src/math/orbital.js +191 -0
- package/src/math/patterns.js +1339 -0
- package/src/math/penrose.js +259 -0
- package/src/math/quantum.js +115 -0
- package/src/math/random.js +195 -0
- package/src/math/tensor.js +1009 -0
- package/src/mixins/anchor.js +131 -0
- package/src/mixins/draggable.js +72 -0
- package/src/mixins/index.js +2 -0
- package/src/motion/bezier.js +132 -0
- package/src/motion/bounce.js +58 -0
- package/src/motion/easing.js +349 -0
- package/src/motion/float.js +130 -0
- package/src/motion/follow.js +125 -0
- package/src/motion/hop.js +52 -0
- package/src/motion/index.js +82 -0
- package/src/motion/motion.js +1124 -0
- package/src/motion/orbit.js +49 -0
- package/src/motion/oscillate.js +39 -0
- package/src/motion/parabolic.js +141 -0
- package/src/motion/patrol.js +147 -0
- package/src/motion/pendulum.js +48 -0
- package/src/motion/pulse.js +88 -0
- package/src/motion/shake.js +83 -0
- package/src/motion/spiral.js +144 -0
- package/src/motion/spring.js +150 -0
- package/src/motion/swing.js +47 -0
- package/src/motion/tween.js +92 -0
- package/src/motion/tweenetik.js +139 -0
- package/src/motion/waypoint.js +210 -0
- package/src/painter/index.js +8 -0
- package/src/painter/painter.colors.js +331 -0
- package/src/painter/painter.effects.js +230 -0
- package/src/painter/painter.img.js +229 -0
- package/src/painter/painter.js +295 -0
- package/src/painter/painter.lines.js +189 -0
- package/src/painter/painter.opacity.js +41 -0
- package/src/painter/painter.shapes.js +277 -0
- package/src/painter/painter.text.js +273 -0
- package/src/particle/emitter.js +124 -0
- package/src/particle/index.js +11 -0
- package/src/particle/particle-system.js +322 -0
- package/src/particle/particle.js +71 -0
- package/src/particle/updaters.js +170 -0
- package/src/shapes/arc.js +43 -0
- package/src/shapes/arrow.js +33 -0
- package/src/shapes/bezier.js +42 -0
- package/src/shapes/circle.js +62 -0
- package/src/shapes/clouds.js +56 -0
- package/src/shapes/cone.js +219 -0
- package/src/shapes/cross.js +70 -0
- package/src/shapes/cube.js +244 -0
- package/src/shapes/cylinder.js +254 -0
- package/src/shapes/diamond.js +48 -0
- package/src/shapes/euclidian.js +111 -0
- package/src/shapes/figure.js +115 -0
- package/src/shapes/geometry.js +220 -0
- package/src/shapes/group.js +375 -0
- package/src/shapes/heart.js +42 -0
- package/src/shapes/hexagon.js +26 -0
- package/src/shapes/image.js +192 -0
- package/src/shapes/index.js +111 -0
- package/src/shapes/line.js +29 -0
- package/src/shapes/pattern.js +90 -0
- package/src/shapes/pin.js +44 -0
- package/src/shapes/poly.js +31 -0
- package/src/shapes/prism.js +226 -0
- package/src/shapes/rect.js +35 -0
- package/src/shapes/renderable.js +333 -0
- package/src/shapes/ring.js +26 -0
- package/src/shapes/roundrect.js +95 -0
- package/src/shapes/shape.js +117 -0
- package/src/shapes/slice.js +26 -0
- package/src/shapes/sphere.js +314 -0
- package/src/shapes/sphere3d.js +537 -0
- package/src/shapes/square.js +15 -0
- package/src/shapes/star.js +99 -0
- package/src/shapes/svg.js +408 -0
- package/src/shapes/text.js +553 -0
- package/src/shapes/traceable.js +83 -0
- package/src/shapes/transform.js +357 -0
- package/src/shapes/transformable.js +172 -0
- package/src/shapes/triangle.js +26 -0
- package/src/sound/index.js +17 -0
- package/src/sound/sound.js +473 -0
- package/src/sound/synth.analyzer.js +149 -0
- package/src/sound/synth.effects.js +207 -0
- package/src/sound/synth.envelope.js +59 -0
- package/src/sound/synth.js +229 -0
- package/src/sound/synth.musical.js +160 -0
- package/src/sound/synth.noise.js +85 -0
- package/src/sound/synth.oscillators.js +293 -0
- package/src/state/index.js +10 -0
- package/src/state/state-machine.js +371 -0
- package/src/util/camera3d.js +438 -0
- package/src/util/index.js +6 -0
- package/src/util/isometric-camera.js +235 -0
- package/src/util/layout.js +317 -0
- package/src/util/position.js +147 -0
- package/src/util/tasks.js +47 -0
- package/src/util/zindex.js +287 -0
- package/src/webgl/index.js +9 -0
- package/src/webgl/shaders/sphere-shaders.js +994 -0
- package/src/webgl/webgl-renderer.js +388 -0
- package/tde.png +0 -0
- package/test/math/orbital.test.js +61 -0
- package/test/math/tensor.test.js +114 -0
- package/test/particle/emitter.test.js +204 -0
- package/test/particle/particle-system.test.js +310 -0
- package/test/particle/particle.test.js +116 -0
- package/test/particle/updaters.test.js +386 -0
- package/test/setup.js +120 -0
- package/test/shapes/euclidian.test.js +44 -0
- package/test/shapes/geometry.test.js +86 -0
- package/test/shapes/group.test.js +86 -0
- package/test/shapes/rectangle.test.js +64 -0
- package/test/shapes/transform.test.js +379 -0
- package/test/util/camera3d.test.js +428 -0
- package/test/util/scene3d.test.js +352 -0
- package/types/collision.d.ts +249 -0
- package/types/common.d.ts +155 -0
- package/types/game.d.ts +497 -0
- package/types/index.d.ts +309 -0
- package/types/io.d.ts +188 -0
- package/types/logger.d.ts +127 -0
- package/types/math.d.ts +268 -0
- package/types/mixins.d.ts +92 -0
- package/types/motion.d.ts +678 -0
- package/types/painter.d.ts +378 -0
- package/types/shapes.d.ts +864 -0
- package/types/sound.d.ts +672 -0
- package/types/state.d.ts +251 -0
- package/types/util.d.ts +253 -0
- package/vite.config.js +50 -0
- package/vitest.config.js +13 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# Rendering Pipeline
|
|
2
|
+
|
|
3
|
+
> The shape inheritance chain from Euclidian to concrete shapes.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Every visual element in GCanvas inherits from a chain of base classes. Each layer adds specific functionality, building from simple spatial properties to full rendering capabilities.
|
|
8
|
+
|
|
9
|
+
## The Inheritance Chain
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
13
|
+
│ │
|
|
14
|
+
│ Euclidian │
|
|
15
|
+
│ ├── x, y (position) │
|
|
16
|
+
│ ├── width, height (dimensions) │
|
|
17
|
+
│ └── debug rendering support │
|
|
18
|
+
│ │ │
|
|
19
|
+
│ ▼ │
|
|
20
|
+
│ Geometry2d │
|
|
21
|
+
│ ├── getBounds() - bounding box calculation │
|
|
22
|
+
│ ├── minX, maxX, minY, maxY - constraints │
|
|
23
|
+
│ ├── crisp - pixel-perfect alignment │
|
|
24
|
+
│ └── dirty flag tracking │
|
|
25
|
+
│ │ │
|
|
26
|
+
│ ▼ │
|
|
27
|
+
│ Traceable │
|
|
28
|
+
│ ├── drawDebug() - debug visualization │
|
|
29
|
+
│ └── logging capabilities │
|
|
30
|
+
│ │ │
|
|
31
|
+
│ ▼ │
|
|
32
|
+
│ Renderable │
|
|
33
|
+
│ ├── visible - show/hide │
|
|
34
|
+
│ ├── opacity - transparency (0-1) │
|
|
35
|
+
│ ├── shadowColor, shadowBlur, shadowOffset │
|
|
36
|
+
│ ├── blendMode - canvas composite operation │
|
|
37
|
+
│ ├── zIndex - stacking order │
|
|
38
|
+
│ └── render() - main render lifecycle │
|
|
39
|
+
│ │ │
|
|
40
|
+
│ ▼ │
|
|
41
|
+
│ Transformable │
|
|
42
|
+
│ ├── rotation - angle in radians │
|
|
43
|
+
│ ├── scaleX, scaleY - scaling factors │
|
|
44
|
+
│ ├── applyTransforms() - canvas transform │
|
|
45
|
+
│ └── getTransformedBounds() - rotated bounds │
|
|
46
|
+
│ │ │
|
|
47
|
+
│ ▼ │
|
|
48
|
+
│ Shape │
|
|
49
|
+
│ ├── color - fill color │
|
|
50
|
+
│ ├── stroke - stroke color │
|
|
51
|
+
│ ├── lineWidth, lineJoin, lineCap │
|
|
52
|
+
│ └── draw() - abstract (override in subclasses) │
|
|
53
|
+
│ │ │
|
|
54
|
+
│ ▼ │
|
|
55
|
+
│ ┌─────────┬─────────┬─────────┬─────────┬─────────┐ │
|
|
56
|
+
│ │ Circle │Rectangle│ Star │ Cube │ ... │ │
|
|
57
|
+
│ │ draw() │ draw() │ draw() │ draw() │ │ │
|
|
58
|
+
│ └─────────┴─────────┴─────────┴─────────┴─────────┘ │
|
|
59
|
+
│ │
|
|
60
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Layer Details
|
|
64
|
+
|
|
65
|
+
### 1. Euclidian
|
|
66
|
+
|
|
67
|
+
**Source:** `src/shapes/euclidian.js`
|
|
68
|
+
|
|
69
|
+
The foundation class providing basic spatial properties.
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
class Euclidian {
|
|
73
|
+
x = 0; // Center X position
|
|
74
|
+
y = 0; // Center Y position
|
|
75
|
+
width = 0; // Width
|
|
76
|
+
height = 0; // Height
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Key Concept:** Position is center-based, not top-left. A shape at `(100, 100)` has its center at that point.
|
|
81
|
+
|
|
82
|
+
### 2. Geometry2d
|
|
83
|
+
|
|
84
|
+
**Source:** `src/shapes/geometry.js`
|
|
85
|
+
|
|
86
|
+
Adds bounding box calculations and positional constraints.
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
// Get the bounding box
|
|
90
|
+
const bounds = shape.getBounds();
|
|
91
|
+
// { x, y, width, height }
|
|
92
|
+
|
|
93
|
+
// Constrain position
|
|
94
|
+
shape.minX = 0;
|
|
95
|
+
shape.maxX = 800;
|
|
96
|
+
shape.applyConstraints();
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 3. Traceable
|
|
100
|
+
|
|
101
|
+
**Source:** `src/shapes/traceable.js`
|
|
102
|
+
|
|
103
|
+
Adds debug visualization capabilities.
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
shape.drawDebug(ctx); // Draw bounding box and center point
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 4. Renderable
|
|
110
|
+
|
|
111
|
+
**Source:** `src/shapes/renderable.js`
|
|
112
|
+
|
|
113
|
+
Adds visual properties and the main `render()` lifecycle.
|
|
114
|
+
|
|
115
|
+
```js
|
|
116
|
+
shape.visible = true;
|
|
117
|
+
shape.opacity = 0.8;
|
|
118
|
+
shape.shadowColor = 'rgba(0,0,0,0.5)';
|
|
119
|
+
shape.shadowBlur = 10;
|
|
120
|
+
shape.shadowOffsetX = 5;
|
|
121
|
+
shape.shadowOffsetY = 5;
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**The `render()` method:**
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
render() {
|
|
128
|
+
if (!this.visible || this.opacity <= 0) return;
|
|
129
|
+
|
|
130
|
+
Painter.save();
|
|
131
|
+
Painter.effects.setBlendMode(this.blendMode);
|
|
132
|
+
Painter.opacity.pushOpacity(this.opacity);
|
|
133
|
+
Painter.translateTo(this.x, this.y);
|
|
134
|
+
|
|
135
|
+
// Apply shadows
|
|
136
|
+
if (this.shadowColor) {
|
|
137
|
+
ctx.shadowColor = this.shadowColor;
|
|
138
|
+
ctx.shadowBlur = this.shadowBlur;
|
|
139
|
+
ctx.shadowOffsetX = this.shadowOffsetX;
|
|
140
|
+
ctx.shadowOffsetY = this.shadowOffsetY;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
this.draw(); // Call subclass implementation
|
|
144
|
+
|
|
145
|
+
Painter.opacity.popOpacity();
|
|
146
|
+
Painter.restore();
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 5. Transformable
|
|
151
|
+
|
|
152
|
+
**Source:** `src/shapes/transformable.js`
|
|
153
|
+
|
|
154
|
+
Adds rotation and scaling.
|
|
155
|
+
|
|
156
|
+
```js
|
|
157
|
+
shape.rotation = Math.PI / 4; // 45 degrees
|
|
158
|
+
shape.scaleX = 2.0;
|
|
159
|
+
shape.scaleY = 0.5;
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Transform application:**
|
|
163
|
+
|
|
164
|
+
```js
|
|
165
|
+
applyTransforms() {
|
|
166
|
+
if (this.rotation !== 0) {
|
|
167
|
+
Painter.rotate(this.rotation);
|
|
168
|
+
}
|
|
169
|
+
if (this.scaleX !== 1 || this.scaleY !== 1) {
|
|
170
|
+
Painter.scale(this.scaleX, this.scaleY);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### 6. Shape
|
|
176
|
+
|
|
177
|
+
**Source:** `src/shapes/shape.js`
|
|
178
|
+
|
|
179
|
+
Adds canvas styling (fill and stroke).
|
|
180
|
+
|
|
181
|
+
```js
|
|
182
|
+
const circle = new Circle(50, {
|
|
183
|
+
color: 'red', // Fill color
|
|
184
|
+
stroke: 'black', // Stroke color
|
|
185
|
+
lineWidth: 2, // Stroke width
|
|
186
|
+
lineJoin: 'round', // Line join style
|
|
187
|
+
lineCap: 'round' // Line cap style
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## The Render Flow
|
|
192
|
+
|
|
193
|
+
When `shape.render()` is called (or `shape.draw()` directly):
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
1. render() called
|
|
197
|
+
│
|
|
198
|
+
├─► Check visible && opacity > 0
|
|
199
|
+
│
|
|
200
|
+
├─► Painter.save() ─── Save canvas state
|
|
201
|
+
│
|
|
202
|
+
├─► Set blend mode
|
|
203
|
+
│
|
|
204
|
+
├─► Push opacity
|
|
205
|
+
│
|
|
206
|
+
├─► Translate to (x, y) ─── Move to shape center
|
|
207
|
+
│
|
|
208
|
+
├─► Apply shadows
|
|
209
|
+
│
|
|
210
|
+
├─► draw() called ─── Subclass implementation
|
|
211
|
+
│ │
|
|
212
|
+
│ ├─► applyTransforms() ─── Rotation & scale
|
|
213
|
+
│ │
|
|
214
|
+
│ └─► Painter.shapes.* ─── Actual drawing
|
|
215
|
+
│
|
|
216
|
+
├─► Pop opacity
|
|
217
|
+
│
|
|
218
|
+
└─► Painter.restore() ─── Restore canvas state
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Coordinate System
|
|
222
|
+
|
|
223
|
+
GCanvas uses a **center-based** coordinate system:
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
┌────────────────────────────────────┐
|
|
227
|
+
│ Canvas │
|
|
228
|
+
│ │
|
|
229
|
+
│ (0,0) top-left │
|
|
230
|
+
│ ┌──────────────────┐ │
|
|
231
|
+
│ │ │ │
|
|
232
|
+
│ │ (x, y) │ │
|
|
233
|
+
│ │ ●──────────┼─width │
|
|
234
|
+
│ │ │ │ │
|
|
235
|
+
│ │ │ │ │
|
|
236
|
+
│ └───────┼──────────┘ │
|
|
237
|
+
│ height │
|
|
238
|
+
│ │
|
|
239
|
+
└────────────────────────────────────┘
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The `(x, y)` point is the **center** of the shape, not the top-left corner.
|
|
243
|
+
|
|
244
|
+
## Creating Custom Shapes
|
|
245
|
+
|
|
246
|
+
Extend `Shape` and implement `draw()`:
|
|
247
|
+
|
|
248
|
+
```js
|
|
249
|
+
import { Shape, Painter } from 'gcanvas';
|
|
250
|
+
|
|
251
|
+
class CustomShape extends Shape {
|
|
252
|
+
constructor(options = {}) {
|
|
253
|
+
super(options);
|
|
254
|
+
this.customProp = options.customProp ?? 'default';
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
draw() {
|
|
258
|
+
super.draw(); // Apply transforms
|
|
259
|
+
|
|
260
|
+
// Draw using Painter
|
|
261
|
+
Painter.shapes.fillCircle(0, 0, this.width / 2, this.color);
|
|
262
|
+
Painter.shapes.strokeCircle(0, 0, this.width / 2, this.stroke, this.lineWidth);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Related
|
|
268
|
+
|
|
269
|
+
- [Architecture Overview](./architecture-overview.md) - Full system architecture
|
|
270
|
+
- [Two-Layer Architecture](./two-layer-architecture.md) - Shape vs Game layer
|
|
271
|
+
- [Shape Hierarchy](../modules/shapes/hierarchy.md) - Detailed class documentation
|
|
272
|
+
|
|
273
|
+
## See Also
|
|
274
|
+
|
|
275
|
+
- [Euclidian](../modules/shapes/base/euclidian.md)
|
|
276
|
+
- [Geometry2d](../modules/shapes/base/geometry2d.md)
|
|
277
|
+
- [Renderable](../modules/shapes/base/renderable.md)
|
|
278
|
+
- [Transformable](../modules/shapes/base/transformable.md)
|
|
279
|
+
- [Shape](../modules/shapes/base/shape.md)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# TDE Demo Z-Order Rendering System
|
|
2
|
+
|
|
3
|
+
This document describes the z-ordering (depth sorting) system used in the Tidal Disruption Event (TDE) demo.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The TDE demo uses a 3D scene with multiple objects that need to be rendered in the correct order based on their depth relative to the camera. The system uses a combination of:
|
|
8
|
+
|
|
9
|
+
1. **Static z-index buckets** for objects that always render in a fixed order
|
|
10
|
+
2. **Dynamic z-index updates** for objects whose render order depends on camera position
|
|
11
|
+
|
|
12
|
+
## Z-Index Buckets
|
|
13
|
+
|
|
14
|
+
Objects are assigned to z-index buckets. Lower z-index values render first (behind), higher values render later (in front).
|
|
15
|
+
|
|
16
|
+
**Only the Star has a dynamic z-index** that changes based on its position relative to the camera. The TidalStream particles always render on top for a cleaner visual effect.
|
|
17
|
+
|
|
18
|
+
| Object | Z-Index | Description |
|
|
19
|
+
|--------|---------|-------------|
|
|
20
|
+
| Star (back) | 10 | Star when behind black hole |
|
|
21
|
+
| BlackHole | 15 | Dark shadow - at the back |
|
|
22
|
+
| AccretionDisk | 20 | Disk renders over the black hole |
|
|
23
|
+
| Star (front) | 25 | Star when in front of black hole |
|
|
24
|
+
| TidalStream | 30 | Particles - always on top |
|
|
25
|
+
| RelativisticJets | 40 | Jets - always on top |
|
|
26
|
+
|
|
27
|
+
### Layering by Camera View
|
|
28
|
+
|
|
29
|
+
**When star is IN FRONT of black hole:**
|
|
30
|
+
- Stream (30) > Star (25) > Disk (20) > BlackHole (15)
|
|
31
|
+
|
|
32
|
+
**When star is BEHIND black hole:**
|
|
33
|
+
- Stream (30) > Disk (20) > BlackHole (15) > Star (10)
|
|
34
|
+
|
|
35
|
+
The accretion disk particles curve around the black hole visually, and the stream always stays on top.
|
|
36
|
+
|
|
37
|
+
## Rendering Rules
|
|
38
|
+
|
|
39
|
+
### Rule 1: TidalStream Always Behind Star
|
|
40
|
+
The tidal stream particles (z-index 10) always render behind the star (z-index 25-35). This ensures the star is always visible and the stream appears to emanate from behind/around it.
|
|
41
|
+
|
|
42
|
+
### Rule 2: Star in Front of Black Hole (When Closer)
|
|
43
|
+
When the star is closer to the camera than the black hole, the star's z-index is set to 35 (starFront), which is higher than the black hole's z-index of 30. This causes the star to render after (on top of) the black hole.
|
|
44
|
+
|
|
45
|
+
### Rule 3: Black Hole in Front of Star (When Star is Behind)
|
|
46
|
+
When the star is farther from the camera than the black hole, the star's z-index is set to 25 (starBack), which is lower than the black hole's z-index of 30. This causes the black hole to render after (on top of) the star.
|
|
47
|
+
|
|
48
|
+
## Dynamic Z-Order Algorithm
|
|
49
|
+
|
|
50
|
+
The `BlackHoleScene.updateStarZOrder()` method handles dynamic z-ordering:
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
updateStarZOrder() {
|
|
54
|
+
const camera = this.game.camera;
|
|
55
|
+
|
|
56
|
+
// Project star position to get depth after camera rotation
|
|
57
|
+
const projStar = camera.project(star.x, star.y, star.z);
|
|
58
|
+
|
|
59
|
+
// Black hole is always at origin
|
|
60
|
+
const projBH = camera.project(0, 0, 0);
|
|
61
|
+
|
|
62
|
+
// Lower projected z = closer to camera
|
|
63
|
+
const starInFront = projStar.z < projBH.z;
|
|
64
|
+
|
|
65
|
+
// Update z-index based on depth comparison
|
|
66
|
+
star.zIndex = starInFront ? Z.starFront : Z.starBack;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Critical: Update Order
|
|
71
|
+
|
|
72
|
+
The z-order update **must be called AFTER** the star position is updated each frame. This is done in `TDEDemo.update()` at the end, after all state-based position updates:
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
// In TDEDemo.update(), at the end:
|
|
76
|
+
if (this.scene) {
|
|
77
|
+
this.scene.updateStarZOrder();
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
If called before the position update, it uses stale position data and causes incorrect ordering.
|
|
82
|
+
|
|
83
|
+
## Camera3D Projection
|
|
84
|
+
|
|
85
|
+
The `Camera3D.project()` method returns:
|
|
86
|
+
- `x, y`: Screen position
|
|
87
|
+
- `z`: Depth after rotation (lower = closer to camera)
|
|
88
|
+
- `scale`: Perspective scale factor
|
|
89
|
+
|
|
90
|
+
The depth (`z`) value is used for z-order comparisons. Objects with lower depth values are closer to the camera and should render on top.
|
|
91
|
+
|
|
92
|
+
## Scene3D Sorting
|
|
93
|
+
|
|
94
|
+
`Scene3D` sorts children before rendering:
|
|
95
|
+
|
|
96
|
+
1. **Primary sort**: By `zIndex` (lower renders first)
|
|
97
|
+
2. **Secondary sort**: By projected `z` depth (back-to-front, as tie-breaker)
|
|
98
|
+
|
|
99
|
+
This ensures objects with different z-indices render in the correct order, while objects with the same z-index are sorted by actual depth.
|
|
100
|
+
|
|
101
|
+
## Implementation Files
|
|
102
|
+
|
|
103
|
+
- `demos/js/tde/blackholescene.js` - Main scene with z-ordering logic
|
|
104
|
+
- `src/game/objects/scene3d.js` - Base Scene3D with depth sorting
|
|
105
|
+
- `src/util/camera3d.js` - Camera projection utilities
|
|
106
|
+
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Two-Layer Architecture
|
|
2
|
+
|
|
3
|
+
> Understanding when to use the Shape Layer vs the Game Layer.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
GCanvas provides two complementary approaches to building canvas applications:
|
|
8
|
+
|
|
9
|
+
1. **Shape Layer** - For declarative, static graphics
|
|
10
|
+
2. **Game Layer** - For interactive, dynamic applications
|
|
11
|
+
|
|
12
|
+
You can use either layer independently or combine them for complex applications.
|
|
13
|
+
|
|
14
|
+
## Shape Layer
|
|
15
|
+
|
|
16
|
+
The Shape Layer is for drawing graphics without a game loop. Shapes are self-contained objects that know how to render themselves.
|
|
17
|
+
|
|
18
|
+
### When to Use
|
|
19
|
+
|
|
20
|
+
- Static visualizations
|
|
21
|
+
- Data charts and graphs
|
|
22
|
+
- Decorative graphics
|
|
23
|
+
- Simple animations (manual redraw)
|
|
24
|
+
- Learning canvas fundamentals
|
|
25
|
+
|
|
26
|
+
### Key Classes
|
|
27
|
+
|
|
28
|
+
- `Shape` and subclasses (`Circle`, `Rectangle`, `Star`, etc.)
|
|
29
|
+
- `Group` for composing shapes
|
|
30
|
+
- `Painter` for direct canvas control
|
|
31
|
+
|
|
32
|
+
### Example
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
import { Circle, Rectangle, Group, Painter } from 'gcanvas';
|
|
36
|
+
|
|
37
|
+
// Initialize Painter with canvas context
|
|
38
|
+
const canvas = document.getElementById('canvas');
|
|
39
|
+
Painter.init(canvas.getContext('2d'));
|
|
40
|
+
|
|
41
|
+
// Create shapes
|
|
42
|
+
const circle = new Circle(50, { x: 100, y: 100, color: 'red' });
|
|
43
|
+
const rect = new Rectangle(80, 40, { x: 200, y: 100, color: 'blue' });
|
|
44
|
+
|
|
45
|
+
// Draw immediately
|
|
46
|
+
Painter.clear();
|
|
47
|
+
circle.draw();
|
|
48
|
+
rect.draw();
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Characteristics
|
|
52
|
+
|
|
53
|
+
| Aspect | Shape Layer |
|
|
54
|
+
|--------|-------------|
|
|
55
|
+
| Loop | None (manual redraw) |
|
|
56
|
+
| State | Shapes hold their own state |
|
|
57
|
+
| Input | Manual event handling |
|
|
58
|
+
| Animation | Call draw() on each frame manually |
|
|
59
|
+
| Complexity | Simple, direct |
|
|
60
|
+
|
|
61
|
+
## Game Layer
|
|
62
|
+
|
|
63
|
+
The Game Layer provides a complete game loop with automatic updates, rendering, and input handling.
|
|
64
|
+
|
|
65
|
+
### When to Use
|
|
66
|
+
|
|
67
|
+
- Games and simulations
|
|
68
|
+
- Interactive applications
|
|
69
|
+
- Real-time animations
|
|
70
|
+
- Complex state management
|
|
71
|
+
- Multi-object coordination
|
|
72
|
+
|
|
73
|
+
### Key Classes
|
|
74
|
+
|
|
75
|
+
- `Game` - Main loop and canvas management
|
|
76
|
+
- `Pipeline` - Object lifecycle management
|
|
77
|
+
- `GameObject` - Interactive entities
|
|
78
|
+
- `Scene` - Hierarchical organization
|
|
79
|
+
|
|
80
|
+
### Example
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
import { Game, Scene, GameObject, Circle } from 'gcanvas';
|
|
84
|
+
|
|
85
|
+
class Player extends GameObject {
|
|
86
|
+
constructor(game) {
|
|
87
|
+
super(game);
|
|
88
|
+
this.shape = new Circle(40, { color: 'blue' });
|
|
89
|
+
this.enableInteractivity(this.shape);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
update(dt) {
|
|
93
|
+
// Called every frame
|
|
94
|
+
if (this.game.input.isKeyDown('ArrowRight')) {
|
|
95
|
+
this.shape.x += 200 * dt;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
render() {
|
|
100
|
+
// Called every frame after update
|
|
101
|
+
this.shape.draw();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
onPointerDown(e) {
|
|
105
|
+
// Automatic input handling
|
|
106
|
+
console.log('Clicked!');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
class MyGame extends Game {
|
|
111
|
+
init() {
|
|
112
|
+
this.enableFluidSize();
|
|
113
|
+
const scene = new Scene(this);
|
|
114
|
+
scene.add(new Player(this));
|
|
115
|
+
this.pipeline.add(scene);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const game = new MyGame(document.getElementById('canvas'));
|
|
120
|
+
game.start();
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Characteristics
|
|
124
|
+
|
|
125
|
+
| Aspect | Game Layer |
|
|
126
|
+
|--------|-------------|
|
|
127
|
+
| Loop | Automatic (requestAnimationFrame) |
|
|
128
|
+
| State | Managed by Pipeline |
|
|
129
|
+
| Input | Automatic dispatching to objects |
|
|
130
|
+
| Animation | Built-in with dt (delta time) |
|
|
131
|
+
| Complexity | Full-featured |
|
|
132
|
+
|
|
133
|
+
## Comparison
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
137
|
+
│ Shape Layer │
|
|
138
|
+
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
|
139
|
+
│ │ Circle │ │Rectangle│ │ Star │ ... more shapes │
|
|
140
|
+
│ └────┬────┘ └────┬────┘ └────┬────┘ │
|
|
141
|
+
│ │ │ │ │
|
|
142
|
+
│ └────────────┼────────────┘ │
|
|
143
|
+
│ ▼ │
|
|
144
|
+
│ ┌──────────┐ │
|
|
145
|
+
│ │ Group │ (optional composition) │
|
|
146
|
+
│ └────┬─────┘ │
|
|
147
|
+
│ │ │
|
|
148
|
+
│ ▼ │
|
|
149
|
+
│ ┌──────────┐ │
|
|
150
|
+
│ │ draw() │ (manual call) │
|
|
151
|
+
│ └──────────┘ │
|
|
152
|
+
└─────────────────────────────────────────────────────────────┘
|
|
153
|
+
|
|
154
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
155
|
+
│ Game Layer │
|
|
156
|
+
│ ┌─────────────────────────────────────────────────────┐ │
|
|
157
|
+
│ │ Game │ │
|
|
158
|
+
│ │ ┌─────────────────────────────────────────────┐ │ │
|
|
159
|
+
│ │ │ Pipeline │ │ │
|
|
160
|
+
│ │ │ ┌─────────────────────────────────────┐ │ │ │
|
|
161
|
+
│ │ │ │ Scene │ │ │ │
|
|
162
|
+
│ │ │ │ ┌───────────┐ ┌───────────┐ │ │ │ │
|
|
163
|
+
│ │ │ │ │GameObject │ │GameObject │ ... │ │ │ │
|
|
164
|
+
│ │ │ │ │ + Shape │ │ + Shape │ │ │ │ │
|
|
165
|
+
│ │ │ │ └───────────┘ └───────────┘ │ │ │ │
|
|
166
|
+
│ │ │ └─────────────────────────────────────┘ │ │ │
|
|
167
|
+
│ │ └─────────────────────────────────────────────┘ │ │
|
|
168
|
+
│ └─────────────────────────────────────────────────────┘ │
|
|
169
|
+
│ │ │
|
|
170
|
+
│ ▼ │
|
|
171
|
+
│ ┌────────────┐ │
|
|
172
|
+
│ │ Game Loop │ (automatic) │
|
|
173
|
+
│ │ update(dt) │ │
|
|
174
|
+
│ │ render() │ │
|
|
175
|
+
│ └────────────┘ │
|
|
176
|
+
└─────────────────────────────────────────────────────────────┘
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Mixing Layers
|
|
180
|
+
|
|
181
|
+
You can use shapes without GameObjects, or combine both approaches:
|
|
182
|
+
|
|
183
|
+
```js
|
|
184
|
+
class HybridGame extends Game {
|
|
185
|
+
init() {
|
|
186
|
+
// Game layer for interactive elements
|
|
187
|
+
const scene = new Scene(this);
|
|
188
|
+
scene.add(new Player(this));
|
|
189
|
+
this.pipeline.add(scene);
|
|
190
|
+
|
|
191
|
+
// Shape layer for static background
|
|
192
|
+
this.background = new Group();
|
|
193
|
+
this.background.add(new Rectangle(this.width, this.height, { color: '#222' }));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
render() {
|
|
197
|
+
// Draw static shapes first
|
|
198
|
+
this.background.draw();
|
|
199
|
+
|
|
200
|
+
// Then let pipeline draw interactive objects
|
|
201
|
+
super.render();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Decision Guide
|
|
207
|
+
|
|
208
|
+
| If you need... | Use |
|
|
209
|
+
|---------------|-----|
|
|
210
|
+
| Static graphics | Shape Layer |
|
|
211
|
+
| Simple animations | Shape Layer + manual loop |
|
|
212
|
+
| Keyboard/mouse input | Game Layer |
|
|
213
|
+
| Multiple interactive objects | Game Layer |
|
|
214
|
+
| Collision detection | Game Layer |
|
|
215
|
+
| Scene organization | Game Layer |
|
|
216
|
+
| Quick prototype | Shape Layer |
|
|
217
|
+
| Full game | Game Layer |
|
|
218
|
+
|
|
219
|
+
## Related
|
|
220
|
+
|
|
221
|
+
- [Architecture Overview](./architecture-overview.md) - Full system architecture
|
|
222
|
+
- [Rendering Pipeline](./rendering-pipeline.md) - Shape inheritance chain
|
|
223
|
+
- [Game Lifecycle](./lifecycle.md) - Update/render cycle
|
|
224
|
+
|
|
225
|
+
## See Also
|
|
226
|
+
|
|
227
|
+
- [Shapes Module](../modules/shapes/README.md)
|
|
228
|
+
- [Game Module](../modules/game/README.md)
|
|
229
|
+
- [Getting Started: Hello World](../getting-started/hello-world.md)
|