diff --git a/LOG.md b/LOG.md
index f56fd6dcb719149e262228959298ce7f47b964e7..597ead7c358a14317dbe7445fd3e008811360d73 100644
--- a/LOG.md
+++ b/LOG.md
@@ -1,12 +1,27 @@
 # Cuttlefish Dev Log / Scratch Notes
 
+### Post Scuttlefish 2019 12 29
+
+I'm not sure that I've merged the branches yet, but I think this exercise is largely done. The next big feats for me would be tightening up to a protocol, handling compound data types, etc. I think I can actually take these things on (save the sub-routing layer q / onion routing q) without fully breaking things apart. Compound data types at least I can implement for motion segments, and then the link state (protocol heavy / careful) work I can do just by working on links themselves. OK. 
+
+Scratch notes from the month below...
+
+- pick state to maintain w/r/t connections-between-views and view sizes, etc.
+- clean .clean() to not-nuke these things,
+- consider refresh, what does it for these things?
+- reloading ah hunk / probably refreshing the view when we have active DOM elements .rm's the native DOM elements, trouble trouble
+
+- large systems are still cumbersome in the browser - probably all of your calls to .position() per block are kinda yikes-like, could be semi-static offsets, calculated on redraw?
+- there is also this serverside bug: your 'save' w/ a 'post' notification is too large, find out what the limit is on these, and maybe websocket them, or something like that?
+- I think there is some chance this stepper bug is coming back: i.e the one where your drivers stall and then short other members of the system out. what's up with that? better gnd nets is a place to start, not stalling is also a place, and so is trying to use a simpler driver / the TMC2130, and look at stall protection diodes.
+
 ### Dev Rebuilding 2019 12 10
 
 OK, kind of last day to pin this together. I think to start, I'll add that button back to the link, then try to run the 'expandlink' routine again. Then I can see about my two views, and how to assemble these layers.
 
 Some progress here, I'm expanding links. To signal that ahn link has another-end, I have linkdef.contains ...
 
-Last question is how to recover the view -> links relationships, i.e. the link.contains is our hookup at the graph level, then the link.contains.plane's existence determines whether / not we are rendering it. To transition between rendering and not-rendering, we create and destroy this plane. 
+Last question is how to recover the view -> links relationships, i.e. the link.contains is our hookup at the graph level, then the link.contains.plane's existence determines whether / not we are rendering it. To transition between rendering and not-rendering, we create and destroy this plane.
 
 ### Dev Rebuilding 2019 12 09
 
