nova64 0.2.5 → 0.2.6

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 (140) hide show
  1. package/README.md +25 -8
  2. package/bin/nova64.js +165 -0
  3. package/dist/assets/console-CY_kygm3.js +14 -0
  4. package/dist/assets/console-CY_kygm3.js.map +1 -0
  5. package/dist/assets/main-l0sNRNKZ.js.map +1 -0
  6. package/dist/assets/sky/studio/nx.png +0 -0
  7. package/dist/assets/sky/studio/ny.png +0 -0
  8. package/dist/assets/sky/studio/nz.png +0 -0
  9. package/dist/assets/sky/studio/px.png +0 -0
  10. package/dist/assets/sky/studio/py.png +0 -0
  11. package/dist/assets/sky/studio/pz.png +0 -0
  12. package/dist/assets/vanilla-Dcuy32gi.js +2 -0
  13. package/dist/assets/vanilla-Dcuy32gi.js.map +1 -0
  14. package/dist/console.html +899 -0
  15. package/dist/docs/BENCHMARK.md +77 -0
  16. package/dist/docs/CHEATSHEET.md +255 -0
  17. package/dist/docs/EFFECTS_API_GUIDE.md +577 -0
  18. package/dist/docs/EFFECTS_QUICK_REFERENCE.md +331 -0
  19. package/dist/docs/FONT_CHARACTER_REFERENCE.md +219 -0
  20. package/dist/docs/FREE_GLB_ASSETS.md +330 -0
  21. package/dist/docs/FULLSCREEN_BUTTON_FEATURE.md +296 -0
  22. package/dist/docs/GAMEPAD_SUPPORT.md +348 -0
  23. package/dist/docs/GAME_IMPROVEMENTS.md +278 -0
  24. package/dist/docs/GAME_QUALITY_STATUS.md +300 -0
  25. package/dist/docs/MIGRATION_GUIDE.md +553 -0
  26. package/dist/docs/NOVA64_3D_API.md +356 -0
  27. package/dist/docs/NOVA64_API_REFERENCE.md +1406 -0
  28. package/dist/docs/NOVA64_UI_API.md +503 -0
  29. package/dist/docs/UI_SYSTEM_SUMMARY.md +445 -0
  30. package/dist/docs/VOXEL_ENGINE_GUIDE.md +662 -0
  31. package/dist/docs/VOXEL_QUICK_REFERENCE.md +386 -0
  32. package/dist/docs/api-3d.html +750 -0
  33. package/dist/docs/api-effects.html +385 -0
  34. package/dist/docs/api-improvements.md +121 -0
  35. package/dist/docs/api-skybox.html +407 -0
  36. package/dist/docs/api-sprites.html +321 -0
  37. package/dist/docs/api-voxel.html +337 -0
  38. package/dist/docs/api.html +543 -0
  39. package/dist/docs/assets.html +306 -0
  40. package/dist/docs/audio.html +340 -0
  41. package/dist/docs/blogs.html +286 -0
  42. package/dist/docs/collision.html +316 -0
  43. package/dist/docs/console.html +247 -0
  44. package/dist/docs/editor.html +297 -0
  45. package/dist/docs/font.html +247 -0
  46. package/dist/docs/framebuffer.html +247 -0
  47. package/dist/docs/fullscreen-button.html +297 -0
  48. package/dist/docs/gpu-systems.html +247 -0
  49. package/dist/docs/index.html +580 -0
  50. package/dist/docs/input.html +491 -0
  51. package/dist/docs/physics.html +311 -0
  52. package/dist/docs/screens.html +311 -0
  53. package/dist/docs/storage.html +311 -0
  54. package/dist/docs/textinput.html +332 -0
  55. package/dist/docs/ui.html +488 -0
  56. package/dist/examples/3d-advanced/code.js +695 -0
  57. package/dist/examples/adventure-comic-3d/code.js +342 -0
  58. package/dist/examples/audio-lab/code.js +150 -0
  59. package/dist/examples/boids-flocking/code.js +270 -0
  60. package/dist/examples/crystal-cathedral-3d/code.js +706 -0
  61. package/dist/examples/cyberpunk-city-3d/code.js +1383 -0
  62. package/dist/examples/demoscene/README.md +192 -0
  63. package/dist/examples/demoscene/code.js +1081 -0
  64. package/dist/examples/demoscene/meta.json +21 -0
  65. package/dist/examples/dungeon-crawler-3d/code.js +1117 -0
  66. package/dist/examples/f-zero-nova-3d/code.js +865 -0
  67. package/dist/examples/f-zero-nova-3d/code_old.js +1555 -0
  68. package/dist/examples/fps-demo-3d/code.js +744 -0
  69. package/dist/examples/game-of-life-3d/code.js +338 -0
  70. package/dist/examples/generative-art/code.js +632 -0
  71. package/dist/examples/hello-3d/code.js +325 -0
  72. package/dist/examples/hello-skybox/code.js +183 -0
  73. package/dist/examples/hello-world/code.js +19 -0
  74. package/dist/examples/input-showcase/code.js +109 -0
  75. package/dist/examples/instancing-demo/code.js +315 -0
  76. package/dist/examples/minecraft-demo/code.js +387 -0
  77. package/dist/examples/model-viewer-3d/code.js +114 -0
  78. package/dist/examples/mystical-realm-3d/code.js +1203 -0
  79. package/dist/examples/nature-explorer-3d/code.js +1318 -0
  80. package/dist/examples/particles-demo/code.js +522 -0
  81. package/dist/examples/pbr-showcase/code.js +140 -0
  82. package/dist/examples/physics-demo-3d/code.js +948 -0
  83. package/dist/examples/screen-demo/code.js +267 -0
  84. package/dist/examples/shooter-demo-3d/code.js +1286 -0
  85. package/dist/examples/space-combat-3d/IMPLEMENTATION_SUMMARY.md +109 -0
  86. package/dist/examples/space-combat-3d/README.md +135 -0
  87. package/dist/examples/space-combat-3d/code.js +1332 -0
  88. package/dist/examples/space-harrier-3d/code.js +923 -0
  89. package/dist/examples/star-fox-nova-3d/code.js +1116 -0
  90. package/dist/examples/star-fox-nova-3d/code_backup.js +410 -0
  91. package/dist/examples/star-fox-nova-3d/code_broken.js +1821 -0
  92. package/dist/examples/storage-quest/code.js +209 -0
  93. package/dist/examples/strider-demo-3d/IMPROVEMENT_OPTIONS.md +285 -0
  94. package/dist/examples/strider-demo-3d/cache-test.html +132 -0
  95. package/dist/examples/strider-demo-3d/code-fixed.js +582 -0
  96. package/dist/examples/strider-demo-3d/code-old.js +1537 -0
  97. package/dist/examples/strider-demo-3d/code.js +1462 -0
  98. package/dist/examples/strider-demo-3d/code.js.bak2 +1169 -0
  99. package/dist/examples/strider-demo-3d/fix-game.sh +53 -0
  100. package/dist/examples/super-plumber-64/README.md +128 -0
  101. package/dist/examples/super-plumber-64/code.js +1185 -0
  102. package/dist/examples/super-plumber-64/index.html +88 -0
  103. package/dist/examples/test-2d-overlay/code.js +32 -0
  104. package/dist/examples/test-font/code.js +51 -0
  105. package/dist/examples/test-minimal/code.js +21 -0
  106. package/dist/examples/ui-demo/code.js +306 -0
  107. package/dist/examples/wing-commander-space/README.md +180 -0
  108. package/dist/examples/wing-commander-space/code.js +1285 -0
  109. package/dist/examples/wizardry-3d/CHANGELOG.md +366 -0
  110. package/dist/examples/wizardry-3d/code.js +3928 -0
  111. package/dist/index.html +666 -0
  112. package/dist/os9-shell/assets/index-DIHfrTaW.css +1 -0
  113. package/dist/os9-shell/assets/index-KchE_ngx.js +483 -0
  114. package/dist/os9-shell/assets/index-KchE_ngx.js.map +1 -0
  115. package/dist/os9-shell/index.html +23 -0
  116. package/dist/os9-shell/nova-icon.svg +12 -0
  117. package/index.html +6 -1
  118. package/package.json +37 -32
  119. package/public/assets/sky/studio/nx.png +0 -0
  120. package/public/assets/sky/studio/ny.png +0 -0
  121. package/public/assets/sky/studio/nz.png +0 -0
  122. package/public/assets/sky/studio/px.png +0 -0
  123. package/public/assets/sky/studio/py.png +0 -0
  124. package/public/assets/sky/studio/pz.png +0 -0
  125. package/public/os9-shell/assets/index-KchE_ngx.js +483 -0
  126. package/public/os9-shell/assets/index-KchE_ngx.js.map +1 -0
  127. package/public/os9-shell/index.html +10 -1
  128. package/runtime/api-2d.js +301 -21
  129. package/runtime/api-3d/pbr.js +45 -1
  130. package/runtime/api-3d.js +1 -0
  131. package/runtime/api-effects.js +90 -3
  132. package/runtime/api-gameutils.js +476 -0
  133. package/runtime/api-generative.js +610 -0
  134. package/runtime/api-skybox.js +54 -0
  135. package/runtime/api-voxel.js +139 -28
  136. package/runtime/gpu-threejs.js +13 -9
  137. package/runtime/ui.js +2 -2
  138. package/src/main.js +20 -0
  139. package/public/os9-shell/assets/index-B1Uvacma.js +0 -32825
  140. package/public/os9-shell/assets/index-B1Uvacma.js.map +0 -1
