@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/src/math/gr.js
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* General Relativity utilities for spacetime visualization.
|
|
3
|
+
* Complements the Tensor class with higher-level embedding and coordinate functions.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* import { flammEmbedding, flammEmbeddingHeight } from './gr.js';
|
|
7
|
+
*
|
|
8
|
+
* // Raw Flamm's paraboloid height
|
|
9
|
+
* const z = flammEmbedding(10, 2, 1); // r=10, rs=2, M=1
|
|
10
|
+
*
|
|
11
|
+
* // Inverted for visualization (well goes "down")
|
|
12
|
+
* const height = flammEmbeddingHeight(10, 2, 1, 20, 25);
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
// EMBEDDING FUNCTIONS
|
|
17
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Flamm's paraboloid embedding for Schwarzschild/Kerr spacetime.
|
|
21
|
+
*
|
|
22
|
+
* The formula z = sqrt(8M(r - r_horizon)) gives the proper embedding
|
|
23
|
+
* of the spatial geometry into 3D Euclidean space.
|
|
24
|
+
*
|
|
25
|
+
* @param {number} r - Radial coordinate
|
|
26
|
+
* @param {number} rHorizon - Event horizon radius (rs for Schwarzschild, r+ for Kerr)
|
|
27
|
+
* @param {number} M - Mass parameter (in geometrized units G=c=1)
|
|
28
|
+
* @returns {number} Embedding height z (positive)
|
|
29
|
+
*/
|
|
30
|
+
export function flammEmbedding(r, rHorizon, M) {
|
|
31
|
+
if (r <= rHorizon) return 0;
|
|
32
|
+
return Math.sqrt(8 * M * (r - rHorizon));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Inverted embedding height for visualization.
|
|
37
|
+
*
|
|
38
|
+
* Returns a height value where:
|
|
39
|
+
* - Far from the black hole: height approaches 0 (flat)
|
|
40
|
+
* - Near the horizon: height increases (deep well)
|
|
41
|
+
*
|
|
42
|
+
* This is what you typically want for rendering the "gravity well" visualization.
|
|
43
|
+
*
|
|
44
|
+
* @param {number} r - Radial coordinate
|
|
45
|
+
* @param {number} rHorizon - Event horizon radius
|
|
46
|
+
* @param {number} M - Mass parameter
|
|
47
|
+
* @param {number} rMax - Maximum radius for normalization (typically grid size)
|
|
48
|
+
* @param {number} scale - Visual scale factor for the well depth
|
|
49
|
+
* @returns {number} Height value for rendering (larger = deeper in well)
|
|
50
|
+
*/
|
|
51
|
+
export function flammEmbeddingHeight(r, rHorizon, M, rMax, scale) {
|
|
52
|
+
// Clamp to just outside horizon
|
|
53
|
+
const rClamped = Math.max(r, rHorizon + 0.01);
|
|
54
|
+
|
|
55
|
+
// Flamm's paraboloid: z = sqrt(8M(r - r_horizon))
|
|
56
|
+
const z = flammEmbedding(rClamped, rHorizon, M);
|
|
57
|
+
const zMax = flammEmbedding(rMax, rHorizon, M);
|
|
58
|
+
|
|
59
|
+
// Invert so well goes "down", normalize by zMax
|
|
60
|
+
// This gives proper curvature behavior: steep near horizon, flat far away
|
|
61
|
+
return ((zMax - z) * scale) / zMax;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
65
|
+
// COORDINATE TRANSFORMATIONS
|
|
66
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Convert Cartesian coordinates to spherical coordinates.
|
|
70
|
+
*
|
|
71
|
+
* @param {number} x - Cartesian x
|
|
72
|
+
* @param {number} y - Cartesian y
|
|
73
|
+
* @param {number} z - Cartesian z
|
|
74
|
+
* @returns {{ r: number, theta: number, phi: number }} Spherical coordinates
|
|
75
|
+
*/
|
|
76
|
+
export function cartesianToSpherical(x, y, z) {
|
|
77
|
+
const r = Math.sqrt(x * x + y * y + z * z);
|
|
78
|
+
const theta = r > 0 ? Math.acos(z / r) : 0;
|
|
79
|
+
const phi = Math.atan2(y, x);
|
|
80
|
+
return { r, theta, phi };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Convert spherical coordinates to Cartesian coordinates.
|
|
85
|
+
*
|
|
86
|
+
* @param {number} r - Radial distance
|
|
87
|
+
* @param {number} theta - Polar angle (0 to π)
|
|
88
|
+
* @param {number} phi - Azimuthal angle (0 to 2π)
|
|
89
|
+
* @returns {{ x: number, y: number, z: number }} Cartesian coordinates
|
|
90
|
+
*/
|
|
91
|
+
export function sphericalToCartesian(r, theta, phi) {
|
|
92
|
+
const sinTheta = Math.sin(theta);
|
|
93
|
+
return {
|
|
94
|
+
x: r * sinTheta * Math.cos(phi),
|
|
95
|
+
y: r * sinTheta * Math.sin(phi),
|
|
96
|
+
z: r * Math.cos(theta),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Convert polar coordinates (r, phi) to Cartesian (x, z) in the equatorial plane.
|
|
102
|
+
* Commonly used for orbital visualization where y is the "height" axis.
|
|
103
|
+
*
|
|
104
|
+
* @param {number} r - Radial distance
|
|
105
|
+
* @param {number} phi - Azimuthal angle
|
|
106
|
+
* @returns {{ x: number, z: number }} Cartesian coordinates in equatorial plane
|
|
107
|
+
*/
|
|
108
|
+
export function polarToCartesian(r, phi) {
|
|
109
|
+
return {
|
|
110
|
+
x: r * Math.cos(phi),
|
|
111
|
+
z: r * Math.sin(phi),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Convert Cartesian (x, z) to polar (r, phi) in the equatorial plane.
|
|
117
|
+
*
|
|
118
|
+
* @param {number} x - Cartesian x
|
|
119
|
+
* @param {number} z - Cartesian z
|
|
120
|
+
* @returns {{ r: number, phi: number }} Polar coordinates
|
|
121
|
+
*/
|
|
122
|
+
export function cartesianToPolar(x, z) {
|
|
123
|
+
return {
|
|
124
|
+
r: Math.sqrt(x * x + z * z),
|
|
125
|
+
phi: Math.atan2(z, x),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
130
|
+
// GRAVITATIONAL LENSING
|
|
131
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Calculate gravitational lensing displacement for a point near a massive object.
|
|
135
|
+
*
|
|
136
|
+
* Light passing near a massive object is deflected, causing background objects
|
|
137
|
+
* to appear displaced radially outward from the lens center. This creates the
|
|
138
|
+
* "Einstein ring" effect where objects directly behind the lens form a ring.
|
|
139
|
+
*
|
|
140
|
+
* This is a simplified screen-space approximation suitable for real-time rendering.
|
|
141
|
+
* True lensing would require ray-tracing through curved spacetime.
|
|
142
|
+
*
|
|
143
|
+
* @param {number} screenDist - Distance from lens center in screen pixels
|
|
144
|
+
* @param {number} effectRadius - Maximum radius of lensing effect in pixels
|
|
145
|
+
* @param {number} strength - Displacement strength (higher = more dramatic)
|
|
146
|
+
* @param {number} falloff - Exponential falloff rate (higher = tighter effect)
|
|
147
|
+
* @param {number} minDist - Minimum distance to apply lensing (avoids singularity)
|
|
148
|
+
* @returns {number} Radial displacement in pixels (0 if outside effect radius)
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* // Calculate displacement for a star 100px from black hole center
|
|
152
|
+
* const displacement = gravitationalLensing(100, 500, 200, 0.008, 5);
|
|
153
|
+
* // Apply: newRadius = screenDist + displacement
|
|
154
|
+
*/
|
|
155
|
+
export function gravitationalLensing(screenDist, effectRadius, strength, falloff, minDist = 5) {
|
|
156
|
+
if (screenDist <= minDist || screenDist >= effectRadius) {
|
|
157
|
+
return 0;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Exponential falloff: stronger closer to lens center
|
|
161
|
+
const lensFactor = Math.exp(-screenDist * falloff);
|
|
162
|
+
|
|
163
|
+
return lensFactor * strength;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Apply gravitational lensing to screen coordinates.
|
|
168
|
+
*
|
|
169
|
+
* Takes a point's screen position (relative to lens center) and returns
|
|
170
|
+
* the displaced position after lensing.
|
|
171
|
+
*
|
|
172
|
+
* @param {number} x - X coordinate relative to lens center
|
|
173
|
+
* @param {number} y - Y coordinate relative to lens center
|
|
174
|
+
* @param {number} effectRadius - Maximum radius of lensing effect
|
|
175
|
+
* @param {number} strength - Displacement strength
|
|
176
|
+
* @param {number} falloff - Exponential falloff rate
|
|
177
|
+
* @param {number} minDist - Minimum distance for lensing
|
|
178
|
+
* @returns {{ x: number, y: number, displacement: number }} Displaced coordinates and displacement amount
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* const result = applyGravitationalLensing(50, 30, 500, 200, 0.008);
|
|
182
|
+
* ctx.drawImage(star, centerX + result.x, centerY + result.y, ...);
|
|
183
|
+
*/
|
|
184
|
+
export function applyGravitationalLensing(x, y, effectRadius, strength, falloff, minDist = 5) {
|
|
185
|
+
const dist = Math.sqrt(x * x + y * y);
|
|
186
|
+
|
|
187
|
+
if (dist <= minDist || dist >= effectRadius) {
|
|
188
|
+
return { x, y, displacement: 0 };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const displacement = gravitationalLensing(dist, effectRadius, strength, falloff, minDist);
|
|
192
|
+
|
|
193
|
+
// Radial displacement: push point outward from center
|
|
194
|
+
const ratio = (dist + displacement) / dist;
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
x: x * ratio,
|
|
198
|
+
y: y * ratio,
|
|
199
|
+
displacement
|
|
200
|
+
};
|
|
201
|
+
}
|
package/src/math/heat.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heat Dynamics Module
|
|
3
|
+
*
|
|
4
|
+
* Particle-based heat physics functions for simulating thermal behavior:
|
|
5
|
+
* - Zone-based temperature changes (heating/cooling regions)
|
|
6
|
+
* - Buoyancy forces from temperature differentials
|
|
7
|
+
* - Heat transfer between particles
|
|
8
|
+
*
|
|
9
|
+
* Designed for lava lamp, fluid simulations, and particle systems.
|
|
10
|
+
*
|
|
11
|
+
* @see Easing.smoothstep, Easing.lerp in src/motion/easing.js for interpolation utilities
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { Easing } from "../motion/easing.js";
|
|
15
|
+
|
|
16
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
17
|
+
// TEMPERATURE FUNCTIONS
|
|
18
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Attempt ot use this as smoothstep with edge parameters (wrapper for Easing.smoothstep).
|
|
22
|
+
* @private
|
|
23
|
+
*/
|
|
24
|
+
function smoothstep(edge0, edge1, x) {
|
|
25
|
+
const t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0)));
|
|
26
|
+
return Easing.smoothstep(t);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Calculate temperature change based on position in thermal zones.
|
|
31
|
+
* Uses smooth transitions between zones instead of hard boundaries.
|
|
32
|
+
*
|
|
33
|
+
* Zone layout (normalized y: 0 = top, 1 = bottom):
|
|
34
|
+
* - Cool zone: y < coolZone (temperature approaches 0)
|
|
35
|
+
* - Middle zone: between coolZone and heatZone (temperature approaches y position)
|
|
36
|
+
* - Heat zone: y > heatZone (temperature approaches 1)
|
|
37
|
+
*
|
|
38
|
+
* @param {number} position - Normalized position [0, 1] (typically y coordinate)
|
|
39
|
+
* @param {number} currentTemp - Current temperature [0, 1]
|
|
40
|
+
* @param {Object} config - Zone configuration
|
|
41
|
+
* @param {number} config.heatZone - Y position where heating begins (e.g., 0.92)
|
|
42
|
+
* @param {number} config.coolZone - Y position where cooling begins (e.g., 0.2)
|
|
43
|
+
* @param {number} config.rate - Base temperature change rate
|
|
44
|
+
* @param {number} [config.heatMultiplier=1.5] - Heating rate multiplier
|
|
45
|
+
* @param {number} [config.coolMultiplier=1.5] - Cooling rate multiplier
|
|
46
|
+
* @param {number} [config.middleMultiplier=0.05] - Middle zone rate multiplier
|
|
47
|
+
* @param {number} [config.transitionWidth=0.1] - Width of smooth transition zones
|
|
48
|
+
* @returns {number} New temperature value [0, 1]
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* const temp = zoneTemperature(0.95, 0.5, {
|
|
52
|
+
* heatZone: 0.92, coolZone: 0.2, rate: 0.0055
|
|
53
|
+
* });
|
|
54
|
+
*/
|
|
55
|
+
export function zoneTemperature(position, currentTemp, config) {
|
|
56
|
+
const {
|
|
57
|
+
heatZone,
|
|
58
|
+
coolZone,
|
|
59
|
+
rate,
|
|
60
|
+
heatMultiplier = 1.5,
|
|
61
|
+
coolMultiplier = 1.5,
|
|
62
|
+
middleMultiplier = 0.05,
|
|
63
|
+
transitionWidth = 0.1,
|
|
64
|
+
} = config;
|
|
65
|
+
|
|
66
|
+
// Calculate zone influence using smoothstep for soft transitions
|
|
67
|
+
// Heat zone influence: ramps up as position exceeds heatZone
|
|
68
|
+
const heatInfluence = smoothstep(heatZone - transitionWidth, heatZone + transitionWidth * 0.5, position);
|
|
69
|
+
|
|
70
|
+
// Cool zone influence: ramps up as position goes below coolZone
|
|
71
|
+
const coolInfluence = 1 - smoothstep(coolZone - transitionWidth * 0.5, coolZone + transitionWidth, position);
|
|
72
|
+
|
|
73
|
+
// Middle zone is whatever's left
|
|
74
|
+
const middleInfluence = 1 - heatInfluence - coolInfluence;
|
|
75
|
+
|
|
76
|
+
// Calculate target temperatures and rates for each zone
|
|
77
|
+
let deltaTemp = 0;
|
|
78
|
+
|
|
79
|
+
// Heat zone: temperature approaches 1.0
|
|
80
|
+
if (heatInfluence > 0) {
|
|
81
|
+
deltaTemp += (1.0 - currentTemp) * rate * heatMultiplier * heatInfluence;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Cool zone: temperature approaches 0.0
|
|
85
|
+
if (coolInfluence > 0) {
|
|
86
|
+
deltaTemp += (0.0 - currentTemp) * rate * coolMultiplier * coolInfluence;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Middle zone: temperature approaches position (linear gradient)
|
|
90
|
+
if (middleInfluence > 0) {
|
|
91
|
+
deltaTemp += (position - currentTemp) * rate * middleMultiplier * middleInfluence;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Apply and clamp
|
|
95
|
+
return Math.max(0, Math.min(1, currentTemp + deltaTemp));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
99
|
+
// BUOYANCY FUNCTIONS
|
|
100
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Calculate buoyancy force from temperature differential.
|
|
104
|
+
* Hot particles rise (negative velocity), cold particles sink (positive velocity).
|
|
105
|
+
*
|
|
106
|
+
* Based on simplified Archimedes principle where temperature acts as
|
|
107
|
+
* inverse density: hotter = less dense = more buoyant.
|
|
108
|
+
*
|
|
109
|
+
* @param {number} temperature - Particle temperature [0, 1]
|
|
110
|
+
* @param {number} neutralTemp - Temperature at which buoyancy is zero (typically 0.5)
|
|
111
|
+
* @param {number} strength - Buoyancy force strength coefficient
|
|
112
|
+
* @returns {number} Velocity adjustment (negative = rise, positive = sink)
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* // Hot particle rises
|
|
116
|
+
* const lift = thermalBuoyancy(0.9, 0.5, 0.00018); // negative value
|
|
117
|
+
* particle.vy -= lift; // subtracting negative = rising
|
|
118
|
+
*
|
|
119
|
+
* // Cold particle sinks
|
|
120
|
+
* const sink = thermalBuoyancy(0.2, 0.5, 0.00018); // positive value
|
|
121
|
+
*/
|
|
122
|
+
export function thermalBuoyancy(temperature, neutralTemp, strength) {
|
|
123
|
+
return (temperature - neutralTemp) * strength;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Calculate weight-adjusted gravity force.
|
|
128
|
+
* Larger particles experience more gravitational pull.
|
|
129
|
+
*
|
|
130
|
+
* @param {number} radius - Particle radius
|
|
131
|
+
* @param {number} baseRadius - Reference radius for weight = 1
|
|
132
|
+
* @param {number} gravity - Base gravity coefficient
|
|
133
|
+
* @returns {number} Gravity force to add to vertical velocity
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* const weight = thermalGravity(0.06, 0.04, 0.000052);
|
|
137
|
+
* particle.vy += weight;
|
|
138
|
+
*/
|
|
139
|
+
export function thermalGravity(radius, baseRadius, gravity) {
|
|
140
|
+
const weight = radius / baseRadius;
|
|
141
|
+
return gravity * weight;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
145
|
+
// HEAT TRANSFER FUNCTIONS
|
|
146
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Calculate heat transfer between two particles.
|
|
150
|
+
* Uses Newton's law of cooling: heat flows from hot to cold proportionally
|
|
151
|
+
* to the temperature difference.
|
|
152
|
+
*
|
|
153
|
+
* @param {number} temp1 - Temperature of first particle [0, 1]
|
|
154
|
+
* @param {number} temp2 - Temperature of second particle [0, 1]
|
|
155
|
+
* @param {number} distance - Distance between particle centers
|
|
156
|
+
* @param {number} maxDistance - Maximum distance for heat transfer
|
|
157
|
+
* @param {number} rate - Heat transfer rate coefficient
|
|
158
|
+
* @returns {number} Temperature change for particle 1 (add to temp1)
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* const dist = Math.sqrt(dx*dx + dy*dy);
|
|
162
|
+
* const maxDist = (blob1.r + blob2.r) * 1.5;
|
|
163
|
+
* const delta = heatTransfer(blob1.temp, blob2.temp, dist, maxDist, 0.0022);
|
|
164
|
+
* blob1.temp += delta;
|
|
165
|
+
*/
|
|
166
|
+
export function heatTransfer(temp1, temp2, distance, maxDistance, rate) {
|
|
167
|
+
if (distance >= maxDistance) return 0;
|
|
168
|
+
|
|
169
|
+
// Heat flows from hot to cold
|
|
170
|
+
const heatDiff = temp2 - temp1;
|
|
171
|
+
|
|
172
|
+
// Optional: scale transfer by proximity (closer = faster transfer)
|
|
173
|
+
// const proximity = 1 - (distance / maxDistance);
|
|
174
|
+
// return heatDiff * rate * proximity;
|
|
175
|
+
|
|
176
|
+
return heatDiff * rate;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Calculate heat transfer with distance falloff.
|
|
181
|
+
* Transfer rate decreases with distance for more realistic behavior.
|
|
182
|
+
*
|
|
183
|
+
* @param {number} temp1 - Temperature of first particle [0, 1]
|
|
184
|
+
* @param {number} temp2 - Temperature of second particle [0, 1]
|
|
185
|
+
* @param {number} distance - Distance between particle centers
|
|
186
|
+
* @param {number} maxDistance - Maximum distance for heat transfer
|
|
187
|
+
* @param {number} rate - Base heat transfer rate coefficient
|
|
188
|
+
* @param {number} [falloff=1] - Distance falloff exponent (1 = linear, 2 = quadratic)
|
|
189
|
+
* @returns {number} Temperature change for particle 1
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* // Quadratic falloff for more localized heat transfer
|
|
193
|
+
* const delta = heatTransferFalloff(t1, t2, dist, maxDist, 0.003, 2);
|
|
194
|
+
*/
|
|
195
|
+
export function heatTransferFalloff(temp1, temp2, distance, maxDistance, rate, falloff = 1) {
|
|
196
|
+
if (distance >= maxDistance) return 0;
|
|
197
|
+
|
|
198
|
+
const heatDiff = temp2 - temp1;
|
|
199
|
+
const proximity = Math.pow(1 - distance / maxDistance, falloff);
|
|
200
|
+
|
|
201
|
+
return heatDiff * rate * proximity;
|
|
202
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export {Random} from "./random.js";
|
|
2
|
+
export {Complex} from "./complex.js";
|
|
3
|
+
export {Fractals} from "./fractal.js";
|
|
4
|
+
export {Patterns} from "./patterns.js";
|
|
5
|
+
export {Noise} from "./noise.js";
|
|
6
|
+
export {Tensor} from "./tensor.js";
|
|
7
|
+
|
|
8
|
+
// Physics modules
|
|
9
|
+
export * from "./gr.js";
|
|
10
|
+
export * from "./orbital.js";
|
|
11
|
+
export * from "./quantum.js";
|
|
12
|
+
export * from "./heat.js";
|