graphico 1.0.0 → 1.1.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
@@ -4,11 +4,20 @@
4
4
 
5
5
  ## Features
6
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`!
7
+ `graphico` boasts several features that make it an extremely versatile package for several project types.
8
+
9
+ - Simple, **object-oriented canvas API** for organized graphics programming
10
+ - Easy debugging and extensive configuration for **complete customizability**
11
+ - Supports multiple independent **canvas layers** with transparency
12
+ - **Hardware-accelerated graphics** for fast and smooth animation
13
+ - **User interaction** captured via keyboard inputs or mouse movements or clicks
14
+ - Multiple audio tracks supported by system **audio player** with volume, mute, and loop toggle
15
+ - Built-in logic for **screenshots** and **screen recordings** that capture both video and audio
16
+
17
+ ## Caveats
18
+
19
+ By default, many browsers prevent autoplay, which arguably is a good thing. (Don't you hate it when you have several tabs open and one of them starts making noise?) This security feature blocks API calls to `Canvas.playAudio()` from being called automatically on page load. It needs to be triggered manually (initially) by some form of user interaction; either a key press or a mouse click. After this initial interaction step, calls to `playAudio()` can be performed automatically. If you wanted to have background music looping for a game, it would need to be triggered after pressing the "start" button, for example.
20
+
21
+ ## Learn More
22
+
23
+ The best way to learn and experience its features is to try it out yourself. See the examples to learn how to use `graphico`!
package/dist/canvas.js CHANGED
@@ -44,6 +44,18 @@ var Canvas = /** @class */ (function () {
44
44
  * Determine whether the client is focused or not
45
45
  */
46
46
  this.focused = false;
47
+ /**
48
+ * Determine whether the user has interacted with this canvas
49
+ */
50
+ this.interacted = false;
51
+ /**
52
+ * Determine whether audio is allowed or muted
53
+ */
54
+ this.muted = false;
55
+ /**
56
+ * Contains the list of all active audio elements
57
+ */
58
+ this.audios = [];
47
59
  this.config = Canvas.setDefaults(options, Canvas.defaults);
48
60
  this.width = this.config.width;
49
61
  this.height = this.config.height;
@@ -95,6 +107,8 @@ var Canvas = /** @class */ (function () {
95
107
  _this.config.mousemove(_this.mouseX, _this.mouseY);
96
108
  });
97
109
  main.addEventListener('keydown', function (e) {
110
+ audioContext.resume();
111
+ _this.interacted = true;
98
112
  if (!_this.focused) {
99
113
  return;
100
114
  }
@@ -119,6 +133,8 @@ var Canvas = /** @class */ (function () {
119
133
  }
120
134
  });
121
135
  main.addEventListener('mousedown', function (e) {
136
+ audioContext.resume();
137
+ _this.interacted = true;
122
138
  if (!_this.focused) {
123
139
  return;
124
140
  }
@@ -158,11 +174,25 @@ var Canvas = /** @class */ (function () {
158
174
  cancelAnimationFrame(_this.animation);
159
175
  });
160
176
  main.addEventListener('contextmenu', function (e) { return e.preventDefault(); });
161
- // Focus on the canvas
162
- main.focus();
177
+ // Initialize audio tracks for recording
178
+ var stream = new MediaStream(main.captureStream()); // video stream
179
+ var audioContext = new window.AudioContext();
180
+ for (var track = 0; track < this.config.numTracks; track++) {
181
+ var audio = new Audio();
182
+ var source = audioContext.createMediaElementSource(audio);
183
+ var destination = audioContext.createMediaStreamDestination();
184
+ source.connect(destination); // contains the audio stream for recording
185
+ source.connect(audioContext.destination); // so the user can hear
186
+ this.audios.push(audio);
187
+ for (var _i = 0, _a = destination.stream.getAudioTracks(); _i < _a.length; _i++) {
188
+ var audioTrack = _a[_i];
189
+ this.log("Adding ".concat(audioTrack.id, " to track ").concat(track, "."));
190
+ stream.addTrack(audioTrack); // add audio track
191
+ }
192
+ }
163
193
  // Initialize the media recorder
164
194
  var recordPart = [];
165
- this.recorder = new MediaRecorder(main.captureStream());
195
+ this.recorder = new MediaRecorder(stream);
166
196
  this.recorder.addEventListener('dataavailable', function (e) {
167
197
  _this.log(e.type);
168
198
  recordPart.push(e.data);
@@ -181,6 +211,8 @@ var Canvas = /** @class */ (function () {
181
211
  _this.keys.splice(0);
182
212
  _this.mouseButtons.splice(0);
183
213
  });
214
+ // Focus on the canvas
215
+ main.focus();
184
216
  }
185
217
  /**
186
218
  * Start the animation.
@@ -252,6 +284,9 @@ var Canvas = /** @class */ (function () {
252
284
  * Start recording all layers on the canvas
253
285
  */
254
286
  Canvas.prototype.startRecording = function () {
287
+ if (!this.interacted) {
288
+ throw new Error('The user has not yet interacted with this canvas.');
289
+ }
255
290
  this.recorder.start();
256
291
  };
257
292
  /**
@@ -262,11 +297,82 @@ var Canvas = /** @class */ (function () {
262
297
  };
263
298
  /**
264
299
  * Determines whether the media recorder is active
265
- * @returns `true` if currently recording
300
+ * @returns True if currently recording
266
301
  */
267
302
  Canvas.prototype.isRecording = function () {
268
303
  return this.recorder.state === 'recording';
269
304
  };
305
+ /**
306
+ * Play an audio file
307
+ * @param src The path of the audio file
308
+ * @param loop Whether to play the audio on loop
309
+ * @param volume The normalized [0-1] volume
310
+ * @param track The track number to play on
311
+ */
312
+ Canvas.prototype.playAudio = function (src, loop, volume, track) {
313
+ if (loop === void 0) { loop = false; }
314
+ if (volume === void 0) { volume = 1; }
315
+ if (track === void 0) { track = 0; }
316
+ this.log("Playing audio on track ".concat(track, "."));
317
+ if (!this.interacted) {
318
+ throw new Error('The user has not yet interacted with this canvas.');
319
+ }
320
+ if (track < 0 || track >= this.config.numTracks) {
321
+ throw new Error("Track ".concat(track, " is out of range. [0,").concat(this.config.numTracks, ")"));
322
+ }
323
+ var audio = this.audios[track];
324
+ audio.src = src;
325
+ audio.loop = loop;
326
+ audio.volume = volume;
327
+ audio.muted = this.muted;
328
+ audio.play();
329
+ };
330
+ /**
331
+ * Stop all audio tracks from playing
332
+ */
333
+ Canvas.prototype.stopAudio = function (track) {
334
+ if (track === void 0) { track = -1; }
335
+ this.log("Stopping audio on track ".concat(track, "."));
336
+ if (track >= this.config.numTracks) {
337
+ throw new Error("Track ".concat(track, " is out of range. [0,").concat(this.config.numTracks, ")"));
338
+ }
339
+ if (track < 0) {
340
+ for (var _i = 0, _a = this.audios; _i < _a.length; _i++) {
341
+ var audio = _a[_i];
342
+ audio.pause();
343
+ }
344
+ }
345
+ else {
346
+ this.audios[track].pause();
347
+ }
348
+ };
349
+ /**
350
+ * Mute all audio
351
+ */
352
+ Canvas.prototype.mute = function () {
353
+ this.muted = true;
354
+ for (var _i = 0, _a = this.audios; _i < _a.length; _i++) {
355
+ var audio = _a[_i];
356
+ audio.muted = this.muted;
357
+ }
358
+ };
359
+ /**
360
+ * Unmute all audio
361
+ */
362
+ Canvas.prototype.unmute = function () {
363
+ this.muted = false;
364
+ for (var _i = 0, _a = this.audios; _i < _a.length; _i++) {
365
+ var audio = _a[_i];
366
+ audio.muted = this.muted;
367
+ }
368
+ };
369
+ /**
370
+ * Determines whether audio is muted
371
+ * @returns True if currently muted
372
+ */
373
+ Canvas.prototype.isMuted = function () {
374
+ return this.muted;
375
+ };
270
376
  /**
271
377
  * Draw an object onto the canvas.
272
378
  * @param drawable Any drawable object
@@ -274,6 +380,9 @@ var Canvas = /** @class */ (function () {
274
380
  */
275
381
  Canvas.prototype.draw = function (drawable, layer) {
276
382
  if (layer === void 0) { layer = 0; }
383
+ if (layer < 0 || layer >= this.config.numLayers) {
384
+ throw new Error("Layer ".concat(layer, " is out of range. [0,").concat(this.config.numLayers, ")"));
385
+ }
277
386
  drawable.draw(this.layers[layer]);
278
387
  };
279
388
  /**
@@ -282,6 +391,9 @@ var Canvas = /** @class */ (function () {
282
391
  */
283
392
  Canvas.prototype.clear = function (layer) {
284
393
  if (layer === void 0) { layer = -1; }
394
+ if (layer >= this.config.numLayers) {
395
+ throw new Error("Layer ".concat(layer, " is out of range. [0,").concat(this.config.numLayers, ")"));
396
+ }
285
397
  if (layer < 0) {
286
398
  for (var _i = 0, _a = this.layers; _i < _a.length; _i++) {
287
399
  var layer_1 = _a[_i];
@@ -330,6 +442,7 @@ var Canvas = /** @class */ (function () {
330
442
  borderBlur: 'transparent',
331
443
  showMouse: true,
332
444
  numLayers: 1,
445
+ numTracks: 1,
333
446
  keydown: function () { return; },
334
447
  keyup: function () { return; },
335
448
  mousemove: function () { return; },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphico",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Canvas 2D rendering toolkit for games and visual projects",
5
5
  "homepage": "https://npm.nicfv.com/",
6
6
  "bin": "",
@@ -23,7 +23,12 @@
23
23
  "drawing",
24
24
  "art",
25
25
  "render",
26
- "2D"
26
+ "2D",
27
+ "layer",
28
+ "audio",
29
+ "track",
30
+ "animate",
31
+ "visual"
27
32
  ],
28
33
  "author": {
29
34
  "name": "Nicolas Ventura",
package/types/canvas.d.ts CHANGED
@@ -55,10 +55,22 @@ export declare class Canvas {
55
55
  * Determine whether the client is focused or not
56
56
  */
57
57
  private focused;
58
+ /**
59
+ * Determine whether the user has interacted with this canvas
60
+ */
61
+ private interacted;
58
62
  /**
59
63
  * The media recording object for screen captures
60
64
  */
61
65
  private readonly recorder;
66
+ /**
67
+ * Determine whether audio is allowed or muted
68
+ */
69
+ private muted;
70
+ /**
71
+ * Contains the list of all active audio elements
72
+ */
73
+ private readonly audios;
62
74
  /**
63
75
  * Create a new canvas with the provided options
64
76
  * @param options Configuration options
@@ -104,9 +116,34 @@ export declare class Canvas {
104
116
  stopRecording(): void;
105
117
  /**
106
118
  * Determines whether the media recorder is active
107
- * @returns `true` if currently recording
119
+ * @returns True if currently recording
108
120
  */
109
121
  isRecording(): boolean;
122
+ /**
123
+ * Play an audio file
124
+ * @param src The path of the audio file
125
+ * @param loop Whether to play the audio on loop
126
+ * @param volume The normalized [0-1] volume
127
+ * @param track The track number to play on
128
+ */
129
+ playAudio(src: string, loop?: boolean, volume?: number, track?: number): void;
130
+ /**
131
+ * Stop all audio tracks from playing
132
+ */
133
+ stopAudio(track?: number): void;
134
+ /**
135
+ * Mute all audio
136
+ */
137
+ mute(): void;
138
+ /**
139
+ * Unmute all audio
140
+ */
141
+ unmute(): void;
142
+ /**
143
+ * Determines whether audio is muted
144
+ * @returns True if currently muted
145
+ */
146
+ isMuted(): boolean;
110
147
  /**
111
148
  * Draw an object onto the canvas.
112
149
  * @param drawable Any drawable object
package/types/types.d.ts CHANGED
@@ -42,6 +42,10 @@ export interface Options {
42
42
  * The number of layers in this canvas
43
43
  */
44
44
  readonly numLayers: number;
45
+ /**
46
+ * The number of audio tracks
47
+ */
48
+ readonly numTracks: number;
45
49
  /**
46
50
  * Event listener for when a key is pressed
47
51
  * @param key The key that was pressed