littlejsengine 1.15.9 → 1.16.1

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 (48) hide show
  1. package/dist/littlejs.d.ts +66 -83
  2. package/dist/littlejs.esm.js +318 -330
  3. package/dist/littlejs.esm.min.js +1 -1
  4. package/dist/littlejs.js +306 -319
  5. package/dist/littlejs.min.js +1 -1
  6. package/dist/littlejs.release.js +229 -242
  7. package/examples/box2d/game.js +1 -1
  8. package/examples/breakout/game.js +3 -3
  9. package/examples/electron/game.js +1 -2
  10. package/examples/electron/index.html +2 -2
  11. package/examples/htmlMenu/game.js +0 -1
  12. package/examples/index.html +1 -1
  13. package/examples/module/game.js +1 -2
  14. package/examples/particles/index.html +1 -1
  15. package/examples/platformer/game.js +4 -4
  16. package/examples/puzzle/game.js +2 -2
  17. package/examples/shorts/base.html +3 -3
  18. package/examples/shorts/box2dPool.js +2 -2
  19. package/examples/shorts/empty.js +1 -1
  20. package/examples/shorts/{systemFont.js → fontImage.js} +3 -3
  21. package/examples/shorts/fps.js +1 -1
  22. package/examples/shorts/helloWorld.js +2 -2
  23. package/examples/shorts/nineSlice.js +2 -2
  24. package/examples/shorts/slidingPuzzle.js +1 -1
  25. package/examples/starter/game.js +1 -2
  26. package/examples/starter/index.html +2 -2
  27. package/examples/stress/index.html +1 -1
  28. package/examples/typescript/game.js +1 -2
  29. package/examples/typescript/game.ts +1 -2
  30. package/package.json +1 -1
  31. package/plugins/box2d.js +8 -8
  32. package/plugins/drawUtilities.js +6 -6
  33. package/plugins/postProcess.js +13 -20
  34. package/plugins/uiSystem.js +15 -3
  35. package/reference.md +4 -6
  36. package/src/engine.js +35 -37
  37. package/src/engineAudio.js +3 -3
  38. package/src/engineDebug.js +78 -78
  39. package/src/engineDraw.js +107 -109
  40. package/src/engineExport.js +12 -11
  41. package/src/engineInput.js +1 -1
  42. package/src/engineMedals.js +3 -3
  43. package/src/engineObject.js +4 -2
  44. package/src/engineRelease.js +1 -1
  45. package/src/engineSettings.js +20 -30
  46. package/src/engineTileLayer.js +5 -4
  47. package/src/engineUtilities.js +2 -10
  48. package/src/engineWebGL.js +6 -5
package/src/engine.js CHANGED
@@ -30,7 +30,7 @@ const engineName = 'LittleJS';
30
30
  * @type {string}
31
31
  * @default
32
32
  * @memberof Engine */
33
- const engineVersion = '1.15.9';
33
+ const engineVersion = '1.16.1';
34
34
 
