diff --git a/packages/client/src/components/App.tsx b/packages/client/src/components/App.tsx
index 63eb065..38494e6 100644
--- a/packages/client/src/components/App.tsx
+++ b/packages/client/src/components/App.tsx
@@ -4,6 +4,7 @@ import { CanvasWrapper } from "./CanvasWrapper";
import { Pallete } from "./Pallete";
import { TemplateContext } from "../contexts/TemplateContext";
import { SettingsSidebar } from "./Settings/SettingsSidebar";
+import { DebugModal } from "./Debug/DebugModal";
const App = () => {
return (
@@ -13,6 +14,7 @@ const App = () => {
+
diff --git a/packages/client/src/components/Debug/DebugModal.tsx b/packages/client/src/components/Debug/DebugModal.tsx
new file mode 100644
index 0000000..f629e75
--- /dev/null
+++ b/packages/client/src/components/Debug/DebugModal.tsx
@@ -0,0 +1,66 @@
+import { useEffect, useState } from "react";
+import { Debug, FlagCategory } from "@sc07-canvas/lib/src/debug";
+import {
+ Button,
+ Modal,
+ ModalBody,
+ ModalContent,
+ ModalFooter,
+ ModalHeader,
+ Switch,
+ useDisclosure,
+} from "@nextui-org/react";
+
+export const DebugModal = () => {
+ const { isOpen, onOpen, onOpenChange } = useDisclosure();
+
+ useEffect(() => {
+ const handleOpen = () => {
+ onOpen();
+ };
+
+ Debug.on("openTools", handleOpen);
+
+ return () => {
+ Debug.off("openTools", handleOpen);
+ };
+ }, []);
+
+ return (
+
+
+ {(onClose) => (
+ <>
+
+ Debug Tools
+
+
+
+ {Debug.flags.getAll().map((flag, i, arr) => (
+ <>
+ {arr[i - 1]?.category !== flag.category && (
+ {FlagCategory[flag.category]}
+ )}
+
+ Debug.flags.setEnabled(flag.id, v)}
+ >
+ {flag.id}
+
+
+ >
+ ))}
+
+
+
+
+ >
+ )}
+
+
+ );
+};
diff --git a/packages/client/src/components/Header.tsx b/packages/client/src/components/Header.tsx
index af3c1f3..2f2788e 100644
--- a/packages/client/src/components/Header.tsx
+++ b/packages/client/src/components/Header.tsx
@@ -1,6 +1,7 @@
import { Button } from "@nextui-org/react";
import { useAppContext } from "../contexts/AppContext";
import { User } from "./Header/User";
+import { Debug } from "@sc07-canvas/lib/src/debug";
export const Header = () => {
const { setSettingsSidebar } = useAppContext();
@@ -12,6 +13,7 @@ export const Header = () => {
+
);
diff --git a/packages/lib/src/debug.ts b/packages/lib/src/debug.ts
new file mode 100644
index 0000000..e615768
--- /dev/null
+++ b/packages/lib/src/debug.ts
@@ -0,0 +1,185 @@
+import EventEmitter from "eventemitter3";
+
+interface DebugEvents {
+ openTools(): void;
+}
+
+interface DebugArgs {
+ point: [x: number, y: number, id?: string];
+ text: [str: any];
+}
+
+export enum FlagCategory {
+ "Renderer",
+ "DebugMessages",
+ "Uncategorized",
+}
+
+class ExperimentFlag {
+ id: string;
+ enabled: boolean;
+ category: FlagCategory = FlagCategory.Uncategorized;
+
+ constructor(id: string, defaultEnabled = false, category?: FlagCategory) {
+ this.id = id;
+ this.enabled = defaultEnabled;
+ if (category) this.category = category;
+ }
+}
+
+interface FlagEvents {
+ enable(flag_id: string): void;
+ disable(flag_id: string): void;
+}
+
+class FlagManager extends EventEmitter {
+ flags: ExperimentFlag[];
+
+ constructor() {
+ super();
+ this.flags = [];
+
+ this.register(
+ // RENDERER
+ new ExperimentFlag(
+ "PANZOOM_PINCH_TRANSFORM_1",
+ false,
+ FlagCategory.Renderer
+ ),
+ new ExperimentFlag(
+ "PANZOOM_PINCH_TRANSFORM_2",
+ false,
+ FlagCategory.Renderer
+ ),
+
+ // DEBUG MESSAGES
+ new ExperimentFlag(
+ "PANZOOM_PINCH_DEBUG_MESSAGES",
+ false,
+ FlagCategory.DebugMessages
+ )
+ );
+ }
+
+ register(...flags: ExperimentFlag[]) {
+ this.flags.push(...flags);
+ }
+
+ getFlag(flag: string) {
+ return this.flags.find((f) => f.id === flag);
+ }
+
+ enabled(flag: string) {
+ return this.getFlag(flag)?.enabled;
+ }
+
+ setEnabled(flagID: string, enabled: boolean) {
+ const flag = this.flags.find((f) => f.id === flagID);
+ if (!flag) throw new Error("Unknown flag " + flagID);
+
+ flag.enabled = enabled;
+
+ if (enabled) {
+ this.emit("enable", flagID);
+ } else {
+ this.emit("disable", flagID);
+ }
+ }
+
+ getAll() {
+ return [...this.flags].sort((a, b) => a.category - b.category);
+ }
+}
+
+/**
+ * Debug wrapper
+ *
+ * Goals:
+ * - toggle debug flags (similar to Discord experiments)
+ * - open blank debug tab with useragent and any flags
+ */
+class Debugcl extends EventEmitter {
+ readonly flags = new FlagManager();
+
+ constructor() {
+ super();
+ }
+
+ openDebug() {
+ const wind = window.open("about:blank", "_blank");
+ if (!wind) {
+ alert(
+ "Failed to open debug tab. Is your anti-popup too powerful? Or did this get triggered from not a trusted event"
+ );
+ return;
+ }
+
+ wind.document.write(`
+ debug menu
+ ${JSON.stringify(
+ {
+ userAgent: navigator.userAgent,
+ flags: this.flags
+ .getAll()
+ .filter((f) => f.enabled)
+ .map((f) => f.id),
+ },
+ null,
+ 2
+ )}
+ `);
+ wind.document.close();
+ }
+
+ openDebugTools() {
+ this.emit("openTools");
+ }
+
+ /**
+ * Create debug marker
+ *
+ * Useful on touchscreen devices
+ *
+ * @param type
+ * @param args
+ * @returns
+ */
+ debug(type: T, ...args: DebugArgs[T]) {
+ switch (type) {
+ case "point": {
+ const [x, y, id] = args;
+
+ if (document.getElementById("debug-" + id)) {
+ document.getElementById("debug-" + id)!.style.top = y + "px";
+ document.getElementById("debug-" + id)!.style.left = x + "px";
+ return;
+ }
+ let el = document.createElement("div");
+ if (id) el.id = "debug-" + id;
+ el.classList.add("debug-point");
+ el.style.setProperty("top", y + "px");
+ el.style.setProperty("left", x + "px");
+ document.body.appendChild(el);
+ break;
+ }
+ case "text": {
+ const [str] = args;
+
+ // create debug box in canvas-meta if it doesn't exist
+ if (!document.getElementById("canvas-meta-debug")) {
+ let debugBox = document.createElement("div");
+ debugBox.id = "canvas-meta-debug";
+ debugBox.style.whiteSpace = "pre";
+ debugBox.style.unicodeBidi = "embed";
+ document.getElementById("canvas-meta")!.prepend(debugBox);
+ }
+
+ document.getElementById("canvas-meta-debug")!.innerText =
+ typeof str === "string" ? str : JSON.stringify(str, null, 2);
+ break;
+ }
+ }
+ }
+}
+
+export const Debug = new Debugcl();
diff --git a/packages/lib/src/renderer/lib/zoom.utils.ts b/packages/lib/src/renderer/lib/zoom.utils.ts
index 3d2752a..5c45f0c 100644
--- a/packages/lib/src/renderer/lib/zoom.utils.ts
+++ b/packages/lib/src/renderer/lib/zoom.utils.ts
@@ -1,3 +1,4 @@
+import { Debug } from "../../debug";
import { PanZoom } from "../PanZoom";
export function handleCalculateZoomPositions(
@@ -17,7 +18,7 @@ export function handleCalculateZoomPositions(
const calculatedPositionX = x - mouseX * scaleDifference;
const calculatedPositionY = y - mouseY * scaleDifference;
- contextInstance.debug(calculatedPositionX, calculatedPositionY, "zoom");
+ // Debug.debug("point", calculatedPositionX, calculatedPositionY, "zoom");
// do not limit to bounds when there is padding animation,
// it causes animation strange behaviour