@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,317 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Applies layout positions to items with optional transformation
|
|
3
|
+
*
|
|
4
|
+
* @param {Object[]} items - Array of objects to position (must have x, y properties)
|
|
5
|
+
* @param {Object[]} positions - Array of position objects from layout functions
|
|
6
|
+
* @param {Object} options - Options for applying positions
|
|
7
|
+
* @param {number} [options.offsetX=0] - X offset to apply to all positions
|
|
8
|
+
* @param {number} [options.offsetY=0] - Y offset to apply to all positions
|
|
9
|
+
* @param {function} [options.transform] - Optional transform function to apply to positions
|
|
10
|
+
* @return {Object[]} The items with updated positions
|
|
11
|
+
*/
|
|
12
|
+
export function applyLayout(items, positions, options = {}) {
|
|
13
|
+
const offsetX = options.offsetX ?? 0;
|
|
14
|
+
const offsetY = options.offsetY ?? 0;
|
|
15
|
+
const transform = options.transform;
|
|
16
|
+
|
|
17
|
+
items.forEach((item, index) => {
|
|
18
|
+
if (index < positions.length) {
|
|
19
|
+
const pos = positions[index];
|
|
20
|
+
|
|
21
|
+
if (transform) {
|
|
22
|
+
const transformed = transform(pos);
|
|
23
|
+
item.x = transformed.x + offsetX;
|
|
24
|
+
item.y = transformed.y + offsetY;
|
|
25
|
+
} else {
|
|
26
|
+
item.x = pos.x + offsetX;
|
|
27
|
+
item.y = pos.y + offsetY;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return items;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Creates a horizontal layout for the given items
|
|
37
|
+
*
|
|
38
|
+
* @param {Object[]} items - Array of objects with width and height properties
|
|
39
|
+
* @param {Object} options - Layout configuration options
|
|
40
|
+
* @param {number} [options.spacing=10] - Space between items
|
|
41
|
+
* @param {number} [options.padding=0] - Padding around the entire layout
|
|
42
|
+
* @param {string} [options.align="start"] - Vertical alignment ("start", "center", "end")
|
|
43
|
+
* @param {boolean} [options.centerItems=true] - Whether to position items relative to their centers
|
|
44
|
+
* @return {Object} Result containing positioned items and layout dimensions
|
|
45
|
+
*/
|
|
46
|
+
export function horizontalLayout(items, options = {}) {
|
|
47
|
+
const spacing = options.spacing ?? 10;
|
|
48
|
+
const padding = options.padding ?? 0;
|
|
49
|
+
const align = options.align ?? "start";
|
|
50
|
+
const centerItems = options.centerItems ?? true;
|
|
51
|
+
|
|
52
|
+
let x = padding;
|
|
53
|
+
let maxHeight = 0;
|
|
54
|
+
const positions = [];
|
|
55
|
+
|
|
56
|
+
// First pass: get max height
|
|
57
|
+
for (const item of items) {
|
|
58
|
+
maxHeight = Math.max(maxHeight, item.height ?? 0);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Second pass: calculate positions
|
|
62
|
+
for (let i = 0; i < items.length; i++) {
|
|
63
|
+
const item = items[i];
|
|
64
|
+
const width = item.width ?? 0;
|
|
65
|
+
const height = item.height ?? 0;
|
|
66
|
+
|
|
67
|
+
// X position depends on whether we're centering the items
|
|
68
|
+
const itemX = centerItems ? x + width / 2 : x;
|
|
69
|
+
|
|
70
|
+
// Y position determined by alignment
|
|
71
|
+
let itemY;
|
|
72
|
+
switch (align) {
|
|
73
|
+
case "center":
|
|
74
|
+
itemY = (maxHeight - height) / 2;
|
|
75
|
+
break;
|
|
76
|
+
case "end":
|
|
77
|
+
itemY = maxHeight - height;
|
|
78
|
+
break;
|
|
79
|
+
case "start":
|
|
80
|
+
default:
|
|
81
|
+
itemY = 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
positions.push({ x: itemX, y: itemY });
|
|
85
|
+
|
|
86
|
+
// Move to next position
|
|
87
|
+
x += width;
|
|
88
|
+
if (i < items.length - 1) {
|
|
89
|
+
x += spacing;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Calculate total dimensions
|
|
94
|
+
const totalWidth = x + padding;
|
|
95
|
+
const totalHeight = maxHeight + padding * 2;
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
positions,
|
|
99
|
+
width: totalWidth,
|
|
100
|
+
height: totalHeight,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Creates a vertical layout for the given items
|
|
106
|
+
*
|
|
107
|
+
* @param {Object[]} items - Array of objects with width and height properties
|
|
108
|
+
* @param {Object} options - Layout configuration options
|
|
109
|
+
* @param {number} [options.spacing=10] - Space between items
|
|
110
|
+
* @param {number} [options.padding=0] - Padding around the entire layout
|
|
111
|
+
* @param {string} [options.align="start"] - Horizontal alignment ("start", "center", "end")
|
|
112
|
+
* @param {boolean} [options.centerItems=true] - Whether to position items relative to their centers
|
|
113
|
+
* @return {Object} Result containing positioned items and layout dimensions
|
|
114
|
+
*/
|
|
115
|
+
export function verticalLayout(items, options = {}) {
|
|
116
|
+
const spacing = options.spacing ?? 10;
|
|
117
|
+
const padding = options.padding ?? 0;
|
|
118
|
+
const align = options.align ?? "start";
|
|
119
|
+
const centerItems = options.centerItems ?? true;
|
|
120
|
+
|
|
121
|
+
let y = padding;
|
|
122
|
+
let maxWidth = 0;
|
|
123
|
+
const positions = [];
|
|
124
|
+
|
|
125
|
+
// First pass: get max width
|
|
126
|
+
for (const item of items) {
|
|
127
|
+
maxWidth = Math.max(maxWidth, item.width ?? 0);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Second pass: calculate positions
|
|
131
|
+
for (let i = 0; i < items.length; i++) {
|
|
132
|
+
const item = items[i];
|
|
133
|
+
const width = item.width ?? 0;
|
|
134
|
+
const height = item.height ?? 0;
|
|
135
|
+
|
|
136
|
+
// Y position depends on whether we're centering the items
|
|
137
|
+
const itemY = centerItems ? y + height / 2 : y;
|
|
138
|
+
|
|
139
|
+
// X position determined by alignment
|
|
140
|
+
let itemX;
|
|
141
|
+
switch (align) {
|
|
142
|
+
case "center":
|
|
143
|
+
itemX = (maxWidth - width) / 2;
|
|
144
|
+
break;
|
|
145
|
+
case "end":
|
|
146
|
+
itemX = maxWidth - width;
|
|
147
|
+
break;
|
|
148
|
+
case "start":
|
|
149
|
+
default:
|
|
150
|
+
itemX = 0;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
positions.push({ x: itemX, y: itemY });
|
|
154
|
+
|
|
155
|
+
// Move to next position
|
|
156
|
+
y += height;
|
|
157
|
+
if (i < items.length - 1) {
|
|
158
|
+
y += spacing;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Calculate total dimensions
|
|
163
|
+
const totalWidth = maxWidth + padding * 2;
|
|
164
|
+
const totalHeight = y + padding;
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
positions,
|
|
168
|
+
width: totalWidth,
|
|
169
|
+
height: totalHeight,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Creates a tile layout for the given items
|
|
175
|
+
*
|
|
176
|
+
* @param {Object[]} items - Array of objects with width and height properties
|
|
177
|
+
* @param {Object} options - Layout configuration options
|
|
178
|
+
* @param {number} [options.columns=4] - Number of columns in the grid
|
|
179
|
+
* @param {number} [options.spacing=10] - Space between items
|
|
180
|
+
* @param {number} [options.padding=0] - Padding around the entire layout
|
|
181
|
+
* @param {boolean} [options.centerItems=true] - Whether to position items relative to their centers
|
|
182
|
+
* @return {Object} Result containing positioned items and layout dimensions
|
|
183
|
+
*/
|
|
184
|
+
export function tileLayout(items, options = {}) {
|
|
185
|
+
if (items.length === 0) {
|
|
186
|
+
return { positions: [], width: 0, height: 0 };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const columns = options.columns ?? 4;
|
|
190
|
+
const spacing = options.spacing ?? 10;
|
|
191
|
+
const padding = options.padding ?? 0;
|
|
192
|
+
const centerItems = options.centerItems ?? true;
|
|
193
|
+
|
|
194
|
+
// Assume uniform tile size based on first item
|
|
195
|
+
const tileWidth = items[0].width ?? 0;
|
|
196
|
+
const tileHeight = items[0].height ?? 0;
|
|
197
|
+
|
|
198
|
+
const rowCount = Math.ceil(items.length / columns);
|
|
199
|
+
const positions = [];
|
|
200
|
+
|
|
201
|
+
// Calculate grid dimensions
|
|
202
|
+
const totalWidth =
|
|
203
|
+
columns * tileWidth + (columns - 1) * spacing + padding * 2;
|
|
204
|
+
const totalHeight =
|
|
205
|
+
rowCount * tileHeight + (rowCount - 1) * spacing + padding * 2;
|
|
206
|
+
|
|
207
|
+
// Set starting position at top-left corner
|
|
208
|
+
let x = padding;
|
|
209
|
+
let y = padding;
|
|
210
|
+
let colIndex = 0;
|
|
211
|
+
|
|
212
|
+
// Calculate positions for each item
|
|
213
|
+
for (let i = 0; i < items.length; i++) {
|
|
214
|
+
// Position depends on whether we're centering the items
|
|
215
|
+
const itemX = centerItems ? x + tileWidth / 2 : x;
|
|
216
|
+
const itemY = centerItems ? y + tileHeight / 2 : y;
|
|
217
|
+
|
|
218
|
+
positions.push({ x: itemX, y: itemY });
|
|
219
|
+
|
|
220
|
+
colIndex++;
|
|
221
|
+
if (colIndex < columns) {
|
|
222
|
+
x += tileWidth + spacing;
|
|
223
|
+
} else {
|
|
224
|
+
colIndex = 0;
|
|
225
|
+
x = padding;
|
|
226
|
+
y += tileHeight + spacing;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
positions,
|
|
232
|
+
width: totalWidth,
|
|
233
|
+
height: totalHeight,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export function gridLayout(items, options = {}) {
|
|
238
|
+
if (items.length === 0) {
|
|
239
|
+
return { positions: [], width: 0, height: 0 };
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const columns = options.columns ?? 4;
|
|
243
|
+
const spacing = options.spacing ?? 10;
|
|
244
|
+
const padding = options.padding ?? 0;
|
|
245
|
+
const centerItems = options.centerItems ?? true;
|
|
246
|
+
|
|
247
|
+
// Determine max width and height for each column and row
|
|
248
|
+
const colWidths = new Array(columns).fill(0);
|
|
249
|
+
const rowHeights = [];
|
|
250
|
+
|
|
251
|
+
items.forEach((item, index) => {
|
|
252
|
+
const col = index % columns;
|
|
253
|
+
const row = Math.floor(index / columns);
|
|
254
|
+
|
|
255
|
+
const itemWidth = item.width ?? 0;
|
|
256
|
+
const itemHeight = item.height ?? 0;
|
|
257
|
+
|
|
258
|
+
// Track max width for each column
|
|
259
|
+
colWidths[col] = Math.max(colWidths[col], itemWidth);
|
|
260
|
+
|
|
261
|
+
// Track max height for each row
|
|
262
|
+
if (rowHeights[row] === undefined) {
|
|
263
|
+
rowHeights[row] = itemHeight;
|
|
264
|
+
} else {
|
|
265
|
+
rowHeights[row] = Math.max(rowHeights[row], itemHeight);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// Calculate positions
|
|
270
|
+
const positions = [];
|
|
271
|
+
let x = padding;
|
|
272
|
+
let y = padding;
|
|
273
|
+
let colIndex = 0;
|
|
274
|
+
|
|
275
|
+
for (let i = 0; i < items.length; i++) {
|
|
276
|
+
const item = items[i];
|
|
277
|
+
const itemWidth = item.width ?? 0;
|
|
278
|
+
const itemHeight = item.height ?? 0;
|
|
279
|
+
const rowHeight = rowHeights[Math.floor(i / columns)];
|
|
280
|
+
|
|
281
|
+
// Position depends on whether we're centering the items
|
|
282
|
+
const posX = centerItems ? x + itemWidth / 2 : x;
|
|
283
|
+
const posY = centerItems ? y + itemHeight / 2 : y;
|
|
284
|
+
|
|
285
|
+
positions.push({ x: posX, y: posY });
|
|
286
|
+
|
|
287
|
+
// Move to next position
|
|
288
|
+
colIndex++;
|
|
289
|
+
if (colIndex < columns) {
|
|
290
|
+
x += colWidths[colIndex - 1] + spacing;
|
|
291
|
+
} else {
|
|
292
|
+
// Move to next row
|
|
293
|
+
colIndex = 0;
|
|
294
|
+
x = padding;
|
|
295
|
+
y += rowHeight + spacing;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Calculate total dimensions
|
|
300
|
+
const totalWidth =
|
|
301
|
+
padding * 2 +
|
|
302
|
+
colWidths.reduce((sum, width) => sum + width, 0) +
|
|
303
|
+
spacing * (columns - 1);
|
|
304
|
+
|
|
305
|
+
const totalHeight =
|
|
306
|
+
padding * 2 +
|
|
307
|
+
rowHeights.reduce((sum, height) => sum + height, 0) +
|
|
308
|
+
spacing * (rowHeights.length - 1);
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
positions,
|
|
312
|
+
width: totalWidth,
|
|
313
|
+
height: totalHeight,
|
|
314
|
+
cols: columns,
|
|
315
|
+
rows: rowHeights.length
|
|
316
|
+
};
|
|
317
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Position utility for consistently positioning objects relative to containers
|
|
3
|
+
* Provides anchor point constants and methods for calculating positions
|
|
4
|
+
*/
|
|
5
|
+
export class Position {
|
|
6
|
+
/**
|
|
7
|
+
* Anchor position constants
|
|
8
|
+
*/
|
|
9
|
+
static TOP_LEFT = "top-left";
|
|
10
|
+
static TOP_CENTER = "top-center";
|
|
11
|
+
static TOP_RIGHT = "top-right";
|
|
12
|
+
static CENTER_LEFT = "center-left";
|
|
13
|
+
static CENTER = "center";
|
|
14
|
+
static CENTER_RIGHT = "center-right";
|
|
15
|
+
static BOTTOM_LEFT = "bottom-left";
|
|
16
|
+
static BOTTOM_CENTER = "bottom-center";
|
|
17
|
+
static BOTTOM_RIGHT = "bottom-right";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Calculates position based on anchor point
|
|
21
|
+
*
|
|
22
|
+
* @param {string} anchor - Anchor position constant
|
|
23
|
+
* @param {Object} object - Object being positioned (with width and height)
|
|
24
|
+
* @param {Object} container - Container to position relative to (with x, y, width, height)
|
|
25
|
+
* @param {number} margin - Margin from the container edges
|
|
26
|
+
* @param {number} offsetX - Additional X offset
|
|
27
|
+
* @param {number} offsetY - Additional Y offset
|
|
28
|
+
* @returns {Object} Position and alignment information
|
|
29
|
+
*/
|
|
30
|
+
static calculate(anchor, object, container, margin = 10, offsetX = 0, offsetY = 0) {
|
|
31
|
+
// Ensure we have valid dimensions
|
|
32
|
+
const objectWidth = object.width || 0;
|
|
33
|
+
const objectHeight = object.height || 0;
|
|
34
|
+
|
|
35
|
+
const containerWidth = container.width || 0;
|
|
36
|
+
const containerHeight = container.height || 0;
|
|
37
|
+
const containerX = container.x || 0;
|
|
38
|
+
const containerY = container.y || 0;
|
|
39
|
+
|
|
40
|
+
// Calculate position based on anchor
|
|
41
|
+
let x, y, align, baseline;
|
|
42
|
+
|
|
43
|
+
switch (anchor) {
|
|
44
|
+
// Top row
|
|
45
|
+
case Position.TOP_LEFT:
|
|
46
|
+
x = (containerX - containerWidth/2) + margin + objectWidth/2;
|
|
47
|
+
y = (containerY - containerHeight/2) + margin + objectHeight/2;
|
|
48
|
+
align = "left";
|
|
49
|
+
baseline = "top";
|
|
50
|
+
break;
|
|
51
|
+
|
|
52
|
+
case Position.TOP_CENTER:
|
|
53
|
+
x = containerX;
|
|
54
|
+
y = (containerY - containerHeight/2) + margin + objectHeight/2;
|
|
55
|
+
align = "center";
|
|
56
|
+
baseline = "top";
|
|
57
|
+
break;
|
|
58
|
+
|
|
59
|
+
case Position.TOP_RIGHT:
|
|
60
|
+
x = (containerX + containerWidth/2) - margin - objectWidth/2;
|
|
61
|
+
y = (containerY - containerHeight/2) + margin + objectHeight/2;
|
|
62
|
+
align = "right";
|
|
63
|
+
baseline = "top";
|
|
64
|
+
break;
|
|
65
|
+
|
|
66
|
+
// Middle row
|
|
67
|
+
case Position.CENTER_LEFT:
|
|
68
|
+
x = (containerX - containerWidth/2) + margin + objectWidth/2;
|
|
69
|
+
y = containerY;
|
|
70
|
+
align = "left";
|
|
71
|
+
baseline = "middle";
|
|
72
|
+
break;
|
|
73
|
+
|
|
74
|
+
case Position.CENTER:
|
|
75
|
+
x = containerX;
|
|
76
|
+
y = containerY;
|
|
77
|
+
align = "center";
|
|
78
|
+
baseline = "middle";
|
|
79
|
+
break;
|
|
80
|
+
|
|
81
|
+
case Position.CENTER_RIGHT:
|
|
82
|
+
x = (containerX + containerWidth/2) - margin - objectWidth/2;
|
|
83
|
+
y = containerY;
|
|
84
|
+
align = "right";
|
|
85
|
+
baseline = "middle";
|
|
86
|
+
break;
|
|
87
|
+
|
|
88
|
+
// Bottom row
|
|
89
|
+
case Position.BOTTOM_LEFT:
|
|
90
|
+
//console.log("BOTTOM_LEFT", containerX, containerWidth, margin, objectWidth);
|
|
91
|
+
x = (containerX - containerWidth/2) + margin + objectWidth/2;
|
|
92
|
+
y = (containerY + containerHeight/2) - margin - objectHeight/2;
|
|
93
|
+
align = "left";
|
|
94
|
+
baseline = "bottom";
|
|
95
|
+
break;
|
|
96
|
+
|
|
97
|
+
case Position.BOTTOM_CENTER:
|
|
98
|
+
x = containerX;
|
|
99
|
+
y = (containerY + containerHeight/2) - margin - objectHeight/2;
|
|
100
|
+
align = "center";
|
|
101
|
+
baseline = "bottom";
|
|
102
|
+
break;
|
|
103
|
+
|
|
104
|
+
case Position.BOTTOM_RIGHT:
|
|
105
|
+
x = (containerX + containerWidth/2) - margin - objectWidth/2;
|
|
106
|
+
y = (containerY + containerHeight/2) - margin - objectHeight/2;
|
|
107
|
+
align = "right";
|
|
108
|
+
baseline = "bottom";
|
|
109
|
+
break;
|
|
110
|
+
|
|
111
|
+
default:
|
|
112
|
+
// Fallback to top-left
|
|
113
|
+
x = (containerX - containerWidth/2) + margin + objectWidth/2;
|
|
114
|
+
y = (containerY - containerHeight/2) + margin + objectHeight/2;
|
|
115
|
+
align = "left";
|
|
116
|
+
baseline = "top";
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Apply custom offsets
|
|
120
|
+
x += offsetX;
|
|
121
|
+
y += offsetY;
|
|
122
|
+
|
|
123
|
+
return { x, y, align, baseline };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Calculates absolute position relative to the game canvas
|
|
128
|
+
*
|
|
129
|
+
* @param {string} anchor - Anchor position constant
|
|
130
|
+
* @param {Object} object - Object being positioned
|
|
131
|
+
* @param {Object} game - Game object with canvas dimensions
|
|
132
|
+
* @param {number} margin - Margin from the edges
|
|
133
|
+
* @param {number} offsetX - Additional X offset
|
|
134
|
+
* @param {number} offsetY - Additional Y offset
|
|
135
|
+
* @returns {Object} Position and alignment information
|
|
136
|
+
*/
|
|
137
|
+
static calculateAbsolute(anchor, object, game, margin = 10, offsetX = 0, offsetY = 0) {
|
|
138
|
+
const container = {
|
|
139
|
+
width: game.width,
|
|
140
|
+
height: game.height,
|
|
141
|
+
x: game.width / 2,
|
|
142
|
+
y: game.height / 2
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
return Position.calculate(anchor, object, container, margin, offsetX, offsetY);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export class TaskManager {
|
|
2
|
+
constructor(workerUrl) {
|
|
3
|
+
this.worker = new Worker(workerUrl);
|
|
4
|
+
this.nextTaskId = 1;
|
|
5
|
+
this.pendingTasks = new Map();
|
|
6
|
+
|
|
7
|
+
// Set up message handler
|
|
8
|
+
this.worker.onmessage = this.handleMessage.bind(this);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
handleMessage(e) {
|
|
12
|
+
const { taskId, status, result, error } = e.data;
|
|
13
|
+
|
|
14
|
+
if (this.pendingTasks.has(taskId)) {
|
|
15
|
+
const { resolve, reject } = this.pendingTasks.get(taskId);
|
|
16
|
+
|
|
17
|
+
if (status === 'complete') {
|
|
18
|
+
resolve(result);
|
|
19
|
+
} else if (status === 'error') {
|
|
20
|
+
reject(new Error(error));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Remove the completed task
|
|
24
|
+
this.pendingTasks.delete(taskId);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
runTask(taskName, params) {
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
const taskId = this.nextTaskId++;
|
|
31
|
+
|
|
32
|
+
// Store the promise callbacks
|
|
33
|
+
this.pendingTasks.set(taskId, { resolve, reject });
|
|
34
|
+
|
|
35
|
+
// Send the task to the worker
|
|
36
|
+
this.worker.postMessage({
|
|
37
|
+
taskId,
|
|
38
|
+
taskName,
|
|
39
|
+
params
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
terminate() {
|
|
45
|
+
this.worker.terminate();
|
|
46
|
+
}
|
|
47
|
+
}
|