@stanko/kaplay-inspector 0.1.6 → 0.2.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 +10 -5
- package/dist/components/anchor-control.d.ts +6 -0
- package/dist/components/anchor-control.js +18 -0
- package/dist/components/blend-control.d.ts +5 -0
- package/dist/components/blend-control.js +12 -0
- package/dist/components/color-control.d.ts +6 -0
- package/dist/components/color-control.js +24 -0
- package/dist/components/game-object.d.ts +1 -3
- package/dist/components/game-object.js +5 -4
- package/dist/components/hold-button.d.ts +2 -1
- package/dist/components/hold-button.js +51 -28
- package/dist/components/hp-control.d.ts +7 -0
- package/dist/components/hp-control.js +8 -0
- package/dist/components/inspector.d.ts +2 -3
- package/dist/components/inspector.js +3 -2
- package/dist/components/number-control.d.ts +7 -0
- package/dist/components/number-control.js +7 -0
- package/dist/components/number-input.d.ts +8 -0
- package/dist/components/number-input.js +51 -0
- package/dist/components/search-results.d.ts +1 -3
- package/dist/components/search-results.js +2 -2
- package/dist/components/sprite-control.d.ts +6 -0
- package/dist/components/sprite-control.js +6 -0
- package/dist/components/text-control.d.ts +6 -0
- package/dist/components/text-control.js +8 -0
- package/dist/components/text-input.d.ts +7 -0
- package/dist/components/text-input.js +26 -0
- package/dist/components/vector-control.d.ts +7 -0
- package/dist/components/vector-control.js +10 -0
- package/dist/init.d.ts +1 -2
- package/dist/init.js +4 -1
- package/dist/k.d.ts +4 -0
- package/dist/k.js +4 -0
- package/dist/lib/draw-bbox.d.ts +1 -2
- package/dist/lib/draw-bbox.js +3 -2
- package/dist/lib/inspect-comps.js +22 -8
- package/dist/lib/to-fixed.d.ts +1 -0
- package/dist/lib/to-fixed.js +3 -0
- package/dist/styles.css +75 -19
- package/package.json +4 -3
- package/public/screenshot.png +0 -0
- package/dist/components/color-controls.d.ts +0 -6
- package/dist/components/color-controls.js +0 -24
- package/dist/components/position-controls.d.ts +0 -6
- package/dist/components/position-controls.js +0 -10
- package/dist/components/sprite-controls.d.ts +0 -6
- package/dist/components/sprite-controls.js +0 -6
- package/dist/components/text-controls.d.ts +0 -6
- package/dist/components/text-controls.js +0 -16
- package/dist/lib/round-to-decimal.d.ts +0 -1
- package/dist/lib/round-to-decimal.js +0 -4
package/README.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
A dev tool for [Kaplay](https://kaplayjs.com/) which allows you to explore and inspect the game object tree real time.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Check the demo: [muffinman.io/kaplay-inspector/](https://muffinman.io/kaplay-inspector/).
|
|
6
|
+
|
|
7
|
+
[](https://muffinman.io/kaplay-inspector/)
|
|
6
8
|
|
|
7
9
|
## Features
|
|
8
10
|
|
|
@@ -11,7 +13,12 @@ A dev tool for [Kaplay](https://kaplayjs.com/) which allows you to explore and i
|
|
|
11
13
|
- Hover an object to draw it's area, anchor and bounding box
|
|
12
14
|
- Inspect object's component and custom props
|
|
13
15
|
- Log an object to console
|
|
14
|
-
- Tweak
|
|
16
|
+
- Tweak object properties live
|
|
17
|
+
- position, scale, rotate, skew, z-index
|
|
18
|
+
- opacity, color, blend mode
|
|
19
|
+
- text
|
|
20
|
+
- anchor
|
|
21
|
+
- health
|
|
15
22
|
- Pause objects
|
|
16
23
|
- Hide objects
|
|
17
24
|
- Search for tags or comps
|
|
@@ -132,6 +139,4 @@ Same as with colors, be sure to have a higher specificity selector if inspector'
|
|
|
132
139
|
## TODO
|
|
133
140
|
|
|
134
141
|
* [ ] Controllable theme - system/light/dark. At the moment it is always matching the system.
|
|
135
|
-
* [ ]
|
|
136
|
-
* [ ] Persist search in URL or local storage
|
|
137
|
-
* [ ] Collapse/Expand all button
|
|
142
|
+
* [ ] Persist search/options in URL or local storage
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
|
|
2
|
+
import { cx } from "../lib/cx";
|
|
3
|
+
import { k } from "../k";
|
|
4
|
+
import { VectorControl } from "./vector-control";
|
|
5
|
+
const strings = [
|
|
6
|
+
["topleft", "top", "topright"],
|
|
7
|
+
["left", "center", "right"],
|
|
8
|
+
["botleft", "bot", "botright"],
|
|
9
|
+
];
|
|
10
|
+
export const AnchorControl = ({ className = "", obj }) => {
|
|
11
|
+
const object = obj;
|
|
12
|
+
const isString = typeof obj.anchor === "string";
|
|
13
|
+
return (_jsx("div", { class: cx(className, "anchor-control"), children: isString ? (_jsxs(_Fragment, { children: [_jsxs("div", { class: "anchor-radios", children: [strings.map((row, i) => {
|
|
14
|
+
return (_jsx("div", { class: "anchor-row", children: row.map((anchor) => {
|
|
15
|
+
return (_jsx("label", { children: _jsx("input", { type: "radio", name: "anchor", value: anchor, checked: anchor === object.anchor, onChange: () => (object.anchor = anchor) }) }, anchor));
|
|
16
|
+
}) }, i));
|
|
17
|
+
}), _jsx("div", { children: isString && object.anchor })] }), _jsx("button", { class: "ki-btn", onClick: () => (object.anchor = k.vec2(0, 0)), children: "Use a vector" })] })) : (_jsxs(_Fragment, { children: [_jsx(VectorControl, { obj: obj, property: "anchor", step: 0.1 }), _jsx("button", { class: "ki-btn", onClick: () => (object.anchor = "center"), children: "Use a named location" })] })) }));
|
|
18
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { cx } from "../lib/cx";
|
|
3
|
+
const MODES = [
|
|
4
|
+
{ label: "normal", value: 0 },
|
|
5
|
+
{ label: "add", value: 1 },
|
|
6
|
+
{ label: "multiply", value: 2 },
|
|
7
|
+
{ label: "screen", value: 3 },
|
|
8
|
+
{ label: "overlay", value: 4 },
|
|
9
|
+
];
|
|
10
|
+
export const BlendControl = ({ className = "", obj }) => {
|
|
11
|
+
return (_jsx("div", { class: cx(className, "blend-control"), children: MODES.map((mode) => (_jsxs("label", { class: "ki-flex", children: [_jsx("input", { type: "radio", name: `blend-${obj.id}`, value: mode.value, checked: obj.blend === mode.value, onChange: () => (obj.blend = mode.value) }), mode.label] }, mode.value))) }));
|
|
12
|
+
};
|
|
@@ -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-control__slider-input", `color-control__slider-input--${channel}`), type: "range", min: "0", max: "255", value: value, onInput: handleChange }));
|
|
10
|
+
};
|
|
11
|
+
export const ColorControl = ({ 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-control", children: [_jsx("div", { class: "color-control__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,5 +1,4 @@
|
|
|
1
1
|
import type { GameObj } from "kaplay";
|
|
2
|
-
import type { KAPLAYCtxType } from "../init";
|
|
3
2
|
export interface GameObjectProps {
|
|
4
3
|
className?: string;
|
|
5
4
|
obj: GameObj;
|
|
@@ -7,6 +6,5 @@ export interface GameObjectProps {
|
|
|
7
6
|
isExpanded?: boolean;
|
|
8
7
|
isRenderRoot?: boolean;
|
|
9
8
|
shouldDrawInspect: boolean;
|
|
10
|
-
k: KAPLAYCtxType;
|
|
11
9
|
}
|
|
12
|
-
export declare const GameObject: ({ obj, className, isExpanded: isExpandedExternal, isRenderRoot, setRenderRoot, shouldDrawInspect,
|
|
10
|
+
export declare const GameObject: ({ obj, className, isExpanded: isExpandedExternal, isRenderRoot, setRenderRoot, shouldDrawInspect, }: GameObjectProps) => import("preact").JSX.Element | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useRef, useState } from "preact/hooks";
|
|
3
3
|
import { MinusIcon, PlusIcon } from "../components/icons";
|
|
4
4
|
import { cx } from "../lib/cx";
|
|
@@ -6,7 +6,8 @@ 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
|
-
|
|
9
|
+
import { k } from "../k";
|
|
10
|
+
export const GameObject = ({ obj, className = "", isExpanded: isExpandedExternal = false, isRenderRoot, setRenderRoot, shouldDrawInspect, }) => {
|
|
10
11
|
const [isExpanded, setIsExpanded] = useState(isExpandedExternal);
|
|
11
12
|
const updateControllers = useRef([]);
|
|
12
13
|
const { compsData, tags, compsLabel } = getObjectInfo(obj);
|
|
@@ -24,7 +25,7 @@ export const GameObject = ({ obj, className = "", isExpanded: isExpandedExternal
|
|
|
24
25
|
const drawInspect = useCallback((obj) => {
|
|
25
26
|
if (!obj.hidden) {
|
|
26
27
|
const updateController = k.onDraw(() => {
|
|
27
|
-
drawBoundingBox(obj
|
|
28
|
+
drawBoundingBox(obj);
|
|
28
29
|
obj.drawInspect();
|
|
29
30
|
});
|
|
30
31
|
updateControllers.current.push(updateController);
|
|
@@ -54,5 +55,5 @@ export const GameObject = ({ obj, className = "", isExpanded: isExpandedExternal
|
|
|
54
55
|
"game-object--no-children": !hasChildren,
|
|
55
56
|
}), children: [isInspecting && _jsx(Breadcrumbs, { setRenderRoot: setRenderRoot, obj: obj }), _jsxs("div", { class: "game-object__content", onMouseEnter: handleMouseEnter, onMouseLeave: cancelUpdateControllers, children: [_jsxs("button", { class: cx("game-object__header", {
|
|
56
57
|
"game-object__header--expandable": showExpandTree,
|
|
57
|
-
}), 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" }), hasSize && (_jsxs("div", { class: "game-object__comps-row", children: [_jsx("b", { children: "size" }), _jsxs("div", { children: [obj.width, " x ", obj.height] })] })), compsData.map((comp) => (_jsxs("div", { class: "game-object__comps-row", 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, {
|
|
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 && (_jsxs(_Fragment, { children: [_jsx("button", { class: "ki-btn ki-btn--red", onClick: () => obj.destroy(), children: "destroy" }), _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" }), hasSize && (_jsxs("div", { class: "game-object__comps-row", children: [_jsx("b", { children: "size" }), _jsxs("div", { children: [obj.width, " x ", obj.height] })] })), compsData.map((comp) => (_jsxs("div", { class: "game-object__comps-row", 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, { obj: child, setRenderRoot: setRenderRoot, shouldDrawInspect: shouldDrawInspect }, child.id))) }))] }, obj.id));
|
|
58
59
|
};
|
|
@@ -3,7 +3,8 @@ export type HoldButtonProps = {
|
|
|
3
3
|
children?: JSX.Element | string | number;
|
|
4
4
|
className?: string;
|
|
5
5
|
onClickAndHold: () => void;
|
|
6
|
+
onHoldEnd?: () => void;
|
|
6
7
|
interval?: number;
|
|
7
8
|
startRepeatingDelay?: number;
|
|
8
9
|
};
|
|
9
|
-
export declare const HoldButton: ({ children, className, onClickAndHold, interval, startRepeatingDelay, }: HoldButtonProps) => JSX.Element;
|
|
10
|
+
export declare const HoldButton: ({ children, className, onClickAndHold, interval, startRepeatingDelay, onHoldEnd, }: HoldButtonProps) => JSX.Element;
|
|
@@ -1,33 +1,56 @@
|
|
|
1
1
|
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
-
import { useEffect, useRef
|
|
3
|
-
export const HoldButton = ({ children, className, onClickAndHold, interval = 50, startRepeatingDelay = 200, }) => {
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
2
|
+
import { useCallback, useEffect, useRef } from "preact/hooks";
|
|
3
|
+
export const HoldButton = ({ children, className, onClickAndHold, interval = 50, startRepeatingDelay = 200, onHoldEnd, }) => {
|
|
4
|
+
// const [isActive, setIsActive] = useState(false);
|
|
5
|
+
const timerRef = useRef();
|
|
6
|
+
const onClickAndHoldRef = useRef(onClickAndHold);
|
|
7
|
+
const onHoldEndRef = useRef(onHoldEnd);
|
|
8
|
+
const startTimer = useCallback(() => {
|
|
9
|
+
stopTimer();
|
|
10
|
+
// setIsActive(true);
|
|
11
|
+
// Trigger once immediately
|
|
12
|
+
onClickAndHoldRef.current();
|
|
13
|
+
// Wait before repeating
|
|
14
|
+
timerRef.current = setTimeout(() => {
|
|
15
|
+
// Repeat
|
|
16
|
+
onClickAndHoldRef.current();
|
|
17
|
+
timerRef.current = setInterval(() => {
|
|
18
|
+
onClickAndHoldRef.current();
|
|
19
|
+
}, interval);
|
|
20
|
+
}, startRepeatingDelay);
|
|
21
|
+
}, [interval, startRepeatingDelay]);
|
|
22
|
+
const stopTimer = useCallback(() => {
|
|
23
|
+
// setIsActive(false);
|
|
24
|
+
clearTimeout(timerRef.current);
|
|
25
|
+
clearInterval(timerRef.current);
|
|
26
|
+
}, []);
|
|
27
|
+
const handleHoldEnd = useCallback(() => {
|
|
28
|
+
// console.log("---------end", isActive);
|
|
29
|
+
// if (isActive) {
|
|
30
|
+
stopTimer();
|
|
31
|
+
onHoldEndRef.current?.();
|
|
32
|
+
// }
|
|
33
|
+
}, [
|
|
34
|
+
stopTimer,
|
|
35
|
+
// , isActive
|
|
36
|
+
]);
|
|
37
|
+
// Keep references updated to the latest callbacks
|
|
38
|
+
// This ensures the interval always calls the latest version
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
onClickAndHoldRef.current = onClickAndHold;
|
|
41
|
+
}, [onClickAndHold]);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
onClickAndHoldRef.current = onClickAndHold;
|
|
44
|
+
}, [onClickAndHold]);
|
|
45
|
+
// Use document on mouseup and touchend for nicer UX
|
|
7
46
|
useEffect(() => {
|
|
8
|
-
document.addEventListener("mouseup",
|
|
47
|
+
document.addEventListener("mouseup", handleHoldEnd);
|
|
48
|
+
document.addEventListener("touchend", handleHoldEnd);
|
|
9
49
|
return () => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
document.removeEventListener("
|
|
50
|
+
stopTimer();
|
|
51
|
+
document.removeEventListener("mouseup", handleHoldEnd);
|
|
52
|
+
document.removeEventListener("touchend", handleHoldEnd);
|
|
13
53
|
};
|
|
14
|
-
}, []);
|
|
15
|
-
|
|
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 }));
|
|
54
|
+
}, [handleHoldEnd]);
|
|
55
|
+
return (_jsx("button", { className: className, onMouseDown: startTimer, onTouchStart: startTimer, children: children }));
|
|
33
56
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { NumberControl } from "./number-control";
|
|
3
|
+
export const HpControl = ({ className = "", obj, step }) => {
|
|
4
|
+
if (obj.hp === undefined) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
return (_jsxs("div", { class: "hp-control ki-flex", children: [_jsx(NumberControl, { className: className, obj: obj, property: "hp", step: step }), " ", "(Max: ", obj.maxHP, ")"] }));
|
|
8
|
+
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { InspectorOptions
|
|
1
|
+
import type { InspectorOptions } from "../init";
|
|
2
2
|
export interface InspectorProps extends InspectorOptions {
|
|
3
|
-
k: KAPLAYCtxType;
|
|
4
3
|
}
|
|
5
|
-
export declare const Inspector: ({ initUpdateTimeout, isVisibleOnLoad, initDrawInspectOnHover,
|
|
4
|
+
export declare const Inspector: ({ initUpdateTimeout, isVisibleOnLoad, initDrawInspectOnHover, }: InspectorProps) => import("preact").JSX.Element;
|
|
@@ -3,6 +3,7 @@ import { useEffect, useRef, useState } from "preact/hooks";
|
|
|
3
3
|
import { GameObject } from "./game-object";
|
|
4
4
|
import { useObjectBoolean } from "./boolean-comp";
|
|
5
5
|
import { SearchResults } from "./search-results";
|
|
6
|
+
import { k } from "../k";
|
|
6
7
|
const INTERVAL_OPTIONS = [
|
|
7
8
|
{ value: 100, label: "100ms" },
|
|
8
9
|
{ value: 250, label: "250ms" },
|
|
@@ -10,7 +11,7 @@ const INTERVAL_OPTIONS = [
|
|
|
10
11
|
{ value: 1000, label: "1s" },
|
|
11
12
|
];
|
|
12
13
|
const TYPING_TIMEOUT = 250;
|
|
13
|
-
export const Inspector = ({ initUpdateTimeout = 250, isVisibleOnLoad = true, initDrawInspectOnHover = true,
|
|
14
|
+
export const Inspector = ({ initUpdateTimeout = 250, isVisibleOnLoad = true, initDrawInspectOnHover = true, }) => {
|
|
14
15
|
const [updateTimeout, setUpdateTimeout] = useState(initUpdateTimeout);
|
|
15
16
|
const [shouldDrawInspect, setShouldDrawInspect] = useState(initDrawInspectOnHover);
|
|
16
17
|
const [root, setRoot] = useState(k.getTreeRoot());
|
|
@@ -44,5 +45,5 @@ export const Inspector = ({ initUpdateTimeout = 250, isVisibleOnLoad = true, ini
|
|
|
44
45
|
if (!isVisible) {
|
|
45
46
|
return (_jsx("button", { class: "ki-btn k-inspector__show", onClick: toggleVisibility, children: "Show Inspector" }));
|
|
46
47
|
}
|
|
47
|
-
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, {
|
|
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 })) })] }));
|
|
48
49
|
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
+
import { NumberInput } from "./number-input";
|
|
3
|
+
export const NumberControl = ({ className = "", obj, property, step, }) => {
|
|
4
|
+
return (_jsx(NumberInput, { className: className, obj: obj, property: property, onChange: (n) => {
|
|
5
|
+
obj[property] = n;
|
|
6
|
+
}, step: step }));
|
|
7
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface NumberInputProps {
|
|
2
|
+
obj: Record<string, any>;
|
|
3
|
+
property: string;
|
|
4
|
+
onChange: (value: number) => void;
|
|
5
|
+
className?: string;
|
|
6
|
+
step?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare const NumberInput: ({ obj, property, className, onChange, step, }: NumberInputProps) => import("preact").JSX.Element | null;
|
|
@@ -0,0 +1,51 @@
|
|
|
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
|
+
import { toFixed } from "../lib/to-fixed";
|
|
5
|
+
import { HoldButton } from "./hold-button";
|
|
6
|
+
export const NumberInput = ({ obj, property, className = "", onChange, step = 1, }) => {
|
|
7
|
+
const [localValue, setLocalValue] = useState(toFixed(obj[property]).toString());
|
|
8
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
9
|
+
const [error, setError] = useState(false);
|
|
10
|
+
// Sync game state -> UI when input is not focused
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (!isFocused) {
|
|
13
|
+
setLocalValue(toFixed(obj[property]).toString());
|
|
14
|
+
}
|
|
15
|
+
}, [obj[property], isFocused]);
|
|
16
|
+
// Has to be after hooks
|
|
17
|
+
if (obj[property] === undefined) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const handleInput = (e) => {
|
|
21
|
+
const value = e.target.value;
|
|
22
|
+
setLocalValue(value);
|
|
23
|
+
const parsedValue = parseFloat(value);
|
|
24
|
+
if (!isNaN(value) && !Number.isNaN(parsedValue)) {
|
|
25
|
+
// Sync UI -> game state
|
|
26
|
+
onChange(parsedValue);
|
|
27
|
+
setError(false);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
setError(true);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const handleClickAndHold = (offset) => {
|
|
34
|
+
// Use local value so we don't wait for the inspector to re-render
|
|
35
|
+
const newValue = parseFloat(localValue) + offset;
|
|
36
|
+
// obj[property] = newValue;
|
|
37
|
+
onChange(newValue);
|
|
38
|
+
setLocalValue(toFixed(newValue).toString());
|
|
39
|
+
};
|
|
40
|
+
return (_jsxs("div", { class: cx(className, "number-input ki-flex"), children: [_jsx(HoldButton, { className: "ki-btn", onClickAndHold: () => handleClickAndHold(-step), onHoldEnd: () => {
|
|
41
|
+
// Final sync to ensure value is in sync
|
|
42
|
+
setLocalValue(toFixed(obj[property]).toString());
|
|
43
|
+
}, children: "-" }), _jsx("input", { class: cx("ki-input", {
|
|
44
|
+
"ki-input--error": error,
|
|
45
|
+
}), value: localValue, onInput: handleInput, onFocus: () => setIsFocused(true), onBlur: () => {
|
|
46
|
+
setIsFocused(false);
|
|
47
|
+
setError(false);
|
|
48
|
+
// Final sync to ensure value is in sync
|
|
49
|
+
setLocalValue(toFixed(obj[property]).toString());
|
|
50
|
+
} }), _jsx(HoldButton, { className: "ki-btn", onClickAndHold: () => handleClickAndHold(step), children: "+" })] }));
|
|
51
|
+
};
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import type { GameObj } from "kaplay";
|
|
2
|
-
import type { KAPLAYCtxType } from "../init";
|
|
3
2
|
export interface SearchResultsProps {
|
|
4
|
-
k: KAPLAYCtxType;
|
|
5
3
|
className?: string;
|
|
6
4
|
results: GameObj[];
|
|
7
5
|
setRenderRoot: (obj: GameObj) => void;
|
|
8
6
|
shouldDrawInspect: boolean;
|
|
9
7
|
}
|
|
10
|
-
export declare const SearchResults: ({
|
|
8
|
+
export declare const SearchResults: ({ results, setRenderRoot, shouldDrawInspect, }: SearchResultsProps) => import("preact").JSX.Element;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
2
|
import { GameObject } from "./game-object";
|
|
3
|
-
export const SearchResults = ({
|
|
3
|
+
export const SearchResults = ({ results, setRenderRoot, shouldDrawInspect, }) => {
|
|
4
4
|
if (results.length === 0) {
|
|
5
5
|
return _jsx("div", { children: "No results found." });
|
|
6
6
|
}
|
|
7
7
|
return (_jsxs("div", { children: [results.map((result) => {
|
|
8
|
-
return (_jsx(GameObject, {
|
|
8
|
+
return (_jsx(GameObject, { className: "game-object--root", obj: result, setRenderRoot: setRenderRoot, shouldDrawInspect: shouldDrawInspect }));
|
|
9
9
|
}), " "] }));
|
|
10
10
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-runtime";
|
|
2
|
+
export const SpriteControl = ({ obj }) => {
|
|
3
|
+
const object = obj;
|
|
4
|
+
const animation = object.getCurAnim();
|
|
5
|
+
return (_jsxs("div", { class: "sprite-control", 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
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
+
import { TextInput } from "./text-input";
|
|
3
|
+
export const TextControl = ({ obj }) => {
|
|
4
|
+
if (typeof obj.text !== "string") {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
return (_jsx("div", { class: "text-control", children: _jsx(TextInput, { className: "text-control__input ki-input", placeholder: "Enter text", value: obj.text, onChange: (text) => (obj.text = text) }) }));
|
|
8
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface TextInputProps {
|
|
2
|
+
className?: string;
|
|
3
|
+
value: string;
|
|
4
|
+
onChange: (text: string) => void;
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const TextInput: ({ className, value, onChange, placeholder, }: TextInputProps) => import("preact").JSX.Element | null;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "preact/hooks";
|
|
3
|
+
import { cx } from "../lib/cx";
|
|
4
|
+
export const TextInput = ({ className = "", value, onChange, placeholder = "", }) => {
|
|
5
|
+
const [localValue, setLocalValue] = useState(value.toString());
|
|
6
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
7
|
+
// Sync game state -> UI when input is not focused
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!isFocused) {
|
|
10
|
+
setLocalValue(value.toString());
|
|
11
|
+
}
|
|
12
|
+
}, [value, isFocused]);
|
|
13
|
+
if (value === undefined) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const handleInput = (e) => {
|
|
17
|
+
const value = e.target.value;
|
|
18
|
+
setLocalValue(value);
|
|
19
|
+
onChange(value);
|
|
20
|
+
};
|
|
21
|
+
return (_jsx("textarea", { class: cx(className, "text-input ki-input"), value: localValue, onInput: handleInput, placeholder: placeholder, onFocus: () => setIsFocused(true), onBlur: () => {
|
|
22
|
+
setIsFocused(false);
|
|
23
|
+
// Final sync to ensure value is in sync
|
|
24
|
+
setLocalValue(value);
|
|
25
|
+
} }));
|
|
26
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { cx } from "../lib/cx";
|
|
3
|
+
import { NumberInput } from "./number-input";
|
|
4
|
+
import { k } from "../k";
|
|
5
|
+
export const VectorControl = ({ className = "", obj, property, step, }) => {
|
|
6
|
+
if (obj[property] === undefined) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
return (_jsxs("div", { className: cx(className, "vector-control ki-flex"), children: ["x:", " ", _jsx(NumberInput, { className: "vector-control__x-input", obj: obj[property], property: "x", onChange: (x) => (obj[property] = k.vec2(x, obj[property].y)), step: step }), "y:", " ", _jsx(NumberInput, { obj: obj[property], property: "y", onChange: (y) => (obj[property] = k.vec2(obj[property].x, y)), step: step })] }));
|
|
10
|
+
};
|
package/dist/init.d.ts
CHANGED
package/dist/init.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
2
|
import { render } from "preact";
|
|
3
3
|
import { Inspector } from "./components/inspector";
|
|
4
|
+
import { setK } from "./k";
|
|
4
5
|
export default function init(k, props = {}) {
|
|
5
6
|
const { className = "", initUpdateTimeout = 250, isVisibleOnLoad = true, initDrawInspectOnHover = true, } = props;
|
|
7
|
+
// Set kaplay context to be imported directly from components to reduce prop drilling
|
|
8
|
+
setK(k);
|
|
6
9
|
const appElement = document.createElement("div");
|
|
7
10
|
appElement.className = `k-inspector ${className}`;
|
|
8
11
|
document.body.appendChild(appElement);
|
|
9
|
-
render(_jsx(Inspector, {
|
|
12
|
+
render(_jsx(Inspector, { initUpdateTimeout: initUpdateTimeout, isVisibleOnLoad: isVisibleOnLoad, initDrawInspectOnHover: initDrawInspectOnHover }), appElement);
|
|
10
13
|
}
|
package/dist/k.d.ts
ADDED
package/dist/k.js
ADDED
package/dist/lib/draw-bbox.d.ts
CHANGED
package/dist/lib/draw-bbox.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { k } from "../k";
|
|
1
2
|
const anchorMap = {
|
|
2
3
|
topleft: [-1, -1],
|
|
3
4
|
top: [0, -1],
|
|
@@ -9,7 +10,7 @@ const anchorMap = {
|
|
|
9
10
|
bot: [0, 1],
|
|
10
11
|
botright: [1, 1],
|
|
11
12
|
};
|
|
12
|
-
export const drawBoundingBox = (obj
|
|
13
|
+
export const drawBoundingBox = (obj) => {
|
|
13
14
|
if (obj.renderArea) {
|
|
14
15
|
const localArea = obj.renderArea();
|
|
15
16
|
const transform = obj.transform.clone();
|
|
@@ -40,7 +41,7 @@ export const drawBoundingBox = (obj, k) => {
|
|
|
40
41
|
}
|
|
41
42
|
obj.children.forEach((child) => {
|
|
42
43
|
if (!child.hidden) {
|
|
43
|
-
drawBoundingBox(child
|
|
44
|
+
drawBoundingBox(child);
|
|
44
45
|
}
|
|
45
46
|
});
|
|
46
47
|
};
|
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
2
|
import { stringify } from "./stringify";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { Color } from "../components/color-controls";
|
|
3
|
+
import { TextControl } from "../components/text-control";
|
|
4
|
+
import { SpriteControl } from "../components/sprite-control";
|
|
5
|
+
import { ColorControl } from "../components/color-control";
|
|
7
6
|
import { ChildObject } from "../components/child-object";
|
|
8
7
|
import { isGameObj } from "./is-game-obj";
|
|
8
|
+
import { AnchorControl } from "../components/anchor-control";
|
|
9
|
+
import { HpControl } from "../components/hp-control";
|
|
10
|
+
import { NumberControl } from "../components/number-control";
|
|
11
|
+
import { VectorControl } from "../components/vector-control";
|
|
12
|
+
import { BlendControl } from "../components/blend-control";
|
|
9
13
|
const componentMap = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
text: TextControl,
|
|
15
|
+
sprite: SpriteControl,
|
|
16
|
+
color: ColorControl,
|
|
17
|
+
anchor: AnchorControl,
|
|
18
|
+
health: HpControl,
|
|
19
|
+
blend: BlendControl,
|
|
20
|
+
// Vectors
|
|
21
|
+
pos: ({ obj }) => _jsx(VectorControl, { obj: obj, property: "pos" }),
|
|
22
|
+
scale: ({ obj }) => _jsx(VectorControl, { obj: obj, property: "scale", step: 0.1 }),
|
|
23
|
+
skew: ({ obj }) => _jsx(VectorControl, { obj: obj, property: "skew", step: 5 }),
|
|
24
|
+
// Numbers
|
|
25
|
+
opacity: ({ obj }) => (_jsx(NumberControl, { obj: obj, property: "opacity", step: 0.1 })),
|
|
26
|
+
rotate: ({ obj }) => _jsx(NumberControl, { obj: obj, property: "angle", step: 5 }),
|
|
27
|
+
z: ({ obj }) => _jsx(NumberControl, { obj: obj, property: "z" }),
|
|
14
28
|
};
|
|
15
29
|
export const inspectComps = (obj) => {
|
|
16
30
|
const object = obj;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const toFixed: (value: number, decimalPlaces?: number) => number;
|
package/dist/styles.css
CHANGED
|
@@ -73,6 +73,22 @@
|
|
|
73
73
|
color: inherit;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
textarea {
|
|
77
|
+
field-sizing: content;
|
|
78
|
+
max-height: 6rem;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
input::-webkit-outer-spin-button,
|
|
82
|
+
input::-webkit-inner-spin-button {
|
|
83
|
+
-webkit-appearance: none;
|
|
84
|
+
margin: 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
input[type="number"] {
|
|
88
|
+
-moz-appearance: textfield;
|
|
89
|
+
appearance: textfield;
|
|
90
|
+
}
|
|
91
|
+
|
|
76
92
|
button {
|
|
77
93
|
border: none;
|
|
78
94
|
cursor: pointer;
|
|
@@ -100,6 +116,14 @@
|
|
|
100
116
|
border: 1px solid var(--ki-primary);
|
|
101
117
|
}
|
|
102
118
|
|
|
119
|
+
.ki-btn--red {
|
|
120
|
+
color: var(--ki-red);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.ki-btn--red:hover {
|
|
124
|
+
border: 1px solid var(--ki-red);
|
|
125
|
+
}
|
|
126
|
+
|
|
103
127
|
.ki-input {
|
|
104
128
|
background-color: var(--ki-bg);
|
|
105
129
|
border: none;
|
|
@@ -114,6 +138,11 @@
|
|
|
114
138
|
border-color: var(--ki-primary);
|
|
115
139
|
}
|
|
116
140
|
|
|
141
|
+
.ki-input--error,
|
|
142
|
+
.ki-input--error:focus-visible {
|
|
143
|
+
border-color: var(--ki-red);
|
|
144
|
+
}
|
|
145
|
+
|
|
117
146
|
/* Main layout */
|
|
118
147
|
|
|
119
148
|
.k-inspector__header {
|
|
@@ -309,35 +338,62 @@
|
|
|
309
338
|
padding-bottom: 1rem;
|
|
310
339
|
}
|
|
311
340
|
|
|
312
|
-
/*
|
|
341
|
+
/* Flex layout for controls */
|
|
313
342
|
|
|
314
|
-
.
|
|
343
|
+
.ki-flex {
|
|
315
344
|
display: flex;
|
|
316
|
-
align-items: center;
|
|
317
345
|
gap: 0.25rem;
|
|
318
|
-
|
|
319
|
-
min-width: 12rem;
|
|
346
|
+
align-items: center;
|
|
320
347
|
}
|
|
321
348
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
349
|
+
/* Number input */
|
|
350
|
+
|
|
351
|
+
.number-input input {
|
|
352
|
+
width: 4.5rem;
|
|
326
353
|
}
|
|
327
354
|
|
|
328
|
-
|
|
329
|
-
|
|
355
|
+
/* Vector control */
|
|
356
|
+
|
|
357
|
+
.vector-control__x-input {
|
|
358
|
+
margin-right: 0.75rem; /* with gap it comes to 1rem */
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/* Blend control */
|
|
362
|
+
|
|
363
|
+
.blend-control {
|
|
364
|
+
display: grid;
|
|
365
|
+
gap: 0.25rem;
|
|
330
366
|
}
|
|
331
367
|
|
|
332
|
-
/* Text
|
|
368
|
+
/* Text control */
|
|
333
369
|
|
|
334
|
-
.text-
|
|
370
|
+
.text-control__input {
|
|
335
371
|
width: 100%;
|
|
336
372
|
}
|
|
337
373
|
|
|
374
|
+
/* Anchor control */
|
|
375
|
+
|
|
376
|
+
.anchor-control {
|
|
377
|
+
display: flex;
|
|
378
|
+
align-items: center;
|
|
379
|
+
gap: 1rem;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.anchor-radios {
|
|
383
|
+
text-align: center;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.anchor-row {
|
|
387
|
+
display: flex;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.anchor-radios label {
|
|
391
|
+
padding: 0.25rem;
|
|
392
|
+
}
|
|
393
|
+
|
|
338
394
|
/* Color */
|
|
339
395
|
|
|
340
|
-
.color-
|
|
396
|
+
.color-control {
|
|
341
397
|
display: flex;
|
|
342
398
|
align-items: center;
|
|
343
399
|
gap: 0.5rem;
|
|
@@ -345,28 +401,28 @@
|
|
|
345
401
|
min-width: 12rem;
|
|
346
402
|
}
|
|
347
403
|
|
|
348
|
-
.color-
|
|
404
|
+
.color-control__swatch {
|
|
349
405
|
width: 2rem;
|
|
350
406
|
height: 2rem;
|
|
351
407
|
border-radius: 8px;
|
|
352
408
|
border: 1px solid var(--ki-border-light);
|
|
353
409
|
}
|
|
354
410
|
|
|
355
|
-
.color-
|
|
411
|
+
.color-control__slider {
|
|
356
412
|
display: flex;
|
|
357
413
|
align-items: center;
|
|
358
414
|
gap: 0.25rem;
|
|
359
415
|
}
|
|
360
416
|
|
|
361
|
-
.color-
|
|
417
|
+
.color-control__slider-input--r {
|
|
362
418
|
accent-color: red;
|
|
363
419
|
}
|
|
364
420
|
|
|
365
|
-
.color-
|
|
421
|
+
.color-control__slider-input--g {
|
|
366
422
|
accent-color: green;
|
|
367
423
|
}
|
|
368
424
|
|
|
369
|
-
.color-
|
|
425
|
+
.color-control__slider-input--b {
|
|
370
426
|
accent-color: blue;
|
|
371
427
|
}
|
|
372
428
|
|
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.2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/init.js",
|
|
8
8
|
"types": "./dist/init.d.ts",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"prepublish": "npm run build-lib"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
|
-
"kaplay": "^4000.0.0-alpha.
|
|
24
|
+
"kaplay": "^4000.0.0-alpha.26"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"preact": "^10.28.2"
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"@preact/preset-vite": "^2.10.2",
|
|
31
31
|
"@types/node": "^25.0.6",
|
|
32
32
|
"typescript": "~5.9.3",
|
|
33
|
-
"vite": "^7.3.1"
|
|
33
|
+
"vite": "^7.3.1",
|
|
34
|
+
"kaplay": "^4000.0.0-alpha.26"
|
|
34
35
|
},
|
|
35
36
|
"repository": {
|
|
36
37
|
"type": "git",
|
package/public/screenshot.png
CHANGED
|
Binary file
|
|
@@ -1,24 +0,0 @@
|
|
|
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 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
-
import { roundToDecimal } from "../lib/round-to-decimal";
|
|
3
|
-
import { HoldButton } from "./hold-button";
|
|
4
|
-
import { ArrowDownIcon, ArrowLeftIcon, ArrowRightIcon, ArrowUpIcon, } from "./icons";
|
|
5
|
-
export const PositionControls = ({ obj }) => {
|
|
6
|
-
if (!obj.pos) {
|
|
7
|
-
return null;
|
|
8
|
-
}
|
|
9
|
-
return (_jsxs("div", { class: "pos-controls", children: [_jsx(HoldButton, { className: "ki-btn", onClickAndHold: () => obj.moveTo(obj.pos.x - 1, obj.pos.y), children: _jsx(ArrowLeftIcon, {}) }), _jsx(HoldButton, { className: "ki-btn", onClickAndHold: () => obj.moveTo(obj.pos.x + 1, obj.pos.y), 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.moveTo(obj.pos.x, obj.pos.y - 1), children: _jsx(ArrowUpIcon, {}) }), _jsx(HoldButton, { className: "ki-btn", onClickAndHold: () => obj.moveTo(obj.pos.x, obj.pos.y + 1), children: _jsx(ArrowDownIcon, {}) })] }));
|
|
10
|
-
};
|
|
@@ -1,6 +0,0 @@
|
|
|
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,16 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from "preact/hooks";
|
|
3
|
-
export const TextControls = ({ obj }) => {
|
|
4
|
-
const [text, setText] = useState(obj.text);
|
|
5
|
-
useEffect(() => {
|
|
6
|
-
setText(obj.text);
|
|
7
|
-
}, [obj.text]);
|
|
8
|
-
if (typeof obj.text !== "string") {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
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 }) }));
|
|
16
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const roundToDecimal: (value: number, decimalPlaces: number) => number;
|