@guinetik/gcanvas 1.0.4 → 2.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.
Files changed (261) hide show
  1. package/dist/CNAME +1 -0
  2. package/dist/aizawa.html +27 -0
  3. package/dist/animations.html +31 -0
  4. package/dist/basic.html +38 -0
  5. package/dist/baskara.html +31 -0
  6. package/dist/bezier.html +35 -0
  7. package/dist/beziersignature.html +29 -0
  8. package/dist/blackhole.html +28 -0
  9. package/dist/blob.html +35 -0
  10. package/dist/clifford.html +25 -0
  11. package/dist/cmb.html +24 -0
  12. package/dist/coordinates.html +698 -0
  13. package/dist/cube3d.html +23 -0
  14. package/dist/dadras.html +26 -0
  15. package/dist/dejong.html +25 -0
  16. package/dist/demos.css +303 -0
  17. package/dist/dino.html +42 -0
  18. package/dist/easing.html +28 -0
  19. package/dist/events.html +195 -0
  20. package/dist/fluent.html +647 -0
  21. package/dist/fluid-simple.html +22 -0
  22. package/dist/fluid.html +37 -0
  23. package/dist/fractals.html +36 -0
  24. package/dist/gameobjects.html +626 -0
  25. package/dist/gcanvas.es.js +14368 -9093
  26. package/dist/gcanvas.es.min.js +1 -1
  27. package/dist/gcanvas.umd.js +1 -1
  28. package/dist/gcanvas.umd.min.js +1 -1
  29. package/dist/genart.html +26 -0
  30. package/dist/gendream.html +26 -0
  31. package/dist/group.html +36 -0
  32. package/dist/halvorsen.html +27 -0
  33. package/dist/home.html +587 -0
  34. package/dist/hyperbolic001.html +23 -0
  35. package/dist/hyperbolic002.html +23 -0
  36. package/dist/hyperbolic003.html +23 -0
  37. package/dist/hyperbolic004.html +23 -0
  38. package/dist/hyperbolic005.html +22 -0
  39. package/dist/index.html +446 -0
  40. package/dist/isometric.html +34 -0
  41. package/dist/js/aizawa.js +425 -0
  42. package/dist/js/animations.js +452 -0
  43. package/dist/js/basic.js +204 -0
  44. package/dist/js/baskara.js +751 -0
  45. package/dist/js/bezier.js +692 -0
  46. package/dist/js/beziersignature.js +241 -0
  47. package/dist/js/blackhole/accretiondisk.obj.js +379 -0
  48. package/dist/js/blackhole/blackhole.obj.js +318 -0
  49. package/dist/js/blackhole/index.js +409 -0
  50. package/dist/js/blackhole/particle.js +56 -0
  51. package/dist/js/blackhole/starfield.obj.js +218 -0
  52. package/dist/js/blob.js +2276 -0
  53. package/dist/js/clifford.js +236 -0
  54. package/dist/js/cmb.js +594 -0
  55. package/dist/js/coordinates.js +840 -0
  56. package/dist/js/cube3d.js +789 -0
  57. package/dist/js/dadras.js +405 -0
  58. package/dist/js/dejong.js +257 -0
  59. package/dist/js/dino.js +1420 -0
  60. package/dist/js/easing.js +477 -0
  61. package/dist/js/fluent.js +183 -0
  62. package/dist/js/fluid-simple.js +253 -0
  63. package/dist/js/fluid.js +527 -0
  64. package/dist/js/fractals.js +932 -0
  65. package/dist/js/fractalworker.js +93 -0
  66. package/dist/js/gameobjects.js +176 -0
  67. package/dist/js/genart.js +268 -0
  68. package/dist/js/gendream.js +209 -0
  69. package/dist/js/group.js +140 -0
  70. package/dist/js/halvorsen.js +405 -0
  71. package/dist/js/hyperbolic001.js +310 -0
  72. package/dist/js/hyperbolic002.js +388 -0
  73. package/dist/js/hyperbolic003.js +319 -0
  74. package/dist/js/hyperbolic004.js +345 -0
  75. package/dist/js/hyperbolic005.js +340 -0
  76. package/dist/js/info-toggle.js +25 -0
  77. package/dist/js/isometric.js +851 -0
  78. package/dist/js/kerr.js +1547 -0
  79. package/dist/js/lavalamp.js +590 -0
  80. package/dist/js/layout.js +354 -0
  81. package/dist/js/lorenz.js +425 -0
  82. package/dist/js/mondrian.js +285 -0
  83. package/dist/js/opacity.js +275 -0
  84. package/dist/js/painter.js +484 -0
  85. package/dist/js/particles-showcase.js +514 -0
  86. package/dist/js/particles.js +299 -0
  87. package/dist/js/patterns.js +397 -0
  88. package/dist/js/penrose/artifact.js +69 -0
  89. package/dist/js/penrose/blackhole.js +121 -0
  90. package/dist/js/penrose/constants.js +73 -0
  91. package/dist/js/penrose/game.js +943 -0
  92. package/dist/js/penrose/lore.js +278 -0
  93. package/dist/js/penrose/penrosescene.js +892 -0
  94. package/dist/js/penrose/ship.js +216 -0
  95. package/dist/js/penrose/sounds.js +211 -0
  96. package/dist/js/penrose/voidparticle.js +55 -0
  97. package/dist/js/penrose/voidscene.js +258 -0
  98. package/dist/js/penrose/voidship.js +144 -0
  99. package/dist/js/penrose/wormhole.js +46 -0
  100. package/dist/js/pipeline.js +555 -0
  101. package/dist/js/plane3d.js +256 -0
  102. package/dist/js/platformer.js +1579 -0
  103. package/dist/js/rossler.js +480 -0
  104. package/dist/js/scene.js +304 -0
  105. package/dist/js/scenes.js +320 -0
  106. package/dist/js/schrodinger.js +706 -0
  107. package/dist/js/schwarzschild.js +1015 -0
  108. package/dist/js/shapes.js +628 -0
  109. package/dist/js/space/alien.js +171 -0
  110. package/dist/js/space/boom.js +98 -0
  111. package/dist/js/space/boss.js +353 -0
  112. package/dist/js/space/buff.js +73 -0
  113. package/dist/js/space/bullet.js +102 -0
  114. package/dist/js/space/constants.js +85 -0
  115. package/dist/js/space/game.js +1884 -0
  116. package/dist/js/space/hud.js +112 -0
  117. package/dist/js/space/laserbeam.js +179 -0
  118. package/dist/js/space/lightning.js +277 -0
  119. package/dist/js/space/minion.js +192 -0
  120. package/dist/js/space/missile.js +212 -0
  121. package/dist/js/space/player.js +430 -0
  122. package/dist/js/space/powerup.js +90 -0
  123. package/dist/js/space/starfield.js +58 -0
  124. package/dist/js/space/starpower.js +90 -0
  125. package/dist/js/spacetime.js +559 -0
  126. package/dist/js/sphere3d.js +229 -0
  127. package/dist/js/sprite.js +473 -0
  128. package/dist/js/starfaux/config.js +118 -0
  129. package/dist/js/starfaux/enemy.js +353 -0
  130. package/dist/js/starfaux/hud.js +78 -0
  131. package/dist/js/starfaux/index.js +482 -0
  132. package/dist/js/starfaux/laser.js +182 -0
  133. package/dist/js/starfaux/player.js +468 -0
  134. package/dist/js/starfaux/terrain.js +560 -0
  135. package/dist/js/study001.js +275 -0
  136. package/dist/js/study002.js +366 -0
  137. package/dist/js/study003.js +331 -0
  138. package/dist/js/study004.js +389 -0
  139. package/dist/js/study005.js +209 -0
  140. package/dist/js/study006.js +194 -0
  141. package/dist/js/study007.js +192 -0
  142. package/dist/js/study008.js +413 -0
  143. package/dist/js/svgtween.js +204 -0
  144. package/dist/js/tde/accretiondisk.js +471 -0
  145. package/dist/js/tde/blackhole.js +219 -0
  146. package/dist/js/tde/blackholescene.js +209 -0
  147. package/dist/js/tde/config.js +59 -0
  148. package/dist/js/tde/index.js +820 -0
  149. package/dist/js/tde/jets.js +290 -0
  150. package/dist/js/tde/lensedstarfield.js +154 -0
  151. package/dist/js/tde/tdestar.js +297 -0
  152. package/dist/js/tde/tidalstream.js +372 -0
  153. package/dist/js/tde_old/blackhole.obj.js +354 -0
  154. package/dist/js/tde_old/debris.obj.js +791 -0
  155. package/dist/js/tde_old/flare.obj.js +239 -0
  156. package/dist/js/tde_old/index.js +448 -0
  157. package/dist/js/tde_old/star.obj.js +812 -0
  158. package/dist/js/tetris/config.js +157 -0
  159. package/dist/js/tetris/grid.js +286 -0
  160. package/dist/js/tetris/index.js +1195 -0
  161. package/dist/js/tetris/renderer.js +634 -0
  162. package/dist/js/tetris/tetrominos.js +280 -0
  163. package/dist/js/thomas.js +394 -0
  164. package/dist/js/tiles.js +312 -0
  165. package/dist/js/tweendemo.js +79 -0
  166. package/dist/js/visibility.js +102 -0
  167. package/dist/kerr.html +28 -0
  168. package/dist/lavalamp.html +27 -0
  169. package/dist/layouts.html +37 -0
  170. package/dist/logo.svg +4 -0
  171. package/dist/loop.html +84 -0
  172. package/dist/lorenz.html +27 -0
  173. package/dist/mondrian.html +32 -0
  174. package/dist/og_image.png +0 -0
  175. package/dist/opacity.html +36 -0
  176. package/dist/painter.html +39 -0
  177. package/dist/particles-showcase.html +28 -0
  178. package/dist/particles.html +24 -0
  179. package/dist/patterns.html +33 -0
  180. package/dist/penrose-game.html +31 -0
  181. package/dist/pipeline.html +737 -0
  182. package/dist/plane3d.html +24 -0
  183. package/dist/platformer.html +43 -0
  184. package/dist/rossler.html +27 -0
  185. package/dist/scene-interactivity-test.html +220 -0
  186. package/dist/scene.html +33 -0
  187. package/dist/scenes.html +96 -0
  188. package/dist/schrodinger.html +27 -0
  189. package/dist/schwarzschild.html +27 -0
  190. package/dist/shapes.html +16 -0
  191. package/dist/space.html +85 -0
  192. package/dist/spacetime.html +27 -0
  193. package/dist/sphere3d.html +24 -0
  194. package/dist/sprite.html +18 -0
  195. package/dist/starfaux.html +22 -0
  196. package/dist/study001.html +23 -0
  197. package/dist/study002.html +23 -0
  198. package/dist/study003.html +23 -0
  199. package/dist/study004.html +23 -0
  200. package/dist/study005.html +22 -0
  201. package/dist/study006.html +24 -0
  202. package/dist/study007.html +24 -0
  203. package/dist/study008.html +22 -0
  204. package/dist/svgtween.html +29 -0
  205. package/dist/tde.html +28 -0
  206. package/dist/tetris3d.html +25 -0
  207. package/dist/thomas.html +27 -0
  208. package/dist/tiles.html +28 -0
  209. package/dist/transforms.html +400 -0
  210. package/dist/tween.html +45 -0
  211. package/dist/visibility.html +33 -0
  212. package/package.json +1 -1
  213. package/readme.md +30 -22
  214. package/src/game/objects/go.js +7 -0
  215. package/src/game/objects/index.js +2 -0
  216. package/src/game/objects/isometric-scene.js +53 -3
  217. package/src/game/objects/layoutscene.js +57 -0
  218. package/src/game/objects/mask.js +241 -0
  219. package/src/game/objects/scene.js +19 -0
  220. package/src/game/objects/wrapper.js +14 -2
  221. package/src/game/pipeline.js +17 -0
  222. package/src/game/ui/button.js +101 -16
  223. package/src/game/ui/theme.js +0 -6
  224. package/src/game/ui/togglebutton.js +25 -14
  225. package/src/game/ui/tooltip.js +12 -4
  226. package/src/index.js +3 -0
  227. package/src/io/gesture.js +409 -0
  228. package/src/io/index.js +4 -1
  229. package/src/io/keys.js +9 -1
  230. package/src/io/screen.js +476 -0
  231. package/src/math/attractors.js +664 -0
  232. package/src/math/heat.js +106 -0
  233. package/src/math/index.js +1 -0
  234. package/src/mixins/draggable.js +15 -19
  235. package/src/painter/painter.shapes.js +11 -5
  236. package/src/particle/particle-system.js +165 -1
  237. package/src/physics/index.js +26 -0
  238. package/src/physics/physics-updaters.js +333 -0
  239. package/src/physics/physics.js +375 -0
  240. package/src/shapes/image.js +5 -5
  241. package/src/shapes/index.js +2 -0
  242. package/src/shapes/parallelogram.js +147 -0
  243. package/src/shapes/righttriangle.js +115 -0
  244. package/src/shapes/svg.js +281 -100
  245. package/src/shapes/text.js +22 -6
  246. package/src/shapes/transformable.js +5 -0
  247. package/src/sound/effects.js +807 -0
  248. package/src/sound/index.js +13 -0
  249. package/src/webgl/index.js +7 -0
  250. package/src/webgl/shaders/clifford-point-shaders.js +131 -0
  251. package/src/webgl/shaders/dejong-point-shaders.js +131 -0
  252. package/src/webgl/shaders/point-sprite-shaders.js +152 -0
  253. package/src/webgl/webgl-clifford-renderer.js +477 -0
  254. package/src/webgl/webgl-dejong-renderer.js +472 -0
  255. package/src/webgl/webgl-line-renderer.js +391 -0
  256. package/src/webgl/webgl-particle-renderer.js +410 -0
  257. package/types/index.d.ts +30 -2
  258. package/types/io.d.ts +217 -0
  259. package/types/physics.d.ts +299 -0
  260. package/types/shapes.d.ts +8 -0
  261. package/types/webgl.d.ts +188 -109
