@stanko/kaplay-inspector 0.0.3 → 0.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 +54 -9
- package/dist/components/game-object.d.ts +5 -3
- package/dist/components/game-object.js +28 -12
- package/dist/components/inspector.d.ts +3 -4
- package/dist/components/inspector.js +10 -2
- package/dist/components/sprite.d.ts +6 -0
- package/dist/components/sprite.js +6 -0
- package/dist/init.d.ts +5 -3
- package/dist/init.js +2 -4
- package/dist/lib/draw-bbox.d.ts +3 -2
- package/dist/lib/draw-bbox.js +24 -21
- package/dist/lib/get-object-info.d.ts +1 -1
- package/dist/lib/inspect-comps.d.ts +1 -1
- package/dist/lib/inspect-comps.js +43 -40
- package/dist/styles.css +15 -1
- package/package.json +5 -5
- package/public/favicon/apple-touch-icon.png +0 -0
- package/public/favicon/favicon.ico +0 -0
- package/public/favicon/favicon.png +0 -0
- package/public/screenshot.png +0 -0
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@ A dev tool for [Kaplay](https://kaplayjs.com/) which allows you to explore and i
|
|
|
15
15
|
- Pause an object
|
|
16
16
|
- Dark theme (is this a feature?)
|
|
17
17
|
|
|
18
|
+
The layout is made with desktop in mind. That said, it is somewhat usable on phones.
|
|
19
|
+
|
|
18
20
|
## Usage
|
|
19
21
|
|
|
20
22
|
Install it:
|
|
@@ -64,22 +66,65 @@ available options are:
|
|
|
64
66
|
|
|
65
67
|
```ts
|
|
66
68
|
interface InspectorOptions {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
// CSS class to add to the root element
|
|
70
|
+
className?: string;
|
|
71
|
+
// is inspector visible on load, default: true
|
|
72
|
+
isVisible?: boolean;
|
|
73
|
+
// default update time in milliseconds, default: 250
|
|
74
|
+
initUpdateTimeout?: number;
|
|
75
|
+
// should area, anchor and bounding box be drawn on object hover, default: true
|
|
76
|
+
shouldDrawInspect?: boolean:
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Customizing colors
|
|
81
|
+
|
|
82
|
+
Kaplay Inspector defines colors in [OKLCH color space](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/oklch). This makes changing of the primary and the secondary color pretty straight forward. You only need to update two hue variables like this:
|
|
83
|
+
|
|
84
|
+
```css
|
|
85
|
+
.k-inspector.your-custom-class {
|
|
86
|
+
--ki-h: 300; /* Purple */
|
|
87
|
+
--ki-h-secondary: 200; /* Teal */
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Please note that if you load inspector's CSS dynamically, you'll have to add a custom class to create a higher specificity selector.
|
|
92
|
+
|
|
93
|
+
If you want to change other colors as well, check the [styles.css](./src/styles/styles.css).
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
## Positioning
|
|
97
|
+
|
|
98
|
+
By default, the inspector has `position: fixed` and it sits at the bottom of the screen. If you want to move it around, the easiest way it to pass a custom class name through the options and position it yourself.
|
|
99
|
+
|
|
100
|
+
Assuming we have only the canvas and the inspector element on the page, here is an example of what I like to do:
|
|
101
|
+
|
|
102
|
+
```css
|
|
103
|
+
body:has(.k-inspector__hide) {
|
|
104
|
+
display: grid;
|
|
105
|
+
grid-template-rows: 60vh 40vh;
|
|
106
|
+
|
|
107
|
+
canvas {
|
|
108
|
+
width: 100% !important;
|
|
109
|
+
height: 60vh !important;
|
|
110
|
+
object-fit: contain;
|
|
111
|
+
display: block;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.k-inspector {
|
|
115
|
+
position: relative;
|
|
116
|
+
}
|
|
70
117
|
}
|
|
71
118
|
```
|
|
72
119
|
|
|
120
|
+
This fixed the game canvas in the upper part of the viewport (60% of it) and the bottom part is taken by the inspector. It only applies this layout when inspector is visible (by checking if the hide button is shown).
|
|
121
|
+
|
|
122
|
+
Same as with colors, be sure to have a higher specificity selector if inspector's CSS is loaded dynamically.
|
|
73
123
|
|
|
74
124
|
## TODO
|
|
75
125
|
|
|
76
|
-
* [ ] Bounding box - handle a case when anchor is a `Vec2`
|
|
77
126
|
* [ ] Controllable theme - system/light/dark. At the moment it is always matching the system.
|
|
78
127
|
* [ ] Filter/search
|
|
79
128
|
* [ ] Persist search in URL or local storage
|
|
80
|
-
* [ ] Figure out why child bounding box are drawn in the wrong position
|
|
81
|
-
* [ ] Add documentation about positioning the inspector
|
|
82
129
|
* [ ] Collapse/Expand all button
|
|
83
|
-
* [
|
|
84
|
-
* [x] Show/Hide button
|
|
85
|
-
* [x] Build and deploy simple demo
|
|
130
|
+
* [ ] Clean up `inspect-comps.tsx`
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import type { GameObj
|
|
1
|
+
import type { GameObj } from "kaplay";
|
|
2
|
+
import type { KAPLAYCtxType } from "../init";
|
|
2
3
|
export interface GameObjectProps {
|
|
3
4
|
className?: string;
|
|
4
5
|
obj: GameObj;
|
|
5
6
|
setRenderRoot: (obj: GameObj) => void;
|
|
6
7
|
isExpanded?: boolean;
|
|
7
8
|
isRenderRoot?: boolean;
|
|
8
|
-
|
|
9
|
+
shouldDrawInspect: boolean;
|
|
10
|
+
k: KAPLAYCtxType;
|
|
9
11
|
}
|
|
10
|
-
export declare const GameObject: ({ obj, className, isExpanded: isExpandedExternal, isRenderRoot, setRenderRoot, k, }: GameObjectProps) => import("preact").JSX.Element;
|
|
12
|
+
export declare const GameObject: ({ obj, className, isExpanded: isExpandedExternal, isRenderRoot, setRenderRoot, shouldDrawInspect, k, }: GameObjectProps) => import("preact").JSX.Element;
|
|
@@ -1,42 +1,58 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
-
import { useEffect, useRef, useState } from "preact/hooks";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "preact/hooks";
|
|
3
3
|
import { MinusIcon, PlusIcon } from "../components/icons";
|
|
4
4
|
import { cx } from "../lib/cx";
|
|
5
5
|
import { drawBoundingBox } from "../lib/draw-bbox";
|
|
6
6
|
import { getObjectInfo } from "../lib/get-object-info";
|
|
7
7
|
import { Breadcrumbs } from "./breadcrumbs";
|
|
8
|
-
export const GameObject = ({ obj, className = "", isExpanded: isExpandedExternal = false, isRenderRoot, setRenderRoot, k, }) => {
|
|
8
|
+
export const GameObject = ({ obj, className = "", isExpanded: isExpandedExternal = false, isRenderRoot, setRenderRoot, shouldDrawInspect, k, }) => {
|
|
9
9
|
const [isExpanded, setIsExpanded] = useState(isExpandedExternal);
|
|
10
|
-
const
|
|
10
|
+
const updateControllers = useRef([]);
|
|
11
11
|
const { compsData, tags, compsLabel } = getObjectInfo(obj);
|
|
12
12
|
const isRootObject = obj.id === 0;
|
|
13
13
|
const isObjectDestroyed = !obj.exists() && !isRootObject;
|
|
14
14
|
const showExpandTree = obj.children.length > 0;
|
|
15
15
|
const hasChildren = obj.children.length > 0;
|
|
16
16
|
const isInspecting = isRenderRoot && obj.id !== 0;
|
|
17
|
+
const cancelUpdateControllers = useCallback(() => {
|
|
18
|
+
updateControllers.current.forEach((controller) => controller.cancel());
|
|
19
|
+
updateControllers.current = [];
|
|
20
|
+
}, []);
|
|
21
|
+
const drawInspect = useCallback((obj, isChild = false) => {
|
|
22
|
+
if (!obj.hidden) {
|
|
23
|
+
const updateController = obj.onDraw(() => {
|
|
24
|
+
// Kaplay calls drawInspect on all of the children, no need to call it again
|
|
25
|
+
if (!isChild) {
|
|
26
|
+
obj.drawInspect();
|
|
27
|
+
}
|
|
28
|
+
drawBoundingBox(obj, k);
|
|
29
|
+
});
|
|
30
|
+
updateControllers.current.push(updateController);
|
|
31
|
+
obj.children.forEach((child) => {
|
|
32
|
+
drawInspect(child, true);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}, []);
|
|
17
36
|
useEffect(() => {
|
|
18
37
|
return () => {
|
|
19
|
-
|
|
38
|
+
cancelUpdateControllers();
|
|
20
39
|
};
|
|
21
40
|
}, []);
|
|
22
41
|
const handleToggleClick = () => {
|
|
23
42
|
setIsExpanded(!isExpanded);
|
|
24
43
|
};
|
|
25
44
|
const handleMouseEnter = () => {
|
|
26
|
-
|
|
27
|
-
if (!
|
|
28
|
-
|
|
29
|
-
obj.drawInspect();
|
|
30
|
-
drawBoundingBox(obj, k);
|
|
31
|
-
});
|
|
45
|
+
cancelUpdateControllers();
|
|
46
|
+
if (!isRootObject && shouldDrawInspect) {
|
|
47
|
+
drawInspect(obj);
|
|
32
48
|
}
|
|
33
49
|
};
|
|
34
50
|
const handleMouseLeave = () => {
|
|
35
|
-
|
|
51
|
+
cancelUpdateControllers();
|
|
36
52
|
};
|
|
37
53
|
return (_jsxs("div", { class: cx("game-object", className, {
|
|
38
54
|
"game-object--no-children": !hasChildren,
|
|
39
55
|
}), children: [isInspecting && _jsx(Breadcrumbs, { setRenderRoot: setRenderRoot, obj: obj }), _jsxs("div", { class: "game-object__content", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [_jsxs("button", { class: cx("game-object__header", {
|
|
40
56
|
"game-object__header--expandable": showExpandTree,
|
|
41
|
-
}), onClick: handleToggleClick, children: [_jsx("span", { class: "game-object__expand-icon", children: isExpanded ? _jsx(MinusIcon, {}) : _jsx(PlusIcon, {}) }), _jsxs("div", { class: "game-object__id", children: ["ID ", obj.id, ":"] }), tags ? (_jsx("div", { class: "game-object__tags", children: isRootObject ? "Root" : tags })) : (_jsx("div", { class: "game-object__comp-names", children: compsLabel })), obj.children.length > 0 && _jsxs("div", { children: ["(", obj.children.length, ")"] }), isObjectDestroyed && (_jsx("div", { class: "game-object__destroyed", children: "DESTROYED" }))] }), _jsxs("div", { class: "game-object__buttons", children: [!isRenderRoot && (_jsx("button", { class: "ki-btn", onClick: () => setRenderRoot(obj), children: "inspect" })), _jsx("button", { class: "ki-btn ", onClick: () => console.log(obj), children: "log" })] }), isExpanded && (_jsx("div", { class: "game-object__comps-wrapper", children: _jsxs("div", { class: "game-object__comps", children: [_jsxs("div", { class: "game-object__comps-row", children: [_jsx("label", { for: `paused-${obj.id}`, children: _jsx("b", { children: "paused" }) }), _jsx("div", { children: _jsx("input", { id: `paused-${obj.id}`, type: "checkbox", defaultChecked: obj.paused, onChange: () => (obj.paused = !obj.paused) }) })] }), compsData.map((comp) => (_jsxs("div", { class: "game-object__comps-row", children: [_jsx("div", { children: _jsx("b", { children: comp.tag }) }), _jsx("div", { children: comp.value })] }, comp.tag)))] }) }))] }), isExpanded && hasChildren && (_jsx("div", { class: "game-object__children", style: { display: isExpanded ? "block" : "none" }, children: obj.children.map((child) => (_jsx(GameObject, { k: k, obj: child, setRenderRoot: setRenderRoot }, child.id))) }))] }, obj.id));
|
|
57
|
+
}), onClick: handleToggleClick, children: [_jsx("span", { class: "game-object__expand-icon", children: isExpanded ? _jsx(MinusIcon, {}) : _jsx(PlusIcon, {}) }), _jsxs("div", { class: "game-object__id", children: ["ID ", obj.id, ":"] }), tags ? (_jsx("div", { class: "game-object__tags", children: isRootObject ? "Root" : tags })) : (_jsx("div", { class: "game-object__comp-names", children: compsLabel })), obj.children.length > 0 && _jsxs("div", { children: ["(", obj.children.length, ")"] }), isObjectDestroyed && (_jsx("div", { class: "game-object__destroyed", children: "DESTROYED" }))] }), _jsxs("div", { class: "game-object__buttons", children: [!isRenderRoot && (_jsx("button", { class: "ki-btn", onClick: () => setRenderRoot(obj), children: "inspect" })), _jsx("button", { class: "ki-btn ", onClick: () => console.log(obj), children: "log" })] }), isExpanded && (_jsx("div", { class: "game-object__comps-wrapper", children: _jsxs("div", { class: "game-object__comps", children: [_jsxs("div", { class: "game-object__comps-row", children: [_jsx("label", { for: `paused-${obj.id}`, children: _jsx("b", { children: "paused" }) }), _jsx("div", { children: _jsx("input", { id: `paused-${obj.id}`, type: "checkbox", defaultChecked: obj.paused, onChange: () => (obj.paused = !obj.paused) }) })] }), _jsxs("div", { class: "game-object__comps-row", children: [_jsx("label", { for: `hidden-${obj.id}`, children: _jsx("b", { children: "hidden" }) }), _jsx("div", { children: _jsx("input", { id: `hidden-${obj.id}`, type: "checkbox", defaultChecked: obj.hidden, onChange: () => (obj.hidden = !obj.hidden) }) })] }), compsData.map((comp) => (_jsxs("div", { class: "game-object__comps-row", children: [_jsx("div", { children: _jsx("b", { children: comp.tag }) }), _jsx("div", { children: comp.value })] }, comp.tag)))] }) }))] }), isExpanded && hasChildren && (_jsx("div", { class: "game-object__children", style: { display: isExpanded ? "block" : "none" }, children: obj.children.map((child) => (_jsx(GameObject, { k: k, obj: child, setRenderRoot: setRenderRoot, shouldDrawInspect: shouldDrawInspect }, child.id))) }))] }, obj.id));
|
|
42
58
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { InspectorOptions } from "../init";
|
|
1
|
+
import type { InspectorOptions, KAPLAYCtxType } from "../init";
|
|
3
2
|
export interface InspectorProps extends InspectorOptions {
|
|
4
|
-
k:
|
|
3
|
+
k: KAPLAYCtxType;
|
|
5
4
|
}
|
|
6
|
-
export declare const Inspector: ({
|
|
5
|
+
export declare const Inspector: ({ initUpdateTimeout, isVisibleOnLoad, initDrawInspectOnHover, k, }: InspectorProps) => import("preact").JSX.Element;
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from "preact/hooks";
|
|
3
3
|
import { GameObject } from "./game-object";
|
|
4
|
-
|
|
4
|
+
const INTERVAL_OPTIONS = [
|
|
5
|
+
{ value: 100, label: "100ms" },
|
|
6
|
+
{ value: 250, label: "250ms" },
|
|
7
|
+
{ value: 500, label: "500ms" },
|
|
8
|
+
{ value: 1000, label: "1s" },
|
|
9
|
+
];
|
|
10
|
+
export const Inspector = ({ initUpdateTimeout = 250, isVisibleOnLoad = true, initDrawInspectOnHover = true, k, }) => {
|
|
11
|
+
const [updateTimeout, setUpdateTimeout] = useState(initUpdateTimeout);
|
|
12
|
+
const [shouldDrawInspect, setShouldDrawInspect] = useState(initDrawInspectOnHover);
|
|
5
13
|
const [root, setRoot] = useState(k.getTreeRoot());
|
|
6
14
|
const [renderIndex, setRenderIndex] = useState(0);
|
|
7
15
|
const [isVisible, setIsVisible] = useState(isVisibleOnLoad);
|
|
@@ -22,5 +30,5 @@ export const Inspector = ({ updateTimeout = 250, isVisibleOnLoad = true, k, }) =
|
|
|
22
30
|
if (!isVisible) {
|
|
23
31
|
return (_jsx("button", { class: "ki-btn k-inspector__show", onClick: toggleVisibility, children: "Show Inspector" }));
|
|
24
32
|
}
|
|
25
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { class: "k-inspector__header", children: [_jsx("button", { class: "ki-btn", onClick: handlePauseClick, children: "Pause/Resume" }), "\u2022", _jsxs("div", { children: [k.get("*", { recursive: true }).length, " objects"] }), "\u2022", _jsxs("div", { children: [Math.round(k.debug.fps()), " fps"] }), _jsx("button", { class: "ki-btn k-inspector__hide", onClick: toggleVisibility, children: "Hide" })] }), _jsx("div", { class: "k-inspector__objects", children: _jsx(GameObject, { k: k, className: "game-object--root", obj: root, setRenderRoot: setRoot, isExpanded: true, isRenderRoot: true }) })] }));
|
|
33
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { class: "k-inspector__header", children: [_jsx("button", { class: "ki-btn", onClick: handlePauseClick, children: "Pause/Resume" }), "\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: _jsx(GameObject, { k: k, className: "game-object--root", obj: root, setRenderRoot: setRoot, shouldDrawInspect: shouldDrawInspect, isExpanded: true, isRenderRoot: true }) })] }));
|
|
26
34
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
|
|
2
|
+
export const Sprite = ({ obj }) => {
|
|
3
|
+
const object = obj;
|
|
4
|
+
const animation = object.getCurAnim();
|
|
5
|
+
return (_jsxs("div", { class: "sprite", children: [_jsx("b", { children: object.sprite }), _jsxs("div", { children: ["frame: ", object.frame] }), animation && (_jsxs(_Fragment, { children: [_jsxs("div", { children: ["animation: ", animation.name] }), _jsxs("div", { children: ["animation frame: ", animation?.frameIndex] })] }))] }));
|
|
6
|
+
};
|
package/dist/init.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import kaplay from "kaplay";
|
|
2
|
+
export type KAPLAYCtxType = ReturnType<typeof kaplay>;
|
|
2
3
|
export interface InspectorOptions {
|
|
3
|
-
|
|
4
|
+
initUpdateTimeout?: number;
|
|
5
|
+
initDrawInspectOnHover?: boolean;
|
|
4
6
|
isVisibleOnLoad?: boolean;
|
|
5
7
|
className?: string;
|
|
6
8
|
}
|
|
7
|
-
export default function init(k:
|
|
9
|
+
export default function init(k: KAPLAYCtxType, props?: InspectorOptions): void;
|
package/dist/init.js
CHANGED
|
@@ -2,11 +2,9 @@ import { jsx as _jsx } from "preact/jsx-runtime";
|
|
|
2
2
|
import { render } from "preact";
|
|
3
3
|
import { Inspector } from "./components/inspector";
|
|
4
4
|
export default function init(k, props = {}) {
|
|
5
|
-
const {
|
|
6
|
-
//
|
|
7
|
-
className = "", updateTimeout = 100, isVisibleOnLoad = true, } = props;
|
|
5
|
+
const { className = "", initUpdateTimeout = 250, isVisibleOnLoad = true, initDrawInspectOnHover = true, } = props;
|
|
8
6
|
const appElement = document.createElement("div");
|
|
9
7
|
appElement.className = `k-inspector ${className}`;
|
|
10
8
|
document.body.appendChild(appElement);
|
|
11
|
-
render(_jsx(Inspector, { k: k,
|
|
9
|
+
render(_jsx(Inspector, { k: k, initUpdateTimeout: initUpdateTimeout, isVisibleOnLoad: isVisibleOnLoad, initDrawInspectOnHover: initDrawInspectOnHover }), appElement);
|
|
12
10
|
}
|
package/dist/lib/draw-bbox.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import type { GameObj
|
|
2
|
-
|
|
1
|
+
import type { GameObj } from "kaplay";
|
|
2
|
+
import type { KAPLAYCtxType } from "../init";
|
|
3
|
+
export declare const drawBoundingBox: (obj: GameObj, k: KAPLAYCtxType) => void;
|
package/dist/lib/draw-bbox.js
CHANGED
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
export const drawBoundingBox = (obj, k) => {
|
|
2
|
-
|
|
3
|
-
const anchor = obj.anchor || "topleft";
|
|
4
|
-
if (obj.renderArea && obj.has("anchor")) {
|
|
5
|
-
const offset = k.vec2(0);
|
|
2
|
+
if (obj.renderArea) {
|
|
6
3
|
const rect = obj.renderArea().bbox();
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
4
|
+
const anchor = obj.anchor || "topleft";
|
|
5
|
+
const offset = k.vec2(0);
|
|
6
|
+
if (typeof anchor === "string") {
|
|
7
|
+
if (anchor.includes("left")) {
|
|
8
|
+
offset.x = 0;
|
|
9
|
+
}
|
|
10
|
+
else if (anchor.includes("right")) {
|
|
11
|
+
offset.x = rect.width;
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
offset.x = rect.width / 2;
|
|
15
|
+
}
|
|
16
|
+
if (anchor.includes("top")) {
|
|
17
|
+
offset.y = 0;
|
|
18
|
+
}
|
|
19
|
+
else if (anchor.includes("bot")) {
|
|
20
|
+
offset.y = rect.height;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
offset.y = rect.height / 2;
|
|
24
|
+
}
|
|
21
25
|
}
|
|
22
26
|
else {
|
|
23
|
-
offset.
|
|
27
|
+
offset.x = (anchor.x * rect.width + 1) / 2 + rect.width / 2;
|
|
28
|
+
offset.y = (anchor.y * rect.height + 1) / 2 + rect.height / 2;
|
|
24
29
|
}
|
|
25
30
|
rect.pos = rect.pos.sub(offset);
|
|
26
31
|
k.drawRect({
|
|
@@ -32,7 +37,5 @@ export const drawBoundingBox = (obj, k) => {
|
|
|
32
37
|
opacity: 0.75,
|
|
33
38
|
},
|
|
34
39
|
});
|
|
35
|
-
// TODO figure out why these positions are wrong
|
|
36
|
-
// obj.children.forEach((child) => drawBoundingBox(child, k));
|
|
37
40
|
}
|
|
38
41
|
};
|
|
@@ -2,7 +2,7 @@ import type { GameObj } from "kaplay";
|
|
|
2
2
|
export declare const getObjectInfo: (obj: GameObj) => {
|
|
3
3
|
compsData: {
|
|
4
4
|
tag: string;
|
|
5
|
-
value?: string | import("preact").JSX.Element;
|
|
5
|
+
value?: string | import("preact").JSX.Element | null;
|
|
6
6
|
}[];
|
|
7
7
|
tags: string;
|
|
8
8
|
compsLabel: string;
|
|
@@ -2,60 +2,63 @@ import { jsx as _jsx } from "preact/jsx-runtime";
|
|
|
2
2
|
import { stringify } from "./stringify";
|
|
3
3
|
import { PositionControls } from "../components/position-controls";
|
|
4
4
|
import { TextControls } from "../components/text-controls";
|
|
5
|
+
import { Sprite } from "../components/sprite";
|
|
6
|
+
const componentMap = {
|
|
7
|
+
pos: PositionControls,
|
|
8
|
+
text: TextControls,
|
|
9
|
+
sprite: Sprite,
|
|
10
|
+
};
|
|
5
11
|
export const inspectComps = (obj) => {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
const object = obj;
|
|
13
|
+
const data = [];
|
|
14
|
+
for (const [tag, comp] of object._compStates) {
|
|
15
|
+
if (componentMap[tag]) {
|
|
16
|
+
const CompComponent = componentMap[tag];
|
|
17
|
+
data.push({
|
|
18
|
+
tag,
|
|
19
|
+
value: _jsx(CompComponent, { obj: obj }),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
else if (comp.inspect) {
|
|
23
|
+
const value = comp.inspect();
|
|
24
|
+
data.push({
|
|
25
|
+
tag,
|
|
26
|
+
// Remove component name if it is present in the inspect result.
|
|
27
|
+
// Native Kaplay components are doing this,
|
|
28
|
+
// and because we are displaying the name in the left column already,
|
|
29
|
+
// we don't need to display it again.
|
|
30
|
+
value: value ? value.replace(`${tag}: `, "") : "",
|
|
31
|
+
});
|
|
32
|
+
}
|
|
9
33
|
}
|
|
10
|
-
for (const [i, comp] of
|
|
34
|
+
for (const [i, comp] of object._anonymousCompStates.entries()) {
|
|
11
35
|
if (comp.inspect) {
|
|
12
|
-
|
|
36
|
+
data.push({
|
|
37
|
+
tag: `anonymous ${i}`,
|
|
38
|
+
value: comp.inspect(),
|
|
39
|
+
});
|
|
13
40
|
continue;
|
|
14
41
|
}
|
|
15
42
|
for (const [key, value] of Object.entries(comp)) {
|
|
16
43
|
if (typeof value === "function") {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
info[key] = `${key}: ${stringify(value)}`;
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
info[key] = `${key}: ${value}`;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
const lines = [];
|
|
28
|
-
for (const tag in info) {
|
|
29
|
-
if (info[tag]) {
|
|
30
|
-
if (tag === "pos") {
|
|
31
|
-
// Custom component for position
|
|
32
|
-
lines.push({
|
|
33
|
-
tag,
|
|
34
|
-
value: _jsx(PositionControls, { obj: obj }),
|
|
44
|
+
data.push({
|
|
45
|
+
tag: key,
|
|
46
|
+
value: "function",
|
|
35
47
|
});
|
|
36
48
|
}
|
|
37
|
-
else {
|
|
38
|
-
|
|
39
|
-
tag,
|
|
40
|
-
value:
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
if (tag === "text") {
|
|
46
|
-
// Custom component for text
|
|
47
|
-
lines.push({
|
|
48
|
-
tag,
|
|
49
|
-
value: _jsx(TextControls, { obj: obj }),
|
|
49
|
+
else if (typeof value === "object") {
|
|
50
|
+
data.push({
|
|
51
|
+
tag: key,
|
|
52
|
+
value: stringify(value),
|
|
50
53
|
});
|
|
51
54
|
}
|
|
52
55
|
else {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
data.push({
|
|
57
|
+
tag: key,
|
|
58
|
+
value,
|
|
56
59
|
});
|
|
57
60
|
}
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
|
-
return
|
|
63
|
+
return data.sort((a, b) => a.tag.localeCompare(b.tag));
|
|
61
64
|
};
|
package/dist/styles.css
CHANGED
|
@@ -113,6 +113,8 @@
|
|
|
113
113
|
background-color: var(--ki-bg);
|
|
114
114
|
border-bottom: 1px solid var(--ki-gray-light);
|
|
115
115
|
border-top: 1px solid var(--ki-gray-light);
|
|
116
|
+
flex-wrap: wrap;
|
|
117
|
+
font-size: 0.75rem;
|
|
116
118
|
}
|
|
117
119
|
|
|
118
120
|
.k-inspector__objects {
|
|
@@ -129,6 +131,18 @@
|
|
|
129
131
|
right: 0.5rem;
|
|
130
132
|
}
|
|
131
133
|
|
|
134
|
+
.k-inspector__interval {
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
gap: 0.5rem;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.k-inspector__header label {
|
|
141
|
+
display: flex;
|
|
142
|
+
align-items: center;
|
|
143
|
+
gap: 0.25rem;
|
|
144
|
+
}
|
|
145
|
+
|
|
132
146
|
/* Game object */
|
|
133
147
|
|
|
134
148
|
.game-object {
|
|
@@ -320,6 +334,6 @@
|
|
|
320
334
|
font-size: 0.75rem;
|
|
321
335
|
display: flex;
|
|
322
336
|
margin-bottom: 0.5rem;
|
|
323
|
-
gap: 0.
|
|
337
|
+
gap: 0.5rem;
|
|
324
338
|
align-items: center;
|
|
325
339
|
}
|
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.0
|
|
5
|
+
"version": "0.1.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/init.js",
|
|
8
8
|
"types": "./dist/init.d.ts",
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
"kaplay": "^4000.0.0-alpha.20"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"preact": "^10.
|
|
27
|
+
"preact": "^10.28.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@preact/preset-vite": "^2.10.2",
|
|
31
|
-
"@types/node": "^
|
|
31
|
+
"@types/node": "^25.0.3",
|
|
32
32
|
"typescript": "~5.9.3",
|
|
33
|
-
"vite": "^7.
|
|
33
|
+
"vite": "^7.3.0"
|
|
34
34
|
},
|
|
35
35
|
"repository": {
|
|
36
36
|
"type": "git",
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"bugs": {
|
|
46
46
|
"url": "https://github.com/Stanko/kaplay-inspector/issues"
|
|
47
47
|
},
|
|
48
|
-
"homepage": "https://
|
|
48
|
+
"homepage": "https://muffinman.io/kaplay-inspector/"
|
|
49
49
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/public/screenshot.png
CHANGED
|
Binary file
|