35
35
  /** Frames per second to update
36
36
  * @type {number}
@@ -177,8 +177,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
177
177
  mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
178
178
 
179
179
  // disable smoothing for pixel art
180
- overlayContext.imageSmoothingEnabled =
181
- mainContext.imageSmoothingEnabled = !tilesPixelated;
180
+ mainContext.imageSmoothingEnabled = !tilesPixelated;
182
181
 
183
182
  // setup gl rendering if enabled
184
183
  glPreRender();
@@ -190,7 +189,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
190
189
  // update time keeping
191
190
  let frameTimeDeltaMS = frameTimeMS - frameTimeLastMS;
192
191
  frameTimeLastMS = frameTimeMS;
193
- if (debug || showWatermark)
192
+ if (debug || debugWatermark)
194
193
  averageFPS = lerp(averageFPS, 1e3/(frameTimeDeltaMS||1), .05);
195
194
  const debugSpeedUp = debug && keyIsDown('Equal'); // +
196
195
  const debugSpeedDown = debug && keyIsDown('Minus'); // -
@@ -218,6 +217,8 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
218
217
  debugUpdate();
219
218
  gameUpdatePost();
220
219
  inputUpdatePost();
220
+ if (debugVideoCaptureIsActive())
221
+ renderFrame();
221
222
  }
222
223
  else
223
224
  {
@@ -281,19 +282,19 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
281
282
  glFlush();
282
283
  debugVideoCaptureUpdate();
283
284
 
284
- if (showWatermark && !debugVideoCaptureIsActive())
285
+ if (debugWatermark && !debugVideoCaptureIsActive())
285
286
  {
286
287
  // update fps display
287
- overlayContext.textAlign = 'right';
288
- overlayContext.textBaseline = 'top';
289
- overlayContext.font = '1em monospace';
290
- overlayContext.fillStyle = '#000';
288
+ mainContext.textAlign = 'right';
289
+ mainContext.textBaseline = 'top';
290
+ mainContext.font = '1em monospace';
291
+ mainContext.fillStyle = '#000';
291
292
  const text = engineName + ' ' + 'v' + engineVersion + ' / '
292
293
  + drawCount + ' / ' + engineObjects.length + ' / ' + averageFPS.toFixed(1)
293
294
  + (glEnable ? ' GL' : ' 2D') ;
294
- overlayContext.fillText(text, mainCanvas.width-3, 3);
295
- overlayContext.fillStyle = '#fff';
296
- overlayContext.fillText(text, mainCanvas.width-2, 2);
295
+ mainContext.fillText(text, mainCanvas.width-3, 3);
296
+ mainContext.fillStyle = '#fff';
297
+ mainContext.fillText(text, mainCanvas.width-2, 2);
297
298
  }
298
299
  drawCount = 0;
299
300
  }
@@ -313,8 +314,8 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
313
314
  const fixedAspect = canvasFixedSize.x / canvasFixedSize.y;
314
315
  const w = innerAspect < fixedAspect ? '100%' : '';
315
316
  const h = innerAspect < fixedAspect ? '' : '100%';
316
- overlayCanvas.style.width = mainCanvas.style.width = w;
317
- overlayCanvas.style.height = mainCanvas.style.height = h;
317
+ mainCanvas.style.width = w;
318
+ mainCanvas.style.height = h;
318
319
  if (glCanvas)
319
320
  {
320
321
  glCanvas.style.width = w;
@@ -329,6 +330,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
329
330
 
330
331
  // responsive aspect ratio with native resolution
331
332
  const innerAspect = innerWidth / innerHeight;
333
+ ASSERT(canvasMinAspect <= canvasMaxAspect);
332
334
  if (canvasMaxAspect && innerAspect > canvasMaxAspect)
333
335
  {
334
336
  // full height
@@ -343,12 +345,12 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
343
345
  }
344
346
  }
345
347
 
346
- // clear main and overlay canvas and set size
347
- overlayCanvas.width = mainCanvas.width = mainCanvasSize.x;
348
- overlayCanvas.height = mainCanvas.height = mainCanvasSize.y;
348
+ // clear main canvas and set size
349
+ mainCanvas.width = mainCanvasSize.x;
350
+ mainCanvas.height = mainCanvasSize.y;
349
351
 
350
352
  // apply the clear color to main canvas
351
- if (canvasClearColor.a > 0)
353
+ if (canvasClearColor.a > 0 && !glEnable)
352
354
  {
353
355
  mainContext.fillStyle = canvasClearColor.toString();
354
356
  mainContext.fillRect(0, 0, mainCanvasSize.x, mainCanvasSize.y);
@@ -356,9 +358,8 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
356
358
  }
357
359
 
358
360
  // set default line join and cap
359
- const lineJoin = 'round', lineCap = 'round';
360
- mainContext.lineJoin = overlayContext.lineJoin = lineJoin;
361
- mainContext.lineCap = overlayContext.lineCap = lineCap;
361
+ mainContext.lineJoin = 'round';
362
+ mainContext.lineCap = 'round';
362
363
  }
363
364
 
364
365
  // wait for gameInit to load
@@ -370,6 +371,9 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
370
371
  if (headlessMode)
371
372
  return startEngine();
372
373
 
374
+ // setup webgl
375
+ glInit(rootElement);
376
+
373
377
  // setup html
374
378
  const styleRoot =
375
379
  'margin:0;' + // fill the window
@@ -380,36 +384,30 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
380
384
  'touch-action:none;' + // prevent mobile pinch to resize
381
385
  '-webkit-touch-callout:none'; // compatibility for ios
382
386
  rootElement.style.cssText = styleRoot;
383
- drawCanvas = mainCanvas = document.createElement('canvas');
384
- rootElement.appendChild(mainCanvas);
387
+ drawCanvas = mainCanvas = rootElement.appendChild(document.createElement('canvas'));
385
388
  drawContext = mainContext = mainCanvas.getContext('2d');
386
389
 
387
390
  // init stuff and start engine
388
391
  inputInit();
389
392
  audioInit();
390
393
  debugInit();
391
- glInit();
392
-
393
- // create overlay canvas for hud to appear above gl canvas
394
- overlayCanvas = document.createElement('canvas')
395
- rootElement.appendChild(overlayCanvas);
396
- overlayContext = overlayCanvas.getContext('2d');
397
394
 
398
395
  // setup canvases
399
396
  // transform way is still more reliable then flexbox or grid
400
397
  const styleCanvas = 'position:absolute;'+ // allow canvases to overlap
401
398
  'top:50%;left:50%;transform:translate(-50%,-50%)'; // center on screen
402
- mainCanvas.style.cssText = overlayCanvas.style.cssText = styleCanvas;
399
+ mainCanvas.style.cssText = styleCanvas;
403
400
  if (glCanvas)
404
401
  glCanvas.style.cssText = styleCanvas;
405
402
  setCanvasPixelated(canvasPixelated);
406
- setOverlayCanvasPixelated(overlayCanvasPixelated);
407
403
  updateCanvas();
408
404
  glPreRender();
409
405
 
410
- // create offscreen canvas for image processing
411
- workCanvas = new OffscreenCanvas(256, 256);
412
- workContext = workCanvas.getContext('2d', { willReadFrequently: true });
406
+ // create offscreen canvases for image processing
407
+ workCanvas = new OffscreenCanvas(64, 64);
408
+ workContext = workCanvas.getContext('2d');
409
+ workReadCanvas = new OffscreenCanvas(64, 64);
410
+ workReadContext = workReadCanvas.getContext('2d', { willReadFrequently: true });
413
411
 
414
412
  // create promises for loading images
415
413
  const promises = imageSources.map((src, textureIndex)=>
@@ -465,9 +463,9 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
465
463
  // LittleJS Splash Screen
466
464
  function drawEngineSplashScreen(t)
467
465
  {
468
- const x = overlayContext;
469
- const w = overlayCanvas.width = innerWidth;
470
- const h = overlayCanvas.height = innerHeight;
466
+ const x = mainContext;
467
+ const w = mainCanvas.width = innerWidth;
468
+ const h = mainCanvas.height = innerHeight;
471
469
 
472
470
  {
473
471
  // background
@@ -178,12 +178,12 @@ class Sound
178
178
  ///////////////////////////////////////////////////////////////////////////////
179
179
 
180
180
  /**
181
- * Sound Wave Object - Stores a wave sound for later use and can be played positionally
182
- * - this can be used to play wave, mp3, and ogg files
181
+ * Sound Wave Object - Loads and stores an audio file for later use
182
+ * - this can be used to load and play wave, mp3, and ogg files
183
183
  * @extends Sound
184
184
  * @memberof Audio
185
185
  * @example
186
- * // create a sound
186
+ * // load an audio asset file
187
187
  * const sound_example = new SoundWave('sound.mp3');
188
188
  *
189
189
  * // play the sound
@@ -26,7 +26,7 @@ const debugPointSize = .5;
26
26
  * @type {boolean}
27
27
  * @default
28
28
  * @memberof Debug */
