@yassine-bouassida/scenecap 1.0.0 → 1.0.2
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 +4 -4
- package/dist/index.js +30 -25
- package/dist/index.mjs +30 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Describe what should happen in **plain English**, and Scenecap parses it, execut
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npm install scenecap
|
|
14
|
+
npm install @yassine-bouassida/scenecap
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
---
|
|
@@ -22,7 +22,7 @@ npm install scenecap
|
|
|
22
22
|
|
|
23
23
|
```tsx
|
|
24
24
|
'use client';
|
|
25
|
-
import { useScenecap } from 'scenecap';
|
|
25
|
+
import { useScenecap } from '@yassine-bouassida/scenecap';
|
|
26
26
|
|
|
27
27
|
export default function MyPage() {
|
|
28
28
|
const { containerRef, record, download, isRecording, progress } = useScenecap();
|
|
@@ -53,7 +53,7 @@ export default function MyPage() {
|
|
|
53
53
|
### Vanilla JS / Imperative
|
|
54
54
|
|
|
55
55
|
```ts
|
|
56
|
-
import { createScenecap } from 'scenecap';
|
|
56
|
+
import { createScenecap } from '@yassine-bouassida/scenecap';
|
|
57
57
|
|
|
58
58
|
const sc = createScenecap({ recording: { fps: 30 } });
|
|
59
59
|
const blob = await sc.record(`
|
|
@@ -70,7 +70,7 @@ a.click();
|
|
|
70
70
|
### Structured Scenario (skip NLP)
|
|
71
71
|
|
|
72
72
|
```ts
|
|
73
|
-
import { ScenarioRunner } from 'scenecap';
|
|
73
|
+
import { ScenarioRunner } from '@yassine-bouassida/scenecap';
|
|
74
74
|
|
|
75
75
|
const runner = new ScenarioRunner();
|
|
76
76
|
const blob = await runner.recordScenario({
|
package/dist/index.js
CHANGED
|
@@ -388,16 +388,20 @@ var VideoRecorder = class {
|
|
|
388
388
|
*/
|
|
389
389
|
async startFromElement(element) {
|
|
390
390
|
const canvas = document.createElement("canvas");
|
|
391
|
-
const dpr = this.options.devicePixelRatio;
|
|
391
|
+
const dpr = this.options.devicePixelRatio ?? 1;
|
|
392
392
|
canvas.width = this.options.width * dpr;
|
|
393
393
|
canvas.height = this.options.height * dpr;
|
|
394
|
-
await this.startFromCanvas(canvas);
|
|
395
394
|
const ctx = canvas.getContext("2d");
|
|
395
|
+
const bg = this.options.backgroundColor || "#ffffff";
|
|
396
|
+
ctx.fillStyle = bg;
|
|
397
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
398
|
+
await this.startFromCanvas(canvas);
|
|
396
399
|
this.captureInterval = window.setInterval(async () => {
|
|
400
|
+
ctx.fillStyle = bg;
|
|
401
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
397
402
|
try {
|
|
398
403
|
const data = await domToImage(element, this.options.width, this.options.height);
|
|
399
404
|
if (data) {
|
|
400
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
401
405
|
ctx.drawImage(data, 0, 0, canvas.width, canvas.height);
|
|
402
406
|
}
|
|
403
407
|
} catch {
|
|
@@ -449,18 +453,31 @@ var VideoRecorder = class {
|
|
|
449
453
|
}
|
|
450
454
|
};
|
|
451
455
|
async function domToImage(element, width, height) {
|
|
456
|
+
let cssText = "";
|
|
457
|
+
for (const sheet of Array.from(document.styleSheets)) {
|
|
458
|
+
try {
|
|
459
|
+
cssText += Array.from(sheet.cssRules).map((r) => r.cssText).join("\n");
|
|
460
|
+
} catch {
|
|
461
|
+
}
|
|
462
|
+
}
|
|
452
463
|
const clone = element.cloneNode(true);
|
|
453
|
-
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
${
|
|
460
|
-
</
|
|
461
|
-
</
|
|
462
|
-
|
|
464
|
+
const innerHtml = clone.outerHTML;
|
|
465
|
+
const xhtml = `
|
|
466
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
467
|
+
<head>
|
|
468
|
+
<style>
|
|
469
|
+
* { box-sizing: border-box; }
|
|
470
|
+
${cssText}
|
|
471
|
+
</style>
|
|
472
|
+
</head>
|
|
473
|
+
<body style="margin:0;padding:0;width:${width}px;height:${height}px;overflow:hidden;">
|
|
474
|
+
${innerHtml}
|
|
475
|
+
</body>
|
|
476
|
+
</html>
|
|
463
477
|
`;
|
|
478
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">
|
|
479
|
+
<foreignObject width="100%" height="100%">${xhtml}</foreignObject>
|
|
480
|
+
</svg>`;
|
|
464
481
|
const svgBlob = new Blob([svg], { type: "image/svg+xml;charset=utf-8" });
|
|
465
482
|
const url = URL.createObjectURL(svgBlob);
|
|
466
483
|
return new Promise((resolve) => {
|
|
@@ -476,18 +493,6 @@ async function domToImage(element, width, height) {
|
|
|
476
493
|
img.src = url;
|
|
477
494
|
});
|
|
478
495
|
}
|
|
479
|
-
function inlineStyles(source, target) {
|
|
480
|
-
const computed = window.getComputedStyle(source);
|
|
481
|
-
const inline = Array.from(computed).map((prop) => `${prop}:${computed.getPropertyValue(prop)}`).join(";");
|
|
482
|
-
target.setAttribute("style", inline);
|
|
483
|
-
const sourceChildren = source.children;
|
|
484
|
-
const targetChildren = target.children;
|
|
485
|
-
for (let i = 0; i < sourceChildren.length; i++) {
|
|
486
|
-
if (targetChildren[i]) {
|
|
487
|
-
inlineStyles(sourceChildren[i], targetChildren[i]);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
496
|
|
|
492
497
|
// src/core/zoom.ts
|
|
493
498
|
var ZoomController = class {
|
package/dist/index.mjs
CHANGED
|
@@ -350,16 +350,20 @@ var VideoRecorder = class {
|
|
|
350
350
|
*/
|
|
351
351
|
async startFromElement(element) {
|
|
352
352
|
const canvas = document.createElement("canvas");
|
|
353
|
-
const dpr = this.options.devicePixelRatio;
|
|
353
|
+
const dpr = this.options.devicePixelRatio ?? 1;
|
|
354
354
|
canvas.width = this.options.width * dpr;
|
|
355
355
|
canvas.height = this.options.height * dpr;
|
|
356
|
-
await this.startFromCanvas(canvas);
|
|
357
356
|
const ctx = canvas.getContext("2d");
|
|
357
|
+
const bg = this.options.backgroundColor || "#ffffff";
|
|
358
|
+
ctx.fillStyle = bg;
|
|
359
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
360
|
+
await this.startFromCanvas(canvas);
|
|
358
361
|
this.captureInterval = window.setInterval(async () => {
|
|
362
|
+
ctx.fillStyle = bg;
|
|
363
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
359
364
|
try {
|
|
360
365
|
const data = await domToImage(element, this.options.width, this.options.height);
|
|
361
366
|
if (data) {
|
|
362
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
363
367
|
ctx.drawImage(data, 0, 0, canvas.width, canvas.height);
|
|
364
368
|
}
|
|
365
369
|
} catch {
|
|
@@ -411,18 +415,31 @@ var VideoRecorder = class {
|
|
|
411
415
|
}
|
|
412
416
|
};
|
|
413
417
|
async function domToImage(element, width, height) {
|
|
418
|
+
let cssText = "";
|
|
419
|
+
for (const sheet of Array.from(document.styleSheets)) {
|
|
420
|
+
try {
|
|
421
|
+
cssText += Array.from(sheet.cssRules).map((r) => r.cssText).join("\n");
|
|
422
|
+
} catch {
|
|
423
|
+
}
|
|
424
|
+
}
|
|
414
425
|
const clone = element.cloneNode(true);
|
|
415
|
-
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
${
|
|
422
|
-
</
|
|
423
|
-
</
|
|
424
|
-
|
|
426
|
+
const innerHtml = clone.outerHTML;
|
|
427
|
+
const xhtml = `
|
|
428
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
429
|
+
<head>
|
|
430
|
+
<style>
|
|
431
|
+
* { box-sizing: border-box; }
|
|
432
|
+
${cssText}
|
|
433
|
+
</style>
|
|
434
|
+
</head>
|
|
435
|
+
<body style="margin:0;padding:0;width:${width}px;height:${height}px;overflow:hidden;">
|
|
436
|
+
${innerHtml}
|
|
437
|
+
</body>
|
|
438
|
+
</html>
|
|
425
439
|
`;
|
|
440
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">
|
|
441
|
+
<foreignObject width="100%" height="100%">${xhtml}</foreignObject>
|
|
442
|
+
</svg>`;
|
|
426
443
|
const svgBlob = new Blob([svg], { type: "image/svg+xml;charset=utf-8" });
|
|
427
444
|
const url = URL.createObjectURL(svgBlob);
|
|
428
445
|
return new Promise((resolve) => {
|
|
@@ -438,18 +455,6 @@ async function domToImage(element, width, height) {
|
|
|
438
455
|
img.src = url;
|
|
439
456
|
});
|
|
440
457
|
}
|
|
441
|
-
function inlineStyles(source, target) {
|
|
442
|
-
const computed = window.getComputedStyle(source);
|
|
443
|
-
const inline = Array.from(computed).map((prop) => `${prop}:${computed.getPropertyValue(prop)}`).join(";");
|
|
444
|
-
target.setAttribute("style", inline);
|
|
445
|
-
const sourceChildren = source.children;
|
|
446
|
-
const targetChildren = target.children;
|
|
447
|
-
for (let i = 0; i < sourceChildren.length; i++) {
|
|
448
|
-
if (targetChildren[i]) {
|
|
449
|
-
inlineStyles(sourceChildren[i], targetChildren[i]);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
458
|
|
|
454
459
|
// src/core/zoom.ts
|
|
455
460
|
var ZoomController = class {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yassine-bouassida/scenecap",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Scriptable screen recording with annotations, zoom effects, and highlights for Next.js — powered by natural language scenarios.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|