diff --git a/src/modules/simulationRenderer/helpers/clearCanvas.ts b/src/common/canvas/helpers/clearCanvas.ts
similarity index 62%
rename from src/modules/simulationRenderer/helpers/clearCanvas.ts
rename to src/common/canvas/helpers/clearCanvas.ts
index 30ec5f1..b707e06 100644
--- a/src/modules/simulationRenderer/helpers/clearCanvas.ts
+++ b/src/common/canvas/helpers/clearCanvas.ts
@@ -1,4 +1,4 @@
-import { SimulationRenderer } from '../classes/SimulationRenderer'
+import { SimulationRenderer } from '../../../modules/simulationRenderer/classes/SimulationRenderer'
 
 export const clearCanvas = (
     ctx: CanvasRenderingContext2D,
diff --git a/src/modules/simulationRenderer/helpers/drawPolygon.ts b/src/common/canvas/helpers/drawPolygon.ts
similarity index 84%
rename from src/modules/simulationRenderer/helpers/drawPolygon.ts
rename to src/common/canvas/helpers/drawPolygon.ts
index c427cea..a5ab378 100644
--- a/src/modules/simulationRenderer/helpers/drawPolygon.ts
+++ b/src/common/canvas/helpers/drawPolygon.ts
@@ -1,4 +1,4 @@
-import { vector2 } from '../../simulation/classes/Transform'
+import { vector2 } from '../../math/types/vector2'
 
 export const drawPolygon = (
     ctx: CanvasRenderingContext2D,
diff --git a/src/common/canvas/helpers/drawRotatedSquare.ts b/src/common/canvas/helpers/drawRotatedSquare.ts
new file mode 100644
index 0000000..f5e4ebf
--- /dev/null
+++ b/src/common/canvas/helpers/drawRotatedSquare.ts
@@ -0,0 +1,33 @@
+import { Transform } from '../../math/classes/Transform'
+import { Material, Shape } from '../../../modules/simulation/types/GateTemplate'
+import { roundRect } from './drawRoundedSquare'
+
+export const drawRotatedSquare = (
+    ctx: CanvasRenderingContext2D,
+    { position, scale, rotation }: Transform,
+    shape: Shape
+) => {
+    ctx.save()
+
+    ctx.translate(...position)
+    ctx.translate(scale[0] / 2, scale[1] / 2)
+
+    ctx.rotate(rotation)
+
+    if (shape.rounded) {
+        roundRect(
+            ctx,
+            -scale[0] / 2,
+            -scale[1] / 2,
+            scale[0],
+            scale[1],
+            shape.radius
+        )
+
+        ctx.fill()
+    } else {
+        ctx.fillRect(scale[0] / -2, scale[1] / -2, ...scale)
+    }
+
+    ctx.restore()
+}
diff --git a/src/common/canvas/helpers/drawRoundedSquare.ts b/src/common/canvas/helpers/drawRoundedSquare.ts
new file mode 100644
index 0000000..70f2c00
--- /dev/null
+++ b/src/common/canvas/helpers/drawRoundedSquare.ts
@@ -0,0 +1,23 @@
+/**
+ * Credit: https://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas
+ */
+export function roundRect(
+    ctx: CanvasRenderingContext2D,
+    x: number,
+    y: number,
+    width: number,
+    height: number,
+    radius: number = 5
+) {
+    ctx.beginPath()
+    ctx.moveTo(x + radius, y)
+    ctx.lineTo(x + width - radius, y)
+    ctx.quadraticCurveTo(x + width, y, x + width, y + radius)
+    ctx.lineTo(x + width, y + height - radius)
+    ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height)
+    ctx.lineTo(x + radius, y + height)
+    ctx.quadraticCurveTo(x, y + height, x, y + height - radius)
+    ctx.lineTo(x, y + radius)
+    ctx.quadraticCurveTo(x, y, x + radius, y)
+    ctx.closePath()
+}
diff --git a/src/common/canvas/helpers/useTransform.ts b/src/common/canvas/helpers/useTransform.ts
new file mode 100644
index 0000000..485be0d
--- /dev/null
+++ b/src/common/canvas/helpers/useTransform.ts
@@ -0,0 +1,14 @@
+import { Transform } from '../../math/classes/Transform'
+import { multiply } from '../../../modules/vector2/helpers/basic'
+
+export const useTransform = (
+    ctx: CanvasRenderingContext2D,
+    { position, rotation, scale }: Transform
+) => {
+    ctx.translate(...position)
+    ctx.translate(scale[0] / 2, scale[1] / 2)
+
+    ctx.rotate(rotation)
+
+    return new Transform(multiply(scale, -0.5), scale, 0)
+}
diff --git a/src/modules/simulation/classes/Transform.ts b/src/common/math/classes/Transform.ts
similarity index 93%
rename from src/modules/simulation/classes/Transform.ts
rename to src/common/math/classes/Transform.ts
index 0ae15cb..cf2dcba 100644
--- a/src/modules/simulation/classes/Transform.ts
+++ b/src/common/math/classes/Transform.ts
@@ -1,19 +1,5 @@
-import { allCombinations } from '../helpers/allCombinations'
-import { rotateAroundVector } from '../../vector2/helpers/rotate'
-
-export type vector2 = [number, number]
-export type vector3 = [number, number, number]
-export type vector4 = [number, number, number, number]
-export type vector8 = [
-    number,
-    number,
-    number,
-    number,
-    number,
-    number,
-    number,
-    number
-]
+import { allCombinations } from '../../../modules/simulation/helpers/allCombinations'
+import { rotateAroundVector } from '../../../modules/vector2/helpers/rotate'
 
 export class Transform {
     public constructor(
@@ -106,3 +92,17 @@ export class Transform {
         this.scale = [this.width, value]
     }
 }
+
+export type vector2 = [number, number]
+export type vector3 = [number, number, number]
+export type vector4 = [number, number, number, number]
+export type vector8 = [
+    number,
+    number,
+    number,
+    number,
+    number,
+    number,
+    number,
+    number
+]
diff --git a/src/common/math/helpers/pointInCircle.ts b/src/common/math/helpers/pointInCircle.ts
new file mode 100644
index 0000000..3495643
--- /dev/null
+++ b/src/common/math/helpers/pointInCircle.ts
@@ -0,0 +1,10 @@
+import { vector2 } from '../types/vector2'
+import { length, relativeTo } from '../../../modules/vector2/helpers/basic'
+
+export const pointInCircle = (
+    point: vector2,
+    center: vector2,
+    radius: number
+) => {
+    return length(relativeTo(point, center)) < radius
+}
diff --git a/src/modules/simulationRenderer/helpers/pointInSquare.ts b/src/common/math/helpers/pointInSquare.ts
similarity index 70%
rename from src/modules/simulationRenderer/helpers/pointInSquare.ts
rename to src/common/math/helpers/pointInSquare.ts
index f250c60..516bfe8 100644
--- a/src/modules/simulationRenderer/helpers/pointInSquare.ts
+++ b/src/common/math/helpers/pointInSquare.ts
@@ -1,4 +1,5 @@
-import { vector2, Transform } from '../../simulation/classes/Transform'
+import { Transform } from '../classes/Transform'
+import { vector2 } from '../types/vector2'
 
 export const pointInSquare = (point: vector2, square: Transform) => {
     return (
diff --git a/src/common/math/types/vector2.ts b/src/common/math/types/vector2.ts
new file mode 100644
index 0000000..9af9e28
--- /dev/null
+++ b/src/common/math/types/vector2.ts
@@ -0,0 +1 @@
+export type vector2 = [number, number]
diff --git a/src/common/math/types/vector3.ts b/src/common/math/types/vector3.ts
new file mode 100644
index 0000000..f4efc70
--- /dev/null
+++ b/src/common/math/types/vector3.ts
@@ -0,0 +1 @@
+export type vector3 = [number, number, number]
diff --git a/src/common/math/types/vector4.ts b/src/common/math/types/vector4.ts
new file mode 100644
index 0000000..aedce11
--- /dev/null
+++ b/src/common/math/types/vector4.ts
@@ -0,0 +1 @@
+export type vector4 = [number, number, number, number]
diff --git a/src/common/math/types/vector8.ts b/src/common/math/types/vector8.ts
new file mode 100644
index 0000000..cfe24a1
--- /dev/null
+++ b/src/common/math/types/vector8.ts
@@ -0,0 +1,10 @@
+export type vector8 = [
+    number,
+    number,
+    number,
+    number,
+    number,
+    number,
+    number,
+    number
+]
diff --git a/src/modules/core/components/App.scss b/src/modules/core/components/App.scss
index 63eaa94..0dbfb1a 100644
--- a/src/modules/core/components/App.scss
+++ b/src/modules/core/components/App.scss
@@ -5,3 +5,7 @@ body {
     display: block;
     overflow: hidden;
 }
+
+canvas {
+    background-color: #222222;
+}
diff --git a/src/modules/core/components/Canvas.tsx b/src/modules/core/components/Canvas.tsx
index bf278c1..f6fb956 100644
--- a/src/modules/core/components/Canvas.tsx
+++ b/src/modules/core/components/Canvas.tsx
@@ -15,14 +15,22 @@ class Canvas extends Component {
     public constructor(props: {}) {
         super(props)
 
-        const foo = new Gate('blue')
-        const bar = new Gate('green')
+        const foo = new Gate({
+            material: {
+                value: 'blue'
+            }
+        })
+        const bar = new Gate({
+            material: {
+                value: 'green'
+            }
+        })
 
         foo.transform.position = [100, 100]
-        foo.transform.scale = [70, 70]
+        foo.transform.scale = [100, 100]
 
-        bar.transform.position = [200, 200]
-        bar.transform.scale = [70, 70]
+        bar.transform.position = [400, 200]
+        bar.transform.scale = [100, 100]
 
         this.renderer.simulation.push(foo, bar)
 
diff --git a/src/modules/core/components/FluidCanvas.tsx b/src/modules/core/components/FluidCanvas.tsx
index 51576ac..cb01886 100644
--- a/src/modules/core/components/FluidCanvas.tsx
+++ b/src/modules/core/components/FluidCanvas.tsx
@@ -2,7 +2,7 @@ import React, { RefObject, forwardRef, MouseEvent } from 'react'
 import { useObservable } from 'rxjs-hooks'
 import { Screen } from '../classes/Screen'
 import { Subject } from 'rxjs'
-import { vector2 } from '../../simulation/classes/Transform'
+import { vector2 } from '../../../common/math/types/vector2'
 
 const screen = new Screen()
 
diff --git a/src/modules/simulation/classes/Gate.ts b/src/modules/simulation/classes/Gate.ts
index 8d930fc..3c0663d 100644
--- a/src/modules/simulation/classes/Gate.ts
+++ b/src/modules/simulation/classes/Gate.ts
@@ -1,9 +1,64 @@
-import { Transform } from './Transform'
+import { Transform } from '../../../common/math/classes/Transform'
+import { Pin } from './Pin'
+import merge from 'deepmerge'
+import { GateTemplate, PinCount } from '../types/GateTemplate'
+import { DefaultGateTemplate } from '../constants'
+
+export interface GatePins {
+    inputs: Pin[]
+    outputs: Pin[]
+}
+
+export interface PinWrapper {
+    total: number
+    index: number
+    value: Pin
+}
 
 export class Gate {
     public static lastId = 0
+
     public transform = new Transform()
     public id = Gate.lastId++
+    public _pins: GatePins = {
+        inputs: [],
+        outputs: []
+    }
 
-    public constructor(public color = 'blue') {}
+    public template: GateTemplate
+
+    public constructor(template: DeepPartial<GateTemplate> = {}) {
+        this.template = merge(DefaultGateTemplate, template) as GateTemplate
+
+        this._pins.inputs = Gate.generatePins(this.template.pins.inputs, 1)
+        this._pins.outputs = Gate.generatePins(this.template.pins.outputs, 2)
+    }
+
+    private wrapPins(pins: Pin[]) {
+        const result: PinWrapper[] = []
+        const length = pins.length
+
+        for (let index = 0; index < length; index++) {
+            result.push({
+                index,
+                total: length,
+                value: pins[index]
+            })
+        }
+
+        return result
+    }
+
+    public get pins() {
+        const result = [
+            ...this.wrapPins(this._pins.inputs),
+            ...this.wrapPins(this._pins.outputs)
+        ]
+
+        return result
+    }
+
+    private static generatePins(options: PinCount, type: number) {
+        return [...Array(options.count)].fill(true).map(() => new Pin(type))
+    }
 }
diff --git a/src/modules/simulation/classes/Pin.ts b/src/modules/simulation/classes/Pin.ts
index 4b48da7..e097b78 100644
--- a/src/modules/simulation/classes/Pin.ts
+++ b/src/modules/simulation/classes/Pin.ts
@@ -1,6 +1,12 @@
 import { SubscriptionData } from '../types/SubscriptionData'
 import { BehaviorSubject } from 'rxjs'
 
+/* Types:
+
+First bit = input
+Second bit = output
+
+*/
 export class Pin {
     public state = new BehaviorSubject(false)
     public connectedTo = new Set<Pin>()
@@ -8,6 +14,8 @@ export class Pin {
     private pairs = new Set<Pin>()
     private subscriptions: SubscriptionData<Pin>[] = []
 
+    public constructor(public type = 0b01) {}
+
     public addPair(pin: Pin) {
         this.pairs.add(pin)
 
diff --git a/src/modules/simulation/constants.ts b/src/modules/simulation/constants.ts
new file mode 100644
index 0000000..4dcf074
--- /dev/null
+++ b/src/modules/simulation/constants.ts
@@ -0,0 +1,22 @@
+import { GateTemplate } from './types/GateTemplate'
+
+export const DefaultGateTemplate: GateTemplate = {
+    material: {
+        type: 'color',
+        value: 'blue'
+    },
+    pins: {
+        inputs: {
+            count: 2,
+            variable: false
+        },
+        outputs: {
+            count: 1,
+            variable: false
+        }
+    },
+    shape: {
+        radius: 10,
+        rounded: true
+    }
+}
diff --git a/src/modules/simulation/types/GateTemplate.ts b/src/modules/simulation/types/GateTemplate.ts
new file mode 100644
index 0000000..b4132c1
--- /dev/null
+++ b/src/modules/simulation/types/GateTemplate.ts
@@ -0,0 +1,23 @@
+export interface PinCount {
+    variable: boolean
+    count: number
+}
+
+export interface Material {
+    type: 'color'
+    value: string
+}
+
+export interface Shape {
+    rounded: boolean
+    radius: number
+}
+
+export interface GateTemplate {
+    material: Material
+    shape: Shape
+    pins: {
+        inputs: PinCount
+        outputs: PinCount
+    }
+}
diff --git a/src/modules/simulationRenderer/classes/Camera.ts b/src/modules/simulationRenderer/classes/Camera.ts
index ada67c3..0d7af61 100644
--- a/src/modules/simulationRenderer/classes/Camera.ts
+++ b/src/modules/simulationRenderer/classes/Camera.ts
@@ -1,4 +1,5 @@
-import { Transform, vector2 } from '../../simulation/classes/Transform'
+import { Transform } from '../../../common/math/classes/Transform'
+import { vector2 } from '../../../common/math/types/vector2'
 import { Screen } from '../../core/classes/Screen'
 import { relativeTo } from '../../vector2/helpers/basic'
 
diff --git a/src/modules/simulationRenderer/classes/SimulationRenderer.ts b/src/modules/simulationRenderer/classes/SimulationRenderer.ts
index 94328c4..ca91092 100644
--- a/src/modules/simulationRenderer/classes/SimulationRenderer.ts
+++ b/src/modules/simulationRenderer/classes/SimulationRenderer.ts
@@ -2,14 +2,17 @@ import { Camera } from './Camera'
 import { Simulation } from '../../simulation/classes/Simulation'
 import { Subject } from 'rxjs'
 import { MouseEventInfo } from '../../core/components/FluidCanvas'
-import { pointInSquare } from '../helpers/pointInSquare'
-import { vector2 } from '../../simulation/classes/Transform'
+import { pointInSquare } from '../../../common/math/helpers/pointInSquare'
+import { vector2 } from '../../../common/math/types/vector2'
 import { MouseVelocityManager } from './MouseVelocityManager'
 import { Screen } from '../../core/classes/Screen'
 import { relativeTo, add, invert } from '../../vector2/helpers/basic'
 import { SimulationRendererOptions } from '../types/SimulationRendererOptions'
 import { defaultSimulationRendererOptions } from '../constants'
 import merge from 'deepmerge'
+import { getPinPosition } from '../helpers/pinPosition'
+import { pointInCircle } from '../../../common/math/helpers/pointInCircle'
+import { SelectedPins } from '../types/SelectedPins'
 
 export class SimulationRenderer {
     public mouseDownOutput = new Subject<MouseEventInfo>()
@@ -23,12 +26,18 @@ export class SimulationRenderer {
     private selectedGate: number | null = null
     private gateSelectionOffset: vector2 = [0, 0]
 
+    public lastMousePosition: vector2 = [0, 0]
     public movedSelection = false
     public options: SimulationRendererOptions
     public mouseManager = new MouseVelocityManager(this.mouseMoveOutput)
     public screen = new Screen()
     public camera = new Camera()
 
+    public selectedPins: SelectedPins = {
+        start: null,
+        end: null
+    }
+
     public constructor(
         options: Partial<SimulationRendererOptions> = {},
         public simulation = new Simulation()
@@ -43,11 +52,13 @@ export class SimulationRenderer {
             const worldPosition = this.camera.toWordPostition(event.position)
             const gates = Array.from(this.simulation.gates)
 
+            this.lastMousePosition = worldPosition
+
             // We need to iterate from the last to the first
             // because if we have 2 overlapping gates,
             // we want to select the one on top
             for (let index = gates.length - 1; index >= 0; index--) {
-                const { transform, id } = gates[index]
+                const { transform, id, pins } = gates[index]
 
                 if (pointInSquare(worldPosition, transform)) {
                     this.mouseManager.clear(worldPosition[0])
@@ -69,9 +80,38 @@ export class SimulationRenderer {
 
                     return
                 }
+
+                for (const pin of pins) {
+                    const position = getPinPosition(this, transform, pin)
+
+                    if (
+                        pointInCircle(
+                            worldPosition,
+                            position,
+                            this.options.gates.pinRadius
+                        )
+                    ) {
+                        if (
+                            (pin.value.type & 0b10) >> 1 &&
+                            this.selectedPins.start === null
+                        ) {
+                            this.selectedPins.start = {
+                                wrapper: pin,
+                                transform
+                            }
+                        } else if (
+                            pin.value.type & 1 &&
+                            this.selectedPins.end === null
+                        ) {
+                            this.selectedPins.end = {
+                                wrapper: pin,
+                                transform
+                            }
+                        }
+                    }
+                }
             }
 
-            this.gateSelectionOffset = worldPosition
             this.mouseState |= 2
         })
 
@@ -110,18 +150,16 @@ export class SimulationRenderer {
 
             if ((this.mouseState >> 1) & 1) {
                 const offset = invert(
-                    relativeTo(this.gateSelectionOffset, worldPosition)
+                    relativeTo(this.lastMousePosition, worldPosition)
                 )
 
                 this.camera.transform.position = add(
                     this.camera.transform.position,
                     invert(offset)
                 )
-
-                this.gateSelectionOffset = this.camera.toWordPostition(
-                    event.position
-                )
             }
+
+            this.lastMousePosition = this.camera.toWordPostition(event.position)
         })
     }
 
diff --git a/src/modules/simulationRenderer/constants.ts b/src/modules/simulationRenderer/constants.ts
index 25a81f7..563a4c0 100644
--- a/src/modules/simulationRenderer/constants.ts
+++ b/src/modules/simulationRenderer/constants.ts
@@ -1,13 +1,13 @@
 import { SimulationRendererOptions } from './types/SimulationRendererOptions'
 
 export const defaultSimulationRendererOptions: SimulationRendererOptions = {
-    shadows: {
-        enabled: true,
-        color: 'rgba(0,0,0,0.3)',
-        gateHeight: 10,
-        lightHeight: 100
-    },
     dnd: {
         rotation: Math.PI / 12 // 7.5 degrees
+    },
+    gates: {
+        connectionLength: 30,
+        pinRadius: 10,
+        pinStrokeColor: '#888888',
+        pinStrokeWidth: 3
     }
 }
diff --git a/src/modules/simulationRenderer/helpers/drawRotatedSquare.ts b/src/modules/simulationRenderer/helpers/drawRotatedSquare.ts
deleted file mode 100644
index e5d37b8..0000000
--- a/src/modules/simulationRenderer/helpers/drawRotatedSquare.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { Transform } from '../../simulation/classes/Transform'
-
-export const drawRotatedSquare = (
-    ctx: CanvasRenderingContext2D,
-    { position, scale, rotation }: Transform
-) => {
-    ctx.save()
-
-    ctx.translate(...position)
-    ctx.translate(scale[0] / 2, scale[1] / 2)
-
-    ctx.rotate(rotation)
-
-    ctx.fillRect(scale[0] / -2, scale[1] / -2, ...scale)
-
-    ctx.restore()
-}
diff --git a/src/modules/simulationRenderer/helpers/pinFill.ts b/src/modules/simulationRenderer/helpers/pinFill.ts
new file mode 100644
index 0000000..0134344
--- /dev/null
+++ b/src/modules/simulationRenderer/helpers/pinFill.ts
@@ -0,0 +1,15 @@
+import { Pin } from '../../simulation/classes/Pin'
+
+export const pinFill = (pin: Pin) => {
+    let color = 'rgba(0,0,0,0)'
+
+    if (pin.connectedTo.size) {
+        if (pin.state) {
+            color = 'yellow'
+        } else {
+            color = 'grey'
+        }
+    }
+
+    return color
+}
diff --git a/src/modules/simulationRenderer/helpers/pinPosition.ts b/src/modules/simulationRenderer/helpers/pinPosition.ts
new file mode 100644
index 0000000..9ec8663
--- /dev/null
+++ b/src/modules/simulationRenderer/helpers/pinPosition.ts
@@ -0,0 +1,66 @@
+import { Transform } from '../../../common/math/classes/Transform'
+import { Gate, PinWrapper } from '../../simulation/classes/Gate'
+import { Pin } from '../../simulation/classes/Pin'
+import { SimulationRenderer } from '../classes/SimulationRenderer'
+import { vector2 } from '../../../common/math/types/vector2'
+import { rotateAroundVector } from '../../vector2/helpers/rotate'
+
+export const calculatePinY = (
+    transform: Transform,
+    index: number,
+    total: number
+) => {
+    const space = transform.height / total
+
+    return (space * (2 * index + 1)) / 2
+}
+
+export const calculatePinStart = (
+    transform: Transform,
+    type: number,
+    width: number
+) => {
+    const direction = (type >> 1) & 1
+    const start =
+        transform.x + direction * transform.width - Number(!direction) * width
+
+    return start
+}
+
+export const calculatePinx = (
+    start: number,
+    type: number,
+    connectionLength: number
+) => {
+    return start + ((type >> 1) & 1) * connectionLength
+}
+
+export const getPinPosition = (
+    renderer: SimulationRenderer,
+    transform: Transform,
+    pin: PinWrapper
+) => {
+    const { connectionLength } = renderer.options.gates
+
+    // render little connection
+    const start = calculatePinStart(
+        transform,
+        pin.value.type,
+        renderer.options.gates.connectionLength
+    )
+
+    const height = calculatePinY(transform, pin.index, pin.total)
+
+    const pinX = calculatePinx(start, pin.value.type, connectionLength)
+    const pinY = height + transform.y
+
+    // rotate
+    const notRotated: vector2 = [pinX, pinY]
+    const rotated = rotateAroundVector(
+        notRotated,
+        transform.center,
+        transform.rotation
+    )
+
+    return rotated
+}
diff --git a/src/modules/simulationRenderer/helpers/projectPoint.ts b/src/modules/simulationRenderer/helpers/projectPoint.ts
index 08f1acf..cbe1f70 100644
--- a/src/modules/simulationRenderer/helpers/projectPoint.ts
+++ b/src/modules/simulationRenderer/helpers/projectPoint.ts
@@ -1,4 +1,5 @@
-import { vector3, vector2 } from '../../simulation/classes/Transform'
+import { vector3 } from '../../../common/math/types/vector3'
+import { vector2 } from '../../../common/math/types/vector2'
 
 export const projectPointOnPlane = (point: vector3, light: vector3) =>
     point.slice(0, 2).map((position, index) => {
diff --git a/src/modules/simulationRenderer/helpers/renderClickedPins.ts b/src/modules/simulationRenderer/helpers/renderClickedPins.ts
new file mode 100644
index 0000000..d6a3648
--- /dev/null
+++ b/src/modules/simulationRenderer/helpers/renderClickedPins.ts
@@ -0,0 +1,29 @@
+import { SimulationRenderer } from '../classes/SimulationRenderer'
+import { getPinPosition } from './pinPosition'
+import { SelectedPin } from '../types/SelectedPins'
+
+export const renderClickedPins = (
+    ctx: CanvasRenderingContext2D,
+    renderer: SimulationRenderer
+) => {
+    let pin: SelectedPin | null = null
+
+    if (renderer.selectedPins.start) {
+        pin = renderer.selectedPins.start
+    } else if (renderer.selectedPins.end) {
+        pin = renderer.selectedPins.end
+    }
+
+    if (pin) {
+        const position = getPinPosition(renderer, pin.transform, pin.wrapper)
+
+        ctx.strokeStyle = 'yellow'
+        ctx.lineWidth = renderer.options.gates.pinRadius * 2
+        ctx.lineCap = 'round'
+
+        ctx.beginPath()
+        ctx.moveTo(...position)
+        ctx.lineTo(...renderer.lastMousePosition)
+        ctx.stroke()
+    }
+}
diff --git a/src/modules/simulationRenderer/helpers/renderGate.ts b/src/modules/simulationRenderer/helpers/renderGate.ts
index 9efb6ee..338561d 100644
--- a/src/modules/simulationRenderer/helpers/renderGate.ts
+++ b/src/modules/simulationRenderer/helpers/renderGate.ts
@@ -1,7 +1,17 @@
 import { Gate } from '../../simulation/classes/Gate'
-import { drawRotatedSquare } from './drawRotatedSquare'
+import { drawRotatedSquare } from '../../../common/canvas/helpers/drawRotatedSquare'
+import { renderPins } from './renderPins'
+import { SimulationRenderer } from '../classes/SimulationRenderer'
 
-export const renderGate = (ctx: CanvasRenderingContext2D, gate: Gate) => {
-    ctx.fillStyle = gate.color
-    drawRotatedSquare(ctx, gate.transform)
+export const renderGate = (
+    ctx: CanvasRenderingContext2D,
+    renderer: SimulationRenderer,
+    gate: Gate
+) => {
+    renderPins(ctx, renderer, gate)
+
+    if (gate.template.material.type === 'color') {
+        ctx.fillStyle = gate.template.material.value
+        drawRotatedSquare(ctx, gate.transform, gate.template.shape)
+    }
 }
diff --git a/src/modules/simulationRenderer/helpers/renderGateShadow.ts b/src/modules/simulationRenderer/helpers/renderGateShadow.ts
deleted file mode 100644
index a102e96..0000000
--- a/src/modules/simulationRenderer/helpers/renderGateShadow.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { Gate } from '../../simulation/classes/Gate'
-import { projectPointOnPlane } from './projectPoint'
-import { drawPolygon } from './drawPolygon'
-import { vector3 } from '../../simulation/classes/Transform'
-
-export const renderGateShadow = (
-    ctx: CanvasRenderingContext2D,
-    color: string,
-    gate: Gate,
-    gateHeight: number,
-    light: vector3
-) => {
-    ctx.fillStyle = color
-
-    const points = gate.transform.getPoints()
-    const projections = points.map(point =>
-        projectPointOnPlane([point[0], point[1], gateHeight], light)
-    )
-
-    drawPolygon(ctx, projections)
-}
diff --git a/src/modules/simulationRenderer/helpers/renderPins.ts b/src/modules/simulationRenderer/helpers/renderPins.ts
new file mode 100644
index 0000000..8bff60b
--- /dev/null
+++ b/src/modules/simulationRenderer/helpers/renderPins.ts
@@ -0,0 +1,53 @@
+import { Gate } from '../../simulation/classes/Gate'
+import { SimulationRenderer } from '../classes/SimulationRenderer'
+import { useTransform } from '../../../common/canvas/helpers/useTransform'
+import { calculatePinStart, calculatePinY, calculatePinx } from './pinPosition'
+import { pinFill } from './pinFill'
+
+export const renderPins = (
+    ctx: CanvasRenderingContext2D,
+    renderer: SimulationRenderer,
+    gate: Gate
+) => {
+    ctx.save()
+
+    const {
+        connectionLength,
+        pinRadius,
+        pinStrokeColor,
+        pinStrokeWidth
+    } = renderer.options.gates
+    const relativeTransform = useTransform(ctx, gate.transform)
+
+    ctx.strokeStyle = pinStrokeColor
+    ctx.lineWidth = pinStrokeWidth
+
+    for (const pin of gate.pins) {
+        ctx.fillStyle = pinFill(pin.value)
+
+        // render little connection
+        const start = calculatePinStart(
+            relativeTransform,
+            pin.value.type,
+            connectionLength
+        )
+
+        const height = calculatePinY(relativeTransform, pin.index, pin.total)
+
+        const pinX = calculatePinx(start, pin.value.type, connectionLength)
+        const pinY = height + relativeTransform.y
+
+        ctx.beginPath()
+        ctx.moveTo(start, pinY)
+        ctx.lineTo(start + connectionLength, pinY)
+        ctx.stroke()
+
+        // render actual pin
+        ctx.beginPath()
+        ctx.ellipse(pinX, pinY, pinRadius, pinRadius, 0, 0, 2 * Math.PI)
+        ctx.fill()
+        ctx.stroke()
+    }
+
+    ctx.restore()
+}
diff --git a/src/modules/simulationRenderer/helpers/renderSimulation.ts b/src/modules/simulationRenderer/helpers/renderSimulation.ts
index 686067f..3d74aef 100644
--- a/src/modules/simulationRenderer/helpers/renderSimulation.ts
+++ b/src/modules/simulationRenderer/helpers/renderSimulation.ts
@@ -1,8 +1,8 @@
 import { SimulationRenderer } from '../classes/SimulationRenderer'
-import { relativeTo, invert } from '../../vector2/helpers/basic'
-import { renderGateShadow } from './renderGateShadow'
+import { invert } from '../../vector2/helpers/basic'
 import { renderGate } from './renderGate'
-import { clearCanvas } from './clearCanvas'
+import { clearCanvas } from '../../../common/canvas/helpers/clearCanvas'
+import { renderClickedPins } from './renderClickedPins'
 
 export const renderSimulation = (
     ctx: CanvasRenderingContext2D,
@@ -12,25 +12,12 @@ export const renderSimulation = (
 
     ctx.translate(...renderer.camera.transform.position)
 
-    const center = relativeTo(
-        renderer.camera.transform.position,
-        renderer.screen.center
-    )
-
     // render gates
     for (const gate of renderer.simulation.gates) {
-        if (renderer.options.shadows.enabled) {
-            renderGateShadow(
-                ctx,
-                renderer.options.shadows.color,
-                gate,
-                renderer.options.shadows.gateHeight,
-                [center[0], center[1], renderer.options.shadows.lightHeight]
-            )
-        }
-
-        renderGate(ctx, gate)
+        renderGate(ctx, renderer, gate)
     }
 
+    renderClickedPins(ctx, renderer)
+
     ctx.translate(...invert(renderer.camera.transform.position))
 }
diff --git a/src/modules/simulationRenderer/types/DeepPartial.ts b/src/modules/simulationRenderer/types/DeepPartial.ts
new file mode 100644
index 0000000..491a933
--- /dev/null
+++ b/src/modules/simulationRenderer/types/DeepPartial.ts
@@ -0,0 +1,7 @@
+type DeepPartial<T> = {
+    [P in keyof T]?: T[P] extends Array<infer U>
+        ? Array<DeepPartial<U>>
+        : T[P] extends ReadonlyArray<infer U>
+        ? ReadonlyArray<DeepPartial<U>>
+        : DeepPartial<T[P]>
+}
diff --git a/src/modules/simulationRenderer/types/SelectedPins.ts b/src/modules/simulationRenderer/types/SelectedPins.ts
new file mode 100644
index 0000000..283e232
--- /dev/null
+++ b/src/modules/simulationRenderer/types/SelectedPins.ts
@@ -0,0 +1,12 @@
+import { Transform } from '../../../common/math/classes/Transform'
+import { PinWrapper } from '../../simulation/classes/Gate'
+
+export interface SelectedPin {
+    wrapper: PinWrapper
+    transform: Transform
+}
+
+export interface SelectedPins {
+    start: SelectedPin | null
+    end: SelectedPin | null
+}
diff --git a/src/modules/simulationRenderer/types/SimulationRendererOptions.ts b/src/modules/simulationRenderer/types/SimulationRendererOptions.ts
index 4e6ce2d..bf471b8 100644
--- a/src/modules/simulationRenderer/types/SimulationRendererOptions.ts
+++ b/src/modules/simulationRenderer/types/SimulationRendererOptions.ts
@@ -1,11 +1,11 @@
 export interface SimulationRendererOptions {
-    shadows: {
-        enabled: boolean
-        color: string
-        lightHeight: number
-        gateHeight: number
-    }
     dnd: {
         rotation: number
     }
+    gates: {
+        connectionLength: number
+        pinRadius: number
+        pinStrokeColor: string
+        pinStrokeWidth: number
+    }
 }
diff --git a/src/modules/vector2/helpers/basic.ts b/src/modules/vector2/helpers/basic.ts
index ba49c11..e9ef333 100644
--- a/src/modules/vector2/helpers/basic.ts
+++ b/src/modules/vector2/helpers/basic.ts
@@ -1,4 +1,4 @@
-import { vector2 } from '../../simulation/classes/Transform'
+import { vector2 } from '../../../common/math/types/vector2'
 
 // Basic stuff for arrays
 
diff --git a/src/modules/vector2/helpers/minmaxVector.ts b/src/modules/vector2/helpers/minmaxVector.ts
index bf9933a..654006d 100644
--- a/src/modules/vector2/helpers/minmaxVector.ts
+++ b/src/modules/vector2/helpers/minmaxVector.ts
@@ -1,4 +1,4 @@
-import { vector2 } from '../../simulation/classes/Transform'
+import { vector2 } from '../../../common/math/types/vector2'
 import { length } from './basic'
 
 export const minVector = (...vectors: vector2[]) => {
diff --git a/src/modules/vector2/helpers/rotate.ts b/src/modules/vector2/helpers/rotate.ts
index 5d465fd..4a4a7b5 100644
--- a/src/modules/vector2/helpers/rotate.ts
+++ b/src/modules/vector2/helpers/rotate.ts
@@ -1,4 +1,4 @@
-import { vector2 } from '../../simulation/classes/Transform'
+import { vector2 } from '../../../common/math/types/vector2'
 import { add, invert } from './basic'
 
 const { cos, sin } = Math
diff --git a/src/modules/vector2/helpers/smoothStep.ts b/src/modules/vector2/helpers/smoothStep.ts
index d6a2901..8d0aef8 100644
--- a/src/modules/vector2/helpers/smoothStep.ts
+++ b/src/modules/vector2/helpers/smoothStep.ts
@@ -1,4 +1,4 @@
-import { vector2 } from '../../simulation/classes/Transform'
+import { vector2 } from '../../../common/math/types/vector2'
 
 // TODO: rename
 export const smoothStep = (step: number, current: vector2, target: vector2) => {