diff --git a/client/src/components/PedigreeTree.jsx b/client/src/components/PedigreeTree.jsx
new file mode 100644
index 0000000..ee72413
--- /dev/null
+++ b/client/src/components/PedigreeTree.jsx
@@ -0,0 +1,167 @@
+import { useState, useCallback, useEffect } from 'react'
+import Tree from 'react-d3-tree'
+import { ZoomIn, ZoomOut, Maximize2, Download } from 'lucide-react'
+import './PedigreeTree.css'
+
+const PedigreeTree = ({ dogId, pedigreeData, coi }) => {
+ const [translate, setTranslate] = useState({ x: 0, y: 0 })
+ const [zoom, setZoom] = useState(0.8)
+ const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
+
+ useEffect(() => {
+ const updateDimensions = () => {
+ const container = document.getElementById('tree-container')
+ if (container) {
+ setDimensions({
+ width: container.offsetWidth,
+ height: container.offsetHeight
+ })
+ setTranslate({
+ x: container.offsetWidth / 4,
+ y: container.offsetHeight / 2
+ })
+ }
+ }
+
+ updateDimensions()
+ window.addEventListener('resize', updateDimensions)
+ return () => window.removeEventListener('resize', updateDimensions)
+ }, [])
+
+ const handleZoomIn = () => setZoom(z => Math.min(z + 0.2, 2))
+ const handleZoomOut = () => setZoom(z => Math.max(z - 0.2, 0.2))
+ const handleReset = () => {
+ setZoom(0.8)
+ setTranslate({
+ x: dimensions.width / 4,
+ y: dimensions.height / 2
+ })
+ }
+
+ const renderCustomNode = ({ nodeDatum, toggleNode }) => {
+ const isMale = nodeDatum.attributes?.sex === 'male'
+ const nodeColor = isMale ? '#3b82f6' : '#ec4899'
+
+ return (
+