@stanko/kaplay-inspector 0.1.1 → 0.1.3

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 CHANGED
@@ -11,8 +11,9 @@ A dev tool for [Kaplay](https://kaplayjs.com/) which allows you to explore and i
11
11
  - Hover an object to draw it's area, anchor and bounding box
12
12
  - Inspect object's component and custom props
13
13
  - Log an object to console
14
- - Tweak position and text
15
- - Pause an object
14
+ - Tweak position, text or color
15
+ - Pause objects
16
+ - Hide objects
16
17
  - Dark theme (is this a feature?)
17
18
 
18
19
  The layout is made with desktop in mind. That said, it is somewhat usable on phones.
@@ -52,7 +53,7 @@ if (
52
53
  }
53
54
  ```
54
55
 
55
- If typescript is complaining about importing CSS files, you probably need to add this to one of your `.d.ts` files.
56
+ If typescript is complaining about importing CSS files, you probably need to add this to `declaration.d.ts` file in you project's root.
56
57
 
57
58
  ```ts
58
59
  declare module '*.scss';
@@ -13,5 +13,15 @@ export const Breadcrumbs = ({ obj, setRenderRoot }) => {
13
13
  });
14
14
  parent = parent.parent;
15
15
  }
16
+ // TODO for destroyed objects always add root as a breadcrumb
17
+ // if (breadcrumbs.length === 0) {
18
+ // const root = k.getTreeRoot()
19
+ // breadcrumbs.push({
20
+ // id: root.id,
21
+ // tags: root.tags,
22
+ // compsLabel: root.compsLabel,
23
+ // object: root,
24
+ // });
25
+ // }
16
26
  return (_jsxs("div", { class: "breadcrumbs", children: ["Back to", breadcrumbs.map((breadcrumb) => (_jsxs("button", { class: "ki-btn", onClick: () => setRenderRoot(breadcrumb.object), children: ["ID ", breadcrumb.id, ": ", breadcrumb.tags || breadcrumb.compsLabel] })))] }));
17
27
  };
@@ -0,0 +1,6 @@
1
+ import type { GameObj } from "kaplay";
2
+ export interface ChildObjectProps {
3
+ className?: string;
4
+ obj: GameObj;
5
+ }
6
+ export declare const ChildObject: ({ className, obj }: ChildObjectProps) => import("preact").JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
+ export const ChildObject = ({ className = "", obj }) => {
3
+ return (_jsxs("div", { class: className, children: ["game object", " ", _jsx("button", { class: "ki-btn", onClick: () => console.log(obj), children: "log" })] }));
4
+ };
@@ -9,4 +9,4 @@ export interface GameObjectProps {
9
9
  shouldDrawInspect: boolean;
10
10
  k: KAPLAYCtxType;
11
11
  }
12
- export declare const GameObject: ({ obj, className, isExpanded: isExpandedExternal, isRenderRoot, setRenderRoot, shouldDrawInspect, k, }: GameObjectProps) => import("preact").JSX.Element;
12
+ export declare const GameObject: ({ obj, className, isExpanded: isExpandedExternal, isRenderRoot, setRenderRoot, shouldDrawInspect, k, }: GameObjectProps) => import("preact").JSX.Element | null;
@@ -14,24 +14,20 @@ export const GameObject = ({ obj, className = "", isExpanded: isExpandedExternal
14
14
  const isObjectDestroyed = !obj.exists() && !isRootObject;
15
15
  const showExpandTree = obj.children.length > 0;
16
16
  const hasChildren = obj.children.length > 0;
17
+ const hasSize = typeof obj.width === "number" && typeof obj.height === "number";
18
+ const isDrawController = compsData.length === 1 && compsData[0].tag === "draw";
17
19
  const isInspecting = isRenderRoot && obj.id !== 0;
18
20
  const cancelUpdateControllers = useCallback(() => {
19
21
  updateControllers.current.forEach((controller) => controller.cancel());
20
22
  updateControllers.current = [];
21
23
  }, []);
22
- const drawInspect = useCallback((obj, isChild = false) => {
24
+ const drawInspect = useCallback((obj) => {
23
25
  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
- }
26
+ const updateController = k.onDraw(() => {
29
27
  drawBoundingBox(obj, k);
28
+ obj.drawInspect();
30
29
  });
31
30
  updateControllers.current.push(updateController);
32
- obj.children.forEach((child) => {
33
- drawInspect(child, true);
34
- });
35
31
  }
36
32
  }, []);
37
33
  useEffect(() => {
@@ -48,12 +44,15 @@ export const GameObject = ({ obj, className = "", isExpanded: isExpandedExternal
48
44
  drawInspect(obj);
49
45
  }
50
46
  };
51
- const handleMouseLeave = () => {
52
- cancelUpdateControllers();
53
- };
47
+ // In Kaplay, onDraw and onUpdate are also game objects
48
+ // For now, I disabled displaying draw objects,
49
+ // mostly because inspector is adding them on hover, making the list jump around
50
+ if (isDrawController) {
51
+ return null;
52
+ }
54
53
  return (_jsxs("div", { class: cx("game-object", className, {
55
54
  "game-object--no-children": !hasChildren,
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", {
55
+ }), 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", {
57
56
  "game-object__header--expandable": showExpandTree,
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));
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, { k: k, obj: child, setRenderRoot: setRenderRoot, shouldDrawInspect: shouldDrawInspect }, child.id))) }))] }, obj.id));
59
58
  };
