@stanko/kaplay-inspector 0.2.2 → 0.3.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.
|
@@ -4,6 +4,7 @@ import { GameObject } from "./game-object";
|
|
|
4
4
|
import { useObjectBoolean } from "./boolean-comp";
|
|
5
5
|
import { SearchResults } from "./search-results";
|
|
6
6
|
import { k } from "../k";
|
|
7
|
+
import { Recorder } from "./recorder";
|
|
7
8
|
const INTERVAL_OPTIONS = [
|
|
8
9
|
{ value: 100, label: "100ms" },
|
|
9
10
|
{ value: 250, label: "250ms" },
|
|
@@ -45,5 +46,5 @@ export const Inspector = ({ initUpdateTimeout = 250, isVisibleOnLoad = true, ini
|
|
|
45
46
|
if (!isVisible) {
|
|
46
47
|
return (_jsx("button", { class: "ki-btn k-inspector__show", onClick: toggleVisibility, children: "Show Inspector" }));
|
|
47
48
|
}
|
|
48
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { class: "k-inspector__header", children: [_jsx("button", { class: "ki-btn", onClick: () => paused.onChange(!paused.checked), children: paused.checked ? "Resume Game" : "Pause Game" }), "\u2022", _jsx("input", { placeholder: "Search tags or comps", type: "text", class: "ki-input", onInput: handleSearchInput }), "\u2022", _jsxs("div", { children: [k.get("*", { recursive: true }).length, " objects"] }), "\u2022", _jsxs("div", { children: [Math.round(k.debug.fps()), " fps"] }), "\u2022", _jsxs("div", { class: "k-inspector__interval", children: ["Update:", INTERVAL_OPTIONS.map((option) => (_jsxs("label", { children: [_jsx("input", { type: "radio", name: "interval", value: option.value, checked: updateTimeout === option.value, onChange: () => setUpdateTimeout(option.value) }), option.label] }, option.value)))] }), "\u2022", _jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: shouldDrawInspect, onChange: () => setShouldDrawInspect(!shouldDrawInspect) }), "Draw bbox on hover"] }), _jsx("button", { class: "ki-btn k-inspector__hide", onClick: toggleVisibility, children: "Hide" })] }), _jsx("div", { class: "k-inspector__objects", children: searchTerm.length > 0 ? (_jsx(SearchResults, { results: searchResults, setRenderRoot: setRoot, shouldDrawInspect: shouldDrawInspect })) : (_jsx(GameObject, { className: "game-object--root", obj: root, setRenderRoot: setRoot, shouldDrawInspect: shouldDrawInspect, isExpanded: true, isRenderRoot: true })) })] }));
|
|
49
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { class: "k-inspector__header", children: [_jsx("button", { class: "ki-btn", onClick: () => paused.onChange(!paused.checked), children: paused.checked ? "Resume Game" : "Pause Game" }), "\u2022", _jsx("input", { placeholder: "Search tags or comps", type: "text", class: "ki-input", onInput: handleSearchInput }), "\u2022", _jsxs("div", { children: [k.get("*", { recursive: true }).length, " objects"] }), "\u2022", _jsxs("div", { children: [Math.round(k.debug.fps()), " fps"] }), "\u2022", _jsxs("div", { class: "k-inspector__interval", children: ["Update:", INTERVAL_OPTIONS.map((option) => (_jsxs("label", { children: [_jsx("input", { type: "radio", name: "interval", value: option.value, checked: updateTimeout === option.value, onChange: () => setUpdateTimeout(option.value) }), option.label] }, option.value)))] }), "\u2022", _jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: shouldDrawInspect, onChange: () => setShouldDrawInspect(!shouldDrawInspect) }), "Draw bbox on hover"] }), "\u2022", _jsx(Recorder, {}), _jsx("button", { class: "ki-btn k-inspector__hide", onClick: toggleVisibility, children: "Hide" })] }), _jsx("div", { class: "k-inspector__objects", children: searchTerm.length > 0 ? (_jsx(SearchResults, { results: searchResults, setRenderRoot: setRoot, shouldDrawInspect: shouldDrawInspect })) : (_jsx(GameObject, { className: "game-object--root", obj: root, setRenderRoot: setRoot, shouldDrawInspect: shouldDrawInspect, isExpanded: true, isRenderRoot: true })) })] }));
|
|
49
50
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const Recorder: () => import("preact").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
+
import { useRef } from "preact/hooks";
|
|
3
|
+
import { recorder } from "../lib/video-recorder";
|
|
4
|
+
export const Recorder = () => {
|
|
5
|
+
const rec = useRef(null);
|
|
6
|
+
const start = () => {
|
|
7
|
+
rec.current = recorder();
|
|
8
|
+
rec.current.start();
|
|
9
|
+
};
|
|
10
|
+
const stop = () => {
|
|
11
|
+
if (rec.current) {
|
|
12
|
+
rec.current.stop();
|
|
13
|
+
rec.current = null;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
return (_jsx("button", { class: "ki-btn", onClick: () => {
|
|
17
|
+
if (rec.current) {
|
|
18
|
+
stop();
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
start();
|
|
22
|
+
}
|
|
23
|
+
}, children: rec.current ? "Stop" : "Record" }));
|
|
24
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const recorder: () => MediaRecorder;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { k } from "../k";
|
|
2
|
+
const mimeTypes = [
|
|
3
|
+
"video/webm; codecs=vp9,opus",
|
|
4
|
+
"video/webm; codecs=vp8,opus",
|
|
5
|
+
"video/webm",
|
|
6
|
+
];
|
|
7
|
+
const mimeType = mimeTypes.find(MediaRecorder.isTypeSupported);
|
|
8
|
+
// Constants I found on the web
|
|
9
|
+
// low 0.06,
|
|
10
|
+
// medium 0.10,
|
|
11
|
+
// high 0.16,
|
|
12
|
+
// veryHigh 0.24,
|
|
13
|
+
const BITS_PER_PIXEL_PER_FRAME = 0.16;
|
|
14
|
+
const FPS = 60;
|
|
15
|
+
const MAX_VIDEO_BITS_PER_SECOND = 40_000_000; // ~40 mbps
|
|
16
|
+
export const recorder = () => {
|
|
17
|
+
const canvasStream = k.canvas.captureStream(60);
|
|
18
|
+
const videoBitsPerSecond = Math.round(k.canvas.width * k.canvas.height * FPS * BITS_PER_PIXEL_PER_FRAME);
|
|
19
|
+
const audioDest = k.audioCtx.createMediaStreamDestination();
|
|
20
|
+
k._k.audio.masterNode.connect(audioDest);
|
|
21
|
+
const stream = new MediaStream([
|
|
22
|
+
...canvasStream.getVideoTracks(),
|
|
23
|
+
...audioDest.stream.getAudioTracks(),
|
|
24
|
+
]);
|
|
25
|
+
const recorder = new MediaRecorder(stream, {
|
|
26
|
+
mimeType,
|
|
27
|
+
videoBitsPerSecond: Math.min(MAX_VIDEO_BITS_PER_SECOND, videoBitsPerSecond),
|
|
28
|
+
});
|
|
29
|
+
const chunks = [];
|
|
30
|
+
recorder.ondataavailable = (e) => {
|
|
31
|
+
if (e.data.size) {
|
|
32
|
+
chunks.push(e.data);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
recorder.onstop = () => {
|
|
36
|
+
const blob = new Blob(chunks, { type: "video/webm" });
|
|
37
|
+
const a = document.createElement("a");
|
|
38
|
+
a.href = URL.createObjectURL(blob);
|
|
39
|
+
a.download = `${k.getSceneName()} (${new Date().toLocaleDateString("en-US")}).webm`;
|
|
40
|
+
a.click();
|
|
41
|
+
k._k.audio.masterNode.disconnect(audioDest);
|
|
42
|
+
canvasStream.getTracks().forEach((t) => t.stop());
|
|
43
|
+
};
|
|
44
|
+
return recorder;
|
|
45
|
+
};
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stanko/kaplay-inspector",
|
|
3
3
|
"description": "A dev tool for Kaplay which allows you to explore and inspect the game object tree real time.",
|
|
4
4
|
"private": false,
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.3.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/init.js",
|
|
8
8
|
"types": "./dist/init.d.ts",
|