@guinetik/gcanvas 1.0.0 → 1.0.1
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/demos/fluid-simple.html +22 -0
- package/demos/fluid.html +37 -0
- package/demos/index.html +2 -0
- package/demos/js/blob.js +18 -5
- package/demos/js/fluid-simple.js +253 -0
- package/demos/js/fluid.js +527 -0
- package/demos/js/tde/accretiondisk.js +64 -11
- package/demos/js/tde/blackholescene.js +2 -2
- package/demos/js/tde/config.js +2 -2
- package/demos/js/tde/index.js +152 -27
- package/demos/js/tde/lensedstarfield.js +32 -25
- package/demos/js/tde/tdestar.js +78 -98
- package/demos/js/tde/tidalstream.js +23 -7
- package/docs/README.md +230 -222
- package/docs/api/FluidSystem.md +173 -0
- package/docs/concepts/architecture-overview.md +204 -204
- package/docs/concepts/rendering-pipeline.md +279 -279
- package/docs/concepts/two-layer-architecture.md +229 -229
- package/docs/fluid-dynamics.md +97 -0
- package/docs/getting-started/first-game.md +354 -354
- package/docs/getting-started/installation.md +175 -157
- package/docs/modules/collision/README.md +2 -2
- package/docs/modules/fluent/README.md +6 -6
- package/docs/modules/game/README.md +303 -303
- package/docs/modules/isometric-camera.md +2 -2
- package/docs/modules/isometric.md +1 -1
- package/docs/modules/painter/README.md +328 -328
- package/docs/modules/particle/README.md +3 -3
- package/docs/modules/shapes/README.md +221 -221
- package/docs/modules/shapes/base/euclidian.md +123 -123
- package/docs/modules/shapes/base/shape.md +262 -262
- package/docs/modules/shapes/base/transformable.md +243 -243
- package/docs/modules/state/README.md +2 -2
- package/docs/modules/util/README.md +1 -1
- package/docs/modules/util/camera3d.md +3 -3
- package/docs/modules/util/scene3d.md +1 -1
- package/package.json +3 -1
- package/readme.md +19 -5
- package/src/collision/collision.js +75 -0
- package/src/game/index.js +2 -1
- package/src/game/pipeline.js +3 -3
- package/src/game/systems/FluidSystem.js +835 -0
- package/src/game/systems/index.js +11 -0
- package/src/game/ui/button.js +39 -18
- package/src/game/ui/cursor.js +14 -0
- package/src/game/ui/fps.js +12 -4
- package/src/game/ui/index.js +2 -0
- package/src/game/ui/stepper.js +549 -0
- package/src/game/ui/theme.js +121 -0
- package/src/game/ui/togglebutton.js +9 -3
- package/src/game/ui/tooltip.js +11 -4
- package/src/math/fluid.js +507 -0
- package/src/math/index.js +2 -0
- package/src/mixins/anchor.js +17 -7
- package/src/motion/tweenetik.js +16 -0
- package/src/shapes/index.js +1 -0
- package/src/util/camera3d.js +218 -12
- package/types/fluent.d.ts +361 -0
- package/types/game.d.ts +303 -0
- package/types/index.d.ts +144 -5
- package/types/math.d.ts +361 -0
- package/types/motion.d.ts +271 -0
- package/types/particle.d.ts +373 -0
- package/types/shapes.d.ts +107 -9
- package/types/util.d.ts +353 -0
- package/types/webgl.d.ts +109 -0
- package/disk_example.png +0 -0
- package/tde.png +0 -0
|
@@ -1,279 +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)
|
|
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 '@guinetik/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)
|