@makefully/platypus 4.1.21 → 4.1.23

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makefully/platypus",
3
- "version": "4.1.21",
3
+ "version": "4.1.23",
4
4
  "description": "2D tile-based HTML5 game engine with a component-based entity model",
5
5
  "license": "MIT",
6
6
  "contributors": [
package/src/Game.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /* global document, platypus, window */
2
2
  import {Application} from 'springroll';
3
- import {CullerPlugin, Application as PixiApplication, Ticker, extensions} from 'pixi.js';
3
+ import {CullerPlugin, Application as PixiApplication, Rectangle, Ticker, extensions} from 'pixi.js';
4
4
  import {arrayCache, greenSlice, greenSplice, union} from './utils/array.js';
5
5
  import Data from './Data.js';
6
6
  import Entity from './Entity.js';
@@ -823,6 +823,110 @@ class Game extends Messenger {
823
823
  }
824
824
  return entities;
825
825
  }
826
+
827
+ /**
828
+ * Captures a screenshot of the currently visible game viewport (the canvas /
829
+ * camera view), not the full stage or world bounds.
830
+ *
831
+ * Uses the same crop approach as Paco's ScreenShooter: after camera
832
+ * transforms, the visible area is stage space (0, 0, screenWidth, screenHeight).
833
+ * Extracting only that frame avoids pulling in off-screen world content and
834
+ * avoids GPU texture-size failures when a full level's stage bounds are huge.
835
+ *
836
+ * @param {Object} [options]
837
+ * @param {string} [options.format='png'] Image format for data URLs (`png`, `jpg`/`jpeg`, `webp`).
838
+ * @param {number} [options.quality] Encoder quality for lossy formats (0–1).
839
+ * @param {boolean} [options.render=true] Render the stage before capturing.
840
+ * @param {string} [options.as='dataURL'] Return type: `dataURL` or `canvas`.
841
+ * @return {Promise<string|HTMLCanvasElement|null>} Screenshot, or null if unavailable.
842
+ **/
843
+ async captureViewport (options = {}) {
844
+ const
845
+ {
846
+ format = 'png',
847
+ quality,
848
+ render = true,
849
+ as = 'dataURL'
850
+ } = options,
851
+ {renderer, stage} = this;
852
+
853
+ if (!renderer || !stage) {
854
+ return null;
855
+ }
856
+
857
+ if (render) {
858
+ renderer.render(stage);
859
+ }
860
+
861
+ const
862
+ width = Math.max(1, renderer.screen.width | 0),
863
+ height = Math.max(1, renderer.screen.height | 0),
864
+ resolution = renderer.resolution || 1,
865
+ backgroundColor = this.options?.display?.backgroundColor,
866
+ hasBackground = typeof backgroundColor === 'number' && backgroundColor >= 0,
867
+ // Opaque clear — transparent extracts read as a black shot in Notefully.
868
+ clearColor = hasBackground ? backgroundColor : 0x000000,
869
+ mime = format === 'jpg' || format === 'jpeg'
870
+ ? 'image/jpeg'
871
+ : format === 'webp'
872
+ ? 'image/webp'
873
+ : 'image/png',
874
+ toOutput = (canvas) => {
875
+ if (as === 'canvas') {
876
+ return canvas;
877
+ }
878
+
879
+ return typeof quality === 'number'
880
+ ? canvas.toDataURL(mime, quality)
881
+ : canvas.toDataURL(mime);
882
+ };
883
+
884
+ try {
885
+ // Screen-sized framed extract (viewport only).
886
+ return toOutput(renderer.extract.canvas({
887
+ target: stage,
888
+ frame: new Rectangle(0, 0, width, height),
889
+ resolution,
890
+ clearColor
891
+ }));
892
+ } catch (err) {
893
+ platypus.debug.warn('Game.captureViewport framed extract failed; trying bounds crop.', err);
894
+ }
895
+
896
+ // Paco ScreenShooter fallback: full extract, then crop the screen origin.
897
+ try {
898
+ const
899
+ bounds = stage.getBounds(),
900
+ full = renderer.extract.canvas(stage),
901
+ dest = document.createElement('canvas'),
902
+ ctx = dest.getContext('2d');
903
+
904
+ dest.width = width;
905
+ dest.height = height;
906
+
907
+ if (hasBackground) {
908
+ ctx.fillStyle = `#${backgroundColor.toString(16).padStart(6, '0')}`;
909
+ ctx.fillRect(0, 0, width, height);
910
+ }
911
+
912
+ ctx.drawImage(
913
+ full,
914
+ -bounds.x,
915
+ -bounds.y,
916
+ width,
917
+ height,
918
+ 0,
919
+ 0,
920
+ width,
921
+ height
922
+ );
923
+
924
+ return toOutput(dest);
925
+ } catch (err) {
926
+ platypus.debug.warn('Game.captureViewport failed.', err);
927
+ return null;
928
+ }
929
+ }
826
930
 
827
931
  /**
828
932
  * This method destroys the game.