@@ -0,0 +1,354 @@
1
+ import {
2
+ Game,
3
+ Scene,
4
+ FPSCounter,
5
+ GameObject,
6
+ HorizontalLayout,
7
+ VerticalLayout,
8
+ Button,
9
+ ShapeGOFactory,
10
+ Rectangle,
11
+ Position,
12
+ Painter,
13
+ TileLayout,
14
+ GridLayout,
15
+ } from "/gcanvas.es.min.js";
16
+
17
+ export class LayoutDemo extends Game {
18
+ constructor(canvas) {
19
+ super(canvas);
20
+ this.enableFluidSize();
21
+ this.backgroundColor = "black";
22
+ this.cellSize = 110;
23
+ this.maxColumns = 6;
24
+ }
25
+
26
+ getResponsiveColumns() {
27
+ const margin = 100; // space for UI
28
+ const availableWidth = this.width - margin;
29
+ return Math.min(
30
+ this.maxColumns,
31
+ Math.max(1, Math.floor(availableWidth / this.cellSize))
32
+ );
33
+ }
34
+
35
+ isMobile() {
36
+ return this.width < 600;
37
+ }
38
+
39
+ getLayoutYOffset() {
40
+ // On mobile (no info bar), move layout up; on desktop keep lower to avoid info bar
41
+ return this.isMobile() ? -80 : 0;
42
+ }
43
+
44
+ /**
45
+ * Get viewport dimensions based on current layout mode.
46
+ * - Horizontal: fixed height (item height + padding), width = screen - margins
47
+ * - Vertical: fixed width (item width + padding), height = screen - nav - margins
48
+ * - Tile/Grid: square-ish viewport with margins on sides, scrolls vertically
49
+ */
50
+ getViewportDimensions() {
51
+ const navHeight = 320; // bottom nav (two rows at -30 and -100 offset + button heights)
52
+ const margin = 50;
53
+
54
+ const layoutModes = this.getLayoutModes();
55
+ const modeConfig = layoutModes[this.mode];
56
+
57
+ switch (this.mode) {
58
+ case "horizontal":
59
+ // Horizontal: fixed height based on item height, scroll horizontally
60
+ return {
61
+ width: Math.max(200, this.width - margin * 2),
62
+ height: 100 + 20, // item height (100) + padding
63
+ };
64
+
65
+ case "vertical":
66
+ // Vertical: fixed width based on item width, scroll vertically
67
+ return {
68
+ width: 200 + 20, // item width (200) + padding
69
+ height: Math.max(200, this.height - navHeight - margin),
70
+ };
71
+
72
+ case "tile":
73
+ case "grid":
74
+ default:
75
+ // Tile/Grid: responsive square-ish viewport, scroll vertically
76
+ return {
77
+ width: Math.max(200, this.width - margin * 2),
78
+ height: Math.max(200, this.height - navHeight - margin),
79
+ };
80
+ }
81
+ }
82
+
83
+ // Define layout modes configuration (uses arrow functions to access `this`)
84
+ getLayoutModes() {
85
+ const columns = this.getResponsiveColumns();
86
+ return {
87
+ horizontal: {
88
+ layoutClass: HorizontalLayout,
89
+ itemDimensions: () => ({
90
+ width: 40 + Math.random() * 60,
91
+ height: 100,
92
+ }),
93
+ },
94
+ vertical: {
95
+ layoutClass: VerticalLayout,
96
+ itemDimensions: () => ({
97
+ width: 200,
98
+ height: 40 + Math.random() * 60,
99
+ }),
100
+ },
101
+ tile: {
102
+ layoutClass: TileLayout,
103
+ itemDimensions: () => ({
104
+ width: 100,
105
+ height: 100,
106
+ }),
107
+ layoutOptions: (baseOpts) => ({
108
+ ...baseOpts,
109
+ columns: columns,
110
+ }),
111
+ },
112
+ grid: {
113
+ layoutClass: GridLayout,
114
+ itemDimensions: () => {
115
+ // Randomly choose between portrait or landscape
116
+ const isPortrait = Math.random() > 0.5;
117
+ if (isPortrait) {
118
+ // Portrait: taller than wide
119
+ if (Math.random() > 0.3) {
120
+ return {
121
+ width: 100,
122
+ height: 200,
123
+ };
124
+ } else {
125
+ return {
126
+ width: 100,
127
+ height: 100,
128
+ };
129
+ }
130
+ } else {
131
+ if (Math.random() > 0.3) {
132
+ // Landscape: wider than tall
133
+ return {
134
+ width: 100,
135
+ height: 50,
136
+ };
137
+ } else {
138
+ return {
139
+ width: 100,
140
+ height: 100,
141
+ };
142
+ }
143
+ }
144
+ },
145
+ layoutOptions: (baseOpts) => ({
146
+ ...baseOpts,
147
+ columns: columns,
148
+ spacing: 10,
149
+ padding: 10,
150
+ centerItems: true,
151
+ }),
152
+ },
153
+ };
154
+ }
155
+
156
+ init() {
157
+ super.init();
158
+ // Config Options
159
+ this.items = [];
160
+ this.mode = "horizontal";
161
+ this.currentColumns = this.getResponsiveColumns();
162
+
163
+ // Create UI
164
+ this.ui = new Scene(this, {
165
+ debug: true,
166
+ debugColor: "pink",
167
+ anchor: Position.CENTER,
168
+ });
169
+ this.pipeline.add(this.ui);
170
+
171
+ // Add FPS Counter
172
+ this.pipeline.add(
173
+ new FPSCounter(this, { color: "#00FF00", anchor: "bottom-right" })
174
+ );
175
+
176
+ // Create bottom navigation - layout type selection (at very bottom)
177
+ this.layoutNav = new HorizontalLayout(this, {
178
+ debug: true,
179
+ debugColor: "purple",
180
+ anchor: Position.BOTTOM_CENTER,
181
+ anchorOffsetY: -30,
182
+ padding: 10,
183
+ spacing: 10,
184
+ });
185
+ this.ui.add(this.layoutNav);
186
+
187
+ // Add layout type buttons
188
+ const layoutModes = this.getLayoutModes();
189
+ Object.keys(layoutModes).forEach((mode) => {
190
+ this.layoutNav.add(
191
+ new Button(this, {
192
+ text: mode.charAt(0).toUpperCase() + mode.slice(1),
193
+ onClick: () => this.setLayout(mode),
194
+ })
195
+ );
196
+ });
197
+
198
+ // Create action buttons (add/remove) - positioned above layout nav
199
+ this.actionNav = new HorizontalLayout(this, {
200
+ anchor: Position.BOTTOM_CENTER,
201
+ debug: true,
202
+ debugColor: "cyan",
203
+ anchorOffsetY: -100, // Space above the layout nav
204
+ padding: 10,
205
+ spacing: 10,
206
+ });
207
+ this.actionNav.add(
208
+ new Button(this, {
209
+ text: "ADD",
210
+ onClick: this.addItem.bind(this),
211
+ })
212
+ );
213
+ this.actionNav.add(
214
+ new Button(this, {
215
+ text: "REMOVE",
216
+ onClick: () => this.removeItem(),
217
+ })
218
+ );
219
+ this.ui.add(this.actionNav);
220
+
221
+ // Create initial layout
222
+ this.createLayout();
223
+
224
+ // Add enough items to enable scrolling
225
+ for (let i = 0; i < 5; i++) {
226
+ this.addItem(i);
227
+ }
228
+ }
229
+
230
+ createLayout() {
231
+ if (this.layout) {
232
+ // Properly clear the layout
233
+ this.layout.clear();
234
+ this.pipeline.remove(this.layout);
235
+ this.layout = null;
236
+ }
237
+
238
+ const viewport = this.getViewportDimensions();
239
+
240
+ const baseOpts = {
241
+ anchor: Position.CENTER,
242
+ anchorOffsetY: this.getLayoutYOffset(),
243
+ spacing: 10,
244
+ padding: 10,
245
+ debug: true,
246
+ autoSize: true,
247
+ debugColor: Painter.colors.randomColorHSL(),
248
+ // Enable scrolling with responsive viewport
249
+ scrollable: true,
250
+ viewportWidth: viewport.width,
251
+ viewportHeight: viewport.height,
252
+ };
253
+
254
+ const layoutModes = this.getLayoutModes();
255
+ const modeConfig = layoutModes[this.mode];
256
+ const layoutOpts = modeConfig.layoutOptions
257
+ ? modeConfig.layoutOptions(baseOpts)
258
+ : baseOpts;
259
+
260
+ this.layout = new modeConfig.layoutClass(this, layoutOpts);
261
+ // Add layout to pipeline
262
+ this.pipeline.add(this.layout);
263
+ // Add items to layout
264
+ if (this.items.length > 0) {
265
+ // Reset each item properly
266
+ setTimeout(() => {
267
+ this.items.forEach((item) => {
268
+ const dimensions = modeConfig.itemDimensions();
269
+ item.width = dimensions.width;
270
+ item.height = dimensions.height;
271
+ // Add to the container
272
+ this.layout.add(item);
273
+ });
274
+ }, 10);
275
+ // Mark the layout as needing recalculation
276
+ this.layout.markBoundsDirty();
277
+ }
278
+ }
279
+
280
+ update(dt) {
281
+ super.update(dt);
282
+ // stuff that has to do with bound checking should be done after super.update.
283
+ if (this.boundsDirty) {
284
+ console.log("update", this.boundsDirty);
285
+ this.ui.width = this.width;
286
+ this.ui.height = this.height;
287
+ this.ui.markBoundsDirty();
288
+ this.layout.markBoundsDirty();
289
+ this.boundsDirty = false;
290
+ }
291
+ }
292
+
293
+ setLayout(mode) {
294
+ if (mode !== this.mode) {
295
+ this.mode = mode;
296
+ this.createLayout();
297
+ }
298
+ }
299
+
300
+ addItem(i) {
301
+ const layoutModes = this.getLayoutModes();
302
+ const modeConfig = layoutModes[this.mode];
303
+ const dimensions = modeConfig.itemDimensions();
304
+ const rect = new Rectangle({
305
+ width: dimensions.width,
306
+ height: dimensions.height,
307
+ color: Painter.colors.randomColorHSL(),
308
+ stroke: "white",
309
+ lineWidth: 2,
310
+ });
311
+ const go = ShapeGOFactory.create(this, rect);
312
+ go.name = "item " + i;
313
+ this.items.push(go);
314
+ this.layout.add(go);
315
+ }
316
+
317
+ removeItem() {
318
+ if (this.items.length > 0) {
319
+ const go = this.items.pop();
320
+ this.layout.remove(go);
321
+ }
322
+ }
323
+
324
+ onResize() {
325
+ if (!this.layout) return;
326
+
327
+ const newColumns = this.getResponsiveColumns();
328
+
329
+ // Recreate layout if columns changed (for tile/grid modes)
330
+ if (this.currentColumns !== newColumns) {
331
+ this.currentColumns = newColumns;
332
+ if (this.mode === "tile" || this.mode === "grid") {
333
+ this.createLayout();
334
+ return; // createLayout already sets up viewport
335
+ }
336
+ }
337
+
338
+ // Update viewport dimensions for scrolling (mode-specific)
339
+ const viewport = this.getViewportDimensions();
340
+ this.layout._viewportWidth = viewport.width;
341
+ this.layout._viewportHeight = viewport.height;
342
+
343
+ // Update layout Y offset based on mobile/desktop
344
+ this.layout.anchorOffsetY = this.getLayoutYOffset();
345
+
346
+ // Update UI dimensions
347
+ this.ui.width = this.width - 20;
348
+ this.ui.height = this.height - 20;
349
+ this.ui.markBoundsDirty();
350
+ this.layoutNav.markBoundsDirty();
351
+ this.actionNav.markBoundsDirty();
352
+ this.layout.markBoundsDirty();
353
+ }
354
+ }