graphico 0.0.4 → 1.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.
package/README.md CHANGED
@@ -1,3 +1,14 @@
1
1
  ## Getting Started
2
2
 
3
- !!! THIS PACKAGE IS STILL UNDER DEVELOPMENT AND WILL BE UNSTABLE !!!
3
+ `graphico` is a package used for creating games, animations, and other visual projects. It simplifies canvas 2D rendering within the browser and provides the foundation for user interaction.
4
+
5
+ ## Features
6
+
7
+ - Simple, object-oriented canvas API for organized graphics programming
8
+ - Easy debugging and extensive configuration
9
+ - Supports multiple canvas layers with transparency
10
+ - Hardware-accelerated graphics and animation
11
+ - User interaction via keyboard or mouse inputs
12
+ - Built-in logic for screenshots and screen recordings
13
+
14
+ See the examples to learn how to use `graphico`!
package/dist/canvas.js CHANGED
@@ -13,9 +13,9 @@ var Canvas = /** @class */ (function () {
13
13
  if (options === void 0) { options = {}; }
14
14
  var _this = this;
15
15
  /**
16
- * Can be used to render 2D graphics onto the canvas
16
+ * Can be used to render 2D graphics onto layers of the canvas
17
17
  */
18
- this.graphics = [];
18
+ this.layers = [];
19
19
  /**
20
20
  * Contains a list of current keys pressed
21
21
  */
@@ -47,40 +47,45 @@ var Canvas = /** @class */ (function () {
47
47
  this.config = Canvas.setDefaults(options, Canvas.defaults);
48
48
  this.width = this.config.width;
49
49
  this.height = this.config.height;
50
- // Create the container <div> element and set properties
51
- var container = document.createElement('div');
52
- container.tabIndex = 1; // For element focus
53
- container.style.outline = 'none';
54
- container.style.width = "".concat(this.config.width * this.config.scale, "px");
55
- container.style.height = "".concat(this.config.height * this.config.scale, "px");
56
- container.style.border = "".concat(this.config.scale, "px solid ").concat(this.config.border);
57
- container.style.background = this.config.background;
58
- container.style.cursor = this.config.showMouse ? 'default' : 'none';
59
- container.style.position = 'relative';
60
- this.config.parent.appendChild(container);
50
+ // Create the main <canvas> element and set properties
51
+ var main = document.createElement('canvas');
52
+ main.tabIndex = 1; // For element focus
53
+ main.style.outline = 'none';
54
+ main.style.imageRendering = 'pixelated';
55
+ main.width = this.config.width;
56
+ main.height = this.config.height;
57
+ main.style.width = "".concat(this.config.width * this.config.scale, "px");
58
+ main.style.height = "".concat(this.config.height * this.config.scale, "px");
59
+ main.style.border = "".concat(this.config.scale, "px solid ").concat(this.config.border);
60
+ main.style.cursor = this.config.showMouse ? 'default' : 'none';
61
+ this.config.parent.appendChild(main);
62
+ // Create main canvas graphics object
63
+ var graphics = main.getContext('2d');
64
+ if (graphics) {
65
+ this.graphic = graphics;
66
+ }
67
+ else {
68
+ throw new Error('Could not initialize canvas graphics.');
69
+ }
70
+ graphics.imageSmoothingEnabled = false;
61
71
  // Create canvas layers
62
72
  for (var i = 0; i < this.config.numLayers; i++) {
63
73
  var canvas = document.createElement('canvas');
64
- var graphics = canvas.getContext('2d', { 'willReadFrequently': this.config.acceleration === 'software' });
65
- if (graphics) {
66
- this.graphics.push(graphics);
74
+ var layer = canvas.getContext('2d');
75
+ if (layer) {
76
+ this.layers.push(layer);
67
77
  }
68
78
  else {
69
79
  throw new Error('Could not initialize canvas graphics.');
70
80
  }
71
81
  // Set properties for canvas
72
82
  canvas.style.imageRendering = 'pixelated';
73
- canvas.style.boxSizing = 'border-box';
74
83
  canvas.width = this.config.width;
75
84
  canvas.height = this.config.height;
76
- canvas.style.width = '100%';
77
- canvas.style.height = '100%';
78
- canvas.style.position = 'absolute';
79
- graphics.imageSmoothingEnabled = false;
80
- container.appendChild(canvas);
85
+ layer.imageSmoothingEnabled = false;
81
86
  }
82
87
  // Event listeners
83
- container.addEventListener('mousemove', function (e) {
88
+ main.addEventListener('mousemove', function (e) {
84
89
  if (!_this.focused) {
85
90
  return;
86
91
  }
@@ -89,7 +94,7 @@ var Canvas = /** @class */ (function () {
89
94
  _this.log(e.type, _this.mouseX, _this.mouseY);
90
95
  _this.config.mousemove(_this.mouseX, _this.mouseY);
91
96
  });
92
- container.addEventListener('keydown', function (e) {
97
+ main.addEventListener('keydown', function (e) {
93
98
  if (!_this.focused) {
94
99
  return;
95
100
  }
@@ -101,7 +106,7 @@ var Canvas = /** @class */ (function () {
101
106
  _this.config.keydown(key);
102
107
  }
103
108
  });
104
- container.addEventListener('keyup', function (e) {
109
+ main.addEventListener('keyup', function (e) {
105
110
  if (!_this.focused) {
106
111
  return;
107
112
  }
@@ -113,7 +118,7 @@ var Canvas = /** @class */ (function () {
113
118
  _this.config.keyup(key);
114
119
  }
115
120
  });
116
- container.addEventListener('mousedown', function (e) {
121
+ main.addEventListener('mousedown', function (e) {
117
122
  if (!_this.focused) {
118
123
  return;
119
124
  }
@@ -124,7 +129,7 @@ var Canvas = /** @class */ (function () {
124
129
  _this.config.mousedown(button);
125
130
  }
126
131
  });
127
- container.addEventListener('mouseup', function (e) {
132
+ main.addEventListener('mouseup', function (e) {
128
133
  if (!_this.focused) {
129
134
  return;
130
135
  }
@@ -136,15 +141,15 @@ var Canvas = /** @class */ (function () {
136
141
  _this.config.mouseup(button);
137
142
  }
138
143
  });
139
- container.addEventListener('focusin', function (e) {
144
+ main.addEventListener('focusin', function (e) {
140
145
  _this.focused = true;
141
- container.style.borderColor = _this.config.border;
146
+ main.style.borderColor = _this.config.border;
142
147
  _this.log(e.type, _this.focused);
143
148
  _this.animation = requestAnimationFrame(function (time) { return _this.startAnimate(time); });
144
149
  });
145
- container.addEventListener('focusout', function (e) {
150
+ main.addEventListener('focusout', function (e) {
146
151
  _this.focused = false;
147
- container.style.borderColor = _this.config.borderBlur;
152
+ main.style.borderColor = _this.config.borderBlur;
148
153
  _this.log(e.type, _this.focused);
149
154
  cancelAnimationFrame(_this.animation);
150
155
  });
@@ -152,9 +157,30 @@ var Canvas = /** @class */ (function () {
152
157
  _this.log(e.type);
153
158
  cancelAnimationFrame(_this.animation);
154
159
  });
155
- container.addEventListener('contextmenu', function (e) { return e.preventDefault(); });
160
+ main.addEventListener('contextmenu', function (e) { return e.preventDefault(); });
156
161
  // Focus on the canvas
157
- container.focus();
162
+ main.focus();
163
+ // Initialize the media recorder
164
+ var recordPart = [];
165
+ this.recorder = new MediaRecorder(main.captureStream());
166
+ this.recorder.addEventListener('dataavailable', function (e) {
167
+ _this.log(e.type);
168
+ recordPart.push(e.data);
169
+ });
170
+ this.recorder.addEventListener('stop', function (e) {
171
+ _this.log(e.type);
172
+ var recording = new Blob(recordPart, { type: 'video/webm;codecs=h264' });
173
+ var url = URL.createObjectURL(recording);
174
+ var downloadLink = document.createElement('a');
175
+ downloadLink.setAttribute('href', url);
176
+ downloadLink.setAttribute('download', "recording-".concat(Date.now()));
177
+ downloadLink.click();
178
+ // Clear out the existing blob parts for recording a new capture
179
+ recordPart.splice(0);
180
+ // Remove all keys and mouse buttons down because we lose focus
181
+ _this.keys.splice(0);
182
+ _this.mouseButtons.splice(0);
183
+ });
158
184
  }
159
185
  /**
160
186
  * Start the animation.
@@ -170,15 +196,16 @@ var Canvas = /** @class */ (function () {
170
196
  */
171
197
  Canvas.prototype.animate = function (time) {
172
198
  var _this = this;
173
- var _a;
174
199
  var currentFrame = time;
175
200
  var dt = currentFrame - this.lastFrame;
176
201
  this.lastFrame = currentFrame;
177
- this.log('animate', dt, currentFrame);
178
- var drawables = (_a = this.config.loop(dt)) !== null && _a !== void 0 ? _a : [];
179
- for (var _i = 0, drawables_1 = drawables; _i < drawables_1.length; _i++) {
180
- var drawable = drawables_1[_i];
181
- this.draw(drawable);
202
+ this.config.loop(dt);
203
+ // Draw all the layers onto the main canvas
204
+ this.graphic.fillStyle = this.config.background;
205
+ this.graphic.fillRect(0, 0, this.width, this.height);
206
+ for (var _i = 0, _a = this.layers; _i < _a.length; _i++) {
207
+ var layer = _a[_i];
208
+ this.graphic.drawImage(layer.canvas, 0, 0);
182
209
  }
183
210
  this.animation = requestAnimationFrame(function (time) { return _this.animate(time); });
184
211
  };
@@ -205,59 +232,14 @@ var Canvas = /** @class */ (function () {
205
232
  Canvas.prototype.getMousePosition = function () {
206
233
  return [this.mouseX, this.mouseY];
207
234
  };
208
- /**
209
- * Get the color of the selected pixel.
210
- * @param x The pixel's x-coordinate
211
- * @param y The pixel's y-coordinate
212
- * @param layer The zero-indexed layer to get data from
213
- * @returns `[red, green, blue, alpha]`
214
- */
215
- Canvas.prototype.getPixel = function (x, y, layer) {
216
- if (layer === void 0) { layer = 0; }
217
- var data = this.graphics[layer].getImageData(x, y, 1, 1).data;
218
- this.log(this.graphics[layer].getImageData(x, y, 2, 2));
219
- ;
220
- return [data[0], data[1], data[2], data[3]];
221
- };
222
- /**
223
- * Set the color of the selected pixel.
224
- * @param x The pixel's x-coordinate
225
- * @param y The pixel's y-coordinate
226
- * @param color `[red, green, blue, alpha]`
227
- * @param layer The zero-indexed layer to set data to
228
- */
229
- Canvas.prototype.setPixel = function (x, y, color, layer) {
230
- if (layer === void 0) { layer = 0; }
231
- var data = this.graphics[layer].getImageData(x, y, 1, 1);
232
- data.data[0] = color[0];
233
- data.data[1] = color[1];
234
- data.data[2] = color[2];
235
- data.data[3] = color[3];
236
- this.log(data);
237
- this.graphics[layer].putImageData(data, x, y);
238
- };
239
235
  /**
240
236
  * Take a screenshot of the canvas contents and save to a .png file.
241
237
  * @param name The file name of the screenshot
242
238
  */
243
239
  Canvas.prototype.screenshot = function (name) {
244
240
  if (name === void 0) { name = 'screenshot'; }
245
- // Create an offscreen canvas
246
- var screen = new Canvas({
247
- parent: document.createElement('div'),
248
- height: this.config.height,
249
- width: this.config.width,
250
- scale: this.config.scale,
251
- });
252
- // Draw the background and each layer
253
- screen.graphics[0].fillStyle = this.config.background;
254
- screen.graphics[0].fillRect(0, 0, screen.width, screen.height);
255
- for (var _i = 0, _a = this.graphics; _i < _a.length; _i++) {
256
- var graphic = _a[_i];
257
- screen.graphics[0].drawImage(graphic.canvas, 0, 0);
258
- }
259
241
  // Generate a data URL and set it as the download parameter for <a>
260
- var dataURL = screen.graphics[0].canvas.toDataURL();
242
+ var dataURL = this.graphic.canvas.toDataURL();
261
243
  var downloadLink = document.createElement('a');
262
244
  downloadLink.setAttribute('href', dataURL);
263
245
  downloadLink.setAttribute('download', name);
@@ -266,6 +248,25 @@ var Canvas = /** @class */ (function () {
266
248
  this.keys.splice(0);
267
249
  this.mouseButtons.splice(0);
268
250
  };
251
+ /**
252
+ * Start recording all layers on the canvas
253
+ */
254
+ Canvas.prototype.startRecording = function () {
255
+ this.recorder.start();
256
+ };
257
+ /**
258
+ * Stop recording and download screen capture
259
+ */
260
+ Canvas.prototype.stopRecording = function () {
261
+ this.recorder.stop();
262
+ };
263
+ /**
264
+ * Determines whether the media recorder is active
265
+ * @returns `true` if currently recording
266
+ */
267
+ Canvas.prototype.isRecording = function () {
268
+ return this.recorder.state === 'recording';
269
+ };
269
270
  /**
270
271
  * Draw an object onto the canvas.
271
272
  * @param drawable Any drawable object
@@ -273,7 +274,7 @@ var Canvas = /** @class */ (function () {
273
274
  */
274
275
  Canvas.prototype.draw = function (drawable, layer) {
275
276
  if (layer === void 0) { layer = 0; }
276
- drawable.draw(this.graphics[layer]);
277
+ drawable.draw(this.layers[layer]);
277
278
  };
278
279
  /**
279
280
  * Completely clears the canvas.
@@ -282,13 +283,13 @@ var Canvas = /** @class */ (function () {
282
283
  Canvas.prototype.clear = function (layer) {
283
284
  if (layer === void 0) { layer = -1; }
284
285
  if (layer < 0) {
285
- for (var _i = 0, _a = this.graphics; _i < _a.length; _i++) {
286
- var graphic = _a[_i];
287
- graphic.clearRect(0, 0, this.config.width, this.config.height);
286
+ for (var _i = 0, _a = this.layers; _i < _a.length; _i++) {
287
+ var layer_1 = _a[_i];
288
+ layer_1.clearRect(0, 0, this.config.width, this.config.height);
288
289
  }
289
290
  }
290
291
  else {
291
- this.graphics[layer].clearRect(0, 0, this.config.width, this.config.height);
292
+ this.layers[layer].clearRect(0, 0, this.config.width, this.config.height);
292
293
  }
293
294
  };
294
295
  /**
@@ -324,12 +325,11 @@ var Canvas = /** @class */ (function () {
324
325
  width: 600,
325
326
  height: 400,
326
327
  scale: 1,
327
- background: 'transparent',
328
+ background: 'white',
328
329
  border: 'transparent',
329
330
  borderBlur: 'transparent',
330
331
  showMouse: true,
331
332
  numLayers: 1,
332
- acceleration: 'hardware',
333
333
  keydown: function () { return; },
334
334
  keyup: function () { return; },
335
335
  mousemove: function () { return; },
package/dist/index.js CHANGED
@@ -22,3 +22,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
22
22
  * ![NPM Last Update](https://img.shields.io/npm/last-update/graphico)
23
23
  */
24
24
  __exportStar(require("./canvas"), exports);
25
+ __exportStar(require("./types"), exports);
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphico",
3
- "version": "0.0.4",
3
+ "version": "1.0.0",
4
4
  "description": "Canvas 2D rendering toolkit for games and visual projects",
5
5
  "homepage": "https://npm.nicfv.com/",
6
6
  "bin": "",
package/types/canvas.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { Drawable, Options } from '.';
1
2
  /**
2
3
  * Represents a canvas for drawing and animating
3
4
  */
@@ -11,9 +12,13 @@ export declare class Canvas {
11
12
  */
12
13
  private readonly config;
13
14
  /**
14
- * Can be used to render 2D graphics onto the canvas
15
+ * Used to render 2D objects onto the main canvas
15
16
  */
16
- private readonly graphics;
17
+ private readonly graphic;
18
+ /**
19
+ * Can be used to render 2D graphics onto layers of the canvas
20
+ */
21
+ private readonly layers;
17
22
  /**
18
23
  * Contains a list of current keys pressed
19
24
  */
@@ -50,6 +55,10 @@ export declare class Canvas {
50
55
  * Determine whether the client is focused or not
51
56
  */
52
57
  private focused;
58
+ /**
59
+ * The media recording object for screen captures
60
+ */
61
+ private readonly recorder;
53
62
  /**
54
63
  * Create a new canvas with the provided options
55
64
  * @param options Configuration options
@@ -81,26 +90,23 @@ export declare class Canvas {
81
90
  */
82
91
  getMousePosition(): [number, number];
83
92
  /**
84
- * Get the color of the selected pixel.
85
- * @param x The pixel's x-coordinate
86
- * @param y The pixel's y-coordinate
87
- * @param layer The zero-indexed layer to get data from
88
- * @returns `[red, green, blue, alpha]`
93
+ * Take a screenshot of the canvas contents and save to a .png file.
94
+ * @param name The file name of the screenshot
95
+ */
96
+ screenshot(name?: string): void;
97
+ /**
98
+ * Start recording all layers on the canvas
89
99
  */
90
- getPixel(x: number, y: number, layer?: number): [number, number, number, number];
100
+ startRecording(): void;
91
101
  /**
92
- * Set the color of the selected pixel.
93
- * @param x The pixel's x-coordinate
94
- * @param y The pixel's y-coordinate
95
- * @param color `[red, green, blue, alpha]`
96
- * @param layer The zero-indexed layer to set data to
102
+ * Stop recording and download screen capture
97
103
  */
98
- setPixel(x: number, y: number, color: [number, number, number, number], layer?: number): void;
104
+ stopRecording(): void;
99
105
  /**
100
- * Take a screenshot of the canvas contents and save to a .png file.
101
- * @param name The file name of the screenshot
106
+ * Determines whether the media recorder is active
107
+ * @returns `true` if currently recording
102
108
  */
103
- screenshot(name?: string): void;
109
+ isRecording(): boolean;
104
110
  /**
105
111
  * Draw an object onto the canvas.
106
112
  * @param drawable Any drawable object
@@ -121,96 +127,3 @@ export declare class Canvas {
121
127
  */
122
128
  private static setDefaults;
123
129
  }
124
- /**
125
- * Configuration Options for Canvas
126
- */
127
- export interface Options {
128
- /**
129
- * Optionally print debug messages to the console
130
- */
131
- readonly debug: boolean;
132
- /**
133
- * Appends the canvas onto the parent element
134
- */
135
- readonly parent: Node;
136
- /**
137
- * The width of the drawing area, in pixels
138
- */
139
- readonly width: number;
140
- /**
141
- * The height of the drawing area, in pixels
142
- */
143
- readonly height: number;
144
- /**
145
- * The scale of the drawing area to the actual size of the canvas element
146
- */
147
- readonly scale: number;
148
- /**
149
- * The background color of the canvas
150
- */
151
- readonly background: string;
152
- /**
153
- * The border color for the canvas (when focused)
154
- */
155
- readonly border: string;
156
- /**
157
- * The border color for the canvas (when not focused)
158
- */
159
- readonly borderBlur: string;
160
- /**
161
- * Optionally show or hide the mouse when hovering over the canvas
162
- */
163
- readonly showMouse: boolean;
164
- /**
165
- * The number of layers in this canvas
166
- */
167
- readonly numLayers: number;
168
- /**
169
- * Uses hardware (GPU) or software (CPU) acceleration
170
- * - For pixel manipulation, software acceleration is recommended
171
- * - Otherwise, hardware acceleration is recommended (default)
172
- */
173
- readonly acceleration: 'hardware' | 'software';
174
- /**
175
- * Event listener for when a key is pressed
176
- * @param key The key that was pressed
177
- */
178
- readonly keydown: (key: string) => void;
179
- /**
180
- * Event listener for when a key is released
181
- * @param key The key that was released
182
- */
183
- readonly keyup: (key: string) => void;
184
- /**
185
- * Event listener for when the mouse is moved
186
- * @param x Cursor X-coordinate
187
- * @param y Cursor Y-coordinate
188
- */
189
- readonly mousemove: (x: number, y: number) => void;
190
- /**
191
- * Event listener for when a button on the mouse is pressed
192
- * @param button The button that was pressed
193
- */
194
- readonly mousedown: (button: number) => void;
195
- /**
196
- * Event listener for when a button on the mouse is released
197
- * @param button The button that was released
198
- */
199
- readonly mouseup: (button: number) => void;
200
- /**
201
- * Event listener for a the main animation loop
202
- * @param dt The number of milliseconds in between frames
203
- * @returns An array of `Drawable` to render on layer 0, or void
204
- */
205
- readonly loop: (dt: number) => Drawable[] | (void | never);
206
- }
207
- /**
208
- * Represents an object that can be drawn on the canvas.
209
- */
210
- export interface Drawable {
211
- /**
212
- * Draw this object onto the canvas.
213
- * @param graphics Canvas 2D rendering interface
214
- */
215
- draw(graphics: CanvasRenderingContext2D): void;
216
- }
package/types/index.d.ts CHANGED
@@ -6,3 +6,4 @@
6
6
  * ![NPM Last Update](https://img.shields.io/npm/last-update/graphico)
7
7
  */
8
8
  export * from './canvas';
9
+ export * from './types';
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Configuration Options for Canvas
3
+ */
4
+ export interface Options {
5
+ /**
6
+ * Optionally print debug messages to the console
7
+ */
8
+ readonly debug: boolean;
9
+ /**
10
+ * Appends the canvas onto the parent element
11
+ */
12
+ readonly parent: Node;
13
+ /**
14
+ * The width of the drawing area, in pixels
15
+ */
16
+ readonly width: number;
17
+ /**
18
+ * The height of the drawing area, in pixels
19
+ */
20
+ readonly height: number;
21
+ /**
22
+ * The scale of the drawing area to the actual size of the canvas element
23
+ */
24
+ readonly scale: number;
25
+ /**
26
+ * The background color of the canvas
27
+ */
28
+ readonly background: string;
29
+ /**
30
+ * The border color for the canvas (when focused)
31
+ */
32
+ readonly border: string;
33
+ /**
34
+ * The border color for the canvas (when not focused)
35
+ */
36
+ readonly borderBlur: string;
37
+ /**
38
+ * Optionally show or hide the mouse when hovering over the canvas
39
+ */
40
+ readonly showMouse: boolean;
41
+ /**
42
+ * The number of layers in this canvas
43
+ */
44
+ readonly numLayers: number;
45
+ /**
46
+ * Event listener for when a key is pressed
47
+ * @param key The key that was pressed
48
+ */
49
+ readonly keydown: (key: string) => void;
50
+ /**
51
+ * Event listener for when a key is released
52
+ * @param key The key that was released
53
+ */
54
+ readonly keyup: (key: string) => void;
55
+ /**
56
+ * Event listener for when the mouse is moved
57
+ * @param x Cursor X-coordinate
58
+ * @param y Cursor Y-coordinate
59
+ */
60
+ readonly mousemove: (x: number, y: number) => void;
61
+ /**
62
+ * Event listener for when a button on the mouse is pressed
63
+ * @param button The button that was pressed
64
+ */
65
+ readonly mousedown: (button: number) => void;
66
+ /**
67
+ * Event listener for when a button on the mouse is released
68
+ * @param button The button that was released
69
+ */
70
+ readonly mouseup: (button: number) => void;
71
+ /**
72
+ * Event listener for a the main animation loop
73
+ * @param dt The number of milliseconds in between frames
74
+ * @returns An array of `Drawable` to render on layer 0, or void
75
+ */
76
+ readonly loop: (dt: number) => void;
77
+ }
78
+ /**
79
+ * Represents an object that can be drawn on the canvas.
80
+ */
81
+ export interface Drawable {
82
+ /**
83
+ * Draw this object onto the canvas.
84
+ * @param graphics Canvas 2D rendering interface
85
+ */
86
+ draw(graphics: CanvasRenderingContext2D): void;
87
+ }