@@ -0,0 +1,209 @@
1
+ // examples/storage-quest/code.js
2
+ // Demonstrates Nova64's persistent storage API.
3
+ // Collect gems to earn points, upgrade your ship, and watch everything
4
+ // persist across full page reloads via saveData/loadData.
5
+
6
+ const SAVE_KEY = 'storagequest';
7
+ const GEM_COLORS = [0xffdd00, 0x00ffaa, 0xff4488, 0x44aaff];
8
+ const UPGRADE_COST = [0, 50, 150, 400]; // cumulative cost per level (level 0 = start)
9
+
10
+ let state; // the persistent game state
11
+ let ship;
12
+ let gems = [];
13
+ let particles = [];
14
+ let upgradeFlash = 0;
15
+ let saveFlash = 0;
16
+
17
+ function defaultState() {
18
+ return { score: 0, highScore: 0, level: 1, shipLevel: 0, totalGems: 0, runs: 0 };
19
+ }
20
+
21
+ function spawnGems(count) {
22
+ for (let i = 0; i < count; i++) {
23
+ const angle = Math.random() * Math.PI * 2;
24
+ const r = 3 + Math.random() * 6;
25
+ const color = GEM_COLORS[(gems.length + i) % GEM_COLORS.length];
26
+ gems.push({
27
+ mesh: createSphere(0.25, color, [Math.cos(angle) * r, 0.5, Math.sin(angle) * r], 6, {
28
+ material: 'holographic',
29
+ emissive: color,
30
+ }),
31
+ x: Math.cos(angle) * r,
32
+ z: Math.sin(angle) * r,
33
+ spin: Math.random() * Math.PI * 2,
34
+ color,
35
+ });
36
+ }
37
+ }
38
+
39
+ export function init() {
40
+ // Load persistent state or create fresh
41
+ state = loadData(SAVE_KEY, defaultState());
42
+ state.runs = (state.runs || 0) + 1;
43
+
44
+ setCameraPosition(0, 12, 16);
45
+ setCameraTarget(0, 0, 0);
46
+ setAmbientLight(0x334466, 1.1);
47
+ setFog(0x050515, 20, 45);
48
+
49
+ // Ground
50
+ const ground = createPlane(30, 30, 0x0a0a22, [0, 0, 0]);
51
+ rotateMesh(ground, -Math.PI / 2, 0, 0);
52
+
53
+ // Ship color reflects upgrade level
54
+ const shipColors = [0x0088ff, 0x00ffaa, 0xffaa00, 0xff44aa];
55
+ const sz = 0.5 + state.shipLevel * 0.15;
56
+ ship = createCube(sz * 2, shipColors[state.shipLevel % shipColors.length], [0, 0.6, 0], {
57
+ material: 'metallic',
58
+ emissive: 0x002244,
59
+ });
60
+
61
+ spawnGems(5 + state.level * 2);
62
+ }
63
+
64
+ export function update(dt) {
65
+ const speed = 4 + state.shipLevel * 0.8;
66
+ let mx = 0,
67
+ mz = 0;
68
+ if (key('KeyW') || key('ArrowUp')) mz -= speed * dt;
69
+ if (key('KeyS') || key('ArrowDown')) mz += speed * dt;
70
+ if (key('KeyA') || key('ArrowLeft')) mx -= speed * dt;
71
+ if (key('KeyD') || key('ArrowRight')) mx += speed * dt;
72
+
73
+ // Move ship — read position, apply delta, write back
74
+ const pos = getMeshPosition(ship);
75
+ const nx = Math.max(-13, Math.min(13, pos.x + mx));
76
+ const nz = Math.max(-13, Math.min(13, pos.z + mz));
77
+ setPosition(ship, nx, pos.y, nz);
78
+ rotateMesh(ship, 0, dt * 0.5, 0);
79
+
80
+ // Gem spin and collection
81
+ gems = gems.filter(g => {
82
+ g.spin += dt * 1.2;
83
+ rotateMesh(g.mesh, dt * 0.5, dt, 0);
84
+ const dist = Math.hypot(nx - g.x, nz - g.z);
85
+ if (dist < 1.0) {
86
+ // Collect!
87
+ removeMesh(g.mesh);
88
+ state.score += 10 * state.level;
89
+ state.totalGems++;
90
+ if (state.score > state.highScore) state.highScore = state.score;
91
+ sfx('coin');
92
+ // Spawn particle burst
93
+ for (let p = 0; p < 6; p++) {
94
+ particles.push({
95
+ x: g.x,
96
+ y: 0.5,
97
+ z: g.z,
98
+ vx: (Math.random() - 0.5) * 4,
99
+ vy: 1 + Math.random() * 2,
100
+ vz: (Math.random() - 0.5) * 4,
101
+ life: 0.6,
102
+ color: g.color,
103
+ mesh: createSphere(0.1, g.color, [g.x, 0.5, g.z], 4),
104
+ });
105
+ }
106
+ return false;
107
+ }
108
+ return true;
109
+ });
110
+
111
+ // Auto-save and level up when all gems collected
112
+ if (gems.length === 0) {
113
+ state.level++;
114
+ saveData(SAVE_KEY, state);
115
+ saveFlash = 1.5;
116
+ sfx('powerup');
117
+ spawnGems(5 + state.level * 2);
118
+ }
119
+
120
+ // Particles
121
+ particles = particles.filter(p => {
122
+ p.vy -= 3 * dt;
123
+ p.x += p.vx * dt;
124
+ p.y += p.vy * dt;
125
+ p.z += p.vz * dt;
126
+ p.life -= dt;
127
+ setPosition(p.mesh, p.x, p.y, p.z);
128
+ if (p.life <= 0) {
129
+ removeMesh(p.mesh);
130
+ return false;
131
+ }
132
+ return true;
133
+ });
134
+
135
+ // Upgrade ship (press U)
136
+ if (keyp('KeyU') && state.shipLevel < 3) {
137
+ const cost = UPGRADE_COST[state.shipLevel + 1];
138
+ if (state.score >= cost) {
139
+ state.score -= cost;
140
+ state.shipLevel++;
141
+ saveData(SAVE_KEY, state);
142
+ saveFlash = 1.5;
143
+ upgradeFlash = 2;
144
+ sfx('powerup');
145
+ }
146
+ }
147
+
148
+ // Manual save (press Enter)
149
+ if (keyp('Enter')) {
150
+ saveData(SAVE_KEY, state);
151
+ saveFlash = 1.5;
152
+ sfx('confirm');
153
+ }
154
+
155
+ // Reset save (press R + Shift together)
156
+ if (key('ShiftLeft') && keyp('KeyR')) {
157
+ deleteData(SAVE_KEY);
158
+ state = defaultState();
159
+ saveFlash = 1.5;
160
+ sfx('error');
161
+ }
162
+
163
+ upgradeFlash = Math.max(0, upgradeFlash - dt);
164
+ saveFlash = Math.max(0, saveFlash - dt);
165
+ }
166
+
167
+ export function draw() {
168
+ // Header
169
+ rect(0, 0, 320, 18, rgba8(10, 5, 30, 255), true);
170
+ printCentered('STORAGE QUEST', 4, 0xffffff);
171
+
172
+ // Score panel
173
+ rect(4, 22, 150, 60, rgba8(15, 10, 40, 200), true);
174
+ rect(4, 22, 150, 60, rgba8(60, 40, 120, 180), false);
175
+ print(`SCORE`, 10, 27, 0xaaaaff);
176
+ print(`${state.score}`, 10, 36, 0xffffff);
177
+ print(`BEST: ${state.highScore}`, 10, 46, 0x888888);
178
+ print(`LEVEL: ${state.level}`, 10, 56, 0x88aaff);
179
+ print(`GEMS: ${state.totalGems}`, 10, 66, 0xffdd44);
180
+
181
+ // Persistence panel
182
+ rect(160, 22, 156, 60, rgba8(15, 10, 40, 200), true);
183
+ rect(160, 22, 156, 60, rgba8(60, 40, 120, 180), false);
184
+ print('PERSISTENT DATA', 166, 27, 0xaaaaff);
185
+ print(`Runs: ${state.runs}`, 166, 37, 0xdddddd);
186
+ print(`Ship lvl: ${state.shipLevel}`, 166, 47, 0xdddddd);
187
+ const nextCost = state.shipLevel < 3 ? UPGRADE_COST[state.shipLevel + 1] : 'MAX';
188
+ print(`Upgrade: ${nextCost}pts`, 166, 57, 0xffaa44);
189
+ print('(U to upgrade)', 166, 67, 0x555577);
190
+
191
+ // Save indicator
192
+ if (saveFlash > 0) {
193
+ const alpha = Math.floor((saveFlash / 1.5) * 220);
194
+ rect(100, 86, 120, 12, rgba8(0, 180, 100, alpha), true);
195
+ print(
196
+ upgradeFlash > 0 ? 'SHIP UPGRADED!' : 'DATA SAVED!',
197
+ 112,
198
+ 89,
199
+ upgradeFlash > 0 ? 0xffdd00 : 0xffffff
200
+ );
201
+ }
202
+
203
+ // Gem counter
204
+ print(`Gems remaining: ${gems.length}`, 10, 90, 0xdddddd);
205
+
206
+ // Controls footer
207
+ rect(0, 170, 320, 10, rgba8(10, 5, 30, 255), true);
208
+ print('WASD: move U: upgrade Enter: save Shift+R: reset', 2, 172, 0x333355);
209
+ }
@@ -0,0 +1,285 @@
1
+ # Shadow Ninja 3D - Improvement Options
2
+
3
+ ## Current Problems & Solutions
4
+
5
+ ### 🔴 **What Was Wrong:**
6
+
7
+ 1. **Broken Physics**
8
+ - Collision detection was unreliable
9
+ - Player would fall through platforms
10
+ - No proper ground detection
11
+ 2. **Bad Level Design**
12
+ - Platforms at random Z positions (confusing depth)
13
+ - No progression or tutorial
14
+ - Unclear where to go
15
+ 3. **Poor Controls**
16
+ - No coyote time (grace period after leaving platform)
17
+ - No jump buffering (early jump presses ignored)
18
+ - Difficult to land jumps
19
+ 4. **Terrible Visuals**
20
+ - Dark colors that hide gameplay
21
+ - Abstract shapes instead of characters
22
+ - No visual feedback
23
+
24
+ ### ✅ **What's Been Fixed (code-fixed.js):**
25
+
26
+ 1. **Proper Platformer Physics**
27
+ - Reliable AABB collision detection
28
+ - Coyote time (150ms grace after leaving platform)
29
+ - Jump buffering (100ms early jump window)
30
+ - Air control vs ground control
31
+ - Proper gravity and friction
32
+
33
+ 2. **Professional Level Design**
34
+ - Tutorial section (teaches basics)
35
+ - Easy section (builds confidence)
36
+ - Medium section (introduces challenges)
37
+ - Hard section (tests skills)
38
+ - Victory area
39
+ - All platforms on same Z plane (no confusing depth)
40
+
41
+ 3. **Responsive Controls**
42
+ - Arrow keys for movement
43
+ - Space for jump
44
+ - Works immediately, feels good
45
+
46
+ 4. **Clear Visual Design**
47
+ - Bright, visible colors
48
+ - Clear character with eyes and feet
49
+ - Animated movement (foot bobbing when walking)
50
+ - Coin rotation and bobbing
51
+
52
+ ## 🎨 **Options to Make It Even Better:**
53
+
54
+ ### Option 1: Use Free GLB Models (Best Quality)
55
+
56
+ **Where to get models:**
57
+
58
+ - [Poly Pizza](https://poly.pizza) - Free low-poly models
59
+ - [Sketchfab](https://sketchfab.com/search?features=downloadable&licenses=7c23a1ba438d4306920229c12afcb5f&type=models) - Free Creative Commons models
60
+ - [Quaternius](http://quaternius.com/assets.html) - Free game assets
61
+ - [Kenney Assets](https://kenney.nl/assets) - Free game models
62
+
63
+ **To use GLB models:**
64
+
65
+ 1. Download a ninja/character GLB file
66
+ 2. Place in `/public/models/ninja.glb`
67
+ 3. Set `CONFIG.USE_GLB_MODELS = true` in code-fixed.js
68
+ 4. The game will automatically load and render the model
69
+
70
+ **Example models:**
71
+
72
+ ```javascript
73
+ // Ninja character
74
+ await loadModel('/models/ninja.glb', [0, 2, 0], 1);
75
+
76
+ // Platform models
77
+ await loadModel('/models/platform.glb', [x, y, 0], 1);
78
+
79
+ // Coin models
80
+ await loadModel('/models/coin.glb', [x, y, 0], 0.3);
81
+
82
+ // Enemy models
83
+ await loadModel('/models/enemy.glb', [x, y, 0], 0.8);
84
+ ```
85
+
86
+ ### Option 2: Improve Graphics with Textures
87
+
88
+ Add textures to the simple geometry:
89
+
90
+ ```javascript
91
+ const texture = await loadTexture('/textures/character.png');
92
+ const material = createTexturedMaterial(texture);
93
+ ```
94
+
95
+ ### Option 3: Add More Game Features
96
+
97
+ **Easy additions:**
98
+
99
+ - Double jump
100
+ - Dash ability
101
+ - Wall jump
102
+ - Moving platforms
103
+ - Collectible power-ups
104
+ - Particle effects on landing
105
+ - Sound effects
106
+
107
+ **Example - Double Jump:**
108
+
109
+ ```javascript
110
+ let doubleJumpAvailable = true;
111
+
112
+ // In updateInput:
113
+ if (isKeyPressed('Space')) {
114
+ if (player.grounded) {
115
+ player.vel.y = CONFIG.JUMP_POWER;
116
+ doubleJumpAvailable = true;
117
+ } else if (doubleJumpAvailable) {
118
+ player.vel.y = CONFIG.JUMP_POWER;
119
+ doubleJumpAvailable = false;
120
+ }
121
+ }
122
+ ```
123
+
124
+ ### Option 4: Add Procedural Level Generation
125
+
126
+ Generate levels automatically:
127
+
128
+ ```javascript
129
+ function generateLevel(difficulty) {
130
+ for (let i = 0; i < 50; i++) {
131
+ const x = i * 5;
132
+ const y = 2 + Math.random() * difficulty * 3;
133
+ addPlatform(x, y, 3 + Math.random() * 2);
134
+
135
+ if (Math.random() < 0.3) addCoin(x, y + 2);
136
+ if (Math.random() < 0.2) addEnemy(x, y + 1);
137
+ }
138
+ }
139
+ ```
140
+
141
+ ### Option 5: Add Visual Polish
142
+
143
+ **Particle systems:**
144
+
145
+ ```javascript
146
+ // Jump dust particles
147
+ function createJumpDust() {
148
+ for (let i = 0; i < 5; i++) {
149
+ const particle = createSphere(0.1, 0xcccccc, [
150
+ player.pos.x + (Math.random() - 0.5),
151
+ player.pos.y - 1,
152
+ player.pos.z,
153
+ ]);
154
+ // Animate and fade out
155
+ }
156
+ }
157
+ ```
158
+
159
+ **Camera shake on impact:**
160
+
161
+ ```javascript
162
+ function shakeCamera(intensity) {
163
+ camera.pos.x += (Math.random() - 0.5) * intensity;
164
+ camera.pos.y += (Math.random() - 0.5) * intensity;
165
+ }
166
+ ```
167
+
168
+ ## 🚀 **Recommended Next Steps:**
169
+
170
+ ### Immediate (Do This Now):
171
+
172
+ 1. ✅ **Use code-fixed.js** instead of current code.js
173
+ 2. Test the game - it should actually work!
174
+ 3. Adjust CONFIG values for difficulty
175
+
176
+ ### Short Term (1-2 hours):
177
+
178
+ 1. Download free GLB models from Poly Pizza
179
+ 2. Add them to the project
180
+ 3. Enable `USE_GLB_MODELS` flag
181
+ 4. Add double jump ability
182
+ 5. Add particle effects
183
+
184
+ ### Medium Term (1 day):
185
+
186
+ 1. Create multiple levels
187
+ 2. Add boss fights
188
+ 3. Add combo system
189
+ 4. Add checkpoints
190
+ 5. Add sound effects
191
+
192
+ ### Long Term (1 week):
193
+
194
+ 1. Procedural level generation
195
+ 2. Multiplayer racing mode
196
+ 3. Level editor
197
+ 4. Mobile controls
198
+ 5. Leaderboards
199
+
200
+ ## 📝 **How to Use code-fixed.js:**
201
+
202
+ 1. **Rename files:**
203
+
204
+ ```bash
205
+ cd /Users/brendonsmith/exp/nova64/examples/strider-demo-3d
206
+ mv code.js code-old.js
207
+ mv code-fixed.js code.js
208
+ ```
209
+
210
+ 2. **Refresh browser** - game should now work properly!
211
+
212
+ 3. **Test the improvements:**
213
+ - Jump should feel responsive
214
+ - Landing on platforms should be reliable
215
+ - Level progression should be clear
216
+ - Character should be visible
217
+
218
+ ## 🎮 **Expected Results:**
219
+
220
+ ### Before (code-old.js):
221
+
222
+ - ❌ Player falls through platforms
223
+ - ❌ Jumps feel unresponsive
224
+ - ❌ Unclear where to go
225
+ - ❌ Dark and confusing visuals
226
+ - ❌ Not fun to play
227
+
228
+ ### After (code-fixed.js):
229
+
230
+ - ✅ Reliable collision detection
231
+ - ✅ Jumps feel good (coyote time + buffering)
232
+ - ✅ Clear level progression
233
+ - ✅ Bright, visible graphics
234
+ - ✅ Actually fun to play!
235
+
236
+ ## 🔧 **Tuning the Game:**
237
+
238
+ Edit CONFIG values in code-fixed.js:
239
+
240
+ ```javascript
241
+ const CONFIG = {
242
+ PLAYER_SPEED: 8, // ← Make character faster/slower
243
+ JUMP_POWER: 12, // ← Make jumps higher/lower
244
+ GRAVITY: 30, // ← Change gravity strength
245
+ CAMERA_DISTANCE: 15, // ← Zoom in/out
246
+ // etc...
247
+ };
248
+ ```
249
+
250
+ ## 📊 **Performance:**
251
+
252
+ The fixed version is actually MORE performant because:
253
+
254
+ - Simpler collision detection
255
+ - Fewer objects in scene
256
+ - Better organized code
257
+ - No unnecessary calculations
258
+
259
+ ## 🆘 **Still Having Issues?**
260
+
261
+ If the game still doesn't feel right:
262
+
263
+ 1. **Check console for errors**
264
+ 2. **Verify all platforms are at Z=0**
265
+ 3. **Test jump timing (should be forgiving)**
266
+ 4. **Check collision box sizes match visuals**
267
+ 5. **Ensure camera follows smoothly**
268
+
269
+ ## 🎯 **The Real Problem:**
270
+
271
+ The original code tried to do too much:
272
+
273
+ - Complex enemy AI before basic physics worked
274
+ - Grappling hooks before basic jumps worked
275
+ - Wall running before collision detection worked
276
+ - Fancy graphics before gameplay worked
277
+
278
+ **Good game design order:**
279
+
280
+ 1. ✅ Physics and collision (make it work)
281
+ 2. ✅ Basic movement (make it feel good)
282
+ 3. ✅ Simple level (prove it's fun)
283
+ 4. Then add: Polish, features, graphics, etc.
284
+
285
+ The new code follows this principle. Start simple, make it work, then iterate!
@@ -0,0 +1,132 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Knight Platformer - Cache Diagnostic</title>
5
+ <style>
6
+ body {
7
+ font-family: monospace;
8
+ padding: 20px;
9
+ background: #1a1a1a;
10
+ color: #00ff00;
11
+ }
12
+ .status {
13
+ padding: 10px;
14
+ margin: 10px 0;
15
+ border-radius: 5px;
16
+ }
17
+ .good { background: #002200; border: 2px solid #00ff00; }
18
+ .bad { background: #220000; border: 2px solid #ff0000; color: #ff6666; }
19
+ .info { background: #001122; border: 2px solid #6666ff; color: #aaaaff; }
20
+ button {
21
+ background: #4444ff;
22
+ color: white;
23
+ padding: 10px 20px;
24
+ border: none;
25
+ border-radius: 5px;
26
+ cursor: pointer;
27
+ margin: 5px;
28
+ }
29
+ button:hover { background: #6666ff; }
30
+ pre {
31
+ background: #000;
32
+ padding: 10px;
33
+ border-radius: 5px;
34
+ overflow-x: auto;
35
+ }
36
+ </style>
37
+ </head>
38
+ <body>
39
+ <h1>🥷 Knight Platformer - Cache Diagnostic</h1>
40
+
41
+ <div id="results"></div>
42
+
43
+ <button onclick="runTest()">🔍 Test Cache Status</button>
44
+ <button onclick="clearAndReload()">🔄 Clear & Reload Game</button>
45
+ <button onclick="openIncognito()">🕵️ Instructions for Incognito</button>
46
+
47
+ <script>
48
+ async function runTest() {
49
+ const results = document.getElementById('results');
50
+ results.innerHTML = '<h2>Testing...</h2>';
51
+
52
+ try {
53
+ // Fetch the code.js file with cache-busting
54
+ const response = await fetch('./code.js?t=' + Date.now());
55
+ const code = await response.text();
56
+
57
+ let html = '<h2>Test Results:</h2>';
58
+
59
+ // Check for triple emoji (correct code)
60
+ if (code.includes('🎯🎯🎯 START BUTTON CLICKED AT')) {
61
+ html += '<div class="status good">✅ SERVER HAS CORRECT CODE (Triple emoji found)</div>';
62
+ } else if (code.includes('🎯 START BUTTON CLICKED!')) {
63
+ html += '<div class="status bad">❌ SERVER HAS OLD CODE (Single emoji found)</div>';
64
+ } else {
65
+ html += '<div class="status bad">❌ CANNOT FIND BUTTON CALLBACK</div>';
66
+ }
67
+
68
+ // Check cache buster
69
+ if (code.includes('CACHE-BUST-FINAL-001-REFRESH-NOW')) {
70
+ html += '<div class="status good">✅ Latest cache-buster present</div>';
71
+ } else {
72
+ html += '<div class="status bad">❌ Old or missing cache-buster</div>';
73
+ }
74
+
75
+ // Check for module-level callback
76
+ if (code.includes('const startGameCallback = ()')) {
77
+ html += '<div class="status good">✅ Callback at module level</div>';
78
+ } else {
79
+ html += '<div class="status bad">❌ Callback not at module level</div>';
80
+ }
81
+
82
+ // Show first 50 lines
83
+ const lines = code.split('\n').slice(0, 50);
84
+ html += '<div class="status info">';
85
+ html += '<h3>First 50 lines of code.js from server:</h3>';
86
+ html += '<pre>' + lines.join('\n').replace(/</g, '&lt;').replace(/>/g, '&gt;') + '</pre>';
87
+ html += '</div>';
88
+
89
+ // Instructions
90
+ html += '<div class="status info">';
91
+ html += '<h3>📋 To Fix Browser Cache:</h3>';
92
+ html += '<ol>';
93
+ html += '<li><strong>Mac:</strong> Press Cmd + Shift + R</li>';
94
+ html += '<li><strong>Windows/Linux:</strong> Press Ctrl + Shift + F5</li>';
95
+ html += '<li><strong>Or:</strong> Open Developer Tools (F12) → Right-click refresh → "Empty Cache and Hard Reload"</li>';
96
+ html += '<li><strong>Or:</strong> Open in incognito/private window</li>';
97
+ html += '</ol>';
98
+ html += '</div>';
99
+
100
+ results.innerHTML = html;
101
+
102
+ } catch (error) {
103
+ results.innerHTML = `<div class="status bad">❌ Error: ${error.message}</div>`;
104
+ }
105
+ }
106
+
107
+ function clearAndReload() {
108
+ // Try to clear cache via JavaScript (limited effect)
109
+ if ('caches' in window) {
110
+ caches.keys().then(names => {
111
+ names.forEach(name => caches.delete(name));
112
+ });
113
+ }
114
+
115
+ alert('Cache cleared (partial). Now do a HARD RELOAD:\n\nMac: Cmd + Shift + R\nWindows: Ctrl + Shift + F5');
116
+
117
+ // Reload with cache bust
118
+ setTimeout(() => {
119
+ window.location.href = '../strider-demo-3d/?cachebust=' + Date.now();
120
+ }, 1000);
121
+ }
122
+
123
+ function openIncognito() {
124
+ const url = window.location.origin + '/examples/strider-demo-3d/';
125
+ alert(`Open this URL in an incognito/private window:\n\n${url}\n\nChrome/Edge: Ctrl+Shift+N\nFirefox: Ctrl+Shift+P\nSafari: Cmd+Shift+N`);
126
+ }
127
+
128
+ // Run test on load
129
+ runTest();
130
+ </script>
131
+ </body>
132
+ </html>