diff --git a/playground/csharp/Program.cs b/playground/csharp/Program.cs
index b07ef27..ad936c4 100644
--- a/playground/csharp/Program.cs
+++ b/playground/csharp/Program.cs
@@ -46,6 +46,37 @@ int test(int a, int b)
Z = 37,
};
+var nested = new NestedClass
+{
+ mat = new Matrix()
+ {
+ Row0 = new Vector
+ {
+ X = 32,
+ Y = 64,
+ Z = 128,
+ },
+
+ Row1 = new Vector
+ {
+ X = 1,
+ Y = 2,
+ Z = 3,
+ },
+
+ Row2 = new Vector
+ {
+ X = 5,
+ Y = 6,
+ Z = 9,
+ },
+ },
+
+ name = "mat",
+ age = 33
+};
+
+
var result = mat.Apply(vec);
for (int i = 0; i < 10; ++i)
@@ -77,3 +108,11 @@ public Vector Apply(Vector target)
};
}
}
+
+class NestedClass
+{
+ public required Matrix mat { get; init; }
+ public required string name { get; init; }
+ public required int age { get; init; }
+}
+
diff --git a/server/index.html b/server/index.html
index 6aa221d..d219c58 100644
--- a/server/index.html
+++ b/server/index.html
@@ -10,7 +10,7 @@
dapviz
-
+
diff --git a/server/src/App.tsx b/server/src/App.tsx
index ac6e8c9..75beec0 100644
--- a/server/src/App.tsx
+++ b/server/src/App.tsx
@@ -3,6 +3,7 @@ import DapvizProvider, { useDapviz } from "./DapvizProvider";
import Visualizer from "./Visualizer";
import Controls from "./Controls";
import { useState } from "react";
+import { ThemeProvider } from "./ThemeProvider";
const NoConnectionError = () => (
No Connection
@@ -24,11 +25,13 @@ const DapvizApp = () => {
}
const App = () => (
- }
- >
-
-
+
+ }
+ >
+
+
+
);
export default App;
diff --git a/server/src/HeapConnectionsProvider.tsx b/server/src/HeapConnectionsProvider.tsx
new file mode 100644
index 0000000..8ddc82a
--- /dev/null
+++ b/server/src/HeapConnectionsProvider.tsx
@@ -0,0 +1,141 @@
+import { Variable } from "./DapvizProvider";
+import { QuadraticBezierLine, QuadraticBezierLineRef } from "@react-three/drei";
+import React, { createContext, useContext, useMemo, useRef } from "react";
+import { useCallback, useState } from "react";
+import * as THREE from "three";
+import { useFrame } from "@react-three/fiber";
+import { useTheme } from "./ThemeProvider";
+
+export type HeapConnectionContextType = {
+ registerNode: (id: number, ref: React.RefObject) => void;
+ unregisterNode: (id: number) => void;
+};
+
+export const HeapConnectionContext = createContext(null);
+
+export const useHeapConnections = () => {
+ const context = useContext(HeapConnectionContext);
+ if (!context) {
+ throw new Error("useHeapConnections called outside of HeapConnectionsProvider");
+ }
+ return context;
+}
+
+interface ConnectionLineProps {
+ parentRef: React.RefObject;
+ childRef: React.RefObject;
+}
+
+const ConnectionLine = ({ parentRef, childRef }: ConnectionLineProps) => {
+ const theme = useTheme();
+
+ const lineRef = useRef(null);
+
+ const startCircleRef = useRef(null);
+ const endCircleRef = useRef(null);
+
+ useFrame(() => {
+ if (!parentRef.current || !childRef.current || !lineRef.current) return;
+
+ const startPos = new THREE.Vector3();
+ const endPos = new THREE.Vector3();
+ const midPos = new THREE.Vector3();
+ const box = new THREE.Box3();
+ const size = new THREE.Vector3();
+
+ parentRef.current.getWorldPosition(startPos);
+ childRef.current.getWorldPosition(endPos);
+
+ box.setFromObject(parentRef.current);
+ box.getSize(size);
+ const startOffset = size.x / 2;
+
+ box.setFromObject(childRef.current);
+ box.getSize(size);
+ const endOffset = size.x / 2;
+
+ const padding = 3;
+
+ const finalStart = startPos.clone();
+ finalStart.x += startOffset + padding;
+
+ const finalEnd = endPos.clone();
+ finalEnd.x -= endOffset + padding;
+
+ midPos.addVectors(finalStart, finalEnd).multiplyScalar(0.5);
+ midPos.y += 80;
+
+ lineRef.current.setPoints(finalStart, finalEnd, midPos);
+ startCircleRef.current?.position.copy(finalStart);
+ endCircleRef.current?.position.copy(finalEnd);
+ });
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
+
+type VariableWithParent = Variable & { parent: NonNullable };
+
+function hasParent(v: Variable): v is VariableWithParent {
+ return !!v.parent && v.reference > 0;
+}
+
+export const HeapConnectionsProvider = ({ children, allVariables }: { children: React.ReactNode, allVariables: Variable[] }) => {
+ const [nodeRefs, setNodeRefs] = useState