@guinetik/gcanvas 1.0.4 → 1.0.5

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.
Files changed (193) hide show
  1. package/dist/CNAME +1 -0
  2. package/dist/animations.html +31 -0
  3. package/dist/basic.html +38 -0
  4. package/dist/baskara.html +31 -0
  5. package/dist/bezier.html +35 -0
  6. package/dist/beziersignature.html +29 -0
  7. package/dist/blackhole.html +28 -0
  8. package/dist/blob.html +35 -0
  9. package/dist/coordinates.html +698 -0
  10. package/dist/cube3d.html +23 -0
  11. package/dist/demos.css +303 -0
  12. package/dist/dino.html +42 -0
  13. package/dist/easing.html +28 -0
  14. package/dist/events.html +195 -0
  15. package/dist/fluent.html +647 -0
  16. package/dist/fluid-simple.html +22 -0
  17. package/dist/fluid.html +37 -0
  18. package/dist/fractals.html +36 -0
  19. package/dist/gameobjects.html +626 -0
  20. package/dist/gcanvas.es.js +517 -0
  21. package/dist/gcanvas.es.min.js +1 -1
  22. package/dist/gcanvas.umd.js +1 -1
  23. package/dist/gcanvas.umd.min.js +1 -1
  24. package/dist/genart.html +26 -0
  25. package/dist/gendream.html +26 -0
  26. package/dist/group.html +36 -0
  27. package/dist/home.html +587 -0
  28. package/dist/hyperbolic001.html +23 -0
  29. package/dist/hyperbolic002.html +23 -0
  30. package/dist/hyperbolic003.html +23 -0
  31. package/dist/hyperbolic004.html +23 -0
  32. package/dist/hyperbolic005.html +22 -0
  33. package/dist/index.html +398 -0
  34. package/dist/isometric.html +34 -0
  35. package/dist/js/animations.js +452 -0
  36. package/dist/js/basic.js +204 -0
  37. package/dist/js/baskara.js +751 -0
  38. package/dist/js/bezier.js +692 -0
  39. package/dist/js/beziersignature.js +241 -0
  40. package/dist/js/blackhole/accretiondisk.obj.js +379 -0
  41. package/dist/js/blackhole/blackhole.obj.js +318 -0
  42. package/dist/js/blackhole/index.js +409 -0
  43. package/dist/js/blackhole/particle.js +56 -0
  44. package/dist/js/blackhole/starfield.obj.js +218 -0
  45. package/dist/js/blob.js +2276 -0
  46. package/dist/js/coordinates.js +840 -0
  47. package/dist/js/cube3d.js +789 -0
  48. package/dist/js/dino.js +1420 -0
  49. package/dist/js/easing.js +477 -0
  50. package/dist/js/fluent.js +183 -0
  51. package/dist/js/fluid-simple.js +253 -0
  52. package/dist/js/fluid.js +527 -0
  53. package/dist/js/fractals.js +932 -0
  54. package/dist/js/fractalworker.js +93 -0
  55. package/dist/js/gameobjects.js +176 -0
  56. package/dist/js/genart.js +268 -0
  57. package/dist/js/gendream.js +209 -0
  58. package/dist/js/group.js +140 -0
  59. package/dist/js/hyperbolic001.js +310 -0
  60. package/dist/js/hyperbolic002.js +388 -0
  61. package/dist/js/hyperbolic003.js +319 -0
  62. package/dist/js/hyperbolic004.js +345 -0
  63. package/dist/js/hyperbolic005.js +340 -0
  64. package/dist/js/info-toggle.js +25 -0
  65. package/dist/js/isometric.js +863 -0
  66. package/dist/js/kerr.js +1547 -0
  67. package/dist/js/lavalamp.js +590 -0
  68. package/dist/js/layout.js +354 -0
  69. package/dist/js/mondrian.js +285 -0
  70. package/dist/js/opacity.js +275 -0
  71. package/dist/js/painter.js +484 -0
  72. package/dist/js/particles-showcase.js +514 -0
  73. package/dist/js/particles.js +299 -0
  74. package/dist/js/patterns.js +397 -0
  75. package/dist/js/penrose/artifact.js +69 -0
  76. package/dist/js/penrose/blackhole.js +121 -0
  77. package/dist/js/penrose/constants.js +73 -0
  78. package/dist/js/penrose/game.js +943 -0
  79. package/dist/js/penrose/lore.js +278 -0
  80. package/dist/js/penrose/penrosescene.js +892 -0
  81. package/dist/js/penrose/ship.js +216 -0
  82. package/dist/js/penrose/sounds.js +211 -0
  83. package/dist/js/penrose/voidparticle.js +55 -0
  84. package/dist/js/penrose/voidscene.js +258 -0
  85. package/dist/js/penrose/voidship.js +144 -0
  86. package/dist/js/penrose/wormhole.js +46 -0
  87. package/dist/js/pipeline.js +555 -0
  88. package/dist/js/plane3d.js +256 -0
  89. package/dist/js/platformer.js +1579 -0
  90. package/dist/js/scene.js +304 -0
  91. package/dist/js/scenes.js +320 -0
  92. package/dist/js/schrodinger.js +410 -0
  93. package/dist/js/schwarzschild.js +1015 -0
  94. package/dist/js/shapes.js +628 -0
  95. package/dist/js/space/alien.js +171 -0
  96. package/dist/js/space/boom.js +98 -0
  97. package/dist/js/space/boss.js +353 -0
  98. package/dist/js/space/buff.js +73 -0
  99. package/dist/js/space/bullet.js +102 -0
  100. package/dist/js/space/constants.js +85 -0
  101. package/dist/js/space/game.js +1884 -0
  102. package/dist/js/space/hud.js +112 -0
  103. package/dist/js/space/laserbeam.js +179 -0
  104. package/dist/js/space/lightning.js +277 -0
  105. package/dist/js/space/minion.js +192 -0
  106. package/dist/js/space/missile.js +212 -0
  107. package/dist/js/space/player.js +430 -0
  108. package/dist/js/space/powerup.js +90 -0
  109. package/dist/js/space/starfield.js +58 -0
  110. package/dist/js/space/starpower.js +90 -0
  111. package/dist/js/spacetime.js +559 -0
  112. package/dist/js/sphere3d.js +229 -0
  113. package/dist/js/sprite.js +473 -0
  114. package/dist/js/starfaux/config.js +118 -0
  115. package/dist/js/starfaux/enemy.js +353 -0
  116. package/dist/js/starfaux/hud.js +78 -0
  117. package/dist/js/starfaux/index.js +482 -0
  118. package/dist/js/starfaux/laser.js +182 -0
  119. package/dist/js/starfaux/player.js +468 -0
  120. package/dist/js/starfaux/terrain.js +560 -0
  121. package/dist/js/study001.js +275 -0
  122. package/dist/js/study002.js +366 -0
  123. package/dist/js/study003.js +331 -0
  124. package/dist/js/study004.js +389 -0
  125. package/dist/js/study005.js +209 -0
  126. package/dist/js/study006.js +194 -0
  127. package/dist/js/study007.js +192 -0
  128. package/dist/js/study008.js +413 -0
  129. package/dist/js/svgtween.js +204 -0
  130. package/dist/js/tde/accretiondisk.js +471 -0
  131. package/dist/js/tde/blackhole.js +219 -0
  132. package/dist/js/tde/blackholescene.js +209 -0
  133. package/dist/js/tde/config.js +59 -0
  134. package/dist/js/tde/index.js +820 -0
  135. package/dist/js/tde/jets.js +290 -0
  136. package/dist/js/tde/lensedstarfield.js +154 -0
  137. package/dist/js/tde/tdestar.js +297 -0
  138. package/dist/js/tde/tidalstream.js +372 -0
  139. package/dist/js/tde_old/blackhole.obj.js +354 -0
  140. package/dist/js/tde_old/debris.obj.js +791 -0
  141. package/dist/js/tde_old/flare.obj.js +239 -0
  142. package/dist/js/tde_old/index.js +448 -0
  143. package/dist/js/tde_old/star.obj.js +812 -0
  144. package/dist/js/tetris/config.js +157 -0
  145. package/dist/js/tetris/grid.js +286 -0
  146. package/dist/js/tetris/index.js +1195 -0
  147. package/dist/js/tetris/renderer.js +634 -0
  148. package/dist/js/tetris/tetrominos.js +280 -0
  149. package/dist/js/tiles.js +312 -0
  150. package/dist/js/tweendemo.js +79 -0
  151. package/dist/js/visibility.js +102 -0
  152. package/dist/kerr.html +28 -0
  153. package/dist/lavalamp.html +27 -0
  154. package/dist/layouts.html +37 -0
  155. package/dist/logo.svg +4 -0
  156. package/dist/loop.html +84 -0
  157. package/dist/mondrian.html +32 -0
  158. package/dist/og_image.png +0 -0
  159. package/dist/opacity.html +36 -0
  160. package/dist/painter.html +39 -0
  161. package/dist/particles-showcase.html +28 -0
  162. package/dist/particles.html +24 -0
  163. package/dist/patterns.html +33 -0
  164. package/dist/penrose-game.html +31 -0
  165. package/dist/pipeline.html +737 -0
  166. package/dist/plane3d.html +24 -0
  167. package/dist/platformer.html +43 -0
  168. package/dist/scene.html +33 -0
  169. package/dist/scenes.html +96 -0
  170. package/dist/schrodinger.html +27 -0
  171. package/dist/schwarzschild.html +27 -0
  172. package/dist/shapes.html +16 -0
  173. package/dist/space.html +85 -0
  174. package/dist/spacetime.html +27 -0
  175. package/dist/sphere3d.html +24 -0
  176. package/dist/sprite.html +18 -0
  177. package/dist/starfaux.html +22 -0
  178. package/dist/study001.html +23 -0
  179. package/dist/study002.html +23 -0
  180. package/dist/study003.html +23 -0
  181. package/dist/study004.html +23 -0
  182. package/dist/study005.html +22 -0
  183. package/dist/study006.html +24 -0
  184. package/dist/study007.html +24 -0
  185. package/dist/study008.html +22 -0
  186. package/dist/svgtween.html +29 -0
  187. package/dist/tde.html +28 -0
  188. package/dist/tetris3d.html +25 -0
  189. package/dist/tiles.html +28 -0
  190. package/dist/transforms.html +400 -0
  191. package/dist/tween.html +45 -0
  192. package/dist/visibility.html +33 -0
  193. package/package.json +1 -1