29
- let showWatermark = true;
29
+ let debugWatermark = true;
30
30
 
31
31
  /** Key code used to toggle debug mode, Esc by default
32
32
  * @type {string}
@@ -312,12 +312,19 @@ function debugUpdate()
312
312
  if (!debug)
313
313
  return;
314
314
 
315
+ if (debugVideoCaptureIsActive())
316
+ {
317
+ // control to stop video capture
318
+ if (keyWasPressed('Digit6') || keyWasPressed(debugKey))
319
+ debugVideoCaptureStop();
320
+ }
321
+
315
322
  if (keyWasPressed(debugKey)) // Esc
316
323
  debugOverlay = !debugOverlay;
317
324
  if (debugOverlay)
318
325
  {
319
326
  if (keyWasPressed('Digit0'))
320
- showWatermark = !showWatermark;
327
+ debugWatermark = !debugWatermark;
321
328
  if (keyWasPressed('Digit1'))
322
329
  debugPhysics = !debugPhysics, debugParticles = false;
323
330
  if (keyWasPressed('Digit2'))
@@ -328,8 +335,8 @@ function debugUpdate()
328
335
  debugRaycast = !debugRaycast;
329
336
  if (keyWasPressed('Digit5'))
330
337
  debugScreenshot();
331
- if (keyWasPressed('Digit6'))
332
- debugVideoCaptureIsActive() ? debugVideoCaptureStop() : debugVideoCaptureStart();
338
+ if (keyWasPressed('Digit6') && !debugVideoCaptureIsActive())
339
+ debugVideoCaptureStart();
333
340
  }
334
341
  }
335
342
 
@@ -345,13 +352,11 @@ function debugRender()
345
352
  {
346
353
  // combine canvases, remove alpha and save
347
354
  combineCanvases();
348
- const w = mainCanvas.width, h = mainCanvas.height;
349
- overlayContext.fillRect(0,0,w,h);
350
- overlayContext.drawImage(mainCanvas, 0, 0);
351
- debugSaveCanvas(overlayCanvas);
355
+ debugSaveCanvas(mainCanvas);
352
356
  debugTakeScreenshot = 0;
353
357
  }
354
358
 
359
+ const debugContext = mainContext;
355
360
  if (debugGamepads && gamepadsEnable)
356
361
  {
357
362
  // draw gamepads
@@ -399,9 +404,6 @@ function debugRender()
399
404
  let debugObject;
400
405
  if (debugOverlay)
401
406
  {
402
- const saveContext = mainContext;
403
- mainContext = overlayContext;
404
-
405
407
  // draw red rectangle around screen
406
408
  const cameraSize = getCameraSize();
407
409
  debugRect(cameraPos, cameraSize.subtract(vec2(.1)), '#f008');
@@ -433,15 +435,14 @@ function debugRender()
433
435
  // show floored tile pick for tile collision
434
436
  drawRect(mousePos.floor().add(vec2(.5)), vec2(1), rgb(1,1,0,.5));
435
437
  }
436
- mainContext = saveContext;
437
438
  }
438
439
 
439
440
  {
440
441
  // draw debug primitives
441
- overlayContext.lineWidth = 2;
442
+ debugContext.lineWidth = 2;
442
443
  debugPrimitives.forEach(p=>
443
444
  {
444
- overlayContext.save();
445
+ debugContext.save();
445
446
 
446
447
  // create canvas transform from world space to screen space
447
448
  // without scaling because we want consistent pixel sizes
@@ -452,55 +453,56 @@ function debugRender()
452
453
  scale = cameraScale;
453
454
  angle -= cameraAngle;
454
455
  }
455
- overlayContext.translate(pos.x|0, pos.y|0);
456
- overlayContext.rotate(angle);
457
- overlayContext.scale(1, p.text ? 1 : -1);
458
- overlayContext.fillStyle = overlayContext.strokeStyle = p.color;
456
+ debugContext.translate(pos.x|0, pos.y|0);
457
+ debugContext.rotate(angle);
458
+ debugContext.scale(1, p.text ? 1 : -1);
459
+ debugContext.fillStyle = p.color;
460
+ debugContext.strokeStyle = p.color;
459
461
  if (p.text !== undefined)
460
462
  {
461
- overlayContext.font = p.size*scale + 'px '+ p.font;
462
- overlayContext.textAlign = 'center';
463
- overlayContext.textBaseline = 'middle';
464
- overlayContext.fillText(p.text, 0, 0);
463
+ debugContext.font = p.size*scale + 'px '+ p.font;
464
+ debugContext.textAlign = 'center';
465
+ debugContext.textBaseline = 'middle';
466
+ debugContext.fillText(p.text, 0, 0);
465
467
  }
466
468
  else if (p.points !== undefined)
467
469
  {
468
470
  // poly
469
- overlayContext.beginPath();
471
+ debugContext.beginPath();
470
472
  for (const point of p.points)
471
473
  {
472
474
  const p2 = point.scale(scale).floor();
473
- overlayContext.lineTo(p2.x, p2.y);
475
+ debugContext.lineTo(p2.x, p2.y);
474
476
  }
475
- overlayContext.closePath();
476
- p.fill && overlayContext.fill();
477
- overlayContext.stroke();
477
+ debugContext.closePath();
478
+ p.fill && debugContext.fill();
479
+ debugContext.stroke();
478
480
  }
479
481
  else if (p.size === 0 || (p.size.x === 0 && p.size.y === 0))
480
482
  {
481
483
  // point
482
484
  const pointSize = debugPointSize * scale;
483
- overlayContext.fillRect(-pointSize/2, -1, pointSize, 3);
484
- overlayContext.fillRect(-1, -pointSize/2, 3, pointSize);
485
+ debugContext.fillRect(-pointSize/2, -1, pointSize, 3);
486
+ debugContext.fillRect(-1, -pointSize/2, 3, pointSize);
485
487
  }
486
488
  else if (p.size.x !== undefined)
487
489
  {
488
490
  // rect
489
491
  const s = p.size.scale(scale).floor();
490
492
  const w = s.x, h = s.y;
491
- p.fill && overlayContext.fillRect(-w/2|0, -h/2|0, w, h);
492
- overlayContext.strokeRect(-w/2|0, -h/2|0, w, h);
493
+ p.fill && debugContext.fillRect(-w/2|0, -h/2|0, w, h);
494
+ debugContext.strokeRect(-w/2|0, -h/2|0, w, h);
493
495
  }
494
496
  else
495
497
  {
496
498
  // circle
497
- overlayContext.beginPath();
498
- overlayContext.arc(0, 0, p.size*scale/2, 0, 9);
499
- p.fill && overlayContext.fill();
500
- overlayContext.stroke();
499
+ debugContext.beginPath();
500
+ debugContext.arc(0, 0, p.size*scale/2, 0, 9);
501
+ p.fill && debugContext.fill();
502
+ debugContext.stroke();
501
503
  }
502
504
 
503
- overlayContext.restore();
505
+ debugContext.restore();
504
506
  });
505
507
 
506
508
  // remove expired primitives
@@ -509,55 +511,53 @@ function debugRender()
509
511
 
510
512
  if (debugObject)
511
513
  {
512
- const saveContext = mainContext;
513
- mainContext = overlayContext;
514
514
  const raycastHitPos = tileCollisionRaycast(debugObject.pos, mousePos);
515
515
  raycastHitPos && drawRect(raycastHitPos.floor().add(vec2(.5)), vec2(1), rgb(0,1,1,.3));
516
516
  drawLine(mousePos, debugObject.pos, .1, raycastHitPos ? rgb(1,0,0,.5) : rgb(0,1,0,.5));
517
517
 
518
- const debugText = 'mouse pos = ' + mousePos +
519
- '\nmouse collision = ' + tileCollisionGetData(mousePos) +
520
- '\n\n--- object info ---\n' +
521
- debugObject.toString();
518
+ let debugText = 'mouse pos = ' + mousePos;
519
+ if (tileCollisionLayers.length)
520
+ debugText += '\nmouse collision = ' + tileCollisionGetData(mousePos);
521
+ debugText += '\n\n--- object info ---\n';
522
+ debugText += debugObject.toString();
522
523
  drawTextScreen(debugText, mousePosScreen, 24, rgb(), .05, undefined, 'center', 'monospace');
523
- mainContext = saveContext;
524
524
  }
525
525
 
526
526
  {
527
527
  // draw debug overlay
528
528
  const fontSize = 20;
529
529
  const lineHeight = fontSize * 1.2 | 0;
530
- overlayContext.save();
531
- overlayContext.fillStyle = '#fff';
532
- overlayContext.textAlign = 'left';
533
- overlayContext.textBaseline = 'top';
534
- overlayContext.font = fontSize + 'px monospace';
535
- overlayContext.shadowColor = '#000';
536
- overlayContext.shadowBlur = 9;
530
+ debugContext.save();
531
+ debugContext.fillStyle = '#fff';
532
+ debugContext.textAlign = 'left';
533
+ debugContext.textBaseline = 'top';
534
+ debugContext.font = fontSize + 'px monospace';
535
+ debugContext.shadowColor = '#000';
536
+ debugContext.shadowBlur = 9;
537
537
 
538
538
  let x = 9, y = 0, h = lineHeight;
539
539
  if (debugOverlay)
540
540
  {
541
- overlayContext.fillText(`${engineName} v${engineVersion}`, x, y += h/2 );
542
- overlayContext.fillText('Time: ' + formatTime(time), x, y += h);
543
- overlayContext.fillText('FPS: ' + averageFPS.toFixed(1) + (glEnable?' WebGL':' Canvas2D'),
541
+ debugContext.fillText(`${engineName} v${engineVersion}`, x, y += h/2 );
542
+ debugContext.fillText('Time: ' + formatTime(time), x, y += h);
543
+ debugContext.fillText('FPS: ' + averageFPS.toFixed(1) + (glEnable?' WebGL':' Canvas2D'),
544
544
  x, y += h);
545
- overlayContext.fillText('Objects: ' + engineObjects.length, x, y += h);
546
- overlayContext.fillText('Draw Count: ' + drawCount, x, y += h);
547
- overlayContext.fillText('---------', x, y += h);
548
- overlayContext.fillStyle = '#f00';
549
- overlayContext.fillText('ESC: Debug Overlay', x, y += h);
550
- overlayContext.fillStyle = debugPhysics ? '#f00' : '#fff';
551
- overlayContext.fillText('1: Debug Physics', x, y += h);
552
- overlayContext.fillStyle = debugParticles ? '#f00' : '#fff';
553
- overlayContext.fillText('2: Debug Particles', x, y += h);
554
- overlayContext.fillStyle = debugGamepads ? '#f00' : '#fff';
555
- overlayContext.fillText('3: Debug Gamepads', x, y += h);
556
- overlayContext.fillStyle = debugRaycast ? '#f00' : '#fff';
557
- overlayContext.fillText('4: Debug Raycasts', x, y += h);
558
- overlayContext.fillStyle = '#fff';
559
- overlayContext.fillText('5: Save Screenshot', x, y += h);
560
- overlayContext.fillText('6: Toggle Video Capture', x, y += h);
545
+ debugContext.fillText('Objects: ' + engineObjects.length, x, y += h);
546
+ debugContext.fillText('Draw Count: ' + drawCount, x, y += h);
547
+ debugContext.fillText('---------', x, y += h);
548
+ debugContext.fillStyle = '#f00';
549
+ debugContext.fillText('ESC: Debug Overlay', x, y += h);
550
+ debugContext.fillStyle = debugPhysics ? '#f00' : '#fff';
551
+ debugContext.fillText('1: Debug Physics', x, y += h);
552
+ debugContext.fillStyle = debugParticles ? '#f00' : '#fff';
553
+ debugContext.fillText('2: Debug Particles', x, y += h);
554
+ debugContext.fillStyle = debugGamepads ? '#f00' : '#fff';
555
+ debugContext.fillText('3: Debug Gamepads', x, y += h);
556
+ debugContext.fillStyle = debugRaycast ? '#f00' : '#fff';
557
+ debugContext.fillText('4: Debug Raycasts', x, y += h);
558
+ debugContext.fillStyle = '#fff';
559
+ debugContext.fillText('5: Save Screenshot', x, y += h);
560
+ debugContext.fillText('6: Toggle Video Capture', x, y += h);
561
561
 
562
562
  let keysPressed = '';
563
563
  let mousePressed = '';
@@ -570,8 +570,8 @@ function debugRender()
570
570
  else if (keyIsDown(i, 0))
571
571
  keysPressed += i + ' ' ;
572
572
  }
573
- mousePressed && overlayContext.fillText('Mouse: ' + mousePressed, x, y += h);
574
- keysPressed && overlayContext.fillText('Keys: ' + keysPressed, x, y += h);
573
+ mousePressed && debugContext.fillText('Mouse: ' + mousePressed, x, y += h);
574
+ keysPressed && debugContext.fillText('Keys: ' + keysPressed, x, y += h);
575
575
 
576
576
  // show gamepad buttons
577
577
  for (let i = 1; i < inputData.length; i++)
@@ -583,18 +583,18 @@ function debugRender()
583
583
  if (keyIsDown(j, i))
584
584
  buttonsPressed += j + ' ' ;
585
585
  }
586
- buttonsPressed && overlayContext.fillText(`Gamepad ${i-1}: ` + buttonsPressed, x, y += h);
586
+ buttonsPressed && debugContext.fillText(`Gamepad ${i-1}: ` + buttonsPressed, x, y += h);
587
587
  }
588
588
  }
589
589
  else
590
590
  {
591
- overlayContext.fillText(debugPhysics ? 'Debug Physics' : '', x, y += h);
592
- overlayContext.fillText(debugParticles ? 'Debug Particles' : '', x, y += h);
593
- overlayContext.fillText(debugRaycast ? 'Debug Raycasts' : '', x, y += h);
594
- overlayContext.fillText(debugGamepads ? 'Debug Gamepads' : '', x, y += h);
591
+ debugContext.fillText(debugPhysics ? 'Debug Physics' : '', x, y += h);
592
+ debugContext.fillText(debugParticles ? 'Debug Particles' : '', x, y += h);
593
+ debugContext.fillText(debugRaycast ? 'Debug Raycasts' : '', x, y += h);
594
+ debugContext.fillText(debugGamepads ? 'Debug Gamepads' : '', x, y += h);
595
595
  }
596
596
 
597
- overlayContext.restore();
597
+ debugContext.restore();
598
598
  }
599
599
  }
600
600
 
@@ -645,7 +645,7 @@ function debugVideoCaptureStart()
645
645
  // start recording
646
646
  LOG('Video capture started.');
647
647
  debugVideoCapture.start();
648
- debugVideoCaptureTimer = new Timer(0);
648
+ debugVideoCaptureTimer = new Timer(0, true);
649
649
 
650
650
  if (!debugVideoCaptureIcon)
651
651
  {