asciify-engine 1.0.35 → 1.0.37
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 +44 -288
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
- **Media → ASCII** — images, videos, and animated GIFs
|
|
17
17
|
- **13 art styles** — Standard, Blocks, Circles, Braille, Katakana, Dense, and more
|
|
18
18
|
- **4 color modes** — Grayscale, Full Color, Matrix, Accent
|
|
19
|
-
- **
|
|
19
|
+
- **14 animated backgrounds** — Wave, Rain, Stars, Pulse, Noise, Grid, Aurora, Silk, Void, Morph, Fire, DNA, Terrain, Circuit
|
|
20
20
|
- **Interactive hover effects** — Spotlight, Flashlight, Magnifier, Force Field, Neon, Fire, Ice, Gravity, Shatter, Ghost
|
|
21
21
|
- **Light & dark mode** — via `colorScheme: 'auto'` or explicit `light` / `dark`
|
|
22
22
|
- **Embed generation** — self-contained HTML output (static or animated)
|
|
@@ -28,8 +28,6 @@
|
|
|
28
28
|
npm install asciify-engine
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
> **90% of use cases need only two functions:** `asciify()` to convert images/video/GIFs to ASCII art, and `asciiBackground()` for animated backgrounds. Start there.
|
|
32
|
-
|
|
33
31
|
## Quick Start
|
|
34
32
|
|
|
35
33
|
### Image → ASCII
|
|
@@ -58,6 +56,25 @@ await asciify('photo.jpg', canvas, {
|
|
|
58
56
|
});
|
|
59
57
|
```
|
|
60
58
|
|
|
59
|
+
> **Canvas sizing:** Set `width` and `height` as HTML attributes on the `<canvas>` element — these control the pixel grid. CSS sizing alone (`style="width:100%"`) won't work (the canvas will be 0×0). Use `canvas.width = el.clientWidth` to fill a container.
|
|
60
|
+
|
|
61
|
+
### Webcam → ASCII
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { asciifyWebcam } from 'asciify-engine';
|
|
65
|
+
|
|
66
|
+
const canvas = document.querySelector('canvas')!;
|
|
67
|
+
|
|
68
|
+
// Requests camera access, starts a live rAF loop, returns stop()
|
|
69
|
+
const stop = await asciifyWebcam(canvas, {
|
|
70
|
+
artStyle: 'terminal',
|
|
71
|
+
mirror: true, // horizontal flip (selfie mode)
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Release camera + cancel loop
|
|
75
|
+
stop();
|
|
76
|
+
```
|
|
77
|
+
|
|
61
78
|
### GIF Animation
|
|
62
79
|
|
|
63
80
|
```ts
|
|
@@ -174,8 +191,8 @@ asciiBackground('#hero', { type: 'aurora', colorScheme: 'auto' });
|
|
|
174
191
|
asciiBackground('#hero', { type: 'wave', colorScheme: 'light' });
|
|
175
192
|
|
|
176
193
|
// Stop / clean up
|
|
177
|
-
const
|
|
178
|
-
|
|
194
|
+
const { destroy } = asciiBackground('#hero', { type: 'stars' });
|
|
195
|
+
destroy();
|
|
179
196
|
```
|
|
180
197
|
|
|
181
198
|
### Background Types
|
|
@@ -192,6 +209,10 @@ stop();
|
|
|
192
209
|
| `silk` | Silky fluid swirls following the cursor |
|
|
193
210
|
| `void` | Gravitational singularity — characters spiral inward toward cursor |
|
|
194
211
|
| `morph` | Characters morph between shapes driven by noise |
|
|
212
|
+
| `fire` | Upward-drifting flame columns with heat-gradient character mapping |
|
|
213
|
+
| `dna` | Rotating double-helix strands with base-pair characters |
|
|
214
|
+
| `terrain` | Procedural heightmap landscape with parallax depth layers |
|
|
215
|
+
| `circuit` | PCB trace network that pulses with traveling electric signals |
|
|
195
216
|
|
|
196
217
|
### `asciiBackground` Options
|
|
197
218
|
|
|
@@ -326,14 +347,15 @@ animId = requestAnimationFrame(tick);
|
|
|
326
347
|
|
|
327
348
|
| Function | Returns | Description |
|
|
328
349
|
|---|---|---|
|
|
329
|
-
| `asciify(source, canvas, opts?)` | `Promise<void>` |
|
|
350
|
+
| `asciify(source, canvas, opts?)` | `Promise<void>` | Render a **single** ASCII frame from an image (or URL). For animated loops use `asciifyGif` / `asciifyVideo` |
|
|
330
351
|
| `asciifyGif(source, canvas, opts?)` | `Promise<() => void>` | Fetch a GIF, convert, and start an animation loop — returns `stop()` |
|
|
331
352
|
| `asciifyVideo(source, canvas, opts?)` | `Promise<() => void>` | Convert a video and start an animation loop — returns `stop()` |
|
|
332
353
|
| `imageToAsciiFrame(source, options, w?, h?)` | `{ frame, cols, rows }` | Convert an image, video frame, or canvas to a raw ASCII frame |
|
|
333
354
|
| `renderFrameToCanvas(ctx, frame, options, w, h, time?, hoverPos?)` | `void` | Render a raw ASCII frame to a 2D canvas context |
|
|
334
355
|
| `gifToAsciiFrames(buffer, options, w, h, onProgress?)` | `{ frames, cols, rows, fps }` | Parse an animated GIF `ArrayBuffer` into ASCII frames |
|
|
335
356
|
| `videoToAsciiFrames(video, options, w, h, fps?, maxDuration?, onProgress?)` | `{ frames, cols, rows, fps }` | Extract and convert video frames to ASCII |
|
|
336
|
-
| `
|
|
357
|
+
| `asciifyWebcam(canvas, opts?)` | `Promise<() => void>` | Start a live webcam → ASCII loop; returns `stop()` to cancel and release the camera |
|
|
358
|
+
| `asciiBackground(target, options)` | `{ destroy: () => void }` | Mount a live animated ASCII background; call `destroy()` to stop and remove |
|
|
337
359
|
| `generateEmbedCode(frame, options)` | `string` | Self-contained static HTML embed |
|
|
338
360
|
| `generateAnimatedEmbedCode(frames, options, fps)` | `string` | Self-contained animated HTML embed |
|
|
339
361
|
|
|
@@ -366,289 +388,23 @@ Used by `asciify()`, `asciifyGif()`, and `asciifyVideo()`:
|
|
|
366
388
|
| `ditherStrength` | `number` | `0` | Floyd-Steinberg dither intensity (0–1) |
|
|
367
389
|
| `dotSizeRatio` | `number` | `0.8` | Dot size when `renderMode === 'dots'` (fraction of cell) |
|
|
368
390
|
|
|
369
|
-
###
|
|
370
|
-
|
|
371
|
-
| Option | Type | Default | Description |
|
|
372
|
-
|---|---|---|---|
|
|
373
|
-
| `type` | `string` | `'wave'` | Background renderer |
|
|
374
|
-
| `colorScheme` | `'auto' \| 'light' \| 'dark'` | `'dark'` | Theme; `'auto'` follows OS preference |
|
|
375
|
-
| `fontSize` | `number` | `13` | Character size |
|
|
376
|
-
| `speed` | `number` | `1` | Animation speed multiplier |
|
|
377
|
-
| `density` | `number` | `0.55` | Fraction of cells active (0–1) |
|
|
378
|
-
| `accentColor` | `string` | varies | Highlight / head colour |
|
|
379
|
-
|
|
380
|
-
## License
|
|
391
|
+
### Art Styles (`artStyle`)
|
|
381
392
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
---
|
|
385
|
-
|
|
386
|
-
<p align="left">
|
|
387
|
-
<a href="https://www.buymeacoffee.com/asciify">☕ Buy me a coffee — if this saved you time, I'd appreciate it!</a>
|
|
388
|
-
</p>
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
**[▶ Live Playground](https://asciify.org) · [npm](https://www.npmjs.com/package/asciify-engine) · [Support the project ☕](https://www.buymeacoffee.com/asciify)**
|
|
392
|
-
|
|
393
|
-
## Features
|
|
394
|
-
|
|
395
|
-
- **Media → ASCII** — images, videos, and animated GIFs
|
|
396
|
-
- **13 art styles** — Standard, Blocks, Circles, Braille, Katakana, Dense, and more
|
|
397
|
-
- **4 color modes** — Grayscale, Full Color, Matrix, Accent
|
|
398
|
-
- **10 animated backgrounds** — Wave, Rain, Stars, Pulse, Noise, Grid, Aurora, Silk, Void, Morph
|
|
399
|
-
- **Interactive hover effects** — Spotlight, Flashlight, Magnifier, Force Field, Neon, Fire, Ice, Gravity, Shatter, Ghost
|
|
400
|
-
- **Light & dark mode** — via `colorScheme: 'auto'` or explicit `light` / `dark`
|
|
401
|
-
- **Embed generation** — self-contained HTML output (static or animated)
|
|
402
|
-
- **Zero dependencies** — works with React, Vue, Angular, Svelte, Next.js, or vanilla JS
|
|
403
|
-
|
|
404
|
-
## Install
|
|
405
|
-
|
|
406
|
-
```bash
|
|
407
|
-
npm install asciify-engine
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
## Animated Backgrounds
|
|
411
|
-
|
|
412
|
-
Drop a live ASCII animation into any element with one call.
|
|
413
|
-
|
|
414
|
-
```ts
|
|
415
|
-
import { asciiBackground } from 'asciify-engine';
|
|
416
|
-
|
|
417
|
-
// Attach to any selector — animates the element's background
|
|
418
|
-
asciiBackground('#hero', { type: 'rain' });
|
|
419
|
-
|
|
420
|
-
// Follows OS dark/light mode automatically
|
|
421
|
-
asciiBackground('#hero', { type: 'aurora', colorScheme: 'auto' });
|
|
422
|
-
|
|
423
|
-
// Force light mode (dark characters on light background)
|
|
424
|
-
asciiBackground('#hero', { type: 'wave', colorScheme: 'light' });
|
|
425
|
-
|
|
426
|
-
// Stop / clean up
|
|
427
|
-
const stop = asciiBackground('#hero', { type: 'stars' });
|
|
428
|
-
stop();
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
### Background Types
|
|
432
|
-
|
|
433
|
-
| Type | Description |
|
|
434
|
-
|---|---|
|
|
435
|
-
| `wave` | Flowing sine-wave field with noise turbulence |
|
|
436
|
-
| `rain` | Matrix-style vertical column rain with glowing head and fading tail |
|
|
437
|
-
| `stars` | Parallax star field that reacts to cursor position |
|
|
438
|
-
| `pulse` | Concentric ripple bursts that emanate from the cursor |
|
|
439
|
-
| `noise` | Smooth value-noise field with organic flow |
|
|
440
|
-
| `grid` | Geometric grid that warps and glows at cursor proximity |
|
|
441
|
-
| `aurora` | Sweeping borealis-style colour bands |
|
|
442
|
-
| `silk` | Silky fluid swirls following the cursor |
|
|
443
|
-
| `void` | Gravitational singularity — characters spiral inward toward cursor |
|
|
444
|
-
| `morph` | Characters morph between shapes driven by noise |
|
|
445
|
-
|
|
446
|
-
### `asciiBackground` Options
|
|
447
|
-
|
|
448
|
-
| Option | Type | Default | Description |
|
|
449
|
-
|---|---|---|---|
|
|
450
|
-
| `type` | `string` | `'wave'` | Which background renderer to use |
|
|
451
|
-
| `colorScheme` | `'auto' \| 'light' \| 'dark'` | `'dark'` | `'auto'` follows OS theme live; `'light'` = dark chars on light bg |
|
|
452
|
-
| `fontSize` | `number` | `13` | Character size in px |
|
|
453
|
-
| `accentColor` | `string` | varies | Head/highlight colour (CSS colour string) |
|
|
454
|
-
| `color` | `string` | — | Override body character colour |
|
|
455
|
-
| `speed` | `number` | `1` | Global animation speed multiplier |
|
|
456
|
-
| `density` | `number` | `0.55` | Fraction of cells active (0–1) |
|
|
457
|
-
| `lightMode` | `boolean` | `false` | Dark characters on light background |
|
|
458
|
-
|
|
459
|
-
Each background type also accepts its own specific options — see the individual type exports (e.g. `RainBackgroundOptions`, `WaveBackgroundOptions`, etc.) for the full list.
|
|
460
|
-
|
|
461
|
-
### Low-level background renderers
|
|
462
|
-
|
|
463
|
-
All renderers are also exported individually for direct canvas use:
|
|
464
|
-
|
|
465
|
-
```ts
|
|
466
|
-
import {
|
|
467
|
-
renderRainBackground,
|
|
468
|
-
renderWaveBackground,
|
|
469
|
-
renderStarsBackground,
|
|
470
|
-
renderPulseBackground,
|
|
471
|
-
renderNoiseBackground,
|
|
472
|
-
renderGridBackground,
|
|
473
|
-
renderAuroraBackground,
|
|
474
|
-
renderSilkBackground,
|
|
475
|
-
renderVoidBackground,
|
|
476
|
-
renderMorphBackground,
|
|
477
|
-
} from 'asciify-engine';
|
|
478
|
-
|
|
479
|
-
// Example: drive the rain renderer yourself
|
|
480
|
-
const canvas = document.getElementById('canvas') as HTMLCanvasElement;
|
|
481
|
-
const ctx = canvas.getContext('2d')!;
|
|
482
|
-
let t = 0;
|
|
483
|
-
function tick() {
|
|
484
|
-
renderRainBackground(ctx, canvas.width, canvas.height, t, {
|
|
485
|
-
speed: 1.2,
|
|
486
|
-
density: 0.6,
|
|
487
|
-
accentColor: '#00ffcc',
|
|
488
|
-
lightMode: false,
|
|
489
|
-
});
|
|
490
|
-
t += 0.016;
|
|
491
|
-
requestAnimationFrame(tick);
|
|
492
|
-
}
|
|
493
|
-
tick();
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
## Quick Start
|
|
497
|
-
|
|
498
|
-
### Vanilla JS
|
|
499
|
-
|
|
500
|
-
```html
|
|
501
|
-
<canvas id="ascii" width="800" height="600"></canvas>
|
|
502
|
-
<script type="module">
|
|
503
|
-
import {
|
|
504
|
-
imageToAsciiFrame,
|
|
505
|
-
renderFrameToCanvas,
|
|
506
|
-
DEFAULT_OPTIONS,
|
|
507
|
-
} from 'asciify-engine';
|
|
508
|
-
|
|
509
|
-
const img = new Image();
|
|
510
|
-
img.crossOrigin = 'anonymous';
|
|
511
|
-
img.src = 'https://picsum.photos/600/400';
|
|
512
|
-
img.onload = () => {
|
|
513
|
-
const canvas = document.getElementById('ascii');
|
|
514
|
-
const options = { ...DEFAULT_OPTIONS, fontSize: 10 };
|
|
515
|
-
const { frame } = imageToAsciiFrame(img, options, canvas.width, canvas.height);
|
|
516
|
-
renderFrameToCanvas(canvas.getContext('2d'), frame, options, canvas.width, canvas.height);
|
|
517
|
-
};
|
|
518
|
-
</script>
|
|
519
|
-
```
|
|
520
|
-
|
|
521
|
-
### React
|
|
522
|
-
|
|
523
|
-
```tsx
|
|
524
|
-
import { useEffect, useRef } from 'react';
|
|
525
|
-
import {
|
|
526
|
-
imageToAsciiFrame,
|
|
527
|
-
renderFrameToCanvas,
|
|
528
|
-
DEFAULT_OPTIONS,
|
|
529
|
-
} from 'asciify-engine';
|
|
530
|
-
|
|
531
|
-
export function AsciiImage({ src }: { src: string }) {
|
|
532
|
-
const ref = useRef<HTMLCanvasElement>(null);
|
|
533
|
-
|
|
534
|
-
useEffect(() => {
|
|
535
|
-
const img = new Image();
|
|
536
|
-
img.crossOrigin = 'anonymous';
|
|
537
|
-
img.src = src;
|
|
538
|
-
img.onload = () => {
|
|
539
|
-
const canvas = ref.current!;
|
|
540
|
-
const opts = { ...DEFAULT_OPTIONS, fontSize: 10 };
|
|
541
|
-
const { frame } = imageToAsciiFrame(img, opts, canvas.width, canvas.height);
|
|
542
|
-
renderFrameToCanvas(canvas.getContext('2d')!, frame, opts, canvas.width, canvas.height);
|
|
543
|
-
};
|
|
544
|
-
}, [src]);
|
|
545
|
-
|
|
546
|
-
return <canvas ref={ref} width={800} height={600} />;
|
|
547
|
-
}
|
|
548
|
-
```
|
|
549
|
-
|
|
550
|
-
### Angular
|
|
551
|
-
|
|
552
|
-
```typescript
|
|
553
|
-
import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
|
|
554
|
-
import {
|
|
555
|
-
imageToAsciiFrame,
|
|
556
|
-
renderFrameToCanvas,
|
|
557
|
-
DEFAULT_OPTIONS,
|
|
558
|
-
} from 'asciify-engine';
|
|
559
|
-
|
|
560
|
-
@Component({
|
|
561
|
-
selector: 'app-ascii',
|
|
562
|
-
template: `<canvas #canvas [width]="800" [height]="600"></canvas>`,
|
|
563
|
-
})
|
|
564
|
-
export class AsciiComponent implements AfterViewInit {
|
|
565
|
-
@ViewChild('canvas') canvasRef!: ElementRef<HTMLCanvasElement>;
|
|
566
|
-
|
|
567
|
-
ngAfterViewInit() {
|
|
568
|
-
const img = new Image();
|
|
569
|
-
img.crossOrigin = 'anonymous';
|
|
570
|
-
img.src = 'https://picsum.photos/600/400';
|
|
571
|
-
img.onload = () => {
|
|
572
|
-
const canvas = this.canvasRef.nativeElement;
|
|
573
|
-
const opts = { ...DEFAULT_OPTIONS, fontSize: 10 };
|
|
574
|
-
const { frame } = imageToAsciiFrame(img, opts, canvas.width, canvas.height);
|
|
575
|
-
renderFrameToCanvas(canvas.getContext('2d')!, frame, opts, canvas.width, canvas.height);
|
|
576
|
-
};
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
```
|
|
580
|
-
|
|
581
|
-
### GIF Animation
|
|
582
|
-
|
|
583
|
-
```ts
|
|
584
|
-
import { gifToAsciiFrames, renderFrameToCanvas, DEFAULT_OPTIONS } from 'asciify-engine';
|
|
585
|
-
|
|
586
|
-
const response = await fetch('https://media.giphy.com/media/ENagATV1Gr9eg/giphy.gif');
|
|
587
|
-
const buffer = await response.arrayBuffer();
|
|
588
|
-
|
|
589
|
-
const canvas = document.getElementById('ascii') as HTMLCanvasElement;
|
|
590
|
-
const ctx = canvas.getContext('2d')!;
|
|
591
|
-
const options = { ...DEFAULT_OPTIONS, fontSize: 8 };
|
|
592
|
-
|
|
593
|
-
const { frames, fps } = await gifToAsciiFrames(buffer, options, canvas.width, canvas.height);
|
|
594
|
-
|
|
595
|
-
let i = 0;
|
|
596
|
-
setInterval(() => {
|
|
597
|
-
renderFrameToCanvas(ctx, frames[i], options, canvas.width, canvas.height);
|
|
598
|
-
i = (i + 1) % frames.length;
|
|
599
|
-
}, 1000 / fps);
|
|
600
|
-
```
|
|
601
|
-
|
|
602
|
-
### Video
|
|
603
|
-
|
|
604
|
-
```ts
|
|
605
|
-
import { videoToAsciiFrames, renderFrameToCanvas, DEFAULT_OPTIONS } from 'asciify-engine';
|
|
606
|
-
|
|
607
|
-
const video = document.createElement('video');
|
|
608
|
-
video.crossOrigin = 'anonymous';
|
|
609
|
-
video.src = '/my-video.mp4';
|
|
610
|
-
await new Promise((r) => (video.onloadeddata = r));
|
|
611
|
-
|
|
612
|
-
const canvas = document.getElementById('ascii') as HTMLCanvasElement;
|
|
613
|
-
const options = { ...DEFAULT_OPTIONS, fontSize: 8 };
|
|
614
|
-
|
|
615
|
-
const { frames, fps } = await videoToAsciiFrames(video, options, canvas.width, canvas.height, 12, 10);
|
|
616
|
-
|
|
617
|
-
let i = 0;
|
|
618
|
-
setInterval(() => {
|
|
619
|
-
renderFrameToCanvas(canvas.getContext('2d')!, frames[i], options, canvas.width, canvas.height);
|
|
620
|
-
i = (i + 1) % frames.length;
|
|
621
|
-
}, 1000 / fps);
|
|
622
|
-
```
|
|
623
|
-
|
|
624
|
-
## API Reference
|
|
625
|
-
|
|
626
|
-
### Core Functions
|
|
627
|
-
|
|
628
|
-
| Function | Returns | Description |
|
|
393
|
+
| Value | Color mode | Description |
|
|
629
394
|
|---|---|---|
|
|
630
|
-
| `
|
|
631
|
-
| `
|
|
632
|
-
| `
|
|
633
|
-
| `
|
|
634
|
-
| `
|
|
635
|
-
| `
|
|
636
|
-
| `
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
|
641
|
-
|
|
642
|
-
| `
|
|
643
|
-
| `colorMode` | `'grayscale' \| 'fullcolor' \| 'matrix' \| 'accent'` | `'grayscale'` | Color output mode |
|
|
644
|
-
| `renderMode` | `'ascii' \| 'dots'` | `'ascii'` | Render as characters or dot particles |
|
|
645
|
-
| `charset` | `string` | standard ramp | Custom character density ramp |
|
|
646
|
-
| `brightness` | `number` | `0` | Brightness adjustment (-1 → 1) |
|
|
647
|
-
| `contrast` | `number` | `1` | Contrast multiplier |
|
|
648
|
-
| `invert` | `boolean` | `false` | Invert luminance mapping |
|
|
649
|
-
| `hoverEffect` | `string` | `'none'` | Interactive effect name |
|
|
650
|
-
| `hoverStrength` | `number` | `0.8` | Effect intensity |
|
|
651
|
-
| `hoverRadius` | `number` | `0.3` | Effect radius (0–1 relative to canvas) |
|
|
395
|
+
| `classic` | Grayscale | Standard density ramp — clean, universally readable |
|
|
396
|
+
| `art` | Full color | 70-char dense ramp for maximum tonal detail |
|
|
397
|
+
| `particles` | Full color | Dot circles (`renderMode: 'dots'`) — great for photos |
|
|
398
|
+
| `letters` | Full color | Alphabet characters with pixel-accurate color |
|
|
399
|
+
| `terminal` | Matrix | Classic charset with green phosphor / Matrix look |
|
|
400
|
+
| `claudeCode` | Accent | Box-drawing chars with accent color — technical/hacker aesthetic |
|
|
401
|
+
| `braille` | Full color | 256-char braille block — ultra-dense, printed feel |
|
|
402
|
+
| `katakana` | Matrix | Half-width katakana — anime / cyberpunk aesthetic |
|
|
403
|
+
| `box` | Grayscale | Filled block elements `▪◾◼■█` |
|
|
404
|
+
| `lines` | Grayscale | Dash/em-dash ramp — minimalist typographic look |
|
|
405
|
+
| `circles` | Accent | Concentric circle chars with accent highlight |
|
|
406
|
+
| `musical` | Accent | Music notation ♩♪♫♬♭♮♯ — playful, low density |
|
|
407
|
+
| `emoji` | Full color | Block emoji mosaic — best at larger `fontSize` |
|
|
652
408
|
|
|
653
409
|
### Background Options
|
|
654
410
|
|
package/package.json
CHANGED