@@ -1,35 +1,35 @@
1
+ const anchorMap = {
2
+ topleft: [-1, -1],
3
+ top: [0, -1],
4
+ topright: [1, -1],
5
+ left: [-1, 0],
6
+ center: [0, 0],
7
+ right: [1, 0],
8
+ botleft: [-1, 1],
9
+ bot: [0, 1],
10
+ botright: [1, 1],
11
+ };
1
12
  export const drawBoundingBox = (obj, k) => {
2
13
  if (obj.renderArea) {
3
- const rect = obj.renderArea().bbox();
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;
14
+ const localArea = obj.renderArea();
15
+ const transform = obj.transform.clone();
16
+ let anchor = obj.anchor || "topleft";
17
+ if (localArea && obj.anchor !== "topleft") {
18
+ if (typeof anchor === "string") {
19
+ const coords = anchorMap[anchor];
20
+ anchor = new k.Vec2(coords[0], coords[1]);
24
21
  }
22
+ const offset = anchor
23
+ .add(1, 1)
24
+ .scale(-0.5 * localArea.width, -0.5 * localArea.height);
25
+ transform.translateSelfV(offset);
25
26
  }
26
- else {
27
- offset.x = (anchor.x * rect.width + 1) / 2 + rect.width / 2;
28
- offset.y = (anchor.y * rect.height + 1) / 2 + rect.height / 2;
29
- }
30
- rect.pos = rect.pos.sub(offset);
27
+ const worldArea = localArea.transform(transform);
28
+ const worldBBox = worldArea.bbox();
31
29
  k.drawRect({
32
- ...rect,
30
+ pos: worldBBox.pos,
31
+ width: worldBBox.width,
32
+ height: worldBBox.height,
33
33
  fill: false,
34
34
  outline: {
35
35
  width: 1,
@@ -38,4 +38,9 @@ export const drawBoundingBox = (obj, k) => {
38
38
  },
39
39
  });
40
40
  }
41
+ obj.children.forEach((child) => {
42
+ if (!child.hidden) {
43
+ drawBoundingBox(child, k);
44
+ }
45
+ });
41
46
  };
@@ -4,6 +4,8 @@ import { PositionControls } from "../components/position-controls";
4
4
  import { TextControls } from "../components/text-controls";
5
5
  import { SpriteControls } from "../components/sprite-controls";
6
6
  import { Color } from "../components/color-controls";
7
+ import { ChildObject } from "../components/child-object";
8
+ import { isGameObj } from "./is-game-obj";
7
9
  const componentMap = {
8
10
  pos: PositionControls,
9
11
  text: TextControls,
@@ -57,6 +59,12 @@ export const inspectComps = (obj) => {
57
59
  value: "function",
58
60
  });
59
61
  }
62
+ else if (isGameObj(value)) {
63
+ data.push({
64
+ tag: key,
65
+ value: _jsx(ChildObject, { obj: value }),
66
+ });
67
+ }
60
68
  else if (typeof value === "object") {
61
69
  data.push({
62
70
  tag: key,
@@ -0,0 +1,2 @@
1
+ import type { GameObj } from "kaplay";
2
+ export declare const isGameObj: (obj: any) => obj is GameObj;
@@ -0,0 +1,5 @@
1
+ export const isGameObj = (obj) => {
2
+ // I selected isAncestorOf as a property to check for
3
+ // it is really unlikely that a non-game object would have this property
4
+ return typeof obj === "object" && obj !== null && "isAncestorOf" in obj;
5
+ };
@@ -1,5 +1,6 @@
1
+ import { isGameObj } from "./is-game-obj";
1
2
  export const stringify = (obj, maxDepth = 1, currentDepth = 0) => {
2
- if (typeof obj !== "object" || obj === null) {
3
+ if (typeof obj !== "object") {
3
4
  return JSON.stringify(obj);
4
5
  }
5
6
  const lines = Object.entries(obj).map(([key, value]) => {
@@ -7,11 +8,14 @@ export const stringify = (obj, maxDepth = 1, currentDepth = 0) => {
7
8
  return `${key}: function`;
8
9
  }
9
10
  else if (typeof value === "object") {
11
+ if (isGameObj(value)) {
12
+ return `${key}: [GameObj]`;
13
+ }
10
14
  if (currentDepth < maxDepth) {
11
15
  return `${key}: ${stringify(value, maxDepth, currentDepth + 1)}`;
12
16
  }
13
17
  else {
14
- return `${key}: [Object object]`;
18
+ return `${key}: [Object]`;
15
19
  }
16
20
  }
17
21
  else {
package/dist/styles.css CHANGED
@@ -197,6 +197,11 @@
197
197
  width: calc(100% + 0.25rem);
198
198
  border-radius: 4px;
199
199
  outline-offset: 0;
200
+ position: sticky;
201
+ /* TODO add sticky header and sticky side buttons */
202
+ /*z-index: 1;
203
+ top: 2.625rem;
204
+ background-color: var(--ki-bg);*/
200
205
 
201
206
  svg rect {
202
207
  fill: var(--ki-bg);
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.1.1",
5
+ "version": "0.1.3",
6
6
  "type": "module",
7
7
  "main": "./dist/init.js",
8
8
  "types": "./dist/init.d.ts",
Binary file