diff --git a/hunks/comm/swSVGSocket.js b/hunks/comm/swSVGSocket.js
new file mode 100644
index 0000000000000000000000000000000000000000..50e7265b21e1c23995a88f90276516cc681afdd1
--- /dev/null
+++ b/hunks/comm/swSVGSocket.js
@@ -0,0 +1,132 @@
+/*
+hunks/comm/swSVGSocket.js
+
+pipe from solidworks, delivers SVGs
+
+Jake Read at the Center for Bits and Atoms
+Shawn Liu at Solidworks
+(c) Massachusetts Institute of Technology 2019
+
+This work may be reproduced, modified, distributed, performed, and
+displayed for any purpose, but must acknowledge the squidworks and cuttlefish projects.
+Copyright is retained and must be preserved. The work is provided as is;
+no warranty is provided, and users accept all liability.
+*/
+
+import {
+  Hunkify,
+  Input,
+  Output,
+  State
+} from '../hunks.js'
+
+export default function SWSVGClient() {
+  Hunkify(this)
+
+  let dtout = this.output('string', 'svg', this)
+
+  // lots!
+  let connectionStatus = this.state('boolean', 'connected', false)
+  let statusMessage = this.state('string', 'status', '...')
+  // conn, and sw conn,
+  let addressState = this.state('string', 'address', '127.0.0.1')
+  let portState = this.state('number', 'port', 8787)
+  let swId = this.state('string', 'swiD', '7772')
+  // svg extraction ...
+  let margin = this.state('number', 'margin (mm)', 10)
+  let includeInner = this.state('boolean', 'include inner faces', true)
+
+  // this ws is a client,
+  let ws = {}
+  let url = `ws://127.0.0.1:${portState.value}`
+
+  // we keep an outgoing set,
+  let outbuffer = new Array()
+
+  // in case saved when 'open'
+  this.init = () => {
+    connectionStatus.set(false)
+  }
+
+  connectionStatus.onChange = (value) => {
+    if(value){
+      startWs()
+    } else {
+      ws.close()
+    }
+  }
+
+  let updateSettings = () => {
+    // req. margin,
+    let marginCmd = {
+      modCmd: "SetMargin",
+      margin: Number(margin.value)
+    }
+    ws.send(JSON.stringify(marginCmd))
+    // req inner / not-inner ...
+    let innerCmd = {
+      modCmd: "SetIncludeInner",
+      includeInner: includeInner.value
+    }
+    ws.send(JSON.stringify(innerCmd))
+    ws.send('{"modCmd":"EnableSelectFaceNotify","selectFaceNotify":true}')
+    console.log('sent settings upd8')
+  }
+
+  let startWs = () => {
+    // manager calls this once
+    // it is loaded and state is updated (from program)
+    url = 'ws://' + addressState.value + ':' + portState.value
+    this.log(`attempt start ws at ${url}`)
+    ws = new WebSocket(url)
+    ws.binaryType = "arraybuffer"
+    ws.onopen = (evt) => {
+      this.log('ws opened')
+      statusMessage.set('open')
+      connectionStatus.set(true)
+      // ack to shawn,
+      ws.send(JSON.stringify({
+        modCmd: 'connect',
+        owner: 'mods',
+        id: swId.value
+      }))
+      // req. data?
+      updateSettings()
+    }
+    ws.onerror = (evt) => {
+      console.log('ws error:', evt)
+      statusMessage.set('error')
+      connectionStatus.set(false)
+    }
+    ws.onclose = (evt) => {
+      statusMessage.set('closed')
+      connectionStatus.set(false)
+    }
+    ws.onmessage = (message) => {
+      let mobj = JSON.parse(message.data)
+      if(true) console.log('sw-ws receives', mobj)
+      try{
+        if(mobj.swType == 'FaceSVG'){
+          outbuffer.push(mobj.data)
+        }
+      } catch (err) {
+        console.error('bad form on SW connect', err)
+      }
+    }
+    statusMessage.set('ws startup...')
+  }
+
+  this.loop = () => {
+    // something like if(ws !== null && ws.isopen)
+    // if we have an open port, and have bytes to send downstream,
+    if (ws !== null && ws.readyState === 1) {
+      // could send,
+    }
+
+    // check if we have outgoing to pass along
+    if (outbuffer.length > 0 && !dtout.io()) {
+      dtout.put(outbuffer.shift())
+    }
+
+  }
+}
diff --git a/hunks/image/svgToImageData.js b/hunks/image/svgToImageData.js
new file mode 100644
index 0000000000000000000000000000000000000000..5f9c6aceb2f9c4601a578a15150184c08d931638
--- /dev/null
+++ b/hunks/image/svgToImageData.js
@@ -0,0 +1,122 @@
+/*
+hunks/image/svgToImageData.js
+
+read svg, make image data.
+
+Jake Read at the Center for Bits and Atoms
+Neil Gershenfeld at the CBA
+(c) Massachusetts Institute of Technology 2019
+
+This work may be reproduced, modified, distributed, performed, and
+displayed for any purpose, but must acknowledge the squidworks and cuttlefish projects.
+Copyright is retained and must be preserved. The work is provided as is;
+no warranty is provided, and users accept all liability.
+*/
+
+import {
+  Hunkify,
+  Input,
+  Output,
+  State
+} from '../hunks.js'
+
+// ahn test string ...
+let svgString = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"100.80402657534\" height=\"151.75086719281\" viewBox=\"0 0 0.0284491370844639 0.0428274680101977\" style=\"background:black\"><path d=\" M  0,0.0328274680101977 L  0,0 L  0.00842724217606665,0 L  0.00842724217606665,0.005 L  0.0134272421760667,0.005 L  0.0134272421760667,0 L  0.0184491370844639,0 L  0.0184491370844639,0.0017 L  0.0151272421760667,0.0017 L  0.0151272421760667,0.0067 L  0.00842724217606665,0.0067 L  0.00842724217606665,0.0328274680101977 L  0,0.0328274680101977\" style=\"fill:#ffffff;fill-rule:evenodd;\" transform=\"translate(0.005 0.0378274680101977), scale(1, -1)\" /></svg>"
+
+export default function svgToImageData() {
+  Hunkify(this)
+  // 'string' 'input', get it?
+  let strin = this.input('string', 'svg')
+  let imgOut = this.output('ImageData', 'image')
+  let width = this.output('number', 'width (mm)')
+  let dpi = this.state('number', 'dpi', 300)
+  // to manipulate full scale:
+  let vcanvas = document.createElement('canvas')
+  let haveImageUpdate = false
+
+  // ... getsize, draw, fill ?
+  let getSize = (svg) => {
+    // where 'svg' is some string, we return width, height, units
+    let i = svg.indexOf("width")
+    if (i == -1) {
+      return ({
+        width: 1,
+        height: 1,
+        units: 90
+      })
+    } else {
+      var i1 = svg.indexOf("\"", i + 1)
+      var i2 = svg.indexOf("\"", i1 + 1)
+      var width = svg.substring(i1 + 1, i2)
+      i = svg.indexOf("height")
+      i1 = svg.indexOf("\"", i + 1)
+      i2 = svg.indexOf("\"", i1 + 1)
+      var height = svg.substring(i1 + 1, i2)
+      let ih = svg.indexOf("height")
+      let units = 0
+      if (width.indexOf("px") != -1) {
+        width = width.slice(0, -2)
+        height = height.slice(0, -2)
+        units = 90
+      } else if (width.indexOf("mm") != -1) {
+        width = width.slice(0, -2)
+        height = height.slice(0, -2)
+        units = 25.4
+      } else if (width.indexOf("cm") != -1) {
+        width = width.slice(0, -2)
+        height = height.slice(0, -2)
+        units = 2.54
+      } else if (width.indexOf("in") != -1) {
+        width = width.slice(0, -2)
+        height = height.slice(0, -2)
+        units = 1
+      } else {
+        units = 90
+      }
+      return ({
+        width: width,
+        height: height,
+        units: units
+      })
+    }
+  }
+
+  let loadImage = (svg, size) => {
+    // btoa converts str. to base 64
+    let src = "data:image/svg+xml;base64," + window.btoa(svg)
+    let img = new Image()
+    img.setAttribute('src', src)
+    let width = size.width * dpi.value / size.units
+    let height = size.height * dpi.value / size.units
+    img.onload = () => {
+      // new vcanvas always,
+      vcanvas = document.createElement('canvas')
+      vcanvas.width = width
+      vcanvas.height = height
+      let ctx = vcanvas.getContext('2d')
+      ctx.drawImage(img, 0, 0, width, height)
+      // now we are set,
+      haveImageUpdate = true
+    }
+  }
+
+  let test = this.state('boolean', 'test', false)
+  test.onChange = (value) => {
+    let size = getSize(svgString)
+    loadImage(svgString, size)
+    test.set(false)
+  }
+
+  this.loop = () => {
+    if(strin.io() && !haveImageUpdate){
+      let str = strin.get()
+      let size = getSize(str)
+      loadImage(str, size)
+    }
+    if (haveImageUpdate && !imgOut.io() && !width.io()) {
+      imgOut.put(vcanvas.getContext('2d').getImageData(0, 0, vcanvas.width, vcanvas.height))
+      width.put(vcanvas.width * 25.4/dpi.value)
+      haveImageUpdate = false
+    }
+  }
+}
diff --git a/hunks/interface/array.js b/hunks/interface/array.js
index d305e6ad8b6b0bf91ac7d2c5903c0f7086e848f1..5541f08e0ef048c27bbe7fc1bddaf5cd37645a0d 100644
--- a/hunks/interface/array.js
+++ b/hunks/interface/array.js
@@ -24,16 +24,7 @@ export default function Number() {
     let op = this.output('array', 'arr')
     let opv = this.state('string', 'csv', '0, 0, 0')
 
-    // as is tradition,
-    this.dom = {}
-
-    this.init = () => {
-        // manager calls this once
-        // it is loaded and state is updated (from program)
-        this.dom = $('<div>').get(0)
-        //this.dom = document.createElement('div')
-    }
-
+    // str -> arr (nums)
     let convert = (str) => {
       let arr = opv.value.split(',')
       for(let i = 0; i < arr.length; i ++){
@@ -42,22 +33,22 @@ export default function Number() {
       return arr
     }
 
-    this.onload = () => {
-      let contact = $('<div>').addClass('btn').append('! shipment !').get(0)
-      $(this.dom).append(contact)
-      contact.addEventListener('click', (evt) => {
+    let dom = this.document()
+    let contact = $('<div>').addClass('btn').append('! ship it !').get(0)
+    contact.addEventListener('click', (evt) => {
+      if(op.io()){
+        console.warn("array attempts to push to occupied output")
+      } else {
         let arr = convert(opv.value)
-        if(!op.io()){
-          op.put(arr)
-        } else {
-          console.warn('this output is blocked')
-        }
-      })
-    }
+        op.put(arr)
+      }
+    })
+    $(dom).append(contact)
 
     this.loop = () => {
       if(ip.io() && !op.io()){
         let str = ip.get()
+        // upd8 the state for this, as well...
         opv.set(str)
         let arr = convert(str)
         op.put(arr)
diff --git a/hunks/statemachines/saturn.js b/hunks/statemachines/saturn.js
index e47e5cdeadcc2b0467c3b6c9d07f424c258db832..086419f12eb919a9ccef74fd6f271c8e07486c4e 100644
--- a/hunks/statemachines/saturn.js
+++ b/hunks/statemachines/saturn.js
@@ -62,8 +62,8 @@ export default function Saturn() {
   accelState.onChange = (val) => {
     if(val > 30){
       val = 30
-    } else if (val < 2){
-      val = 2
+    } else if (val < 0.5){
+      val = 0.5
     }
     accelState.set(val)
     accel = accelState.value