@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,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module FluentLayer
|
|
3
|
+
* @description Builder class for layer (z-indexed group) operations within a scene
|
|
4
|
+
*
|
|
5
|
+
* Layers are implemented as GameObjects containing Groups, allowing for
|
|
6
|
+
* z-indexed sub-grouping within a scene.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { GameObject } from "../game/objects/go.js";
|
|
10
|
+
import { FluentGO } from "./fluent-go.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* FluentLayer - Builder for layer (z-indexed group) within a scene
|
|
14
|
+
*/
|
|
15
|
+
export class FluentLayer {
|
|
16
|
+
/** @type {import('./fluent-scene.js').FluentScene} */
|
|
17
|
+
#parent;
|
|
18
|
+
/** @type {GameObject} */
|
|
19
|
+
#layerGO;
|
|
20
|
+
/** @type {import('../shapes/group.js').Group} */
|
|
21
|
+
#group;
|
|
22
|
+
/** @type {Object} */
|
|
23
|
+
#refs;
|
|
24
|
+
/** @type {Object} */
|
|
25
|
+
#state;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {import('./fluent-scene.js').FluentScene} parent - Parent FluentScene
|
|
29
|
+
* @param {GameObject} layerGO - The GameObject holding the layer
|
|
30
|
+
* @param {import('../shapes/group.js').Group} group - The Group for the layer
|
|
31
|
+
* @param {Object} refs - Shared refs object
|
|
32
|
+
* @param {Object} state - Shared state object
|
|
33
|
+
*/
|
|
34
|
+
constructor(parent, layerGO, group, refs, state) {
|
|
35
|
+
this.#parent = parent;
|
|
36
|
+
this.#layerGO = layerGO;
|
|
37
|
+
this.#group = group;
|
|
38
|
+
this.#refs = refs;
|
|
39
|
+
this.#state = state;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Create a GameObject in this layer
|
|
44
|
+
* @param {Object} [opts] - GameObject options
|
|
45
|
+
* @param {Function} [builderFn] - Optional builder callback
|
|
46
|
+
* @returns {FluentGO|FluentLayer}
|
|
47
|
+
*/
|
|
48
|
+
go(opts = {}, builderFn) {
|
|
49
|
+
const {
|
|
50
|
+
name,
|
|
51
|
+
x = 0,
|
|
52
|
+
y = 0,
|
|
53
|
+
visible = true,
|
|
54
|
+
...rest
|
|
55
|
+
} = opts;
|
|
56
|
+
|
|
57
|
+
const go = new GameObject({ x, y, visible, ...rest });
|
|
58
|
+
|
|
59
|
+
// Set game reference from parent
|
|
60
|
+
if (this.#parent.parent?.game) {
|
|
61
|
+
go.game = this.#parent.parent.game;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Add to the layer's group
|
|
65
|
+
this.#group.add(go);
|
|
66
|
+
|
|
67
|
+
// Register in refs if named
|
|
68
|
+
if (name) {
|
|
69
|
+
go.name = name;
|
|
70
|
+
this.#refs[name] = go;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const fluentGO = new FluentGO(this, go, this.#refs, this.#state);
|
|
74
|
+
|
|
75
|
+
if (builderFn) {
|
|
76
|
+
builderFn(fluentGO);
|
|
77
|
+
return this;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return fluentGO;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Set layer visibility
|
|
85
|
+
* @param {boolean} visible - Visibility state
|
|
86
|
+
* @returns {FluentLayer}
|
|
87
|
+
*/
|
|
88
|
+
visible(visible) {
|
|
89
|
+
this.#layerGO.visible = visible;
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Set layer opacity
|
|
95
|
+
* @param {number} value - Opacity (0-1)
|
|
96
|
+
* @returns {FluentLayer}
|
|
97
|
+
*/
|
|
98
|
+
opacity(value) {
|
|
99
|
+
this.#group.opacity = value;
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* End layer context and return to scene
|
|
105
|
+
* @returns {import('./fluent-scene.js').FluentScene}
|
|
106
|
+
*/
|
|
107
|
+
endLayer() {
|
|
108
|
+
return this.#parent;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Navigate back to parent (same as endLayer)
|
|
113
|
+
* @returns {import('./fluent-scene.js').FluentScene}
|
|
114
|
+
*/
|
|
115
|
+
end() {
|
|
116
|
+
return this.#parent;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Switch to another scene
|
|
121
|
+
* @param {string} name - Scene name
|
|
122
|
+
* @param {Object} [opts] - Scene options
|
|
123
|
+
* @returns {import('./fluent-scene.js').FluentScene}
|
|
124
|
+
*/
|
|
125
|
+
scene(name, opts) {
|
|
126
|
+
return this.#parent.scene(name, opts);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Start the game
|
|
131
|
+
* @returns {import('./fluent-game.js').FluentGame}
|
|
132
|
+
*/
|
|
133
|
+
start() {
|
|
134
|
+
return this.#parent.start();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ─────────────────────────────────────────────────────────
|
|
138
|
+
// ACCESSORS
|
|
139
|
+
// ─────────────────────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
/** @returns {GameObject} The layer's wrapper GameObject */
|
|
142
|
+
get layerGO() { return this.#layerGO; }
|
|
143
|
+
|
|
144
|
+
/** @returns {import('../shapes/group.js').Group} The layer's Group */
|
|
145
|
+
get group() { return this.#group; }
|
|
146
|
+
|
|
147
|
+
/** @returns {Object} Named object references */
|
|
148
|
+
get refs() { return this.#refs; }
|
|
149
|
+
|
|
150
|
+
/** @returns {Object} Shared state */
|
|
151
|
+
get state() { return this.#state; }
|
|
152
|
+
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module FluentScene
|
|
3
|
+
* @description Builder class for Scene operations in the fluent API
|
|
4
|
+
*
|
|
5
|
+
* Provides chainable methods for creating and managing GameObjects within a scene.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { GameObject } from "../game/objects/go.js";
|
|
9
|
+
import { Group } from "../shapes/group.js";
|
|
10
|
+
import { FluentGO } from "./fluent-go.js";
|
|
11
|
+
import { FluentLayer } from "./fluent-layer.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* FluentScene - Builder class for Scene operations
|
|
15
|
+
*/
|
|
16
|
+
export class FluentScene {
|
|
17
|
+
/** @type {import('./fluent-game.js').FluentGame} */
|
|
18
|
+
#parent;
|
|
19
|
+
/** @type {import('../game/objects/scene.js').Scene} */
|
|
20
|
+
#scene;
|
|
21
|
+
/** @type {Object} */
|
|
22
|
+
#refs;
|
|
23
|
+
/** @type {Object} */
|
|
24
|
+
#state;
|
|
25
|
+
/** @type {GameObject|null} */
|
|
26
|
+
#lastGO = null;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {import('./fluent-game.js').FluentGame} parent - Parent FluentGame
|
|
30
|
+
* @param {import('../game/objects/scene.js').Scene} scene - Wrapped Scene instance
|
|
31
|
+
* @param {Object} refs - Shared refs object
|
|
32
|
+
* @param {Object} state - Shared state object
|
|
33
|
+
*/
|
|
34
|
+
constructor(parent, scene, refs, state) {
|
|
35
|
+
this.#parent = parent;
|
|
36
|
+
this.#scene = scene;
|
|
37
|
+
this.#refs = refs;
|
|
38
|
+
this.#state = state;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ─────────────────────────────────────────────────────────
|
|
42
|
+
// GAMEOBJECT CREATION
|
|
43
|
+
// ─────────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Create a GameObject in this scene
|
|
47
|
+
*
|
|
48
|
+
* Supports multiple signatures:
|
|
49
|
+
* - go() - Create plain GameObject at origin
|
|
50
|
+
* - go(options) - Create plain GameObject with options
|
|
51
|
+
* - go(CustomClass) - Create custom GameObject class
|
|
52
|
+
* - go(CustomClass, options) - Custom class with options
|
|
53
|
+
* - go(options, builderFn) - Plain GO with builder callback
|
|
54
|
+
* - go(CustomClass, options, builderFn) - Custom class with builder
|
|
55
|
+
*
|
|
56
|
+
* @param {Object|Function} [optionsOrClass] - GameObject options or custom class
|
|
57
|
+
* @param {Object|Function} [optionsOrBuilder] - Options or builder function
|
|
58
|
+
* @param {Function} [builderFn] - Optional builder callback
|
|
59
|
+
* @returns {FluentGO|FluentScene}
|
|
60
|
+
*/
|
|
61
|
+
go(optionsOrClass, optionsOrBuilder, builderFn) {
|
|
62
|
+
// Parse flexible arguments
|
|
63
|
+
let GOClass, options, builder;
|
|
64
|
+
|
|
65
|
+
if (typeof optionsOrClass === 'function' && optionsOrClass.prototype) {
|
|
66
|
+
// go(CustomClass) or go(CustomClass, options) or go(CustomClass, options, builder)
|
|
67
|
+
GOClass = optionsOrClass;
|
|
68
|
+
if (typeof optionsOrBuilder === 'function') {
|
|
69
|
+
options = {};
|
|
70
|
+
builder = optionsOrBuilder;
|
|
71
|
+
} else {
|
|
72
|
+
options = optionsOrBuilder || {};
|
|
73
|
+
builder = builderFn;
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
// go() or go(options) or go(options, builder)
|
|
77
|
+
GOClass = GameObject;
|
|
78
|
+
options = optionsOrClass || {};
|
|
79
|
+
builder = optionsOrBuilder;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const {
|
|
83
|
+
name,
|
|
84
|
+
x = 0,
|
|
85
|
+
y = 0,
|
|
86
|
+
visible = true,
|
|
87
|
+
...rest
|
|
88
|
+
} = options;
|
|
89
|
+
|
|
90
|
+
// Instantiate the GO class (custom or default)
|
|
91
|
+
// GameObject constructor signature is (game, options)
|
|
92
|
+
const go = new GOClass(this.#parent.game, { x, y, visible, ...rest });
|
|
93
|
+
this.#scene.add(go);
|
|
94
|
+
this.#lastGO = go;
|
|
95
|
+
|
|
96
|
+
// Register in refs if named
|
|
97
|
+
if (name) {
|
|
98
|
+
go.name = name;
|
|
99
|
+
this.#refs[name] = go;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const fluentGO = new FluentGO(this, go, this.#refs, this.#state);
|
|
103
|
+
|
|
104
|
+
// If builder function provided, execute and return scene context
|
|
105
|
+
if (builder) {
|
|
106
|
+
builder(fluentGO);
|
|
107
|
+
return this;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return fluentGO;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Create multiple GOs with a builder
|
|
115
|
+
* @param {string|Function} groupNameOrFn - Group name or builder function
|
|
116
|
+
* @param {Function} [builderFn] - Builder function if name provided
|
|
117
|
+
* @returns {FluentScene}
|
|
118
|
+
*/
|
|
119
|
+
group(groupNameOrFn, builderFn) {
|
|
120
|
+
const groupName = typeof groupNameOrFn === 'string' ? groupNameOrFn : null;
|
|
121
|
+
const fn = typeof groupNameOrFn === 'function' ? groupNameOrFn : builderFn;
|
|
122
|
+
|
|
123
|
+
const groupGOs = [];
|
|
124
|
+
|
|
125
|
+
const groupApi = {
|
|
126
|
+
go: (opts) => {
|
|
127
|
+
const fluentGO = this.go(opts);
|
|
128
|
+
groupGOs.push(fluentGO.goInstance);
|
|
129
|
+
return fluentGO;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
fn(groupApi);
|
|
134
|
+
|
|
135
|
+
if (groupName) {
|
|
136
|
+
this.#refs[groupName] = groupGOs;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ─────────────────────────────────────────────────────────
|
|
143
|
+
// LAYER MANAGEMENT (sub-grouping within scene)
|
|
144
|
+
// ─────────────────────────────────────────────────────────
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Create a layer (z-indexed group) within the scene
|
|
148
|
+
* @param {string} name - Layer name
|
|
149
|
+
* @param {number} [zIndex=0] - Layer z-index (relative to scene)
|
|
150
|
+
* @returns {FluentLayer}
|
|
151
|
+
*/
|
|
152
|
+
layer(name, zIndex = 0) {
|
|
153
|
+
// Layers are implemented as Groups with zIndex
|
|
154
|
+
const layerGroup = new Group({ zIndex });
|
|
155
|
+
layerGroup.name = name;
|
|
156
|
+
|
|
157
|
+
// Create a wrapper GO to hold the group
|
|
158
|
+
// GameObject constructor signature is (game, options)
|
|
159
|
+
const layerGO = new GameObject(this.#parent.game, { x: 0, y: 0 });
|
|
160
|
+
layerGO._fluentShape = layerGroup;
|
|
161
|
+
layerGO.renderable = layerGroup;
|
|
162
|
+
layerGO.zIndex = zIndex;
|
|
163
|
+
|
|
164
|
+
// Hook into draw to render the group
|
|
165
|
+
const originalDraw = layerGO.draw?.bind(layerGO) || (() => {});
|
|
166
|
+
layerGO.draw = function() {
|
|
167
|
+
originalDraw();
|
|
168
|
+
if (this._fluentShape && this.visible) {
|
|
169
|
+
this._fluentShape.render();
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
this.#scene.add(layerGO);
|
|
174
|
+
|
|
175
|
+
if (name) {
|
|
176
|
+
this.#refs[`${this.#scene.name}_${name}`] = layerGO;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return new FluentLayer(this, layerGO, layerGroup, this.#refs, this.#state);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ─────────────────────────────────────────────────────────
|
|
183
|
+
// SCENE LIFECYCLE HOOKS
|
|
184
|
+
// ─────────────────────────────────────────────────────────
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Register scene enter callback
|
|
188
|
+
* @param {Function} handler
|
|
189
|
+
* @returns {FluentScene}
|
|
190
|
+
*/
|
|
191
|
+
onEnter(handler) {
|
|
192
|
+
this.#scene._onEnter = handler;
|
|
193
|
+
return this;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Register scene exit callback
|
|
198
|
+
* @param {Function} handler
|
|
199
|
+
* @returns {FluentScene}
|
|
200
|
+
*/
|
|
201
|
+
onExit(handler) {
|
|
202
|
+
this.#scene._onExit = handler;
|
|
203
|
+
return this;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ─────────────────────────────────────────────────────────
|
|
207
|
+
// NAVIGATION
|
|
208
|
+
// ─────────────────────────────────────────────────────────
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Switch to another scene (creates if needed)
|
|
212
|
+
* @param {string} name - Scene name
|
|
213
|
+
* @param {Object} [options] - Scene options
|
|
214
|
+
* @returns {FluentScene}
|
|
215
|
+
*/
|
|
216
|
+
scene(name, options) {
|
|
217
|
+
return this.#parent.scene(name, options);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Return to game context
|
|
222
|
+
* @returns {import('./fluent-game.js').FluentGame}
|
|
223
|
+
*/
|
|
224
|
+
end() {
|
|
225
|
+
return this.#parent;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ─────────────────────────────────────────────────────────
|
|
229
|
+
// SHORTCUTS (delegate to parent)
|
|
230
|
+
// ─────────────────────────────────────────────────────────
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Start the game
|
|
234
|
+
* @returns {import('./fluent-game.js').FluentGame}
|
|
235
|
+
*/
|
|
236
|
+
start() {
|
|
237
|
+
return this.#parent.start();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Stop the game
|
|
242
|
+
* @returns {import('./fluent-game.js').FluentGame}
|
|
243
|
+
*/
|
|
244
|
+
stop() {
|
|
245
|
+
return this.#parent.stop();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Register event handler
|
|
250
|
+
* @param {string} event - Event name
|
|
251
|
+
* @param {Function} handler - Handler function
|
|
252
|
+
* @returns {import('./fluent-game.js').FluentGame}
|
|
253
|
+
*/
|
|
254
|
+
on(event, handler) {
|
|
255
|
+
return this.#parent.on(event, handler);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Use a plugin
|
|
260
|
+
* @param {Function} plugin - Plugin function
|
|
261
|
+
* @returns {import('./fluent-game.js').FluentGame}
|
|
262
|
+
*/
|
|
263
|
+
use(plugin) {
|
|
264
|
+
return this.#parent.use(plugin);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Set state
|
|
269
|
+
* @param {Object} stateObj - State object
|
|
270
|
+
* @returns {import('./fluent-game.js').FluentGame}
|
|
271
|
+
*/
|
|
272
|
+
state(stateObj) {
|
|
273
|
+
return this.#parent.state(stateObj);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// ─────────────────────────────────────────────────────────
|
|
277
|
+
// ACCESSORS
|
|
278
|
+
// ─────────────────────────────────────────────────────────
|
|
279
|
+
|
|
280
|
+
/** @returns {import('../game/objects/scene.js').Scene} Underlying Scene instance */
|
|
281
|
+
get sceneInstance() { return this.#scene; }
|
|
282
|
+
|
|
283
|
+
/** @returns {Object} Named object references */
|
|
284
|
+
get refs() { return this.#refs; }
|
|
285
|
+
|
|
286
|
+
/** @returns {Object} Shared state */
|
|
287
|
+
get state() { return this.#state; }
|
|
288
|
+
|
|
289
|
+
/** @returns {import('./fluent-game.js').FluentGame} Parent FluentGame */
|
|
290
|
+
get parent() { return this.#parent; }
|
|
291
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Fluent
|
|
3
|
+
* @description Declarative fluent builder API for GCanvas
|
|
4
|
+
*
|
|
5
|
+
* This module provides a chainable, declarative API layer on top of GCanvas's
|
|
6
|
+
* object-oriented architecture. It enables rapid creative coding while maintaining
|
|
7
|
+
* full access to the underlying power.
|
|
8
|
+
*
|
|
9
|
+
* ## Entry Points
|
|
10
|
+
*
|
|
11
|
+
* - **gcanvas(options)** - Full fluent API for building games and interactive apps
|
|
12
|
+
* - **sketch(w, h, bg)** - Ultra-simple mode for quick creative coding prototypes
|
|
13
|
+
*
|
|
14
|
+
* ## Quick Start
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // Full fluent API
|
|
18
|
+
* import { gcanvas } from 'gcanvas';
|
|
19
|
+
*
|
|
20
|
+
* gcanvas({ bg: 'black' })
|
|
21
|
+
* .scene('game')
|
|
22
|
+
* .go({ x: 400, y: 300, name: 'player' })
|
|
23
|
+
* .circle({ radius: 30, fill: 'lime' })
|
|
24
|
+
* .pulse({ min: 0.9, max: 1.1, duration: 1 })
|
|
25
|
+
* .scene('ui', { zIndex: 100 })
|
|
26
|
+
* .go({ x: 20, y: 20 })
|
|
27
|
+
* .text('SCORE: 0', { font: '24px monospace', fill: 'white' })
|
|
28
|
+
* .on('update', (dt, ctx) => {
|
|
29
|
+
* // Game logic
|
|
30
|
+
* })
|
|
31
|
+
* .start();
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // Sketch mode for quick prototypes
|
|
35
|
+
* import { sketch } from 'gcanvas';
|
|
36
|
+
*
|
|
37
|
+
* sketch(800, 600, '#1a1a1a')
|
|
38
|
+
* .grid(10, 10, 80, (s, x, y, i, j) => {
|
|
39
|
+
* s.circle(x, y, 20, `hsl(${(i + j) * 20}, 70%, 60%)`);
|
|
40
|
+
* })
|
|
41
|
+
* .update((dt, ctx) => {
|
|
42
|
+
* ctx.shapes.forEach((shape, i) => {
|
|
43
|
+
* shape.y += Math.sin(ctx.time * 2 + i * 0.1) * 0.5;
|
|
44
|
+
* });
|
|
45
|
+
* })
|
|
46
|
+
* .start();
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // Class injection - use custom classes with fluent API
|
|
50
|
+
* import { gcanvas } from 'gcanvas';
|
|
51
|
+
* import { SpaceScene } from './scenes/space-scene';
|
|
52
|
+
* import { Player, Alien, Boss } from './entities';
|
|
53
|
+
*
|
|
54
|
+
* gcanvas({ bg: 'black' })
|
|
55
|
+
* // Pass custom scene class
|
|
56
|
+
* .scene(SpaceScene)
|
|
57
|
+
* // Or with name: .scene('game', SpaceScene, { zIndex: 0 })
|
|
58
|
+
*
|
|
59
|
+
* // Pass custom GameObject classes
|
|
60
|
+
* .go(Player, { x: 400, y: 500, name: 'player' })
|
|
61
|
+
* .go(Alien, { x: 100, y: 100, type: 0 })
|
|
62
|
+
* .go(Boss, { x: 400, y: 150, bossType: 2 })
|
|
63
|
+
*
|
|
64
|
+
* .start();
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* // Composable scene modules
|
|
68
|
+
* // scenes/player.js
|
|
69
|
+
* export const playerScene = (g) => g
|
|
70
|
+
* .inScene('game')
|
|
71
|
+
* .go({ x: 400, y: 300, name: 'player' })
|
|
72
|
+
* .circle({ radius: 25, fill: '#00ff88' });
|
|
73
|
+
*
|
|
74
|
+
* // main.js
|
|
75
|
+
* import { gcanvas } from 'gcanvas';
|
|
76
|
+
* import { playerScene } from './scenes/player';
|
|
77
|
+
*
|
|
78
|
+
* gcanvas({ bg: 'black' })
|
|
79
|
+
* .scene('game')
|
|
80
|
+
* .use(playerScene)
|
|
81
|
+
* .start();
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
// Main entry points
|
|
85
|
+
export { gcanvas, FluentGame } from "./fluent-game.js";
|
|
86
|
+
export { sketch } from "./sketch.js";
|
|
87
|
+
|
|
88
|
+
// Builder classes (for advanced usage/extension)
|
|
89
|
+
export { FluentScene } from "./fluent-scene.js";
|
|
90
|
+
export { FluentGO } from "./fluent-go.js";
|
|
91
|
+
export { FluentLayer } from "./fluent-layer.js";
|
|
92
|
+
|
|
93
|
+
// Re-export commonly used items for convenience
|
|
94
|
+
export { Motion } from "../motion/motion.js";
|
|
95
|
+
export { Easing } from "../motion/easing.js";
|
|
96
|
+
export { Tweenetik } from "../motion/tweenetik.js";
|
|
97
|
+
export { Keys } from "../io/keys.js";
|
|
98
|
+
export { Mouse } from "../io/mouse.js";
|