@@ -0,0 +1,157 @@
1
+ /**
2
+ * 3D Tetris Configuration
3
+ * All game constants and settings
4
+ */
5
+
6
+ export const CONFIG = {
7
+ // Grid dimensions
8
+ grid: {
9
+ width: 6, // X axis
10
+ depth: 6, // Z axis
11
+ height: 16, // Y axis (pieces fall down Y)
12
+ },
13
+
14
+ // Timing (in seconds)
15
+ timing: {
16
+ fallSpeed: 1.0, // Seconds per row at level 1
17
+ lockDelay: 0.5, // Seconds before piece locks after landing
18
+ softDropMultiplier: 15, // Speed multiplier when holding down
19
+ moveRepeatDelay: 0.15, // Delay before key repeat starts
20
+ moveRepeatRate: 0.05, // Rate of key repeat
21
+ },
22
+
23
+ // Camera settings
24
+ camera: {
25
+ perspective: 800,
26
+ rotationX: 0.4,
27
+ rotationY: -0.5,
28
+ inertia: true,
29
+ friction: 0.95,
30
+ // Preset camera views for cycling
31
+ presets: [
32
+ { name: "Default", rotationX: 0.4, rotationY: -0.5 },
33
+ { name: "Front", rotationX: 0.3, rotationY: 0 },
34
+ { name: "Side", rotationX: 0.3, rotationY: -Math.PI / 2 },
35
+ { name: "Top", rotationX: 1.2, rotationY: 0 },
36
+ { name: "Isometric", rotationX: 0.6, rotationY: -0.78 },
37
+ ],
38
+ },
39
+
40
+ // Visual settings (cubeSize is calculated dynamically based on screen)
41
+ visual: {
42
+ // These are fractions of min(width, height) for responsive scaling
43
+ cubeSizeFraction: 0.055, // Cube size as fraction of screen (bigger = fills more screen)
44
+ cubeGapFraction: 0.003, // Gap between cubes
45
+ wellColor: "#00FF41", // Terminal green
46
+ wellLineWidth: 2,
47
+ ghostAlpha: 0.25,
48
+ backgroundColor: "#000000",
49
+
50
+ // Sticker mode for cubes
51
+ stickerMode: true,
52
+ stickerMargin: 0.1,
53
+ stickerBackgroundColor: "#0A0A0A",
54
+ },
55
+
56
+ // Piece colors (classic Tetris colors)
57
+ pieceColors: {
58
+ I: "#00FFFF", // Cyan
59
+ O: "#FFFF00", // Yellow
60
+ T: "#AA00FF", // Purple
61
+ S: "#00FF00", // Green
62
+ Z: "#FF0000", // Red
63
+ L: "#FFA500", // Orange
64
+ J: "#0066FF", // Blue
65
+ },
66
+
67
+ // Scoring
68
+ scoring: {
69
+ single: 100,
70
+ double: 300,
71
+ triple: 500,
72
+ tetris: 800, // 4 lines at once
73
+ softDrop: 1, // Per cell
74
+ hardDrop: 2, // Per cell
75
+ },
76
+
77
+ // Leveling
78
+ leveling: {
79
+ linesPerLevel: 10,
80
+ speedMultiplier: 0.85, // Multiply fall time by this each level
81
+ maxLevel: 15,
82
+ },
83
+
84
+ // Sound (placeholder for future)
85
+ sound: {
86
+ enabled: false,
87
+ masterVolume: 0.5,
88
+ },
89
+ };
90
+
91
+ /**
92
+ * Tetromino shape definitions
93
+ * Each shape is a 2D array representing the XZ plane
94
+ * Pieces fall along the Y axis
95
+ */
96
+ export const SHAPES = {
97
+ I: {
98
+ // Long bar - 4x1
99
+ matrix: [
100
+ [1, 1, 1, 1],
101
+ ],
102
+ color: CONFIG.pieceColors.I,
103
+ },
104
+ O: {
105
+ // Square - 2x2
106
+ matrix: [
107
+ [1, 1],
108
+ [1, 1],
109
+ ],
110
+ color: CONFIG.pieceColors.O,
111
+ },
112
+ T: {
113
+ // T-shape - 3x2
114
+ matrix: [
115
+ [1, 1, 1],
116
+ [0, 1, 0],
117
+ ],
118
+ color: CONFIG.pieceColors.T,
119
+ },
120
+ S: {
121
+ // S-shape - 3x2
122
+ matrix: [
123
+ [0, 1, 1],
124
+ [1, 1, 0],
125
+ ],
126
+ color: CONFIG.pieceColors.S,
127
+ },
128
+ Z: {
129
+ // Z-shape - 3x2
130
+ matrix: [
131
+ [1, 1, 0],
132
+ [0, 1, 1],
133
+ ],
134
+ color: CONFIG.pieceColors.Z,
135
+ },
136
+ L: {
137
+ // L-shape - 2x3
138
+ matrix: [
139
+ [1, 0],
140
+ [1, 0],
141
+ [1, 1],
142
+ ],
143
+ color: CONFIG.pieceColors.L,
144
+ },
145
+ J: {
146
+ // J-shape - 2x3
147
+ matrix: [
148
+ [0, 1],
149
+ [0, 1],
150
+ [1, 1],
151
+ ],
152
+ color: CONFIG.pieceColors.J,
153
+ },
154
+ };
155
+
156
+ // List of all piece types for random selection
157
+ export const PIECE_TYPES = Object.keys(SHAPES);
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Grid - 3D grid for tracking placed blocks
3
+ *
4
+ * Coordinate system:
5
+ * - X: left to right (0 to width-1)
6
+ * - Y: top to bottom (0 to height-1, 0 is top)
7
+ * - Z: front to back (0 to depth-1)
8
+ */
9
+
10
+ import { CONFIG } from "./config.js";
11
+
12
+ /**
13
+ * Cell data structure
14
+ * @typedef {Object} Cell
15
+ * @property {boolean} filled - Whether the cell is occupied
16
+ * @property {string|null} color - Color of the block, or null if empty
17
+ */
18
+
19
+ export class Grid {
20
+ constructor() {
21
+ const { width, depth, height } = CONFIG.grid;
22
+ this.width = width;
23
+ this.depth = depth;
24
+ this.height = height;
25
+
26
+ // 3D array: cells[x][y][z]
27
+ this.cells = [];
28
+
29
+ this._init();
30
+ }
31
+
32
+ /**
33
+ * Initialize empty grid
34
+ * @private
35
+ */
36
+ _init() {
37
+ this.cells = [];
38
+ for (let x = 0; x < this.width; x++) {
39
+ this.cells[x] = [];
40
+ for (let y = 0; y < this.height; y++) {
41
+ this.cells[x][y] = [];
42
+ for (let z = 0; z < this.depth; z++) {
43
+ this.cells[x][y][z] = { filled: false, color: null };
44
+ }
45
+ }
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Clear the grid (for game restart)
51
+ */
52
+ clear() {
53
+ this._init();
54
+ }
55
+
56
+ /**
57
+ * Check if coordinates are within grid bounds
58
+ * @param {number} x
59
+ * @param {number} y
60
+ * @param {number} z
61
+ * @returns {boolean}
62
+ */
63
+ isInBounds(x, y, z) {
64
+ return (
65
+ x >= 0 &&
66
+ x < this.width &&
67
+ y >= 0 &&
68
+ y < this.height &&
69
+ z >= 0 &&
70
+ z < this.depth
71
+ );
72
+ }
73
+
74
+ /**
75
+ * Check if a cell is occupied (or out of bounds)
76
+ * @param {number} x
77
+ * @param {number} y
78
+ * @param {number} z
79
+ * @returns {boolean}
80
+ */
81
+ isOccupied(x, y, z) {
82
+ // Out of bounds on sides/bottom counts as occupied
83
+ if (x < 0 || x >= this.width || z < 0 || z >= this.depth) {
84
+ return true;
85
+ }
86
+ // Above grid is not occupied (pieces spawn there)
87
+ if (y < 0) {
88
+ return false;
89
+ }
90
+ // Below grid counts as occupied (floor)
91
+ if (y >= this.height) {
92
+ return true;
93
+ }
94
+ return this.cells[x][y][z].filled;
95
+ }
96
+
97
+ /**
98
+ * Check if a piece can be placed at given positions
99
+ * @param {Array<{x: number, y: number, z: number}>} positions
100
+ * @returns {boolean}
101
+ */
102
+ canPlace(positions) {
103
+ for (const pos of positions) {
104
+ if (this.isOccupied(pos.x, pos.y, pos.z)) {
105
+ return false;
106
+ }
107
+ }
108
+ return true;
109
+ }
110
+
111
+ /**
112
+ * Lock a piece into the grid
113
+ * @param {Array<{x: number, y: number, z: number}>} positions
114
+ * @param {string} color
115
+ */
116
+ placePiece(positions, color) {
117
+ for (const pos of positions) {
118
+ if (this.isInBounds(pos.x, pos.y, pos.z)) {
119
+ this.cells[pos.x][pos.y][pos.z] = {
120
+ filled: true,
121
+ color: color,
122
+ };
123
+ }
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Check for complete layers and clear them
129
+ * @returns {{clearedCount: number, clearedLayers: number[]}}
130
+ */
131
+ checkAndClearLayers() {
132
+ const clearedLayers = [];
133
+
134
+ // Check each layer from bottom to top
135
+ for (let y = this.height - 1; y >= 0; y--) {
136
+ if (this._isLayerComplete(y)) {
137
+ clearedLayers.push(y);
138
+ }
139
+ }
140
+
141
+ // Clear the layers (from bottom to top to maintain indices)
142
+ clearedLayers.sort((a, b) => b - a);
143
+ for (const y of clearedLayers) {
144
+ this._clearLayer(y);
145
+ }
146
+
147
+ return {
148
+ clearedCount: clearedLayers.length,
149
+ clearedLayers: clearedLayers,
150
+ };
151
+ }
152
+
153
+ /**
154
+ * Check if a horizontal layer is completely filled
155
+ * @param {number} y - Layer Y coordinate
156
+ * @returns {boolean}
157
+ * @private
158
+ */
159
+ _isLayerComplete(y) {
160
+ for (let x = 0; x < this.width; x++) {
161
+ for (let z = 0; z < this.depth; z++) {
162
+ if (!this.cells[x][y][z].filled) {
163
+ return false;
164
+ }
165
+ }
166
+ }
167
+ return true;
168
+ }
169
+
170
+ /**
171
+ * Clear a layer and drop everything above
172
+ * @param {number} clearedY - Layer to clear
173
+ * @private
174
+ */
175
+ _clearLayer(clearedY) {
176
+ // Move all layers above down by one
177
+ for (let y = clearedY; y > 0; y--) {
178
+ for (let x = 0; x < this.width; x++) {
179
+ for (let z = 0; z < this.depth; z++) {
180
+ this.cells[x][y][z] = { ...this.cells[x][y - 1][z] };
181
+ }
182
+ }
183
+ }
184
+
185
+ // Clear the top layer
186
+ for (let x = 0; x < this.width; x++) {
187
+ for (let z = 0; z < this.depth; z++) {
188
+ this.cells[x][0][z] = { filled: false, color: null };
189
+ }
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Get all filled cells for rendering
195
+ * @returns {Array<{x: number, y: number, z: number, color: string}>}
196
+ */
197
+ getFilledCells() {
198
+ const filled = [];
199
+
200
+ for (let x = 0; x < this.width; x++) {
201
+ for (let y = 0; y < this.height; y++) {
202
+ for (let z = 0; z < this.depth; z++) {
203
+ const cell = this.cells[x][y][z];
204
+ if (cell.filled) {
205
+ filled.push({
206
+ x: x,
207
+ y: y,
208
+ z: z,
209
+ color: cell.color,
210
+ });
211
+ }
212
+ }
213
+ }
214
+ }
215
+
216
+ return filled;
217
+ }
218
+
219
+ /**
220
+ * Get the highest filled Y coordinate in each column
221
+ * Used for efficient ghost piece calculation
222
+ * @returns {number[][]} 2D array [x][z] of highest filled Y (or height if empty)
223
+ */
224
+ getColumnHeights() {
225
+ const heights = [];
226
+
227
+ for (let x = 0; x < this.width; x++) {
228
+ heights[x] = [];
229
+ for (let z = 0; z < this.depth; z++) {
230
+ heights[x][z] = this.height; // Default to bottom
231
+ for (let y = 0; y < this.height; y++) {
232
+ if (this.cells[x][y][z].filled) {
233
+ heights[x][z] = y;
234
+ break;
235
+ }
236
+ }
237
+ }
238
+ }
239
+
240
+ return heights;
241
+ }
242
+
243
+ /**
244
+ * Check if the game is over (blocks above playfield)
245
+ * @returns {boolean}
246
+ */
247
+ isGameOver() {
248
+ // Check if any blocks are in the top 2 rows
249
+ for (let x = 0; x < this.width; x++) {
250
+ for (let z = 0; z < this.depth; z++) {
251
+ if (this.cells[x][0][z].filled || this.cells[x][1][z].filled) {
252
+ return true;
253
+ }
254
+ }
255
+ }
256
+ return false;
257
+ }
258
+
259
+ /**
260
+ * Calculate where a piece would land (for ghost piece)
261
+ * @param {TetrisPiece} piece
262
+ * @returns {number} The Y coordinate where piece would land
263
+ */
264
+ calculateLandingY(piece) {
265
+ let testY = piece.y;
266
+
267
+ while (true) {
268
+ testY++;
269
+ // Use voxels to calculate positions at testY
270
+ const positions = piece.voxels.map((v) => ({
271
+ x: piece.x + v.x,
272
+ y: testY + v.y,
273
+ z: piece.z + v.z,
274
+ }));
275
+
276
+ if (!this.canPlace(positions)) {
277
+ return testY - 1;
278
+ }
279
+
280
+ // Safety check to prevent infinite loop
281
+ if (testY > this.height + 5) {
282
+ return piece.y;
283
+ }
284
+ }
285
+ }
286
+ }