@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
package/readme.md
ADDED
|
@@ -0,0 +1,599 @@
|
|
|
1
|
+
# GCanvas ๐จ
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
A minimalist 2D canvas rendering library built for learning, expression, and creative coding.
|
|
6
|
+
|
|
7
|
+
Inspired by the simplicity of p5.js and the composability of game engines โ **GCanvas** gives you structured primitives, a game loop, interactivity, and a growing set of intuitive, declarative shapes.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# What is this?
|
|
12
|
+
|
|
13
|
+
GCanvas is a modular 2D rendering and game framework built on top of the HTML5 Canvas API.
|
|
14
|
+
|
|
15
|
+
At its core, it's split into two powerful layers:
|
|
16
|
+
|
|
17
|
+
- ๐จ **Shape Layer** โ for clean, declarative drawing via transformable primitives like `Circle`, `Rectangle`, and `Group`.
|
|
18
|
+
- ๐ฎ **Game Layer** โ for interactive, updatable `GameObject`s managed through a pipeline and real-time loop.
|
|
19
|
+
|
|
20
|
+
You can use GCanvas purely for visuals, or build full simulations, games, or creative tools on top.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## ๐ Features
|
|
25
|
+
|
|
26
|
+
- ๐ **Primitives** like `Circle`, `Line`, `Rectangle`, `Star`, `Polygon`, and more
|
|
27
|
+
- โฝ **2.5D Shapes** like `Cube`, `Cylinder`, `Prism`, `Sphere`, `Cone`
|
|
28
|
+
- ๐ฆ **Groups** for transformable shape collections
|
|
29
|
+
- ๐ **Transforms** โ rotation, scale, constraints, group nesting
|
|
30
|
+
- ๐๏ธ **Painter API** for imperative canvas control
|
|
31
|
+
- ๐พ **GameObjects** for updatable, interactive entities
|
|
32
|
+
- ๐ฑ **UI Components** like `Button`, `ToggleButton`, `Cursor`, and layout managers
|
|
33
|
+
- ๐๏ธ **Motion API** for game-time-driven animations
|
|
34
|
+
- ๐
**Tweenetik** for UI-style, self-running tweens
|
|
35
|
+
- ๐ **Event system** โ hover, click, mouse, and touch
|
|
36
|
+
- ๐ **Works with Vite, Rollup, or standalone**
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## ๐ Demo
|
|
41
|
+
|
|
42
|
+
Open [`https://gcanvas.guinetik.com`](https://gcanvas.guinetik.com) or run:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm run dev
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## ๐ข API Docs
|
|
49
|
+
|
|
50
|
+
Each shape and utility is JSDoc-annotated.
|
|
51
|
+
I'm organizing a docs folder on Github Pages.
|
|
52
|
+
For now, you can do `npm run docs` to generate the docs site.
|
|
53
|
+
|
|
54
|
+
### TypeScript Support
|
|
55
|
+
|
|
56
|
+
GCanvas includes TypeScript definitions (`gcanvas.d.ts`) for full IDE intellisense and type checking. The types are automatically included when you install the package.
|
|
57
|
+
|
|
58
|
+
## ๐งโ๐ป Installation
|
|
59
|
+
|
|
60
|
+
๏ธโ ๏ธComing soon to NPM.
|
|
61
|
+
|
|
62
|
+
For now, clone this repo:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git clone https://github.com/guinetik/gcanvas.git
|
|
66
|
+
cd gcanvas
|
|
67
|
+
npm install
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
To run our tech demos:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm run dev
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
To build the library:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npm run build
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
To generate a readable single-file debug build:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm run build:debug
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## ๐ Quick Start
|
|
91
|
+
|
|
92
|
+
### Using via ESM:
|
|
93
|
+
|
|
94
|
+
```js
|
|
95
|
+
import { Circle } from './dist/gcanvas.es.min.js';
|
|
96
|
+
|
|
97
|
+
const circle = new Circle(100, 100, 50, { fillColor: 'red' });
|
|
98
|
+
circle.draw(); // uses static Painter.ctx internally
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Using via inline script:
|
|
102
|
+
|
|
103
|
+
```html
|
|
104
|
+
<script src="./dist/gcanvas.umd.min.js"></script>
|
|
105
|
+
<script>
|
|
106
|
+
const circle = new GCanvas.Circle(200, 200, 40, { fillColor: 'blue' });
|
|
107
|
+
circle.draw();
|
|
108
|
+
</script>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## ๐ง Core Architecture
|
|
114
|
+
|
|
115
|
+
Our engine follows a layered architecture that builds from simple drawing primitives up to interactive game objects and scenes.
|
|
116
|
+
|
|
117
|
+
### ๐๏ธ Painter Layer
|
|
118
|
+
|
|
119
|
+
At the foundation is `Painter` - a wrapper around the canvas context that centralizes all drawing operations. Instead of working with the Canvas API directly, we use `Painter` as an intermediate layer:
|
|
120
|
+
|
|
121
|
+
```js
|
|
122
|
+
// Painter is initialized with a canvas context
|
|
123
|
+
Painter.init(ctx);
|
|
124
|
+
|
|
125
|
+
// Now drawing operations use Painter's methods
|
|
126
|
+
Painter.shapes.circle(100, 100, 50, { fillColor: "red" });
|
|
127
|
+
Painter.shapes.rect(200, 200, 80, 40, { strokeColor: "blue" });
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### ๐ Transformable Properties
|
|
131
|
+
|
|
132
|
+
Next we have `Transformable`, which provides standard properties for positioning and displaying objects:
|
|
133
|
+
|
|
134
|
+
- Position (`x`, `y`)
|
|
135
|
+
- Size (`width`, `height`)
|
|
136
|
+
- Visual properties (opacity, visibility)
|
|
137
|
+
- Transformations (rotation, scaleX, scaleY)
|
|
138
|
+
|
|
139
|
+
Every visual element in the engine inherits from Transformable.
|
|
140
|
+
|
|
141
|
+
### ๐ Shape Layer
|
|
142
|
+
|
|
143
|
+
The Shape Layer is built on a hierarchy of classes that provide increasingly sophisticated rendering capabilities:
|
|
144
|
+
|
|
145
|
+
1. **Euclidian** - The base class that defines spatial properties (x, y, width, height)
|
|
146
|
+
2. **Geometry2d** - Adds bounding box calculations and constraints
|
|
147
|
+
3. **Transformable** - Introduces rotation and scaling capabilities
|
|
148
|
+
4. **Renderable** - Adds visual properties like opacity and visibility
|
|
149
|
+
5. **Shape** - The final layer that adds styling (fill, stroke, line width)
|
|
150
|
+
|
|
151
|
+
Each layer uses underscore-prefixed private fields (`_property`) for encapsulation, following a consistent pattern throughout the codebase:
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
class Shape extends Transformable {
|
|
155
|
+
constructor(options = {}) {
|
|
156
|
+
super(options);
|
|
157
|
+
this._fillColor = options.fillColor ?? null;
|
|
158
|
+
this._strokeColor = options.strokeColor ?? null;
|
|
159
|
+
this._lineWidth = options.lineWidth ?? 1;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
get fillColor() { return this._fillColor; }
|
|
163
|
+
set fillColor(v) { this._fillColor = v; }
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The engine provides standard shapes like `Circle`, `Rectangle`, `Star`, etc., all built on this foundation.
|
|
168
|
+
|
|
169
|
+
### ๐ฆ Group
|
|
170
|
+
|
|
171
|
+
`Group` is a special shape that contains other shapes. It applies its transforms to all children, allowing composite visuals to move and transform as a unit:
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
const group = new Group(400, 300);
|
|
175
|
+
group.add(new Circle(0, 0, 40, { fillColor: "red" }));
|
|
176
|
+
group.add(new Rectangle(0, 60, 80, 30, { fillColor: "blue" }));
|
|
177
|
+
|
|
178
|
+
// All shapes draw relative to the group position
|
|
179
|
+
group.draw();
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### ๐ช Pipeline
|
|
183
|
+
|
|
184
|
+
The `Pipeline` manages collections of objects that need to be updated and rendered each frame. It handles:
|
|
185
|
+
|
|
186
|
+
- The update/render sequence
|
|
187
|
+
- Addition/removal of objects
|
|
188
|
+
- Input event dispatch to the proper objects
|
|
189
|
+
|
|
190
|
+
```js
|
|
191
|
+
// Create and add objects to the pipeline
|
|
192
|
+
pipeline.add(player);
|
|
193
|
+
pipeline.add(enemy);
|
|
194
|
+
|
|
195
|
+
// Pipeline handles updates in sequence
|
|
196
|
+
pipeline.update(dt);
|
|
197
|
+
pipeline.render();
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### ๐น๏ธ Game
|
|
201
|
+
|
|
202
|
+
The `Game` class brings everything together with:
|
|
203
|
+
|
|
204
|
+
- Canvas management
|
|
205
|
+
- Animation frame timing
|
|
206
|
+
- Input system initialization
|
|
207
|
+
- Pipeline management
|
|
208
|
+
- Motion system integration
|
|
209
|
+
|
|
210
|
+
It's the core engine that drives everything:
|
|
211
|
+
|
|
212
|
+
```js
|
|
213
|
+
const game = new Game(canvasElement);
|
|
214
|
+
game.init(); // Set up your game
|
|
215
|
+
game.start(); // Start the game loop
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### โ๏ธ GameObject
|
|
219
|
+
|
|
220
|
+
`GameObject` extends `Transformable` and adds lifecycle methods:
|
|
221
|
+
|
|
222
|
+
- `update(dt)` โ Run game logic each frame
|
|
223
|
+
- `render()` โ Optional custom rendering
|
|
224
|
+
- Event handling through `enableInteractivity(shape)`
|
|
225
|
+
|
|
226
|
+
This is the base class for all interactive entities:
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
class Player extends GameObject {
|
|
230
|
+
constructor(game) {
|
|
231
|
+
super(game);
|
|
232
|
+
this.shape = new Circle(100, 100, 40, { fillColor: "blue" });
|
|
233
|
+
this.enableInteractivity(this.shape);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
update(dt) {
|
|
237
|
+
// Move based on input
|
|
238
|
+
if (this.game.input.isKeyDown('ArrowRight')) {
|
|
239
|
+
this.x += 200 * dt;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
render() {
|
|
244
|
+
this.shape.draw();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
onPointerDown(e) {
|
|
248
|
+
console.log('Player clicked!');
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### ๐ผ๏ธ Scene
|
|
254
|
+
|
|
255
|
+
`Scene` is a special GameObject that manages child GameObjects:
|
|
256
|
+
|
|
257
|
+
- Organizes objects into logical groups
|
|
258
|
+
- Handles nested input events
|
|
259
|
+
- Manages coordinate systems for children
|
|
260
|
+
|
|
261
|
+
```js
|
|
262
|
+
// Create a level scene
|
|
263
|
+
const level = new Scene(game);
|
|
264
|
+
level.add(new Player(game));
|
|
265
|
+
level.add(new Enemy(game));
|
|
266
|
+
|
|
267
|
+
// Add scene to the game
|
|
268
|
+
game.pipeline.add(level);
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### ๐ฑ UI System
|
|
272
|
+
|
|
273
|
+
Built on top of `GameObject` and `Scene`, the UI system provides:
|
|
274
|
+
|
|
275
|
+
- `Button` โ Clickable elements with visual states
|
|
276
|
+
- `ToggleButton` โ On/off toggleable buttons
|
|
277
|
+
- `Cursor` โ Custom cursor shapes
|
|
278
|
+
- Layout containers for automatic positioning:
|
|
279
|
+
- `HorizontalLayout`
|
|
280
|
+
- `VerticalLayout`
|
|
281
|
+
- `TileLayout`
|
|
282
|
+
|
|
283
|
+
```js
|
|
284
|
+
const ui = new Scene(game);
|
|
285
|
+
const menu = new VerticalLayout(game, {
|
|
286
|
+
spacing: 20,
|
|
287
|
+
align: "center"
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
menu.add(new Button(game, "Play"));
|
|
291
|
+
menu.add(new Button(game, "Options"));
|
|
292
|
+
menu.add(new Button(game, "Quit"));
|
|
293
|
+
|
|
294
|
+
ui.add(menu);
|
|
295
|
+
game.pipeline.add(ui);
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
All UI elements integrate with the animation systems for smooth transitions and effects.
|
|
299
|
+
|
|
300
|
+
## Building with Layers
|
|
301
|
+
|
|
302
|
+
This architecture lets you work at the appropriate level of abstraction:
|
|
303
|
+
|
|
304
|
+
1. **Simple visuals**: Use Shape and Group directly
|
|
305
|
+
2. **Interactive elements**: Create GameObjects
|
|
306
|
+
3. **Organized worlds**: Use Scenes to structure content
|
|
307
|
+
4. **Complete games**: Subclass Game with your own logic
|
|
308
|
+
5. **Rich interfaces**: Add UI elements for player interaction
|
|
309
|
+
|
|
310
|
+
Each layer builds on the ones below, creating a flexible and powerful framework for 2D canvas games.
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## ๐๏ธ Motion System
|
|
315
|
+
|
|
316
|
+
The framework provides standard easing functions along with two complementary animation systems:
|
|
317
|
+
|
|
318
|
+
### 1. `Motion` - Stateless animation primitives
|
|
319
|
+
|
|
320
|
+
The `Motion` system provides mathematical animation functions that calculate positions based on time input. These functions don't modify objects directly - instead they return values that you apply in your game logic.
|
|
321
|
+
|
|
322
|
+
```js
|
|
323
|
+
class Asteroid extends GameObject {
|
|
324
|
+
constructor(game) {
|
|
325
|
+
super(game);
|
|
326
|
+
this.shape = new Circle(0, 0, 40, { fillColor: "#555" });
|
|
327
|
+
this.time = 0;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
update(dt) {
|
|
331
|
+
this.time += dt;
|
|
332
|
+
|
|
333
|
+
// Get position from a spiral pattern
|
|
334
|
+
const result = Motion.spiral(
|
|
335
|
+
400, 300, // center point
|
|
336
|
+
50, 200, // start and end radius
|
|
337
|
+
0, 3, // start angle, revolutions
|
|
338
|
+
this.time, 5, // current time, duration
|
|
339
|
+
true, // loop
|
|
340
|
+
Easing.easeInOutSine
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
// Apply the result to our shape
|
|
344
|
+
this.shape.x = result.x;
|
|
345
|
+
this.shape.y = result.y;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
render() {
|
|
349
|
+
this.shape.draw();
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Motion functions:
|
|
355
|
+
- `bezier` - Follows along a cubic bezier curve.
|
|
356
|
+
- `bounce` - Objects that drop and bounce with decreasing height
|
|
357
|
+
- `float` - Natural floating motion with randomness
|
|
358
|
+
- `follow` - Follow paths of waypoints with turning
|
|
359
|
+
- `orbit` - Circular or elliptical orbits
|
|
360
|
+
- `oscillate` - Values that cycle between min and max
|
|
361
|
+
- `parabolic` - Arcing projectile motion
|
|
362
|
+
- `patrol` - Entities that wander within bounds
|
|
363
|
+
- `pendulum` - Swinging motion around a pivot (cosine)
|
|
364
|
+
- `pulse` - Values that pulse up and down
|
|
365
|
+
- `shake` - Camera or object shake effects
|
|
366
|
+
- `spiral` - Spiral paths with variable radius
|
|
367
|
+
- `spring` - Physics-based spring motion
|
|
368
|
+
- `swing` - Rotational swinging (sine)
|
|
369
|
+
- `waypoint` - Character movement between points
|
|
370
|
+
|
|
371
|
+
Each function returns standardized results with position, rotation, and animation metadata like progress and completion state.
|
|
372
|
+
|
|
373
|
+
Key advantages:
|
|
374
|
+
- Deterministic (same input time = same output)
|
|
375
|
+
- No state to track between frames
|
|
376
|
+
- Compatible with any rendering system
|
|
377
|
+
- Composable through grouping and sequencing
|
|
378
|
+
|
|
379
|
+
### 2. `Tweenetik` - Property animation
|
|
380
|
+
|
|
381
|
+
The `Tweenetik` system animates object properties directly over time using easing functions:
|
|
382
|
+
|
|
383
|
+
```js
|
|
384
|
+
// Animate a button when pressed
|
|
385
|
+
onPointerDown() {
|
|
386
|
+
Tweenetik.to(this.shape,
|
|
387
|
+
{ scaleX: 1.2, scaleY: 1.2 },
|
|
388
|
+
0.2,
|
|
389
|
+
Easing.easeOutBack,
|
|
390
|
+
{
|
|
391
|
+
onComplete: () => {
|
|
392
|
+
Tweenetik.to(this.shape,
|
|
393
|
+
{ scaleX: 1.0, scaleY: 1.0 },
|
|
394
|
+
0.3,
|
|
395
|
+
Easing.easeInOutQuad
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Tweenetik is ideal for:
|
|
404
|
+
- UI animations and transitions
|
|
405
|
+
- Simple property tweens
|
|
406
|
+
- Sequential animations with callbacks
|
|
407
|
+
|
|
408
|
+
All animations integrate with the game's update/render cycle. Tweenetik is automatically updated by the Pipeline, while Motion functions are called directly in your GameObject's update method.
|
|
409
|
+
|
|
410
|
+
### 3. `Easing` - Timing functions
|
|
411
|
+
|
|
412
|
+
Both systems use the same easing functions for consistent animation curves:
|
|
413
|
+
|
|
414
|
+
```js
|
|
415
|
+
Easing.easeInQuad // accelerating
|
|
416
|
+
Easing.easeOutBounce // bouncy ending
|
|
417
|
+
Easing.easeInOutCubic // smooth acceleration and deceleration
|
|
418
|
+
// ...and many more
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
These functions transform linear time (0-1) into curved progressions for natural motion.
|
|
422
|
+
|
|
423
|
+
### ๐งฉ Mixins
|
|
424
|
+
|
|
425
|
+
Mixins are behavior modules that add optional functionality to any `GameObject`. They're lightweight and composable: apply only what you need.
|
|
426
|
+
|
|
427
|
+
Current mixins include:
|
|
428
|
+
|
|
429
|
+
- `applyAnchor(go, options)` โ anchors the GameObject to a screen position like `"top-left"`, `"bottom-right"`, etc. Automatically repositions on resize.
|
|
430
|
+
- `applyDraggable(go, shape, options)` โ enables drag-and-drop behavior with pointer support and optional friction.
|
|
431
|
+
|
|
432
|
+
Example:
|
|
433
|
+
|
|
434
|
+
```js
|
|
435
|
+
applyAnchor(myUIElement, { anchor: "top-right", padding: 20 });
|
|
436
|
+
applyDraggable(myCard, myCard.shape);
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
You can combine multiple mixins to build rich UI/GameObject interactions without subclassing.
|
|
440
|
+
|
|
441
|
+
Mixins can also be passed as options:
|
|
442
|
+
```js
|
|
443
|
+
// Add FPS counter
|
|
444
|
+
this.scene.add(
|
|
445
|
+
new FPSCounter(game, {
|
|
446
|
+
anchor: "bottom-right",
|
|
447
|
+
})
|
|
448
|
+
);
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
...
|
|
452
|
+
|
|
453
|
+
## ๐ Example
|
|
454
|
+
|
|
455
|
+
### Hello World
|
|
456
|
+
```html
|
|
457
|
+
<html lang="en">
|
|
458
|
+
<head>
|
|
459
|
+
<meta charset="UTF-8" />
|
|
460
|
+
<title>Basic Game Template</title>
|
|
461
|
+
</head>
|
|
462
|
+
<body>
|
|
463
|
+
<canvas id="game"></canvas>
|
|
464
|
+
<script type="module">
|
|
465
|
+
import { Game, Scene, GameObject, FPSCounter, Rectangle, TextShape, Group } from "gcanvas";
|
|
466
|
+
class HelloWorld extends Game {
|
|
467
|
+
constructor(canvas) {
|
|
468
|
+
super(canvas);
|
|
469
|
+
this.enableFluidSize();
|
|
470
|
+
this.backgroundColor = "black";
|
|
471
|
+
}
|
|
472
|
+
init() {
|
|
473
|
+
// Set up scenes
|
|
474
|
+
this.scene = new Scene(this);
|
|
475
|
+
this.ui = new Scene(this);
|
|
476
|
+
this.pipeline.add(this.scene); // game layer
|
|
477
|
+
this.pipeline.add(this.ui); // UI layer
|
|
478
|
+
// Hello World box in the game scene
|
|
479
|
+
this.scene.add(new HelloWorldBox(this));
|
|
480
|
+
// FPS counter in the UI scene
|
|
481
|
+
this.ui.add(new FPSCounter(this, { anchor: "bottom-right" }));
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
//A Simple game object with a Shape and a Text box
|
|
486
|
+
class HelloWorldBox extends GameObject {
|
|
487
|
+
constructor(game) {
|
|
488
|
+
super(game);
|
|
489
|
+
|
|
490
|
+
const box = new Rectangle(0, 0, 200, 80, {
|
|
491
|
+
fillColor: "#111",
|
|
492
|
+
strokeColor: "#0f0",
|
|
493
|
+
lineWidth: 2,
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
const label = new TextShape(0, 0, "Hello World!", {
|
|
497
|
+
font: "18px monospace",
|
|
498
|
+
color: "#0f0",
|
|
499
|
+
align: "center",
|
|
500
|
+
baseline: "middle"
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
this.group = new Group(game.width / 2, game.height / 2);
|
|
504
|
+
this.group.add(box);
|
|
505
|
+
this.group.add(label);
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Render the Group
|
|
509
|
+
*/
|
|
510
|
+
render() {
|
|
511
|
+
this.group.draw();
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
window.addEventListener("load", () => {
|
|
516
|
+
const canvas = document.getElementById("game");
|
|
517
|
+
const game = new HelloWorld(canvas);
|
|
518
|
+
game.init();
|
|
519
|
+
game.start();
|
|
520
|
+
});
|
|
521
|
+
</script>
|
|
522
|
+
</body>
|
|
523
|
+
|
|
524
|
+
</html>
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### ๐ GameObject with Shape
|
|
528
|
+
|
|
529
|
+
```js
|
|
530
|
+
class Bob extends GameObject {
|
|
531
|
+
constructor(game) {
|
|
532
|
+
super(game);
|
|
533
|
+
this.shape = new Circle(100, 100, 40, { fillColor: "tomato" });
|
|
534
|
+
this.enableInteractivity(this.shape);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
update(dt) {
|
|
538
|
+
this.shape.x += Math.sin(Date.now() * 0.001) * dt * 60;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
render() {
|
|
542
|
+
this.shape.draw();
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
If you want to quickly wrap a `Shape` in a `GameObject` without writing a full class, you can use `ShapeGOFactory.create(...)`:
|
|
548
|
+
|
|
549
|
+
```js
|
|
550
|
+
const shape = new Rectangle(0, 0, 100, 50, { fillColor: "lime" });
|
|
551
|
+
const go = ShapeGOFactory.create(game, shape);
|
|
552
|
+
game.pipeline.add(go);
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
This creates a `GameObjectShapeWrapper` behind the scenes that keeps the transform in sync and draws the shape on each frame.
|
|
556
|
+
|
|
557
|
+
### ๐ซ Spinning Shape on Hover
|
|
558
|
+
|
|
559
|
+
```js
|
|
560
|
+
class SpinningShape extends GameObject {
|
|
561
|
+
constructor(game) {
|
|
562
|
+
super(game);
|
|
563
|
+
this.shape = new Circle(200, 200, 50, { fillColor: 'cyan' });
|
|
564
|
+
this.enableInteractivity(this.shape);
|
|
565
|
+
this.hovered = false;
|
|
566
|
+
|
|
567
|
+
this.on('mouseover', () => this.hovered = true);
|
|
568
|
+
this.on('mouseout', () => this.hovered = false);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
update(dt) {
|
|
572
|
+
if (this.hovered) this.shape.rotation += 2 * dt;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
render() {
|
|
576
|
+
this.shape.draw();
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
---
|
|
582
|
+
|
|
583
|
+
## ๐ File Structure
|
|
584
|
+
|
|
585
|
+
```bash
|
|
586
|
+
src/
|
|
587
|
+
โโโ shapes/ # All shape definitions (Circle, Triangle, Cube, etc.)
|
|
588
|
+
โโโ motion/ # Motion & Tweening systems
|
|
589
|
+
โโโ io/ # Mouse, Touch, Input
|
|
590
|
+
โโโ game/ # Game loop, GameObject, Pipeline
|
|
591
|
+
โโโ painter.js # Canvas context abstraction
|
|
592
|
+
โโโ index.js # Public API entry point
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
---
|
|
596
|
+
```
|
|
597
|
+
"jsdoc": "^4.0.4"
|
|
598
|
+
"better-docs": "^2.7.3"
|
|
599
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
|
|
9
|
+
const ROOT = path.join(__dirname, "..");
|
|
10
|
+
const DEMOS = path.join(ROOT, "demos");
|
|
11
|
+
const DIST = path.join(ROOT, "dist");
|
|
12
|
+
const PUBLIC = path.join(ROOT, "public");
|
|
13
|
+
const ESM_FILE = path.join(DIST, "gcanvas.es.min.js");
|
|
14
|
+
|
|
15
|
+
function cleanPublic() {
|
|
16
|
+
if (fs.existsSync(PUBLIC)) fs.rmSync(PUBLIC, { recursive: true });
|
|
17
|
+
fs.mkdirSync(PUBLIC);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function copyRecursive(src, dest) {
|
|
21
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
22
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
23
|
+
const srcPath = path.join(src, entry.name);
|
|
24
|
+
const destPath = path.join(dest, entry.name);
|
|
25
|
+
if (entry.isDirectory()) copyRecursive(srcPath, destPath);
|
|
26
|
+
else fs.copyFileSync(srcPath, destPath);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function rewriteImports(dir) {
|
|
31
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
32
|
+
const fullPath = path.join(dir, entry.name);
|
|
33
|
+
|
|
34
|
+
if (entry.isDirectory()) {
|
|
35
|
+
rewriteImports(fullPath);
|
|
36
|
+
} else if (entry.isFile() && /\.(js|html)$/.test(entry.name)) {
|
|
37
|
+
let content = fs.readFileSync(fullPath, "utf-8");
|
|
38
|
+
|
|
39
|
+
// Replace all imports pointing to any form of src/
|
|
40
|
+
content = content.replace(
|
|
41
|
+
/from\s+["'](\.{1,2}\/)+src\/[^"']+["']/g,
|
|
42
|
+
`from "/gcanvas.es.min.js"`
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
fs.writeFileSync(fullPath, content);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function run() {
|
|
51
|
+
console.log("๐งน Cleaning public/");
|
|
52
|
+
cleanPublic();
|
|
53
|
+
|
|
54
|
+
console.log("๐ฆ Running build");
|
|
55
|
+
execSync("npm run build", { stdio: "inherit" });
|
|
56
|
+
|
|
57
|
+
console.log("๐ Copying demos โ public/");
|
|
58
|
+
copyRecursive(DEMOS, PUBLIC);
|
|
59
|
+
|
|
60
|
+
console.log("๐ Copying gcanvas.es.min.js โ public/");
|
|
61
|
+
fs.copyFileSync(ESM_FILE, path.join(PUBLIC, "gcanvas.es.min.js"));
|
|
62
|
+
|
|
63
|
+
console.log("โ๏ธ Rewriting imports in public/...");
|
|
64
|
+
rewriteImports(PUBLIC);
|
|
65
|
+
|
|
66
|
+
console.log("โ
build:demo complete");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
run();
|