@stanko/kaplay-inspector 0.0.4 → 0.1.1
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 +56 -6
- package/dist/components/boolean-comp.d.ts +11 -0
- package/dist/components/boolean-comp.js +21 -0
- package/dist/components/color-controls.d.ts +6 -0
- package/dist/components/color-controls.js +24 -0
- package/dist/components/game-object.d.ts +5 -3
- package/dist/components/game-object.js +29 -12
- package/dist/components/hold-button.d.ts +9 -0
- package/dist/components/hold-button.js +33 -0
- package/dist/components/icons.d.ts +10 -6
- package/dist/components/icons.js +12 -12
- package/dist/components/inspector.d.ts +3 -4
- package/dist/components/inspector.js +16 -6
- package/dist/components/position-controls.js +2 -1
- package/dist/components/sprite-controls.d.ts +6 -0
- package/dist/components/sprite-controls.js +6 -0
- package/dist/components/text-controls.js +10 -3
- 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 +54 -40
- package/dist/lib/stringify.js +1 -1
- package/dist/styles.css +57 -8
- package/package.json +2 -2
- 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:
|
|
@@ -50,6 +52,12 @@ if (
|
|
|
50
52
|
}
|
|
51
53
|
```
|
|
52
54
|
|
|
55
|
+
If typescript is complaining about importing CSS files, you probably need to add this to one of your `.d.ts` files.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
declare module '*.scss';
|
|
59
|
+
```
|
|
60
|
+
|
|
53
61
|
### Options
|
|
54
62
|
|
|
55
63
|
You can pass options object to the init method as a second parameter:
|
|
@@ -64,22 +72,64 @@ available options are:
|
|
|
64
72
|
|
|
65
73
|
```ts
|
|
66
74
|
interface InspectorOptions {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
75
|
+
// CSS class to add to the root element
|
|
76
|
+
className?: string;
|
|
77
|
+
// is inspector visible on load, default: true
|
|
78
|
+
isVisible?: boolean;
|
|
79
|
+
// default update time in milliseconds, default: 250
|
|
80
|
+
initUpdateTimeout?: number;
|
|
81
|
+
// should area, anchor and bounding box be drawn on object hover, default: true
|
|
82
|
+
shouldDrawInspect?: boolean:
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Customizing colors
|
|
87
|
+
|
|
88
|
+
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:
|
|
89
|
+
|
|
90
|
+
```css
|
|
91
|
+
.k-inspector.your-custom-class {
|
|
92
|
+
--ki-h: 300; /* Purple */
|
|
93
|
+
--ki-h-secondary: 200; /* Teal */
|
|
70
94
|
}
|
|
71
95
|
```
|
|
72
96
|
|
|
73
|
-
|
|
97
|
+
Please note that if you load inspector's CSS dynamically, you'll have to add a custom class to create a higher specificity selector.
|
|
98
|
+
|
|
99
|
+
If you want to change other colors as well, check the [styles.css](./src/styles/styles.css).
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
## Positioning
|
|
74
103
|
|
|
75
104
|
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.
|
|
76
105
|
|
|
106
|
+
Assuming we have only the canvas and the inspector element on the page, here is an example of what I like to do:
|
|
107
|
+
|
|
108
|
+
```css
|
|
109
|
+
body:has(.k-inspector__hide) {
|
|
110
|
+
display: grid;
|
|
111
|
+
grid-template-rows: 60vh 40vh;
|
|
112
|
+
|
|
113
|
+
canvas {
|
|
114
|
+
width: 100% !important;
|
|
115
|
+
height: 60vh !important;
|
|
116
|
+
object-fit: contain;
|
|
117
|
+
display: block;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.k-inspector {
|
|
121
|
+
position: relative;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
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).
|
|
127
|
+
|
|
128
|
+
Same as with colors, be sure to have a higher specificity selector if inspector's CSS is loaded dynamically.
|
|
77
129
|
|
|
78
130
|
## TODO
|
|
79
131
|
|
|
80
|
-
* [ ] Bounding box - handle a case when anchor is a `Vec2`
|
|
81
132
|
* [ ] Controllable theme - system/light/dark. At the moment it is always matching the system.
|
|
82
133
|
* [ ] Filter/search
|
|
83
134
|
* [ ] Persist search in URL or local storage
|
|
84
|
-
* [ ] Figure out why child bounding box are drawn in the wrong position
|
|
85
135
|
* [ ] Collapse/Expand all button
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { GameObj } from "kaplay";
|
|
2
|
+
type CheckboxCompProps = {
|
|
3
|
+
obj: GameObj;
|
|
4
|
+
propName: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const useObjectBoolean: (obj: GameObj, propName: string) => {
|
|
7
|
+
checked: any;
|
|
8
|
+
onChange: (checked: boolean) => void;
|
|
9
|
+
};
|
|
10
|
+
export declare const BooleanComp: ({ obj, propName }: CheckboxCompProps) => import("preact").JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "preact/hooks";
|
|
3
|
+
export const useObjectBoolean = (obj, propName) => {
|
|
4
|
+
const [checked, setChecked] = useState(obj[propName]);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
setChecked(obj[propName]);
|
|
7
|
+
}, [obj[propName]]);
|
|
8
|
+
const onChange = (checked) => {
|
|
9
|
+
setChecked(checked);
|
|
10
|
+
obj[propName] = checked;
|
|
11
|
+
};
|
|
12
|
+
return {
|
|
13
|
+
checked,
|
|
14
|
+
onChange,
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export const BooleanComp = ({ obj, propName }) => {
|
|
18
|
+
const id = `${propName}-${obj.id}`;
|
|
19
|
+
const { checked, onChange } = useObjectBoolean(obj, propName);
|
|
20
|
+
return (_jsxs("div", { class: "game-object__comps-row", children: [_jsx("label", { for: id, children: _jsx("b", { children: propName }) }), _jsx("div", { children: _jsx("input", { id: id, type: "checkbox", checked: checked, onChange: (e) => onChange(e.target.checked) }) })] }));
|
|
21
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "preact/hooks";
|
|
3
|
+
import { cx } from "../lib/cx";
|
|
4
|
+
const ColorSlider = ({ onChange, value, channel }) => {
|
|
5
|
+
const handleChange = (e) => {
|
|
6
|
+
const target = e.target;
|
|
7
|
+
onChange(channel, parseInt(target.value));
|
|
8
|
+
};
|
|
9
|
+
return (_jsx("input", { className: cx("color-controls__slider-input", `color-controls__slider-input--${channel}`), type: "range", min: "0", max: "255", value: value, onInput: handleChange }));
|
|
10
|
+
};
|
|
11
|
+
export const Color = ({ obj }) => {
|
|
12
|
+
const object = obj;
|
|
13
|
+
const { r, g, b } = object.color;
|
|
14
|
+
const [color, setColor] = useState({ r, g, b });
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
setColor({ r, g, b });
|
|
17
|
+
}, [r, g, b]);
|
|
18
|
+
const updateColor = (channel, value) => {
|
|
19
|
+
const newColor = { ...color, [channel]: value };
|
|
20
|
+
setColor(newColor);
|
|
21
|
+
object.color[channel] = value;
|
|
22
|
+
};
|
|
23
|
+
return (_jsxs("div", { class: "color-controls", children: [_jsx("div", { class: "color-controls__swatch", style: { background: `rgb(${color.r} ${color.g} ${color.b})` } }), _jsxs("div", { children: [_jsx(ColorSlider, { value: color.r, onChange: updateColor, channel: "r" }), _jsx(ColorSlider, { value: color.g, onChange: updateColor, channel: "g" }), _jsx(ColorSlider, { value: color.b, onChange: updateColor, channel: "b" })] }), _jsxs("div", { children: ["rgb(", color.r, ", ", color.g, ", ", color.b, ")"] })] }));
|
|
24
|
+
};
|
|
@@ -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,59 @@
|
|
|
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
|
-
|
|
8
|
+
import { BooleanComp } from "./boolean-comp";
|
|
9
|
+
export const GameObject = ({ obj, className = "", isExpanded: isExpandedExternal = false, isRenderRoot, setRenderRoot, shouldDrawInspect, k, }) => {
|
|
9
10
|
const [isExpanded, setIsExpanded] = useState(isExpandedExternal);
|
|
10
|
-
const
|
|
11
|
+
const updateControllers = useRef([]);
|
|
11
12
|
const { compsData, tags, compsLabel } = getObjectInfo(obj);
|
|
12
13
|
const isRootObject = obj.id === 0;
|
|
13
14
|
const isObjectDestroyed = !obj.exists() && !isRootObject;
|
|
14
15
|
const showExpandTree = obj.children.length > 0;
|
|
15
16
|
const hasChildren = obj.children.length > 0;
|
|
16
17
|
const isInspecting = isRenderRoot && obj.id !== 0;
|
|
18
|
+
const cancelUpdateControllers = useCallback(() => {
|
|
19
|
+
updateControllers.current.forEach((controller) => controller.cancel());
|
|
20
|
+
updateControllers.current = [];
|
|
21
|
+
}, []);
|
|
22
|
+
const drawInspect = useCallback((obj, isChild = false) => {
|
|
23
|
+
if (!obj.hidden) {
|
|
24
|
+
const updateController = obj.onDraw(() => {
|
|
25
|
+
// Kaplay calls drawInspect on all of the children, no need to call it again
|
|
26
|
+
if (!isChild) {
|
|
27
|
+
obj.drawInspect();
|
|
28
|
+
}
|
|
29
|
+
drawBoundingBox(obj, k);
|
|
30
|
+
});
|
|
31
|
+
updateControllers.current.push(updateController);
|
|
32
|
+
obj.children.forEach((child) => {
|
|
33
|
+
drawInspect(child, true);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}, []);
|
|
17
37
|
useEffect(() => {
|
|
18
38
|
return () => {
|
|
19
|
-
|
|
39
|
+
cancelUpdateControllers();
|
|
20
40
|
};
|
|
21
41
|
}, []);
|
|
22
42
|
const handleToggleClick = () => {
|
|
23
43
|
setIsExpanded(!isExpanded);
|
|
24
44
|
};
|
|
25
45
|
const handleMouseEnter = () => {
|
|
26
|
-
|
|
27
|
-
if (!
|
|
28
|
-
|
|
29
|
-
obj.drawInspect();
|
|
30
|
-
drawBoundingBox(obj, k);
|
|
31
|
-
});
|
|
46
|
+
cancelUpdateControllers();
|
|
47
|
+
if (!isRootObject && shouldDrawInspect) {
|
|
48
|
+
drawInspect(obj);
|
|
32
49
|
}
|
|
33
50
|
};
|
|
34
51
|
const handleMouseLeave = () => {
|
|
35
|
-
|
|
52
|
+
cancelUpdateControllers();
|
|
36
53
|
};
|
|
37
54
|
return (_jsxs("div", { class: cx("game-object", className, {
|
|
38
55
|
"game-object--no-children": !hasChildren,
|
|
39
56
|
}), 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
57
|
"game-object__header--expandable": showExpandTree,
|
|
41
|
-
}), onClick: handleToggleClick, children: [_jsx(
|
|
58
|
+
}), onClick: handleToggleClick, children: [isExpanded ? (_jsx(MinusIcon, { className: "game-object__expand-icon" })) : (_jsx(PlusIcon, { className: "game-object__expand-icon" })), _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: [_jsx(BooleanComp, { obj: obj, propName: "paused" }), _jsx(BooleanComp, { obj: obj, propName: "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
59
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { JSX } from "preact/jsx-runtime";
|
|
2
|
+
export type HoldButtonProps = {
|
|
3
|
+
children?: JSX.Element | string | number;
|
|
4
|
+
className?: string;
|
|
5
|
+
onClickAndHold: () => void;
|
|
6
|
+
interval?: number;
|
|
7
|
+
startRepeatingDelay?: number;
|
|
8
|
+
};
|
|
9
|
+
export declare const HoldButton: ({ children, className, onClickAndHold, interval, startRepeatingDelay, }: HoldButtonProps) => JSX.Element;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from "preact/hooks";
|
|
3
|
+
export const HoldButton = ({ children, className, onClickAndHold, interval = 50, startRepeatingDelay = 200, }) => {
|
|
4
|
+
const intervalRef = useRef();
|
|
5
|
+
const timeoutRef = useRef();
|
|
6
|
+
const [isMouseDown, setIsMouseDown] = useState(false);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
9
|
+
return () => {
|
|
10
|
+
clearTimeout(timeoutRef.current);
|
|
11
|
+
clearInterval(intervalRef.current);
|
|
12
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
13
|
+
};
|
|
14
|
+
}, []);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
clearTimeout(timeoutRef.current);
|
|
17
|
+
clearInterval(intervalRef.current);
|
|
18
|
+
if (isMouseDown) {
|
|
19
|
+
timeoutRef.current = setTimeout(() => {
|
|
20
|
+
intervalRef.current = setInterval(() => {
|
|
21
|
+
onClickAndHold();
|
|
22
|
+
}, interval);
|
|
23
|
+
}, startRepeatingDelay);
|
|
24
|
+
}
|
|
25
|
+
}, [isMouseDown]);
|
|
26
|
+
const handleMouseDown = () => {
|
|
27
|
+
setIsMouseDown(true);
|
|
28
|
+
};
|
|
29
|
+
const handleMouseUp = () => {
|
|
30
|
+
setIsMouseDown(false);
|
|
31
|
+
};
|
|
32
|
+
return (_jsx("button", { className: className, onMouseDown: handleMouseDown, onClick: onClickAndHold, children: children }));
|
|
33
|
+
};
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const
|
|
6
|
-
export declare const
|
|
1
|
+
type IconProps = {
|
|
2
|
+
className?: string;
|
|
3
|
+
};
|
|
4
|
+
export declare const PlusIcon: ({ className }: IconProps) => import("preact").JSX.Element;
|
|
5
|
+
export declare const MinusIcon: ({ className }: IconProps) => import("preact").JSX.Element;
|
|
6
|
+
export declare const ArrowUpIcon: ({ className }: IconProps) => import("preact").JSX.Element;
|
|
7
|
+
export declare const ArrowDownIcon: ({ className }: IconProps) => import("preact").JSX.Element;
|
|
8
|
+
export declare const ArrowLeftIcon: ({ className }: IconProps) => import("preact").JSX.Element;
|
|
9
|
+
export declare const ArrowRightIcon: ({ className }: IconProps) => import("preact").JSX.Element;
|
|
10
|
+
export {};
|
package/dist/components/icons.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
-
export const PlusIcon = () => {
|
|
3
|
-
return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", xmlns: "http://www.w3.org/2000/svg", children: _jsxs("g", { fill: "none", "stroke-width": "1.25", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: [_jsx("rect", { width: "14", height: "14", x: "1", y: "1", rx: "4" }), _jsx("path", { d: "M 8 4 V 12 M 4 8 H12" })] }) }));
|
|
2
|
+
export const PlusIcon = ({ className = "" }) => {
|
|
3
|
+
return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", xmlns: "http://www.w3.org/2000/svg", class: className, children: _jsxs("g", { fill: "none", "stroke-width": "1.25", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: [_jsx("rect", { width: "14", height: "14", x: "1", y: "1", rx: "4" }), _jsx("path", { d: "M 8 4 V 12 M 4 8 H12" })] }) }));
|
|
4
4
|
};
|
|
5
|
-
export const MinusIcon = () => {
|
|
6
|
-
return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsxs("g", { fill: "none", "stroke-width": "1.25", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: [_jsx("rect", { width: "14", height: "14", x: "1", y: "1", rx: "4" }), _jsx("path", { d: "M 4 8 H 12" })] }) }));
|
|
5
|
+
export const MinusIcon = ({ className = "" }) => {
|
|
6
|
+
return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", class: className, children: _jsxs("g", { fill: "none", "stroke-width": "1.25", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: [_jsx("rect", { width: "14", height: "14", x: "1", y: "1", rx: "4" }), _jsx("path", { d: "M 4 8 H 12" })] }) }));
|
|
7
7
|
};
|
|
8
|
-
export const ArrowUpIcon = () => {
|
|
9
|
-
return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 3 10 L 8 6 L 13 10" }) }) }));
|
|
8
|
+
export const ArrowUpIcon = ({ className = "" }) => {
|
|
9
|
+
return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", class: className, children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 3 10 L 8 6 L 13 10" }) }) }));
|
|
10
10
|
};
|
|
11
|
-
export const ArrowDownIcon = () => {
|
|
12
|
-
return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 3 6 L 8 10 L 13 6" }) }) }));
|
|
11
|
+
export const ArrowDownIcon = ({ className = "" }) => {
|
|
12
|
+
return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", class: className, children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 3 6 L 8 10 L 13 6" }) }) }));
|
|
13
13
|
};
|
|
14
|
-
export const ArrowLeftIcon = () => {
|
|
15
|
-
return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 10 3 L 6 8 L 10 13" }) }) }));
|
|
14
|
+
export const ArrowLeftIcon = ({ className = "" }) => {
|
|
15
|
+
return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", class: className, children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 10 3 L 6 8 L 10 13" }) }) }));
|
|
16
16
|
};
|
|
17
|
-
export const ArrowRightIcon = () => {
|
|
18
|
-
return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 6 3 L 10 8 L 6 13" }) }) }));
|
|
17
|
+
export const ArrowRightIcon = ({ className = "" }) => {
|
|
18
|
+
return (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", class: className, children: _jsx("g", { fill: "none", stroke: "currentColor", "stroke-linejoin": "round", "stroke-linecap": "round", children: _jsx("path", { d: "M 6 3 L 10 8 L 6 13" }) }) }));
|
|
19
19
|
};
|
|
@@ -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,10 +1,20 @@
|
|
|
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
|
+
import { useObjectBoolean } from "./boolean-comp";
|
|
5
|
+
const INTERVAL_OPTIONS = [
|
|
6
|
+
{ value: 100, label: "100ms" },
|
|
7
|
+
{ value: 250, label: "250ms" },
|
|
8
|
+
{ value: 500, label: "500ms" },
|
|
9
|
+
{ value: 1000, label: "1s" },
|
|
10
|
+
];
|
|
11
|
+
export const Inspector = ({ initUpdateTimeout = 250, isVisibleOnLoad = true, initDrawInspectOnHover = true, k, }) => {
|
|
12
|
+
const [updateTimeout, setUpdateTimeout] = useState(initUpdateTimeout);
|
|
13
|
+
const [shouldDrawInspect, setShouldDrawInspect] = useState(initDrawInspectOnHover);
|
|
5
14
|
const [root, setRoot] = useState(k.getTreeRoot());
|
|
6
15
|
const [renderIndex, setRenderIndex] = useState(0);
|
|
7
16
|
const [isVisible, setIsVisible] = useState(isVisibleOnLoad);
|
|
17
|
+
const paused = useObjectBoolean(k.getTreeRoot(), "paused");
|
|
8
18
|
// Force re-render every updateTimeout milliseconds
|
|
9
19
|
useEffect(() => {
|
|
10
20
|
const interval = setInterval(() => {
|
|
@@ -12,15 +22,15 @@ export const Inspector = ({ updateTimeout = 250, isVisibleOnLoad = true, k, }) =
|
|
|
12
22
|
}, updateTimeout);
|
|
13
23
|
return () => clearInterval(interval);
|
|
14
24
|
}, [renderIndex, updateTimeout]);
|
|
15
|
-
const handlePauseClick = () => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
};
|
|
25
|
+
// const handlePauseClick = () => {
|
|
26
|
+
// const root = k.getTreeRoot();
|
|
27
|
+
// root.paused = !root.paused;
|
|
28
|
+
// };
|
|
19
29
|
const toggleVisibility = () => {
|
|
20
30
|
setIsVisible(!isVisible);
|
|
21
31
|
};
|
|
22
32
|
if (!isVisible) {
|
|
23
33
|
return (_jsx("button", { class: "ki-btn k-inspector__show", onClick: toggleVisibility, children: "Show Inspector" }));
|
|
24
34
|
}
|
|
25
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { class: "k-inspector__header", children: [_jsx("button", { class: "ki-btn", onClick:
|
|
35
|
+
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", _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
36
|
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
2
|
import { roundToDecimal } from "../lib/round-to-decimal";
|
|
3
|
+
import { HoldButton } from "./hold-button";
|
|
3
4
|
import { ArrowDownIcon, ArrowLeftIcon, ArrowRightIcon, ArrowUpIcon, } from "./icons";
|
|
4
5
|
export const PositionControls = ({ obj }) => {
|
|
5
6
|
if (!obj.pos) {
|
|
6
7
|
return null;
|
|
7
8
|
}
|
|
8
|
-
return (_jsxs("div", { class: "pos-controls", children: [_jsx(
|
|
9
|
+
return (_jsxs("div", { class: "pos-controls", children: [_jsx(HoldButton, { className: "ki-btn", onClickAndHold: () => (obj.pos.x -= 1), children: _jsx(ArrowLeftIcon, {}) }), _jsx(HoldButton, { className: "ki-btn", onClickAndHold: () => (obj.pos.x += 1), children: _jsx(ArrowRightIcon, {}) }), _jsxs("div", { class: "pos-controls__value", children: ["x: ", roundToDecimal(obj.pos.x, 2)] }), _jsxs("div", { class: "pos-controls__value", children: ["y: ", roundToDecimal(obj.pos.y, 2)] }), _jsx(HoldButton, { className: "ki-btn", onClickAndHold: () => (obj.pos.y -= 1), children: _jsx(ArrowUpIcon, {}) }), _jsx(HoldButton, { className: "ki-btn", onClickAndHold: () => (obj.pos.y += 1), children: _jsx(ArrowDownIcon, {}) })] }));
|
|
9
10
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
|
|
2
|
+
export const SpriteControls = ({ obj }) => {
|
|
3
|
+
const object = obj;
|
|
4
|
+
const animation = object.getCurAnim();
|
|
5
|
+
return (_jsxs("div", { class: "sprite-controls", 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
|
+
};
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "preact/hooks";
|
|
2
3
|
export const TextControls = ({ obj }) => {
|
|
4
|
+
const [text, setText] = useState(obj.text);
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
setText(obj.text);
|
|
7
|
+
}, [obj.text]);
|
|
3
8
|
if (typeof obj.text !== "string") {
|
|
4
9
|
return null;
|
|
5
10
|
}
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
11
|
+
const handleInput = (e) => {
|
|
12
|
+
obj.text = e.target.value;
|
|
13
|
+
setText(text);
|
|
14
|
+
};
|
|
15
|
+
return (_jsx("div", { class: "text-controls", children: _jsx("input", { class: "text-controls__input", type: "text", placeholder: "Enter text", value: text, onInput: handleInput }) }));
|
|
9
16
|
};
|
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,74 @@ 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 { SpriteControls } from "../components/sprite-controls";
|
|
6
|
+
import { Color } from "../components/color-controls";
|
|
7
|
+
const componentMap = {
|
|
8
|
+
pos: PositionControls,
|
|
9
|
+
text: TextControls,
|
|
10
|
+
sprite: SpriteControls,
|
|
11
|
+
color: Color,
|
|
12
|
+
};
|
|
5
13
|
export const inspectComps = (obj) => {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
14
|
+
const object = obj;
|
|
15
|
+
const data = [];
|
|
16
|
+
for (const [tag, comp] of object._compStates) {
|
|
17
|
+
if (componentMap[tag]) {
|
|
18
|
+
const CompComponent = componentMap[tag];
|
|
19
|
+
data.push({
|
|
20
|
+
tag,
|
|
21
|
+
value: _jsx(CompComponent, { obj: obj }),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
else if (comp.inspect) {
|
|
25
|
+
const value = comp.inspect();
|
|
26
|
+
data.push({
|
|
27
|
+
tag,
|
|
28
|
+
// Remove component name if it is present in the inspect result.
|
|
29
|
+
// Native Kaplay components are doing this,
|
|
30
|
+
// and because we are displaying the name in the left column already,
|
|
31
|
+
// we don't need to display it again.
|
|
32
|
+
value: value ? value.replace(`${tag}: `, "") : "",
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
data.push({
|
|
37
|
+
tag,
|
|
38
|
+
// Commented out on purpose
|
|
39
|
+
// For now, only the name of the component is shown,
|
|
40
|
+
// until I try it out and figure if it would be useful to display the full component state
|
|
41
|
+
// value: stringify(comp),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
9
44
|
}
|
|
10
|
-
for (const [i, comp] of
|
|
45
|
+
for (const [i, comp] of object._anonymousCompStates.entries()) {
|
|
11
46
|
if (comp.inspect) {
|
|
12
|
-
|
|
47
|
+
data.push({
|
|
48
|
+
tag: `anonymous ${i}`,
|
|
49
|
+
value: comp.inspect(),
|
|
50
|
+
});
|
|
13
51
|
continue;
|
|
14
52
|
}
|
|
15
53
|
for (const [key, value] of Object.entries(comp)) {
|
|
16
54
|
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 }),
|
|
55
|
+
data.push({
|
|
56
|
+
tag: key,
|
|
57
|
+
value: "function",
|
|
35
58
|
});
|
|
36
59
|
}
|
|
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 }),
|
|
60
|
+
else if (typeof value === "object") {
|
|
61
|
+
data.push({
|
|
62
|
+
tag: key,
|
|
63
|
+
value: stringify(value),
|
|
50
64
|
});
|
|
51
65
|
}
|
|
52
66
|
else {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
67
|
+
data.push({
|
|
68
|
+
tag: key,
|
|
69
|
+
value,
|
|
56
70
|
});
|
|
57
71
|
}
|
|
58
72
|
}
|
|
59
73
|
}
|
|
60
|
-
return
|
|
74
|
+
return data.sort((a, b) => a.tag.localeCompare(b.tag));
|
|
61
75
|
};
|
package/dist/lib/stringify.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const stringify = (obj, maxDepth = 1, currentDepth = 0) => {
|
|
2
2
|
if (typeof obj !== "object" || obj === null) {
|
|
3
|
-
return
|
|
3
|
+
return JSON.stringify(obj);
|
|
4
4
|
}
|
|
5
5
|
const lines = Object.entries(obj).map(([key, value]) => {
|
|
6
6
|
if (typeof value === "function") {
|
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 {
|
|
@@ -312,14 +326,49 @@
|
|
|
312
326
|
outline: none;
|
|
313
327
|
border-color: var(--ki-primary);
|
|
314
328
|
}
|
|
315
|
-
}
|
|
316
329
|
|
|
317
|
-
/*
|
|
330
|
+
/* Color */
|
|
331
|
+
|
|
332
|
+
.color-controls {
|
|
333
|
+
display: flex;
|
|
334
|
+
align-items: center;
|
|
335
|
+
gap: 0.5rem;
|
|
336
|
+
width: fit-content;
|
|
337
|
+
min-width: 12rem;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.color-controls__swatch {
|
|
341
|
+
width: 2rem;
|
|
342
|
+
height: 2rem;
|
|
343
|
+
border-radius: 8px;
|
|
344
|
+
border: 1px solid var(--ki-border-light);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.color-controls__slider {
|
|
348
|
+
display: flex;
|
|
349
|
+
align-items: center;
|
|
350
|
+
gap: 0.25rem;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.color-controls__slider-input--r {
|
|
354
|
+
accent-color: red;
|
|
355
|
+
}
|
|
318
356
|
|
|
319
|
-
.
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
357
|
+
.color-controls__slider-input--g {
|
|
358
|
+
accent-color: green;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.color-controls__slider-input--b {
|
|
362
|
+
accent-color: blue;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/* Breadcrumbs */
|
|
366
|
+
|
|
367
|
+
.breadcrumbs {
|
|
368
|
+
font-size: 0.75rem;
|
|
369
|
+
display: flex;
|
|
370
|
+
margin-bottom: 0.5rem;
|
|
371
|
+
gap: 0.5rem;
|
|
372
|
+
align-items: center;
|
|
373
|
+
}
|
|
325
374
|
}
|
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.1.1",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/init.js",
|
|
8
8
|
"types": "./dist/init.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@preact/preset-vite": "^2.10.2",
|
|
31
|
-
"@types/node": "^25.0.
|
|
31
|
+
"@types/node": "^25.0.3",
|
|
32
32
|
"typescript": "~5.9.3",
|
|
33
33
|
"vite": "^7.3.0"
|
|
34
34
|
},
|
package/public/screenshot.png
CHANGED
|
Binary file
|