diff --git a/java/2-8-Transformation/BarExercise.java b/java/2-8-Transformation/BarExercise.java
new file mode 100644
index 0000000000000000000000000000000000000000..89b1e8024d9fb6247515df64afc52d379639fa4b
--- /dev/null
+++ b/java/2-8-Transformation/BarExercise.java
@@ -0,0 +1,130 @@
+/*
+* CS 349 Java Code Examples
+*
+* BarExercise        Demo of multiple transformation exercise.
+*
+*/
+import javax.swing.JFrame;
+import javax.swing.JComponent;
+import javax.swing.JButton;
+import java.awt.*;
+import java.awt.geom.*;
+import java.util.ArrayList;
+import javax.vecmath.*;
+import java.lang.Math.*;
+import java.util.Random;
+import java.awt.event.*;
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+
+// create the window and run the demo
+public class BarExercise {
+	
+    public static void main(String[] args) {
+        // create the window        
+    	Canvas canvas = new Canvas();
+        JFrame f = new JFrame("BarExercise"); // jframe is the app window
+        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        f.setSize(500, 500); // window size
+        f.setContentPane(canvas); // add canvas to jframe    
+        f.setBackground(Color.WHITE);     
+        f.setVisible(true); // show the window
+    }
+} 
+
+class Canvas extends JComponent {
+
+	// the house shape (model position is centred at top left corner)
+	private Polygon shape = new Polygon(new int[] { -50, 50,  50, 	0, -50}, 
+										new int[] { 75,  75, -25, -75, -25}, 5);
+
+	int step = 0;
+
+	Canvas() {
+
+		// only mouse clicked events
+		addMouseListener(new MouseAdapter() { 
+	          public void mouseClicked(MouseEvent me) { 
+	          	step ++;
+	        	repaint();
+	          } 
+	        }); 
+	}
+    
+    // custom graphics drawing 
+    public void paintComponent(Graphics g) {
+    	super.paintComponent(g); // JPanel paint
+    	Graphics2D g2 = (Graphics2D)g;
+
+    	// make a centred grid
+    	int gridSize = 250;
+    	g2.translate((this.getWidth() - gridSize) / 2, (this.getHeight() - gridSize) / 2);
+    	drawGrid(g2, gridSize, gridSize, gridSize / 10);
+    	
+    	// draw the original shape in "model" coordinates
+    	g2.setColor(Color.BLACK);
+    	drawBar(g2, 50, 100, 150, 100);
+
+    	// save the current transform matrix 
+    	AffineTransform M = g2.getTransform();    	
+
+    	// the shape will get transformed into "world" coordinates
+    	if (true) {
+    		g2.translate(50, 100);
+	    	g2.rotate(Math.toRadians(30));
+	    	g2.translate(-50, -100);
+	    	g2.setColor(Color.BLUE.darker());
+	    	drawBar(g2, 50, 100, 150, 100);	
+
+	    // demo the steps
+	    } else {
+	    	g2.setColor(Color.BLUE.darker());
+    		switch (step % 4) {
+
+    		case 1:
+    		g2.translate(-50, -100);
+	    	drawBar(g2, 50, 100, 150, 100); 
+	    	g2.setTransform(M);
+	    	break;
+    		case 2:
+	    	g2.rotate(Math.toRadians(30));
+	    	g2.translate(-50, -100);
+	    	drawBar(g2, 50, 100, 150, 100);
+	    	g2.setTransform(M);
+	    	break;
+    		case 3:
+	    	g2.translate(50, 100);
+	    	g2.rotate(Math.toRadians(30));
+	    	g2.translate(-50, -100);
+	    	drawBar(g2, 50, 100, 150, 100);	
+	    	g2.setTransform(M);
+	    	break;
+    		}
+    	} 
+    }
+
+    private void drawBar(Graphics2D g2, int x1, int y1, int x2, int y2) {
+    	int d = 12; 
+    	g2.setStroke(new BasicStroke(4));
+    	g2.drawLine(x1, y1, x2, y2);
+    	g2.fillOval(x1 - d/2, y1 - d/2, d, d);
+    	g2.fillOval(x2 - d/2, y2 - d/2, d, d);
+    }
+
+
+     private void drawGrid(Graphics2D g2, int w, int h, int s) {
+
+        // Draw grid
+        g2.setStroke(new BasicStroke(1));
+        g2.setColor(Color.GRAY.brighter());
+        // horizontal lines
+        for(int i = 0; i <= h; i += s) {
+            g2.drawLine(0, i, w, i);
+        }
+        // vertical lines
+        for(int i = 0; i <= w; i += s) {
+            g2.drawLine(i, 0, i, h);
+        }
+    }
+
+}
diff --git a/java/2-8-Transformation/CompositionOrder.java b/java/2-8-Transformation/CompositionOrder.java
new file mode 100644
index 0000000000000000000000000000000000000000..e4a2e88cb3eac89d584b0174361d24ebb5a95879
--- /dev/null
+++ b/java/2-8-Transformation/CompositionOrder.java
@@ -0,0 +1,181 @@
+/*
+* CS 349 Java Code Examples
+*
+* CompositionOrder        Demo of different concatenation orders of matrix transforms.
+*					 Click the window to change the order.
+*
+*/
+import javax.swing.JFrame;
+import javax.swing.JComponent;
+import javax.swing.JButton;
+import java.awt.*;
+import java.awt.geom.*;
+import java.util.ArrayList;
+import javax.vecmath.*;
+import java.lang.Math.*;
+import java.util.Random;
+import java.awt.event.*;
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+
+// create the window and run the demo
+public class CompositionOrder {
+	
+    public static void main(String[] args) {
+        // create the window        
+    	Canvas canvas = new Canvas();
+        JFrame f = new JFrame("CompositionOrder"); // jframe is the app window
+        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        f.setSize(500, 500); // window size
+        f.setContentPane(canvas); // add canvas to jframe   
+        f.setBackground(Color.WHITE);       
+        f.setVisible(true); // show the window
+    }
+} 
+
+class Canvas extends JComponent {
+
+	// rotate
+	double theta = 30;
+	// translate
+	double tx = 100;
+	double ty = 0;
+	// scale
+	double sx = 2;
+	double sy = 1.2;
+	
+	// the house shape (model position is centred at top left corner)
+	private Polygon shape = new Polygon(new int[] { -50, 50,  50, 	0, -50}, 
+										new int[] { 75,  75, -25, -75, -25}, 5);
+
+	// a larger font for displaying the concatenation order
+	private Font font = new Font("SansSerif", Font.PLAIN, 30);
+
+	// the concatenation order
+    private int order = 0;
+
+	Canvas() {
+		
+		// only mouse clicked events
+		addMouseListener(new MouseAdapter() { 
+	          public void mouseClicked(MouseEvent me) { 
+	        	  order = (order + 1) % 6;
+	        	  repaint();
+	          } 
+	        }); 
+		
+		System.out.println("click to change transformation composition order");
+	}
+    
+    // custom graphics drawing 
+    public void paintComponent(Graphics g) {
+    	super.paintComponent(g); // JPanel paint
+    	Graphics2D g2 = (Graphics2D)g;
+
+    	// make a centred grid
+    	int gridSize = 250;
+    	g2.translate((this.getWidth() - gridSize) / 2, (this.getHeight() - gridSize) / 2);
+    	drawGrid(g2, gridSize, gridSize, gridSize / 10);
+    	
+    	// save the current transform matrix 
+    	AffineTransform M = g2.getTransform();
+    	
+    	// draw the original shape in "model" coordinates
+    	g2.setColor(Color.BLACK);
+    	g2.setStroke(new BasicStroke(3));
+    	g2.drawPolygon(shape.xpoints, shape.ypoints, shape.npoints);
+    	// mark 0, 0 too
+    	g2.setStroke(new BasicStroke(1)); 
+    	g2.drawOval(-5, -5, 10, 10);
+    	
+    	// create transformation matrices
+    	AffineTransform R = 
+            AffineTransform.getRotateInstance(Math.toRadians(theta));
+    	AffineTransform T = 
+            AffineTransform.getTranslateInstance(tx, ty);
+    	AffineTransform S = 
+            AffineTransform.getScaleInstance(sx, sy);
+    	
+    	// concatenate the matrices in 1 of 6 orders
+    	String s = "p'=";
+    	switch (order)
+    	{
+    	case 0:
+	    	s += "TRS";
+	    	g2.transform(T);
+	    	g2.transform(R);
+	    	g2.transform(S);
+	    	break;	
+	    	
+    	case 1:
+	    	s += "TSR";
+	    	g2.transform(T);
+	    	g2.transform(S);
+	    	g2.transform(R);
+	    	break;
+	    	
+    	case 2:
+	    	s += "RST";
+	    	g2.transform(R);
+	    	g2.transform(S);
+	    	g2.transform(T);
+	    	break;		
+
+    	case 3:
+	    	s += "RTS";
+	    	g2.transform(R);
+	    	g2.transform(T);
+	    	g2.transform(S);
+	    	break;
+	    	
+    	case 4:
+	    	s += "SRT";
+	    	g2.transform(S);
+	    	g2.transform(R);
+	    	g2.transform(T);
+	    	break;	
+	    	
+    	case 5:
+	    	s += "STR";
+	    	g2.transform(S);
+	    	g2.transform(T);
+	    	g2.transform(R);
+	    	break;		    	
+    	}
+    	s += "p";
+    	
+    	// the shape will get transformed into "world" coordinates
+    	g2.setColor(Color.RED);  
+    	g2.setStroke(new BasicStroke(3)); 	
+    	g2.drawPolygon(shape.xpoints, shape.ypoints, shape.npoints);
+    	// mark 0, 0 too
+    	g2.setStroke(new BasicStroke(1)); 
+    	g2.drawOval(-5, -5, 10, 10);   	
+    	
+    	// reset to transform before we did the T, R, and S
+    	// so we can draw the text
+    	g2.setTransform(M);
+    	
+    	// display the order text
+    	g2.setColor(Color.BLACK);
+    	g2.setFont(font);
+    	g2.drawString(s, 0, gridSize + 50);
+    }
+
+
+     private void drawGrid(Graphics2D g2, int w, int h, int s) {
+
+        // Draw grid
+        g2.setStroke(new BasicStroke(1));
+        g2.setColor(Color.GRAY.brighter());
+        // horizontal lines
+        for(int i = 0; i <= h; i += s) {
+            g2.drawLine(0, i, w, i);
+        }
+        // vertical lines
+        for(int i = 0; i <= w; i += s) {
+            g2.drawLine(i, 0, i, h);
+        }
+    }
+
+}
diff --git a/java/2-8-Transformation/SceneGraph.java b/java/2-8-Transformation/SceneGraph.java
new file mode 100644
index 0000000000000000000000000000000000000000..96b744337823f54a6fa0feed810ea184d5f63465
--- /dev/null
+++ b/java/2-8-Transformation/SceneGraph.java
@@ -0,0 +1,135 @@
+/*
+* CS 349 Java Code Examples
+*
+* SceneGraph   Demonstrate simple scene graph that draws a house.
+*
+*/
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.geom.*;
+
+public class SceneGraph extends JPanel {
+
+    public static void main(String[] args) {
+        // create the window
+        JFrame f = new JFrame("SceneGraph"); // jframe is the app window
+        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        f.setSize(400, 400); // window size
+        f.setContentPane(new SceneGraph()); // add canvas to jframe
+        f.setVisible(true); // show the window
+
+    }
+
+    SceneGraph() {
+        setOpaque(true);
+        setBackground(Color.WHITE);
+
+        // make sure panel is focusable for getting key events
+        // (remember focus dispatch?)
+        setFocusable(true);
+        this.addKeyListener(new KeyAdapter() {
+            public void keyPressed(KeyEvent e) {
+
+                switch(e.getKeyCode()) {
+                    case KeyEvent.VK_RIGHT:
+                        rotateBy += 5;
+                        break;
+                    case KeyEvent.VK_LEFT:
+                        rotateBy -= 5;
+                        break;
+                    case KeyEvent.VK_UP:
+                        scaleBy += .1;
+                        break;
+                    case KeyEvent.VK_DOWN:
+                        scaleBy -= .1;
+                        break;
+
+                }
+                repaint();
+            }
+        });
+    }
+
+    // scaleBy and rotation
+    double scaleBy = 2;
+    double rotateBy = 0;
+
+    // custom graphics drawing
+    public void paintComponent(Graphics g) {
+        super.paintComponent(g);
+        Graphics2D g2 = (Graphics2D) g;
+
+
+        // draw the house in centre of screen
+        g2.translate(getWidth() / 2, getHeight()/ 2);
+        g2.rotate(Math.toRadians(rotateBy));
+        g2.scale(scaleBy, scaleBy);
+
+        g2.setStroke(new BasicStroke(3));
+        g2.drawPolygon(houseShape.xpoints, houseShape.ypoints, houseShape.npoints);
+
+        // save transform for later
+        AffineTransform save = g2.getTransform();
+
+        // remember: these are all in "house coordinates"
+        g2.translate(-25, 0); // window centred 25 px
+        g2.scale(0.4, 0.4); // window is 40% house width
+        drawWindow(g2);
+
+        // translate to right 50 px
+        g2.translate(50 / 0.4, 0);
+        drawWindow(g2);
+
+        // draw third window twice to demo different coordinate frames
+
+        // set transform to saved matrix to return to "House" coordinates
+        // since this window is drawn in house coordinates, it will be
+        // transformed with the house
+        g2.setTransform(save);
+        drawWindow(g2, 0, -50, 45, 0.25);
+
+        // set transform to identity to reset
+        // this means third window is drawn in World Coordinates
+        // and won't be transformed with the house
+        g2.setTransform(new AffineTransform());
+
+        // using function which has a model-to-world transform built in
+        drawWindow(g2, getWidth()/2, 89, 45, 0.5);
+    }
+
+    // 100 x 100 house shape using Java Polygon structure
+    // (model position is centred at top left corner)
+    private Polygon houseShape = new Polygon(new int[] { -50, 50,  50,  0, -50},
+            new int[] { 75,  75, -25, -75, -25}, 5);
+
+    // draws 100 x 100 window shape centred at 0,0
+    void drawWindow(Graphics2D g2) {
+        g2.setColor(Color.BLACK);
+        g2.fillRect(-50, -50, 100, 100);
+        g2.setColor(Color.WHITE);
+        g2.fillRect(-40, -40, 35, 35);
+        g2.fillRect(5, -40, 35, 35);
+        g2.fillRect(-40, 5, 35, 35);
+        g2.fillRect(5, 5, 35, 35);
+    }
+
+    // draws 100 x 100 window shape centred at 0,0
+    void drawWindow(Graphics2D g2, double x, double y, double theta, double s) {
+
+        // save the current g2 transform matrix
+        AffineTransform save = g2.getTransform();
+
+        // do the model to world transformation
+        g2.translate(x, y);  // T
+        g2.rotate(Math.toRadians(theta)); // R
+        g2.scale(s, s);  // S
+
+        // draws 100 x 100 window centred at 0,0
+        drawWindow(g2);
+        // reset the transform to what it was before we drew the shape
+        g2.setTransform(save);
+    }
+}
diff --git a/java/2-8-Transformation/Transform2.java b/java/2-8-Transformation/Transform2.java
new file mode 100644
index 0000000000000000000000000000000000000000..ba650cf01eef889052a85f8493fde2cd9403ce3a
--- /dev/null
+++ b/java/2-8-Transformation/Transform2.java
@@ -0,0 +1,63 @@
+/*
+* CS 349 Java Code Examples
+*
+* Transform2  Shows how to use Graphics2D matrix tranformations to transform a shape model. 
+*
+*/
+import javax.swing.JFrame;
+import javax.swing.JComponent;
+import javax.swing.JButton;
+import java.awt.*;
+import java.awt.geom.*;
+import java.util.ArrayList;
+import javax.vecmath.*;
+import java.lang.Math.*;
+import java.util.Random;
+import java.awt.event.*;
+
+// create the window and run the demo
+public class Transform2 {
+	
+    public static void main(String[] args) {
+        // create the window        
+    	Canvas canvas = new Canvas();
+        JFrame f = new JFrame("Transform2"); // jframe is the app window
+        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        f.setSize(400, 400); // window size
+        f.setContentPane(canvas); // add canvas to jframe         
+        f.setVisible(true); // show the window
+    }
+} 
+
+class Canvas extends JComponent {
+	
+	// the house shape (model position is centred at top left corner)
+	private Polygon shape = new Polygon(new int[] { -50, 50,  50, 	0, -50}, 
+										new int[] { 75,  75, -25, -75, -25}, 5);
+
+	Point2d M = new Point2d();
+
+	Canvas() {
+		// events
+        this.addMouseMotionListener(new MouseAdapter(){
+            public void mouseMoved(MouseEvent e){
+                M.x = e.getX();
+                M.y = e.getY();
+                repaint();
+            }});
+	}
+    
+    // custom graphics drawing 
+    public void paintComponent(Graphics g) {
+    	super.paintComponent(g); // JPanel paint
+    	Graphics2D g2 = (Graphics2D)g;
+    	
+    	// the shape will get transformed when rendered
+		g2.translate(M.x, M.y);
+		g2.rotate(45);
+		g2.scale(2, 1);
+
+     	g2.setStroke(new BasicStroke(3)); 
+    	g2.drawPolygon(shape.xpoints, shape.ypoints, shape.npoints);
+    } 
+}
diff --git a/java/2-8-Transformation/makefile b/java/2-8-Transformation/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..06ac46ed1f6b3fa8ecf418952a5efd52b48eb0c9
--- /dev/null
+++ b/java/2-8-Transformation/makefile
@@ -0,0 +1,25 @@
+# super simple makefile
+# call it using 'make NAME=name_of_code_file_without_extension'
+# (assumes a .java extension)
+NAME = Transform2
+# you may need to pass OS=win to run on windows
+OS = 
+
+# HACK: vecmath is included regardless if needed
+all:
+	@echo "Compiling..."
+	javac -cp vecmath.jar $(NAME).java
+
+run: all
+# windows needs a semicolon
+ifeq ($(OS),win)
+		@echo "Running on windows ..."
+		java -cp "vecmath.jar;." $(NAME)
+# everyone else likes a colon
+else
+		@echo "Running ..."
+		java -cp "vecmath.jar:." $(NAME)
+endif
+
+clean:
+	rm -rf *.class
diff --git a/java/2-8-Transformation/shapemodel/Shape.java b/java/2-8-Transformation/shapemodel/Shape.java
new file mode 100644
index 0000000000000000000000000000000000000000..716741f9d9f9c2cd2f4aaac3b956e7af8c59321b
--- /dev/null
+++ b/java/2-8-Transformation/shapemodel/Shape.java
@@ -0,0 +1,151 @@
+/*
+*  Shape: See ShapeDemo for an example how to use this class.
+*
+*/
+import java.util.ArrayList;
+import java.awt.*;
+import java.awt.geom.*;
+import javax.vecmath.*;
+
+// simple shape model class
+class Shape {
+
+    // shape points
+    ArrayList<Point2d> points;
+
+    public void clearPoints() {
+        points = new ArrayList<Point2d>();
+        pointsChanged = true;
+    }
+  
+    // add a point to end of shape
+    public void addPoint(Point2d p) {
+        if (points == null) clearPoints();
+        points.add(p);
+        pointsChanged = true;
+    }    
+
+    // add a point to end of shape
+    public void addPoint(double x, double y) {
+        addPoint(new Point2d(x, y));  
+    }
+
+    public int npoints() {
+        return points.size();
+    }
+
+    // shape is polyline or polygon
+    Boolean isClosed = false; 
+
+    public Boolean getIsClosed() {
+        return isClosed;
+    }
+
+    public void setIsClosed(Boolean isClosed) {
+        this.isClosed = isClosed;
+    }    
+
+    // if polygon is filled or not
+    Boolean isFilled = false; 
+
+    public Boolean getIsFilled() {
+        return isFilled;
+    }
+
+    public void setIsFilled(Boolean isFilled) {
+        this.isFilled = isFilled;
+    }    
+
+    // drawing attributes
+    Color colour = Color.BLACK;
+    float strokeThickness = 3.0f;
+
+    public Color getColour() {
+		return colour;
+	}
+
+	public void setColour(Color colour) {
+		this.colour = colour;
+	}
+
+    public float getStrokeThickness() {
+		return strokeThickness;
+	}
+
+	public void setStrokeThickness(float strokeThickness) {
+		this.strokeThickness = strokeThickness;
+	}
+
+    // shape's transform
+
+    // quick hack, get and set would be better
+    float scale = 1.0f;
+
+    // some optimization to cache points for drawing
+    Boolean pointsChanged = false; // dirty bit
+    int[] xpoints, ypoints;
+    int npoints = 0;
+
+    void cachePointsArray() {
+        xpoints = new int[points.size()];
+        ypoints = new int[points.size()];
+        for (int i=0; i < points.size(); i++) {
+            xpoints[i] = (int)points.get(i).x;
+            ypoints[i] = (int)points.get(i).y;
+        }
+        npoints = points.size();
+        pointsChanged = false;
+    }
+	
+    
+    // let the shape draw itself
+    // (note this isn't good separation of shape View from shape Model)
+    public void draw(Graphics2D g2) {
+
+        // don't draw if points are empty (not shape)
+        if (points == null) return;
+
+        // see if we need to update the cache
+        if (pointsChanged) cachePointsArray();
+
+        // save the current g2 transform matrix 
+        AffineTransform M = g2.getTransform();
+
+        // multiply in this shape's transform
+        // (uniform scale)
+        g2.scale(scale, scale);
+
+        // call drawing functions
+        g2.setColor(colour);            
+        if (isFilled) {
+            g2.fillPolygon(xpoints, ypoints, npoints);
+        } else {
+            // can adjust stroke size using scale
+        	g2.setStroke(new BasicStroke(strokeThickness / scale)); 
+        	if (isClosed)
+                g2.drawPolygon(xpoints, ypoints, npoints);
+            else
+                g2.drawPolyline(xpoints, ypoints, npoints);
+        }
+
+        // reset the transform to what it was before we drew the shape
+        g2.setTransform(M);            
+    }
+    
+   
+    // let shape handle its own hit testing
+    // (x,y) is the point to test against
+    // (x,y) needs to be in same coordinate frame as shape, you could add
+    // a panel-to-shape transform as an extra parameter to this function
+    // (note this isn't good separation of shape Controller from shape Model)    
+    public boolean hittest(double x, double y)
+    {   
+    	if (points != null) {
+
+            // TODO Implement
+
+    	}
+    	
+    	return false;
+    }
+}
diff --git a/java/2-8-Transformation/shapemodel/ShapeDemo.java b/java/2-8-Transformation/shapemodel/ShapeDemo.java
new file mode 100644
index 0000000000000000000000000000000000000000..eb1ebc19f366bc7b2e1195b5ecb8e4d76987a842
--- /dev/null
+++ b/java/2-8-Transformation/shapemodel/ShapeDemo.java
@@ -0,0 +1,65 @@
+/*
+* CS 349 Java Code Examples
+*
+* ShapeDemo    Demo of Shape class: draw shapes using mouse.
+*
+*/
+import javax.swing.*;
+import java.awt.*;
+import java.awt.geom.*;
+import java.awt.event.*;
+
+import javax.vecmath.*;
+
+// create the window and run the demo
+public class ShapeDemo extends JPanel {
+
+    Shape shape;
+
+    ShapeDemo() {
+
+        this.addMouseListener(new MouseAdapter(){
+            public void mousePressed(MouseEvent e) {
+
+                shape = new Shape();
+                // change shape type
+                // shape.setIsClosed(true);
+                // shape.setIsFilled(true);
+                shape.setColour(Color.BLUE);
+
+                // try setting scale to something other than 1 
+                shape.scale = 1.0f;
+
+                repaint();
+            }
+        });
+
+        this.addMouseMotionListener(new MouseAdapter(){
+            public void mouseDragged(MouseEvent e) {
+                shape.addPoint(e.getX(), e.getY());
+                repaint();      
+            }
+        }); 
+    }
+
+    public static void main(String[] args) {
+        // create the window         
+        ShapeDemo canvas = new ShapeDemo();
+        JFrame f = new JFrame("ShapeDemo"); // jframe is the app window
+        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        f.setSize(300, 300); // window size
+        f.setContentPane(canvas); // add canvas to jframe
+        f.setVisible(true); // show the window
+    }
+    // custom graphics drawing 
+    public void paintComponent(Graphics g) {
+        super.paintComponent(g);
+        Graphics2D g2 = (Graphics2D) g; // cast to get 2D drawing methods
+        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,  // antialiasing look nicer
+                            RenderingHints.VALUE_ANTIALIAS_ON);
+ 
+        if (shape != null)
+            shape.draw(g2);
+    }
+}
+
diff --git a/java/2-8-Transformation/shapemodel/makefile b/java/2-8-Transformation/shapemodel/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1a5cedbb7bb4d0df60de3e9efa9b0b4465077824
--- /dev/null
+++ b/java/2-8-Transformation/shapemodel/makefile
@@ -0,0 +1,26 @@
+# super simple makefile
+# call it using 'make NAME=name_of_code_file_without_extension'
+# (assumes a .java extension)
+NAME="ShapeDemo"
+# you may need to pass OS=win to run on windows
+OS = 
+
+# HACK: vecmath is included regardless if needed
+all:
+	@echo "Compiling..."
+	javac -cp vecmath.jar *.java
+
+run: all
+# windows needs a semicolon
+ifeq ($(OS),win)
+		@echo "Running on windows ..."
+		java -cp "vecmath.jar;." $(NAME)
+# everyone else likes a colon
+else
+		@echo "Running ..."
+		java -cp "vecmath.jar:." $(NAME)
+endif
+
+clean:
+	rm -rf *.class
+
diff --git a/java/2-8-Transformation/shapemodel/vecmath.jar b/java/2-8-Transformation/shapemodel/vecmath.jar
new file mode 100644
index 0000000000000000000000000000000000000000..6d8b3a11c9c7a02d736a2ccc7f07fa70eb319832
Binary files /dev/null and b/java/2-8-Transformation/shapemodel/vecmath.jar differ
diff --git a/java/2-8-Transformation/vecmath.jar b/java/2-8-Transformation/vecmath.jar
new file mode 100644
index 0000000000000000000000000000000000000000..6d8b3a11c9c7a02d736a2ccc7f07fa70eb319832
Binary files /dev/null and b/java/2-8-Transformation/vecmath.jar differ