diff --git a/README.md b/README.md
index fdcaf83415897e3e79e87bd5a2d4807da91e47e0..f84ccd55d02f17b75decf768635b3d6860c2c820 100644
--- a/README.md
+++ b/README.md
@@ -16,122 +16,66 @@ Native Cuttlefish 'Hunks' are given access to a DOM/div element, making them nic
 
 'aye, but as the legends state: software doth make the hardware singeth'
 
-## The Current Pickle
+IAA ... it's all addressing -> ->
 
-while writing up the patchset tool, to load 'patches' (collections of hunks and links), and proceeded by a realization earlier this morning, I am thinking that I should re-cast messages more explicitly as trees: in particular, that I should index and ID objects (hunks, states, etc) by their position in the arrays where they live. this prevents me from needing to do string-based lookups (which is easy in js, but slow in real life) to make local calls via the network. i.e - it's routing all the way down. I'm going to split this branch here, and start re-rolling through serialization to go again. 
+remote managers can't just throw messages about: they have to have some contextual awareness of the view ? or their connectedness ? can keep existing structure and just wait until have-said-hello or not
 
-as I'm rolling through this I'm coming to a question about state item management. right now, what I've set out to do its:
- - load hunk(s)
- - and then, if program-saved state is different in a hunk, make a 'statechange request', and wait for those to come back in whatever state they do.
- - this means that I don't get updated state when programs init, which is how it would it would presumably work inside of a manager opening up a program : load the hunk, write the state values, init, loop
- - instead I'll see load -> loop -> make statechange requests
- - while this feels a bit cumbersome at the moment, it might be nice because this way when I'm writing hunks I'm only writing 'onchange' functions for state, and I can assume that init happens with default values.
- - i'm weary of this approach for systems that I want to run without the view in play, but that point is a bit farther away. code is easy to rewrite.
+ -> added 'isConnectedTo' feature, won't work when connections disappear though !
 
-I'm also thinking that state-messages might want to be 'routed' - like stateChange should go by state[index], rather than looking up names. the same might be nice of hunks in a list, but then I am having to assign key to each one ! ... let's see how much of a PITA id-lookups are in the next ponyo loop
+... so, and view needs to be sensitive to that, and watch state on a refresh also ?
 
-w/r/t ponyo - I'll have to see how difficult this is when writing motor control hunks; what about enable pins etc, that are important to startup in known conditions ??
+... towards decent views ... and a debug-thru-cuttlefish portal for ponyo
+ - patchload is nice, ok, this direction
+ - layout ... save positions in patches ? unf- force layout ?
+ - write cobs, and a cobs patch -> proto logs out into a browser
+ - ... link work ? ... links agreeing with one another before startup
+  - results in link saying 'updatehunkdefinition' and manager ... reporting ? or not ?
+ - load -> then load -> then log, up through a few links
 
-another way to write these is to send 'addhunk' requests with names, potentially ids, and potentially state-index updates, before inits happen. this feels cleaner, and I think I need to do this now
+## On Friday the Hardware Singeth
 
-ok, I want to chart a path through this ... I need to
- - load programs,
-  - sidebar: re-write addHunk(name, id, state) ... and messages accordingly, and manager. ok.
-  - double sidebar: everything-by-index-of-list, with lenBytes ?
-  - hunk    - alive     (index)   - descr ... (also tree)
-            - removed   (index)   eom (and assume bump-down?)
-            - update    (index)   - state   (index)   - value
-                                  - links   - descr()
-  - problems:
-    - ids !== indexes ? both ? uuids ?
+ok, patches via this (numexcludes) hack ... that's ... just fine
+before walking over, probably a few final rites
+ - just sanity check the manager, probably write something (including notes about what-happens-next) ... and, like, where are you at with the manager message set? is this a complete set? consider embedded ... minimizing embedded work, and the corner cases like state loading and state-before-init ... !
+ - before you 'take the dive', wrap up typeset, and write those things down also
+ - also, to avoid insanity, maybe take tuesday morning for hardware / swd debugging ? load that bootloader, say hello to ponyo ?
 
- - some of the issue is a worry about the speed of string == calls in cpp,
- - and regardless, a find-by-lookup rather than a route-to-item structure
- - I think, given the world as it is, route-to-item makes a lot of sense
- - this is also going to pinch message sizes
- - fak
- - this is a lot to re-write
+really, genuinely, things you'll want as you go  
+ - bring back splash loading ? save positions into patches? I'm imagining a more complete system with in heavy program-reps-in-json only world ...
 
+ok, for the future, save will only be possible with a 'save selected' patch or something similar: picking whether bootstrap hunks should be added etc ... I can't make this decision right now
 
-  - 2nd sidebar: states by index ?
+for now, just don't save those... you know which ones they are, and you can check the version in the view, and have a standard (known) bootstrap program set. ok... then we can rip thru adding programs !  
 
- - load a program that speaks to nautilus
-  - (and then) load a nautilus program that speaks to ponyo
-  - then I'm on trax for ponyo dev, that's ok
-  - I think I can hit all of these steps today ... nt soon,
-  - it's probably worth some time at that point to organize the net-via-net-via-view issue? this problem as it goes ...
+still need to work out those relative-links-and-indices
 
-once I'm back at ponyo, wakeup, I'll minmax some pnp time to make the headboards, and a stepper
-
- -> view
-  - could save some headache, place contextmenu in top-level dom, not on plane? makes some sense
-  - style the save-patch input box to match states
-
- -> typeset
-  - do name -> names: ['float64', 'number'], for same byte-cast for colloquial type cast ... i.e. uint8 and byte, ? what else ? is it worth it, or just copy pasta ? should also be lists of things that can be hooked up !
-
-  what of these hunks that will autoload each time, the bootstraps?
-  ... np, fam, when we send a request to the manager to add them,
-  managers should just reply w/ an error - we have paths for that
-  this is a bug we can iron out later and ignore
-
- -> with programs, prototype a bootstrap that loads cuttlefish and waits ... then loads a program there ?
-
-maybe this is something of a JAMTOC moment ... the view stores and manipulates represenations, we only need a minimum set of messages to load that representation remotely
-
-I'm very close, though, and want to focus. I should be talking to a nautilus manager tonight and prototyping how I want remote resources to open up from cuttlefish.
-
-OK. I'm just through serializing things. I'd really like to be into ponyo early tomorrow.
-
-So I'm going to take a minute and see if I can find a reasonable way to scrape view into a few different files...
- - view.js ... is messaging entry point, loop and init ...
- - vdom.js ... writedefdom, etc (done)
- - vmsg.js ... that message board (pull this out first) (done)
- - vbzt.js ... bztools (this next) (done)
- - vflo.js ... force layout (next time)
- - then I can do like vprgmem.js (ok)
-
-questions
- - why does a new view init with the same 'ok' in the titlebox / msgbox ?
- - because  #ids are not really unique and you were jquerying to the (0th) instance
+this is an impatience thing, I should note. on another loop through the view, this will be first order.
 
 ...
-then, go to nautilus, write cobserial, consider how to quickload program for ponyo test
 
-The next meaningful work on ponyo happens when I can:
- - easily load the messy program-via-links that is cuttlefish -> nautilus with-a-link, from cuttlefish, with minimal clicks (assuming a running nautilus scratch)
+monday circuits, programming, ponyo hello / refresher, and instron assembly ?
 
--> manager cleanup, ref to old code ...
- - refresh wipes and then asks for currently-running program,
- - i doth want to break the view up into constituent parts,
+cuttlefish -> nautilus on tuesday, and see about drawing links // coordinating across links 'well' (but what of the split link ?)
 
--> now, to have a day at it, finish writing and go through view as you do
- - at the very moment, to test removing a link, find link-rm-message-writing code again in view, and modify it to work as a serial message ... then fill in on the manager side. this is a good time to break view up!
- - then hunk state changes ...
- - then adding links ...  etc
+ponyo late tueday, and wednesday,
+thursday machine assy ... friday same, probably
 
- - now (maybe) bring program loading back into the view? saving programs?
+## A Pickle Averted
 
-Here's my list of things I think I will need ...
+ - ctrl f for INDSWAP
+ - and RETURN
 
-## Views can send ...
+program save / load
+ - rewrite / integrate with briefstate messages ?
+ - once up, test deleting etc, some uncertainty about connection unhooking
 
-hello           -> eom
-reqprogram      -> eom
-reqlistavail    -> eom
-reqaddhunk      -> (string) name
-reqstatechange  -> (string) hunkid, (uint8) index, (type) value
-reqaddlink      -> (string) outId, (uint8) otpi, (string) inId, (uint8) inpti
+ // for interest, 'startStateRefresh()' inside of vptch.js is where you broke off
 
-## Managers can reply ...
+ // to restart, go back to saving patches: do by index, etc... and then on reloads, you'll have to contend with that same-ness issue ... i.e. those first two hunks, or whatever other bootstrap structure is being replaced
 
-brief           -> (string) interpreter, (uint16) numhunks, (uint16) numlinks
-listofavail     -> (list of strings)
-hunkalive       -> (hunk serialization)
-hunkremoved     -> (string) id
-hunkstatechange -> (state change args)
-linkalive       -> (link args)
-linkremoved     -> (link args)
+links, cuttlefish
+ - going to have to wrastle type conversion allowances, i.e. want to go from num -> uint8 at the link, fluidly, and want to be able to name js types with 'uint8' - particularely at the link, try this first, that's your entry bug
+ - link also doesn't build inputs / outputs when the names are 1 char long
 
 ---
 
diff --git a/bootstrap.js b/bootstrap.js
index dc6bc8b7369d2ba3f727fc462da49442d9e31082..aca6859cfc80a50fc95fa5f6713d71bde449534c 100644
--- a/bootstrap.js
+++ b/bootstrap.js
@@ -16,38 +16,41 @@ import Manager from './hunks/manager.js'
 
 // our invisible overlord
 let NROL = new Manager()
-NROL.name = 'manager'
-NROL.id = 'NROL39_0'
 NROL.init()
 // this is going to sit in the outbuffer until the view resolves
 
 function bootloop() {
-    // js u wyldin !
-    try{
-      NROL.loop()
-    } catch (err) {
-      console.log('top level err:', err)
-    }
-    setTimeout(bootloop)
+  // js u wyldin ! (this is probably slow)
+  //let go = true
+  try {
+    NROL.loop()
+  } catch (err) {
+    //go = false
+    console.error('top level err:', err)
+  }
+  setTimeout(bootloop)
 }
 
 // want handles on this we think ?
 let View = {}
 
 window.onload = () => {
-    console.log('BOOTUP')
-    NROL.addHunk('view', 'TLView').then((view) => {
-        // console.log('ADDHUNK VIEW RESOLVES')
-        View = view
-        $(View.dom).attr('id', 'NROLVIEW')
-        $('#wrapper').get(0).append(View.dom)
-    }).then(() => {
-        NROL.addLink(View.id, 'msgs', NROL.id, 'msgs')
-        NROL.addLink(NROL.id, 'msgs', View.id, 'msgs')
-        bootloop()
-        // kick this later
-        setTimeout(View.refresh, 150)
-    }).catch((err) => {
-        console.log(err)
-    })
+  console.log('BOOTUP')
+  NROL.addHunk('view').then((view) => {
+    // console.log('ADDHUNK VIEW RESOLVES')
+    View = view
+    view.isTopLevelView = true
+    // not really sure about this yet
+    $(View.dom).attr('id', 'NROLVIEW')
+    $('#wrapper').get(0).append(View.dom)
+  }).then(() => {
+    // outHunkIndex, outIndex, inHunkIndex, inIndex, debug
+    NROL.addLink(1, 0, 0, 0, false)
+    NROL.addLink(0, 0, 1, 0, false)
+    bootloop()
+    // kick this later
+    setTimeout(View.refresh, 150)
+  }).catch((err) => {
+    console.log(err)
+  })
 }
diff --git a/hunks/comm/websocketclient.js b/hunks/comm/websocketclient.js
index c6a53fcf1a7e44ae612f7fb5606ac1654ed63bd3..d94956c5c5d8429b33ac7a8e7cf22b44728c12bf 100644
--- a/hunks/comm/websocketclient.js
+++ b/hunks/comm/websocketclient.js
@@ -12,21 +12,24 @@ import {
 } from '../hunks.js'
 
 function WebSocketClient() {
-  Hunkify(this, 'WebSocketClient')
+  Hunkify(this)
 
-  let dtin = new Input('Object', 'data')
+  let debug = false
+
+  let dtin = new Input('byteArray', 'data', this)
   this.inputs.push(dtin)
 
-  let dtout = new Output('Object', 'data')
+  let dtout = new Output('byteArray', 'data', this)
   this.outputs.push(dtout)
 
   // TODO is tackling state sets / updates / onupdate fn's
   // this is hunk -> manager commune ...
-  let statusMessage = new State('String', 'status', 'closed')
-  let retryCountHandle = new State('Number', 'retrycount', 3)
-  let addressState = new State('String', 'address', '127.0.0.1')
-  let portState = new State('String', 'port', '2042')
-  this.state.push(statusMessage, retryCountHandle, addressState, portState)
+  let statusMessage = new State('string', 'status', 'closed')
+  let retryCountHandle = new State('number', 'retrycount', 3)
+  let resetRetryHandle = new State('boolean', 'retryreset', false)
+  let addressState = new State('string', 'address', '127.0.0.1')
+  let portState = new State('number', 'port', 2042)
+  this.states.push(statusMessage, retryCountHandle, resetRetryHandle, addressState, portState)
 
   // this ws is a client,
   let ws = {}
@@ -37,21 +40,27 @@ function WebSocketClient() {
     setTimeout(startWs, 500)
   }
 
+  resetRetryHandle.change = (value) => {
+    retryCountHandle.set(3)
+    startWs()
+    // to actually change the value, we would do:
+    // resetRetryHandle.set(value)
+  }
+
   let startWs = () => {
     // manager calls this once
     // it is loaded and state is updated (from program)
     url = 'ws://' + addressState.value + ':' + portState.value
-    console.log('INIT WS', url)
+    if(debug) console.log('INIT WS', url)
     ws = new WebSocket(url)
+    ws.binaryType = "arraybuffer"
     ws.onopen = (evt) => {
       this.log('ws opened')
-      this.log('the ws object', ws)
-      this.log(evt)
-      statusMessage.set('opened')
+      statusMessage.set('open')
     }
     ws.onerror = (evt) => {
       this.log('ws error, will reset to check')
-      console.log(evt)
+      if(debug) console.log(evt)
       statusMessage.set('error')
       setCheck(500)
     }
@@ -59,12 +68,18 @@ function WebSocketClient() {
       this.log('ws close')
       setCheck(500)
     }
-    ws.onmessage = (msg) => {
-      console.log("WS RX:", msg.data)
-      if (!dtout.io && this.outbuffer.length === 0) {
-        dtout.put(JSON.parse(msg.data))
+    ws.onmessage = (message) => {
+      // this should be a buffer
+      if(debug) console.log('WS receives', message.data)
+      // tricks?
+      // ok, message.data is a blob, we know it's str8 up bytes, want that
+      // as an array
+      let msgAsArray = new Uint8Array(message.data)
+      if(debug) console.log('WS receive, as an array:', msgAsArray);
+      if (dtout.ie && this.outbuffer.length === 0) {
+        dtout.put(msgAsArray)
       } else {
-        this.outbuffer.push(msg.data)
+        this.outbuffer.push(msgAsArray)
       }
     }
     statusMessage.set('connecting ...')
@@ -126,10 +141,12 @@ function WebSocketClient() {
     if (ws !== null && ws.readyState === 1) {
       // no buffering
       if (dtin.io) {
-        let message = dtin.get()
+        let arr = dtin.get()
+        if(debug) console.log('WS transmission as array', arr)
+        let bytesOut = Uint8Array.from(arr)
         // HERE insertion -> buffer.from() ?
-        console.log("WS SENDING", message)
-        ws.send(JSON.stringify(message))
+        if(debug) console.log("WS sending buffer", bytesOut.buffer)
+        ws.send(bytesOut.buffer)
       }
     }
 
diff --git a/hunks/hidden/primitives/objects/move.js b/hunks/hidden/primitives/objects/move.js
index f17afd4c3fde76a1c2052c3fb56121e060d3283e..ec29f85e0b00efb69c921c033093d358ed03654c 100644
--- a/hunks/hidden/primitives/objects/move.js
+++ b/hunks/hidden/primitives/objects/move.js
@@ -15,7 +15,7 @@ function Name() {
 
     this.inputs.a = Input('type', 'name')
     this.outputs.b = Output('type', 'name')
-    this.state.item = State('type', 'name')
+    this.states.item = State('type', 'name')
 
     this.init = () => {
         // manager calls this once 
diff --git a/hunks/hidden/primitives/objects/primal/array.js b/hunks/hidden/primitives/objects/primal/array.js
index f17afd4c3fde76a1c2052c3fb56121e060d3283e..ec29f85e0b00efb69c921c033093d358ed03654c 100644
--- a/hunks/hidden/primitives/objects/primal/array.js
+++ b/hunks/hidden/primitives/objects/primal/array.js
@@ -15,7 +15,7 @@ function Name() {
 
     this.inputs.a = Input('type', 'name')
     this.outputs.b = Output('type', 'name')
-    this.state.item = State('type', 'name')
+    this.states.item = State('type', 'name')
 
     this.init = () => {
         // manager calls this once 
diff --git a/hunks/hidden/primitives/string.js b/hunks/hidden/primitives/string.js
index f17afd4c3fde76a1c2052c3fb56121e060d3283e..ec29f85e0b00efb69c921c033093d358ed03654c 100644
--- a/hunks/hidden/primitives/string.js
+++ b/hunks/hidden/primitives/string.js
@@ -15,7 +15,7 @@ function Name() {
 
     this.inputs.a = Input('type', 'name')
     this.outputs.b = Output('type', 'name')
-    this.state.item = State('type', 'name')
+    this.states.item = State('type', 'name')
 
     this.init = () => {
         // manager calls this once 
diff --git a/hunks/hidden/primitives/template.js b/hunks/hidden/primitives/template.js
index f17afd4c3fde76a1c2052c3fb56121e060d3283e..ec29f85e0b00efb69c921c033093d358ed03654c 100644
--- a/hunks/hidden/primitives/template.js
+++ b/hunks/hidden/primitives/template.js
@@ -15,7 +15,7 @@ function Name() {
 
     this.inputs.a = Input('type', 'name')
     this.outputs.b = Output('type', 'name')
-    this.state.item = State('type', 'name')
+    this.states.item = State('type', 'name')
 
     this.init = () => {
         // manager calls this once 
diff --git a/hunks/hunks.js b/hunks/hunks.js
index ca04ed14ec7cf5212d6c9cd2611e3d38a786332e..492dbbf675cd72193aed85ec6e402a56d455a5a9 100644
--- a/hunks/hunks.js
+++ b/hunks/hunks.js
@@ -2,22 +2,29 @@
 /* ------------------------ HUNKITUP ------------------------- */
 /* ---------------------------    ---------------------------- */
 
-function Hunkify(hunk, name) {
+import { TSET } from '../typeset.js'
+
+function Hunkify(hunk) {
   // scripting languages should name hunks by their script location and filename
   // compiled languages will assign a string
-  hunk.id = null
+  // because this is always added by .addHunk(path) (path == name)
+  // we set this during load, only once, this avoids some confusion
   hunk.name = null
+  // we keep a copy of our position-in-the-array ...
+  hunk.ind = null
 
   hunk.log = function(msg) {
+    let str = `LG from ${hunk.name} at ${hunk.ind}: `
     for (let i = 0; i < arguments.length; i++) {
-      console.log('LG:', hunk.id, ':', arguments[i])
+      str += arguments[i] + ', '
     }
+    console.log(str)
   }
 
   // input, output, and state: ay balls, here we go
   hunk.inputs = new Array()
   hunk.outputs = new Array()
-  hunk.state = new Array()
+  hunk.states = new Array()
 
   // top-secret backdoor
   hunk.mgr = {}
@@ -27,14 +34,16 @@ function Hunkify(hunk, name) {
 /* -------------------------- INPUT -------------------------- */
 /* ---------------------------    ---------------------------- */
 
-function Input(type, name, linktype) {
+function Input(type, name, parent, linktype) {
   this.name = name
   this.type = type
+  // need this ...
+  this.parent = parent
   this.ref = null
   this.data = null
   this.io = false
   // rules, baby
-  if(!isOKType(type)){
+  if (!isOKType(type)) {
     throw new Error(`unknown type specified at input, wyd? type: ${this.type}, name: ${this.name}`)
   }
 
@@ -48,7 +57,7 @@ function Input(type, name, linktype) {
     } else {
       this.data = data
       // minutia hack for view function
-      if(ref) this.ref = ref
+      if (ref) this.ref = ref
       this.io = true
     }
   }
@@ -64,8 +73,33 @@ function Input(type, name, linktype) {
     }
   }
 
-  // hurmmm
-  if(linktype){
+  this.findOwnIndex = () => {
+    // find self in parent's inputs
+    let index = this.parent.inputs.findIndex((cand) => {
+      return (cand.name === this.name && cand.type === this.type)
+    })
+    if (index === -1) throw new Error('input could not find itself in parent')
+    return index
+  }
+
+  // we keep a list as well,
+  this.connections = new Array()
+  this.disconnect = (output) => {
+    let index = this.connections.findIndex((cand) => {
+      return (cand.parent.ind === output.parent.ind && cand.name === output.name && cand.type === output.type)
+    })
+    if (index === -1) throw new Error('during output disconnect, input cannot find output...')
+    this.connections.splice(index, 1)
+    // find the reference in our array,
+  }
+  this.disconnectAll = () => {
+    for (let op of this.connections) {
+      op.disconnect(this)
+    }
+  }
+
+  // inputs / outputs for 'link' (a hunk) ports have more state,
+  if (linktype) {
     // assume clear upstream on startup, maybe dangerous?
     this.icus = true
   }
@@ -75,9 +109,10 @@ function Input(type, name, linktype) {
 /* ------------------------- OUTPUT -------------------------- */
 /* ---------------------------    ---------------------------- */
 
-function Output(type, name, linktype) {
+function Output(type, name, parent, linktype) {
   this.name = name
   this.type = type
+  this.parent = parent
   this.ref = null
   this.data = null
   this.posted = false
@@ -108,8 +143,8 @@ function Output(type, name, linktype) {
       }
     }
     this.transport = () => {
-      for(let pair of this.connections){
-        pair.input.put(this.data)
+      for (let input of this.connections) {
+        input.put(this.data)
       }
       this.posted = true
     }
@@ -133,8 +168,8 @@ function Output(type, name, linktype) {
       }
     }
     this.transport = () => {
-      for(let pair of this.connections){
-        pair.input.put(deepCopy(this.data), this.ref)
+      for (let input of this.connections) {
+        input.put(deepCopy(this.data), this.ref)
       }
       this.posted = true
     }
@@ -149,50 +184,57 @@ function Output(type, name, linktype) {
   /* ---------------- OUTPUT MANAGE CONNECTIONS ---------------- */
   /* ---------------------------    ---------------------------- */
 
-  this.attach = (input, pid) => {
+  this.attach = (input) => {
     // no rules on types ATM, historic placeholder
-    if (this.type === input.type || input.type === 'Any' || true ) {
-      this.connections.push({
-        input: input,
-        parentId: pid
-      })
+    if (this.type === input.type || input.type === 'any' || true) {
+      input.connections.push(this)
+      this.connections.push(input)
+      return true
     } else {
       throw new Error('attempt to attach mismatched types')
     }
   }
 
-  this.remove = (input, pid) => {
+  this.remove = (input) => {
     // find by names pls
-    let recip = {
-      input: input,
-      parentId: pid
-    }
-    let pos = -1
-    let conn = this.connections.find((cn, i) => {
-      pos = i
-      return ((cn.parentId === recip.parentId) && (cn.input.name === recip.input.name))
+    let ind = this.connections.findIndex((cand) => {
+      return (cand.name === input.name && cand.type === input.type)
     })
-    if (conn !== undefined | conn !== null) {
-      this.connections.splice(pos, 1)
+    if (ind !== -1) {
+      input.disconnect(this)
+      this.connections.splice(ind, 1)
       return true
     } else {
-      console.log('was looking for ', recip, 'in', this.connections)
+      console.log('remove err, was looking for', input, 'in', this.connections)
       return false
     }
   }
 
-  this.unhook = (pid) => {
-    for (let conn of this.connections) {
-      if (conn.parentId === pid) {
-        this.remove(conn)
-      }
+  this.findOwnIndex = () => {
+    // find self in parent's inputs
+    let index = this.parent.outputs.findIndex((cand) => {
+      return (cand.name === this.name && cand.type === this.type)
+    })
+    if (index === -1) {
+      console.log(`output could not find itself in parent: ${index}`, this, 'unstrung', this.parent.outputs, 'strung', JSON.parse(JSON.stringify(this.parent.outputs)))
+      throw new Error(`output could not find itself in parent: ${index}`)
     }
+    return index
+  }
+
+  this.disconnectAll = () => {
+    for (let ip of this.connections) {
+      // here we're disconnecting the input, meaning the input is removing this from its list of connections
+      ip.disconnect(this)
+    }
+    // this is actually a genuine way to delete an array in js, http://shrugguy.com
+    this.connections.length = 0
   }
 
   /* ---------------------------    ---------------------------- */
   /* ----------- OUTPUT TRICKS FOR LINK CONNECTIONS ------------ */
   /* ---------------------------    ---------------------------- */
-  if(linktype){
+  if (linktype) {
     // has stash ?
     this.needsAck = false;
   }
@@ -203,7 +245,7 @@ function State(type, name, startup) {
   this.name = name
   this.type = type
   // have to be a type we can recognize,
-  if(!isOKType(type)){
+  if (!isOKType(type)) {
     throw new Error(`unknown type specified at state, wyd? type: ${this.type}, name: ${this.name}`)
   }
   // TODO pls add check for missing startup value ?
@@ -235,27 +277,21 @@ function deepCopy(obj) {
   return JSON.parse(JSON.stringify(obj))
 }
 
-function isOKType(type){
+function isOKType(type) {
   // etc, lowecase to match with typeof ~ queeeries ~
-  return (type === 'number'
-    || type === 'boolean'
-    || type === 'string'
-    || type === 'object'
-    || type === 'any'
-    || type === 'byte'
-    || type === 'byteArray'
-    || type === 'uint8'
-    || type === 'uint8Array'
-    || type === 'int8'
-    || type === 'int8Array'
-    || type === 'uint32'
-    || type === 'uint32Array'
-    || type === 'int32'
-    || type === 'int32Array'
-  )
+  let ind = TSET.findIndex((cand) => {
+    return cand.name === type
+  })
+  if(ind === -1){
+    return false
+  } else if (type === 'any') {
+    console.log('WARN!, type of "any" is a bit risky, and cannot traverse a link')
+    return true
+  } else {
+    return true
+  }
 }
 
-
 export {
   Hunkify,
   Input,
diff --git a/hunks/input/string.js b/hunks/input/string.js
index 4272342fb498db1a2d8413168d3715e86e7d9996..27f3d4fae839e6bdf6882ee30b6016603e11604a 100644
--- a/hunks/input/string.js
+++ b/hunks/input/string.js
@@ -17,8 +17,8 @@ function Strang() {
     let stringOutput = new Output('string', 'string')
     this.outputs.push(stringOutput)
 
-    // this.state.prefix = new State('string', 'prefix', 'LOG:')
-    // this.state.onchange = new State('boolean', 'onchange', true)
+    // this.states.prefix = new State('string', 'prefix', 'LOG:')
+    // this.states.onchange = new State('boolean', 'onchange', true)
 
     this.dom = {}
 
diff --git a/hunks/interface/button.js b/hunks/interface/button.js
index 20fd611657d41eb542df72cd834e9af202d90e1b..d7d9707a0e0cd35eae83564cfde190c245f6c117 100644
--- a/hunks/interface/button.js
+++ b/hunks/interface/button.js
@@ -16,11 +16,11 @@ function Button() {
     this.outputs.mouseup = new Output('event', 'mouseup')
     */
 
-    this.state.strang = new State('string', 'strng', 'start value')
-    this.state.numbr = new State('number', 'nmbr', 101)
-    this.state.blen = new State('boolean', 'bln', false)
+    this.states.strang = new State('string', 'strng', 'start value')
+    this.states.numbr = new State('number', 'nmbr', 101)
+    this.states.blen = new State('boolean', 'bln', false)
 
-    this.state.strang.update('value is the real part')
+    this.states.strang.update('value is the real part')
 
     this.dom = {}
 
diff --git a/hunks/interface/logger.js b/hunks/interface/logger.js
index b4c8d1b2ffea2495035c2e1a80d03ac012d8eee8..542950c0149b16dc8a0c581101772d10d01a2000 100644
--- a/hunks/interface/logger.js
+++ b/hunks/interface/logger.js
@@ -14,7 +14,7 @@ function Logger() {
 
     let prefix = new State('string', 'prefix', 'LOG:')
     let logToConsole = new State('boolean', 'console', true)
-    this.state.push(prefix, logToConsole)
+    this.statess.push(prefix, logToConsole)
 
     this.dom = {}
 
diff --git a/hunks/interface/number.js b/hunks/interface/number.js
index a531fdaf1651efbf6d8b55da9d4577def2fc611e..c97a338a1f0db76c17b950cebe1f6dec849d7d15 100644
--- a/hunks/interface/number.js
+++ b/hunks/interface/number.js
@@ -12,13 +12,13 @@ import {
 } from '../hunks.js'
 
 function Number() {
-    Hunkify(this, 'Number Input')
+    Hunkify(this)
 
-    let numout = new Output('number', 'num')
+    let numout = new Output('number', 'num', this)
     this.outputs.push(numout)
 
     let numrep = new State('number', 'numrep', 275074)
-    this.state.push(numrep)
+    this.states.push(numrep)
 
     // as is tradition,
     this.dom = {}
diff --git a/hunks/link.js b/hunks/link.js
index dcc147f13267838a9545b8d0cabb53d3b49cb371..3095aa1c5d0910718fb0527c10f35818855ac806 100644
--- a/hunks/link.js
+++ b/hunks/link.js
@@ -1,6 +1,6 @@
 /*
 
-line input
+hookup,
 
 */
 
@@ -13,21 +13,23 @@ import {
 } from './hunks.js'
 // END HEADER
 
-import { TSET, MSGKEY_ACK } from '../typeset.js'
+import { TSET, LK, MSGS } from '../typeset.js'
 
 function Link() {
-  Hunkify(this, 'Link')
+  Hunkify(this)
 
-  let dtin = new Input('byteArray', 'data')
+  let debug = false
+
+  let dtin = new Input('byteArray', 'data', this)
   this.inputs.push(dtin)
 
-  let dtout = new Output('byteArray', 'data')
+  let dtout = new Output('byteArray', 'data', this)
   this.outputs.push(dtout)
 
   // default messages -> manager, besides also data link
   let inputList = new State('string', 'inputList', "mgrMsgs (byteArray)")
   let outputList = new State('string', 'outputList', "mgrMsgs (byteArray)")
-  this.state.push(inputList, outputList)
+  this.states.push(inputList, outputList)
 
   /* ---------------------------    ---------------------------- */
   /* ------------------ OP ON KEYS FROM STATE ------------------ */
@@ -80,9 +82,9 @@ function Link() {
       } else {
         // the object doesn't already exist,
         if(input){
-          this.inputs[kp + 1] = new Input(nks[kp].typeKey, nks[kp].nameKey, true)
+          this.inputs[kp + 1] = new Input(nks[kp].typeKey, nks[kp].nameKey, this, true)
         } else {
-          this.outputs[kp + 1] = new Output(nks[kp].typeKey, nks[kp].nameKey, true)
+          this.outputs[kp + 1] = new Output(nks[kp].typeKey, nks[kp].nameKey, this, true)
         }
       }
     }
@@ -104,14 +106,15 @@ function Link() {
     swapLists(value, true)
     // if OK
     inputList.set(value)
-    this.mgr.serializeAndSendHunk(this)
+    // we have to report this ...
+    this.mgr.evaluateHunk(this)
   }
 
   outputList.change = (value) => {
     swapLists(value, false)
     // if ok
     outputList.set(value)
-    this.mgr.serializeAndSendHunk(this)
+    this.mgr.evaluateHunk(this)
   }
 
   /* ---------------------------    ---------------------------- */
@@ -125,12 +128,12 @@ function Link() {
     // just add in order
     let ipKeys = getTypeAndNameKeys(inputList.value)
     for(let kp of ipKeys){
-      this.inputs.push(new Input(kp.typeKey, kp.nameKey, true))
+      this.inputs.push(new Input(kp.typeKey, kp.nameKey, this, true))
     }
 
     let opKeys = getTypeAndNameKeys(outputList.value)
     for(let kp of opKeys){
-      this.outputs.push(new Output(kp.typeKey, kp.nameKey, true))
+      this.outputs.push(new Output(kp.typeKey, kp.nameKey, this, true))
     }
 
   }
@@ -146,7 +149,7 @@ function Link() {
     // data[0] is the route, the link we need to bump on
     msg.port = data[0]
     // check for ack,
-    if(data[1] === MSGKEY_ACK){
+    if(data[1] === LK.ACK){
       msg.isAck = true
       return msg
     }
@@ -155,7 +158,8 @@ function Link() {
       return item.key === data[1]
     })
     if(phy === undefined) throw new Error(`type not found at deserialization for expected key ${data[1]}`)
-    msg.data = phy.read(data, 2)
+    msg.data = phy.read(data, 1).item
+    if(debug) console.log('demsg:', msg)
     return msg
   }
 
@@ -164,22 +168,22 @@ function Link() {
   // this ...
   let ack = (port) => {
     let msg = new Array()
-    msg.push(port, MSGKEY_ACK)
+    msg.push(port, LK.ACK)
     outbuffer.push(msg)
   }
 
   // serialize messages:
   let sermsg = (port, data, type) => {
-    let msg = new Array()
     if(typeof port !== 'number' || port > 254) throw new Error('port is no good at serialize')
-    msg.push(port)
     // type via this handy object:
     let phy = TSET.find((item) => {
       return item.name === type
     })
     if(phy === undefined) throw new Error(`type not found at serialization: ${type}`)
-    msg.push(phy.key)
-    msg = msg.concat(phy.write(data))
+    // we r ready,
+    let msg = [port]
+    MSGS.writeTo(msg, data, type)
+    if(debug) console.log('sermsg to outbuffer', msg)
     outbuffer.push(msg)
   }
 
@@ -192,6 +196,7 @@ function Link() {
       // pull it and deserialize it,
       let msg = demsg(dtin.get())
       if(msg.isAck){
+        if(debug) console.log('link ack conf on ', msg.port)
         // AN ACK
         if(this.inputs[msg.port].isNetClear){
           throw new Error('received ack on unexpected port')
@@ -207,6 +212,7 @@ function Link() {
         // not an ack, for port, if open, put data
         if(!(this.outputs[msg.port].io)){
           // clear ahead, typecheck and put
+          if(debug) console.log('link putting', msg.data, 'on', msg.port)
           this.outputs[msg.port].put(msg.data)
           this.outputs[msg.port].needsAck = true
           // and ack when it is pulled off,
@@ -219,10 +225,10 @@ function Link() {
     }// end if(dataIn is occupied)
 
     // (2) check if we can put
-    if(!dtout.io && outbuffer.length > 0){ // if we can send things to the world, do so
+    if(!(dtout.io) && outbuffer.length > 0){ // if we can send things to the world, do so
       // because of looping sys, we can only do this once per turn
       let turn = outbuffer.shift()
-      console.log('LINK OUT ->>', turn)
+      if(debug) console.log('LINK OUT ->>', turn)
       dtout.put(turn)
     }
 
@@ -240,6 +246,7 @@ function Link() {
       // only pull off of inputs if we are known to be clear downstream
       if(this.inputs[i].icus && this.inputs[i].io){
         let data = this.inputs[i].get()
+        if(debug) console.log(`link pulling message from ${i}, key ${data[0]}`)
         sermsg(i, data, this.inputs[i].type)
       }
     }
diff --git a/hunks/manager.js b/hunks/manager.js
index 1eb02e4f4edd6db2efdac77afd605f44bf109641..fdb3965f6b83138f2245a053546093e313221f5d 100644
--- a/hunks/manager.js
+++ b/hunks/manager.js
@@ -21,8 +21,8 @@ function Manager() {
   // need this tool
   let gg = new GoGetter
 
-  let msgsin = new Input('byteArray', 'msgs')
-  let msgsout = new Output('byteArray', 'msgs')
+  let msgsin = new Input('byteArray', 'msgs', this)
+  let msgsout = new Output('byteArray', 'msgs', this)
 
   this.inputs.push(msgsin)
   this.outputs.push(msgsout)
@@ -31,9 +31,13 @@ function Manager() {
   let hunks = new Array()
   this.hunks = hunks
 
+  // we keep track of whether-or-not we have any connections ...
+  this.isConnectedTo = false
+
   // debug flags
   let verbose = false
   let msgverbose = false
+  let addHunkVerbose = false
 
   /* ---------------------------    ---------------------------- */
   /* ---------------------- BUILDING LIST ---------------------- */
@@ -56,13 +60,18 @@ function Manager() {
 
   let serializeHunk = (hunk, bytes) => {
     // write the hunk into this array
-    bytes.push(HK.ID)
-    MSGS.writeTo(bytes, hunk.id, 'string')
+    bytes.push(HK.IND)
+    // here, we're counting on the hunk containing its own address-within-the-array
+    // that gets set during an add, or decremented during a remove
+    MSGS.writeTo(bytes, hunk.ind, 'uint16')
+    // an id, also, is nice, for optional human names ? maybe ?
     bytes.push(HK.NAME)
     MSGS.writeTo(bytes, hunk.name, 'string')
     // write inputs,
     if (hunk.inputs.length > 0) {
       for (let ip of hunk.inputs) {
+        // these should perhaps get their index, as well?
+        // but we're sending them in order, so ...
         bytes.push(HK.INPUT)
         MSGS.writeTo(bytes, ip.name, 'string')
         MSGS.writeTo(bytes, ip.type, 'string')
@@ -77,13 +86,13 @@ function Manager() {
       }
     }
     // write state,
-    if (hunk.state.length > 0) {
-      for (let st of hunk.state) {
+    if (hunk.states.length > 0) {
+      for (let st of hunk.states) {
         bytes.push(HK.STATE)
         MSGS.writeTo(bytes, st.name, 'string')
         MSGS.writeTo(bytes, st.type, 'string')
         // yarr, last is a debug flag
-        MSGS.writeTo(bytes, st.value, st.type, true)
+        MSGS.writeTo(bytes, st.value, st.type)
       }
     }
   }
@@ -92,21 +101,44 @@ function Manager() {
   /* ------------------- ADD / REMOVE A HUNK ------------------- */
   /* ---------------------------    ---------------------------- */
 
-  let addHunkVerbose = true
+  let stateSetFromSerial = (msg, inc) => {
+    // pull state index / value pairs
+    let temp
+    let stateSet = []
+    while(inc < msg.length){
+      if(msg[inc] !== HK.STATE) throw new Error(`error reading in state set, starts with ${msg[start]} at ${start}, should be ${HK.STATE}`)
+      let stateItem = {}
+      inc += 1
+      stateItem.ind = MSGS.readFrom(msg, inc, 'uint8').item
+      inc += 2
+      // pull type by key
+      let phy = TSET.find((cand) => {
+        return cand.key === msg[inc]
+      })
+      if(!phy) throw new Error(`error finding a key for this type, key is ${msg[inc]}`)
+      stateItem.type = phy.name
+      temp = MSGS.readFrom(msg, inc, stateItem.type)
+      stateItem.value = temp.item
+      stateSet.push(stateItem)
+      if(inc < 1) throw new Error('dangerous looping, exiting')
+      inc += temp.increment
+    }
+    return stateSet
+  }
 
-  this.addHunk = (hunkName, id, state) => {
+  this.addHunk = (hunkName, state) => {
     // hunks are named by path in js
     // so that we can add
     // so that we can link
     // so that we can go to links, websockets, node
     let path = './hunks/' + hunkName + '.js'
-    console.log('ok, from path', path)
+    if(verbose) console.log('ok, loading hunk from path', path)
 
     return new Promise((resolve, reject) => {
-      gg.importSource(path).then((src) => {
+      gg.importSource(path, false).then((src) => {
         if (addHunkVerbose) console.log('gg importing source resolves', src)
         try {
-          let hunk = sourceToHunk(src, hunkName, id, state)
+          let hunk = sourceToHunk(src, hunkName, state)
           hunks.push(hunk)
           resolve(hunk)
         } catch (err) {
@@ -117,53 +149,69 @@ function Manager() {
         reject(err)
       })
     })
-  }
+  } // end addHunk function,
 
-  let sourceToHunk = (src, name, id, state) => {
+  let sourceToHunk = (src, name, state) => {
     // make the instance from the constructor
     let hunk = {}
     try {
       hunk = new src()
       if (addHunkVerbose) console.log('cast to hunk as thing is ok', hunk)
     } catch (err) {
-      console.log('new() error', err)
+      console.error('new() error', err)
       throw new Error('cannot cast hunk as new thing()')
     }
+
     // name it (this is just the path)
     hunk.name = name
-    // id it, with a new ID if it doesn't have one, or
-    // with the ID from its program (occasionally provided) s
-    if (id !== undefined && id !== null) {
-      // TODO: BIGBOI: also check for duplicate ids ?? totally possible, very likely
-      hunk.id = id
-    } else {
-      // TODO: probably there is a better id, and what of program loads?
-      hunk.id = 'hnk_' + hunks.length
-    }
+    // and ref it (this is its address in the array of hunks)
+    // it's going to get pushed into this array next, so
+    hunk.ind = hunks.length
+    // a backdoor, a greeting, an ouroboros
+    hunk.mgr = this
 
     // now we open our doors to state changes
-    if (Array.isArray(hunk.state)) {
-      for (let st of hunk.state) {
-        st.hookup = (value) => {
-          console.log('MGR->View StateChange return via hookup')
+    // also: instead of this, since hunks have mgr hooks, something else?
+    if (Array.isArray(hunk.states)) {
+      for (let st in hunk.states) {
+        hunk.states[st].hookup = (value) => {
+          console.log('MGR -> View StateChange Return ... ')
           let msg = [MK.HUNKSTATECHANGE]
-          MSGS.writeTo(msg, hunk.id, 'string')
-          MSGS.writeTo(msg, st.name, 'string')
-          MSGS.writeTo(msg, value, st.type)
+          MSGS.writeTo(msg, hunk.ind, 'uint16')
+          // these calls to 'parseInt' on what look like indexed for-loops
+          // i.e. this for (let ...) is a javascriptism:
+          // an Array is just a JS object, so indices are also js 'key'
+          // and in a 'for item in iterable' loop in js, it assigns to each
+          // instance of item the 'key', keys being strings, hence the index
+          // coming through as a string... jsArray[1] is the same as jsArray["1"]
+          MSGS.writeTo(msg, parseInt(st), 'uint8')
+          MSGS.writeTo(msg, value, hunk.states[st].type)
           writeMessage(msg)
         }
       }
     }
 
-    // a backdoor, a greeting, an ouroboros
-    hunk.mgr = this
+    // if we have state arguments, set those now,
+    if(state){
+      for(let item of state){
+        try{
+          if(hunk.states[item.ind].type !== item.type){
+            console.error('skipping state update during hunk load, mismatched types')
+          } else {
+            hunk.states[item.ind].value = item.value
+          }
+        } catch (err) {
+          console.error('probably non-existent state while lookup via ind', err)
+        }
+      }
+    }
 
-    // startup code if it exists
+    // run init code (apres state setup!)
     if (hunk.init != null) {
       try {
         hunk.init()
       } catch (err) {
-        throw err
+        console.error('ERR caught while running hunk init code', err)
       }
     }
 
@@ -171,39 +219,50 @@ function Manager() {
     if (hunk.dom !== null && hunk.dom !== undefined) {
       // this is only allowed in the tlview, and we manage that...
       let tlv = hunks.find((cnd) => {
-        return cnd.id === 'TLView'
+        return cnd.isTopLevelView
       })
-      if (tlv === undefined) {
-        if (hunk.id !== 'TLView') writeErrMessage(`hunk appears with dom element, but no view is present ${hunk.id}`)
+      // via bootloop, tlv is always 2nd element
+      if (hunk.ind === 1 && hunk.name === 'view') {
+        if(verbose) console.log('passing on tlview')
+        // this is the top level, it's fine, we add in bootstrap.js
+      } else if (tlv === undefined) {
+        writeErrMessage(`something is up ... no toplevelview, trying to add native hunk with dom element`)
       } else {
-        console.log('cf taking native hunk')
+        tlv.msgbox.write('cf taking native hunk DOM element')
         tlv.take(hunk)
       }
-    }
+    } // end if-have-dom
 
     return hunk
   }
 
-  this.removeHunk = (id) => {
-    let hnk = hunks.find((element) => {
-      return id === element.id
-    })
-    if (hnk !== undefined) {
-      if (hnk.name === 'Manager' || id === 'TLView') {
-        writeErrMessage("I can't let you do that, dave")
-        return false
-      }
-      // rm then
-      hunks.splice(hunks.indexOf(hnk), 1)
-      // and unlink,
-      for (let hks of hunks) {
-        for (let otp of hks.outputs) {
-          otp.unhook(id)
-        }
+  this.removeHunk = (ind) => {
+    let hnk = hunks[ind]
+    if (hnk === undefined) return false
+    // else,
+    for (let ip in hnk.inputs) {
+      // dconn from outputs,
+      hnk.inputs[ip].disconnectAll()
+    }
+    // outputs, of whom a reference is stored in previously-attached inputs
+    for (let op in hnk.outputs) {
+      hnk.outputs[op].disconnectAll()
+    }
+    // then rm
+    hunks.splice(ind, 1)
+    // now, hunks have been reordered, so
+    onHunkReorder()
+    // and confirm we have done the deed, the body is in the river
+    return true
+  }
+
+  let onHunkReorder = () => {
+    for (let ind in hunks) {
+      // alright look, we keep a copy of this
+      if (hunks[ind].ind !== parseInt(ind)) {
+        console.log(`swapping ${hunks[ind].ind} for ${parseInt(ind)}`)
+        hunks[ind].ind = parseInt(ind)
       }
-      return true
-    } else {
-      return false
     }
   }
 
@@ -215,35 +274,62 @@ function Manager() {
     writeMessage(msg)
   }
 
+  // for links,
+
+  let serializeAndSendLink = (output, input) => {
+    console.log('sending this link again', output, input)
+    let msg = [MK.LINKALIVE]
+    MSGS.writeTo(msg, output.parent.ind, 'uint16')
+    MSGS.writeTo(msg, output.findOwnIndex(), 'uint8')
+    MSGS.writeTo(msg, input.parent.ind, 'uint16')
+    MSGS.writeTo(msg, input.findOwnIndex(), 'uint8')
+    writeMessage(msg)
+  }
+
+  // one for updating hunks,
+
+  this.evaluateHunk = (hunk) => {
+    // input and output lists have probably changed, so there's some work to do.
+    // first, we reply with a new definition,
+    this.serializeAndSendHunk(hunk)
+    // on a renewed definition, the view will remove all links associated.
+    // now we need to walk inputs and outputs, and message about the links
+    // that still exist
+    // so we can search over inputs ... since references are maintained
+    // if there's anything attached to them, those are links to send
+    for (let ip in hunk.inputs) {
+      for (let op in hunk.inputs[ip].connections) {
+        serializeAndSendLink(hunk.inputs[ip].connections[op], hunk.inputs[ip])
+      }
+    }
+    // same with the outputs,
+    for (let op in hunk.outputs) {
+      for (let ip in hunk.outputs[op].connections) {
+        serializeAndSendLink(hunk.outputs[op], hunk.outputs[op].connections[ip])
+      }
+    }
+  }
+
   /* ---------------------------    ---------------------------- */
   /* ----------------- LINKS HELLO / GOODBYTE ------------------ */
   /* ---------------------------    ---------------------------- */
 
-  this.addLink = (outHunkId, outputName, inHunkId, inputName) => {
+  this.addLink = (outHunkIndex, outputIndex, inHunkIndex, inputIndex, debug) => {
     // synchronous, doesn't need to be a promise
-    let outHunk = hunks.find((hunk) => {
-      return hunk.id == outHunkId
-    })
-    let inHunk = hunks.find((hunk) => {
-      return hunk.id == inHunkId
-    })
+    let outHunk = hunks[outHunkIndex]
+    let inHunk = hunks[inHunkIndex]
     // throw possible errs,
     if (outHunk === undefined) {
       writeErrMessage("MGR on add link: outHunk is undefined, on request for: " + outHunkId)
       return false
-    }
-    if (inHunk === undefined) {
+    } else if (inHunk === undefined) {
       writeErrMessage("MGR on add link: inHunk is undefined, on request for: " + inHunkId)
       return false
     }
 
     // find outputs, inputs
-    let otp = outHunk.outputs.find((op) => {
-      return op.name === outputName
-    })
-    let inp = inHunk.inputs.find((ip) => {
-      return ip.name === inputName
-    })
+    let otp = outHunk.outputs[outputIndex]
+    let inp = inHunk.inputs[inputIndex]
     // throw errs,
     if (otp === undefined) {
       writeErrMessage('MGR on add link: output is undefined. on request for hunk: ' + outHunkId + " and output: " + outputName)
@@ -251,54 +337,33 @@ function Manager() {
     } else if (inp === undefined) {
       writeErrMessage('MGR on add link: input is null or undefined. for hunk: ' + inHunk.id + " and input: " + inputName)
       return false
-    } else {
-      if (verbose) this.log(`hooking ${outHunk.id}, ${otp.name} to ${inHunk.id}, ${inp.name}`)
-      otp.attach(inp, inHunk.id)
-      // ok we gucc,
-      return true
     }
+    // if we're here, have passed all selection gauntlets, so
+    if (debug) this.log(`hooking ${outHunk.name} ${outHunk.ind}, ${otp.name} to ${inHunk.name} ${inHunk.ind}, ${inp.name}`)
+    return otp.attach(inp)
   }
 
-  this.removeLink = (outHunkId, outputName, inHunkId, inputName) => {
-    // synchronous, doesn't need to be a promise
-    let outHunk = hunks.find((hunk) => {
-      return hunk.id == outHunkId
-    })
-    let inHunk = hunks.find((hunk) => {
-      return hunk.id == inHunkId
-    })
-    // throw possible errs,
+  this.removeLink = (outHunkIndex, outputIndex, inHunkIndex, inputIndex, debug) => {
+    let outHunk = hunks[outHunkIndex]
+    let inHunk = hunks[inHunkIndex]
     if (outHunk === undefined) {
-      writeErrMessage("MGR on remove link: outHunk is undefined, on request for: " + outHunkId)
+      writeErrMessage("MGR on add link: outHunk is undefined, on request for: " + outHunkId)
       return false
-    }
-    if (inHunk === undefined) {
-      writeErrMessage("MGR on remove link: inHunk is undefined, on request for: " + inHunkId)
+    } else if (inHunk === undefined) {
+      writeErrMessage("MGR on add link: inHunk is undefined, on request for: " + inHunkId)
       return false
     }
-
-    // find outputs, inputs
-    let otp = outHunk.outputs.find((op) => {
-      return op.name === outputName
-    })
-    let inp = inHunk.inputs.find((ip) => {
-      return ip.name === inputName
-    })
-    // throw errs,
+    let otp = outHunk.outputs[outputIndex]
+    let inp = inHunk.inputs[inputIndex]
     if (otp === undefined) {
-      writeErrMessage('MGR on remove link: output is undefined. on request for hunk: ' + outHunkId + " and output: " + outputName)
+      writeErrMessage('MGR on add link: output is undefined. on request for hunk: ' + outHunkId + " and output: " + outputName)
       return false
     } else if (inp === undefined) {
-      writeErrMessage('MGR on remove link: input is null or undefined. for hunk: ' + inHunk.id + " and input: " + inputName)
+      writeErrMessage('MGR on add link: input is null or undefined. for hunk: ' + inHunk.id + " and input: " + inputName)
       return false
-    } else {
-      if (verbose) this.log(`hooking ${outHunk.id}, ${otp.name} to ${inHunk.id}, ${inp.name}`)
-      if (otp.remove(inp, inHunk.id)) {
-        return true
-      } else {
-        return false
-      }
     }
+    if (debug) this.log(`hooking ${outHunk.id}, ${otp.name} to ${inHunk.id}, ${inp.name}`)
+    return otp.remove(inp)
   }
 
   // programmatically, and as makes sense in memory, link connections are lists that are stored
@@ -309,15 +374,18 @@ function Manager() {
   let writeLinkList = () => {
     let links = new Array()
     // for hunks,
-    for (let hnk of hunks) {
+    for (let hnk in hunks) {
       // have outputs,
-      for (let otp of hnk.outputs) {
-        for (let cn of otp.connections) {
+      for (let otp in hunks[hnk].outputs) {
+        for (let cn in hunks[hnk].outputs[otp].connections) {
+          // we can know the output index, and the hunk index,
+          // but we need to find the index-relative position for the input
+          // RETURN
           links.push({
-            outHunkId: hnk.id,
-            outputName: otp.name,
-            inHunkId: cn.parentId,
-            inputName: cn.input.name
+            outInd: parseInt(hnk), // truth in index
+            outputInd: parseInt(otp), // a num,
+            inInd: hunks[hnk].outputs[otp].connections[cn].parent.ind,
+            inputInd: hunks[hnk].outputs[otp].connections[cn].findOwnIndex()
           })
         }
       }
@@ -326,28 +394,6 @@ function Manager() {
     return links
   }
 
-  /* ---------------------------    ---------------------------- */
-  /* ---------------------- STATE CHANGES ---------------------- */
-  /* ---------------------------    ---------------------------- */
-
-  this.stateChange = (hunkId, stateName, newValue) => {
-    // this is probably a good example of whomst to implement things-like-this
-    return new Promise((resolve, reject) => {
-      if (verbose) this.log(`to change ${stateName} to ${newValue} in ${hunkId}`)
-      let theHunk = hunks.find((hunk) => {
-        return hunk.id == hunkId
-      })
-      if (theHunk === undefined) reject(new Error('no hunk found for statechange'))
-      let theState = theHunk.state.find((st8) => {
-        return st8.name === stateName
-      })
-      if (theState === undefined) reject(new Error('no state found for statechange'))
-      // otherwise, do business
-      theState.change(newValue)
-      resolve()
-    })
-  }
-
   /* ---------------------------    ---------------------------- */
   /* ---------------------- STARTUP, LOOP ---------------------- */
   /* ---------------------------    ---------------------------- */
@@ -355,32 +401,37 @@ function Manager() {
   this.init = () => {
     // startup by giving ourselves an ID if we haven't been assigned one?
     // and then adding ourselves to ourselves ?
-    if (this.id === null || this.id === undefined) throw new Error('managers with no IDs are no good 4 u')
+    // have to cover these bases ourselves
+    this.name = 'manager'
+    this.ind = 0
     // nest in self,
     hunks.push(this)
-    this.log(`manager hello, id is ${this.id}`)
+    this.log(`manager hello`)
   }
 
   this.loop = () => {
     // getting messages
     if (msgsin.io) {
       let msg = msgsin.get()
-      if (msgverbose) this.log(`gets msg ${header}`)
+      if (msgverbose) console.log('MGR RX MSG:', msg)
       if (!Array.isArray(msg)) throw new Error(`manager throwing object message, having header ${msg.header}`)
       // once
       let resp = new Array()
       // rules: bytes in this switch, objects elsewhere ?
       switch (msg[0]) {
         case MK.HELLO:
+          if (msgverbose) console.log('MGR MSG is hello')
           writeMessage([MK.HELLO])
           break
         case MK.REQDESCRIBESELF:
+          if (msgverbose) console.log('MGR MSG is a brief request')
+          this.isConnectedTo = true
+          // with ids, this is ok
           resp.push(MK.BRIEF)
-          MSGS.writeTo(resp, this.id, 'string')
           MSGS.writeTo(resp, gg.interpreterName, 'string')
           MSGS.writeTo(resp, gg.interpreterVersion, 'string')
-          MSGS.writeTo(resp, hunks.length, 'uint32')
-          MSGS.writeTo(resp, writeLinkList().length, 'uint32')
+          MSGS.writeTo(resp, hunks.length, 'uint16')
+          MSGS.writeTo(resp, writeLinkList().length, 'uint16')
           writeMessage(resp)
           // now start sending hunks,
           for (let hnk of hunks) {
@@ -392,14 +443,15 @@ function Manager() {
           let links = writeLinkList()
           for (let lnk of links) {
             let serlink = [MK.LINKALIVE]
-            MSGS.writeTo(serlink, lnk.outHunkId, 'string')
-            MSGS.writeTo(serlink, lnk.outputName, 'string')
-            MSGS.writeTo(serlink, lnk.inHunkId, 'string')
-            MSGS.writeTo(serlink, lnk.inputName, 'string')
+            MSGS.writeTo(serlink, lnk.outInd, 'uint16')
+            MSGS.writeTo(serlink, lnk.outputInd, 'uint8')
+            MSGS.writeTo(serlink, lnk.inInd, 'uint16')
+            MSGS.writeTo(serlink, lnk.inputInd, 'uint8')
             writeMessage(serlink)
           }
           break
         case MK.REQLISTAVAIL:
+          if (msgverbose) console.log('MGR MSG is a request for available items')
           // allow for error path,
           getListOfAvailableComponents().then((list) => {
             // probable success,
@@ -417,23 +469,26 @@ function Manager() {
           })
           break
         case MK.REQADDHUNK:
+          if (msgverbose) console.log('MGR MSG is a request to add a hunk')
           // pull the rest out,
           // unknown-len types return with return.item and return.increment
           let reqaddinc = 1
           let strname = MSGS.readFrom(msg, reqaddinc, 'string')
           reqaddinc += strname.increment
           strname = strname.item
-          let strid = undefined
-          if(reqaddinc < msg.length) {
-            strid = MSGS.readFrom(msg, reqaddinc, 'string').item
+          // might exist,
+          let state
+          if(reqaddinc < msg.length){
+            state = stateSetFromSerial(msg, reqaddinc)
+            console.log('MGR to add', strname, 'with state included:', state)
+          } else {
+            console.log('MGR to add', strname)
           }
-          // then do,
           // a meta comment is that this add promise doesn't fail for
           // things like path-loading errors, that would be inside of gogetter.js
           // i.e. pulling a hunk loads it into that import script hack, that just
           // gets evaluated into the dom ...
-          console.log('manager to add', strname)
-          this.addHunk(strname, strid).then((hunk) => {
+          this.addHunk(strname, state).then((hunk) => {
             console.log('successfully added hunk', hunk)
             // serialize
             resp.push(MK.HUNKALIVE)
@@ -445,80 +500,66 @@ function Manager() {
           })
           break
         case MK.REQSTATECHANGE:
+          if (msgverbose) console.log('MGR MSG is a state change request')
           // ok,
           // mgrMsgs (byteArray), chonker (uint32)
-          //
-          let stchinc = 1
-          let stChId = MSGS.readFrom(msg, stchinc, 'string')
-          stchinc += stChId.increment
-          // ye olden javascript switch
-          stChId = stChId.item
-          let stChName = MSGS.readFrom(msg, stchinc, 'string')
-          stchinc += stChName.increment
-          stChName = stChName.item
-          // debugging atm
-          console.log('MGR state change searcheth', stChId, stChName)
-          // seek out the hunk,
-          let stHunk = hunks.find((cand) => {
-            return cand.id === stChId
-          })
-          if (stHunk === undefined) {
-            writeErrMessage(`on state change, could not find hunk with id ${stChId}`)
-            break
-          }
-          // and the state item, if it exists
-          let stSt = stHunk.state.find((cand) => {
-            return cand.name === stChName
-          })
-          if (stSt === undefined) {
-            writeErrMessage(`on state change, could not find state item with name ${stChName} within ${stChId}`)
-            break
-          }
-          // now this is knowable,
-          let stChType = stSt.type
-          // so we can use the right tools,
-          let value = MSGS.readFrom(msg, stchinc, stChType)
-          // yarrr ... ok, do all readFrom calls need to return an incrment?
-          // tharin is the problem
-          // here *is* a workaround
-          console.log('for state change, going to send value', value)
-          if (Object.keys(value).includes('item') && Object.keys(value).includes('increment')) {
-            // an inc-type appears,
-            stSt.change(value.item)
-          } else {
-            // yarrr, primitives
-            stSt.change(value)
+          // TODO
+          let stchHnkInd = MSGS.readFrom(msg, 1, 'uint16').item
+          let stchStInd = MSGS.readFrom(msg, 4, 'uint8').item
+          // to pull, we need to know the type at the end
+          let stItem
+          try {
+            stItem = hunks[stchHnkInd].states[stchStInd]
+          } catch (err) {
+            writeErrMessage('probably messed up state indexing here')
+            console.error(err)
           }
+          console.log('would swap at', stItem)
+          console.log('with type', stItem.type)
+          let stValRequest = MSGS.readFrom(msg, 6, stItem.type).item
+          console.log('for value', stValRequest)
+          // going
+          stItem.change(stValRequest)
           break
         case MK.REQRMHUNK:
-          let rmid = MSGS.readFrom(msg, 1, 'string').item
-          console.log('requests rm of', rmid)
-          if (this.removeHunk(rmid)) {
+          // it's gonna be messy ! ... HERE NOW
+          if (msgverbose) console.log('MGR MSG is a request to remove a hunk')
+          let rmind = MSGS.readFrom(msg, 1, 'uint16').item
+          if (this.removeHunk(rmind)) {
             let rmconf = [MK.HUNKREMOVED]
-            MSGS.writeTo(rmconf, rmid, 'string')
+            MSGS.writeTo(rmconf, rmind, 'uint16')
             writeMessage(rmconf)
           } else {
-            writeErrMessage(`failure to remove hunk ${rmid} as requested`)
+            writeErrMessage(`failure to remove hunk ${rmind} as requested`)
           }
           break
         case MK.REQADDLINK:
-          let adargs = MSGS.readListFrom(msg, 1, 'string')
-          if (this.addLink(adargs[0], adargs[1], adargs[2], adargs[3])) {
+          if (msgverbose) console.log('MGR MSG is a request to add a link')
+          // these, and then draw links again ... and send links ?
+          let addOutInd = MSGS.readFrom(msg, 1, 'uint16').item
+          let addOutputInt = MSGS.readFrom(msg, 4, 'uint8').item
+          let addInInd = MSGS.readFrom(msg, 6, 'uint16').item
+          let addInputInd = MSGS.readFrom(msg, 9, 'uint8').item
+          if (this.addLink(addOutInd, addOutputInt, addInInd, addInputInd)) {
             // identical arguments, so
             let reply = [MK.LINKALIVE].concat(msg.slice(1))
             writeMessage(reply)
           } else {
-            writeErrMessage(`failure to add link from ${adargs[0]} ${adargs[1]} to ${adargs[2]} ${adargs[3]} as requested`)
+            writeErrMessage(`failure to add link as requested`)
           }
           break
         case MK.REQRMLINK:
-          let rmargs = MSGS.readListFrom(msg, 1, 'string')
-          if (this.removeLink(rmargs[0], rmargs[1], rmargs[2], rmargs[3])) {
+          if (msgverbose) console.log('MGR MSG is a request to remove a link')
+          let rmOutInd = MSGS.readFrom(msg, 1, 'uint16').item
+          let rmOutputInt = MSGS.readFrom(msg, 4, 'uint8').item
+          let rmInInd = MSGS.readFrom(msg, 6, 'uint16').item
+          let rmInputInd = MSGS.readFrom(msg, 9, 'uint8').item
+          if (this.removeLink(rmOutInd, rmOutputInt, rmInInd, rmInputInd)) {
             // identical arguments, so
             let reply = [MK.LINKREMOVED].concat(msg.slice(1))
             writeMessage(reply)
           } else {
-            writeErrMessage(`failure to remove link from ${rmargs[0]} ${rmargs[1]} and ${rmargs[2]} ${rmargs[3]} as requested`)
+            writeErrMessage(`failure to remove link as requested`)
           }
           break
         default:
@@ -542,6 +583,8 @@ function Manager() {
       }
     } // end msgs output check
 
+    // TRANSPORT
+
     hunks.forEach((hunk) => {
       // begin transport, walk each output and push along
       hunk.outputs.forEach((output) => {
@@ -553,8 +596,8 @@ function Manager() {
               // if it has not been posted to inputs (it's fresh)
               // double check that all inputs are clear
               let clear = true
-              for (let pair of output.connections) {
-                if (pair.input.io) {
+              for (let input of output.connections) {
+                if (input.io) {
                   clear = false
                 }
               }
@@ -568,8 +611,8 @@ function Manager() {
             } else {
               // output has been posted, check if all clear
               let clear = true
-              for (let pair of output.connections) {
-                if (pair.input.io) {
+              for (let input of output.connections) {
+                if (input.io) {
                   clear = false
                 }
               }
@@ -602,14 +645,18 @@ function Manager() {
   let outmsgbuffer = new Array()
 
   let writeMessage = (bytes) => {
-    if (!msgsout.io && outmsgbuffer.length < 1) {
-      // str8 shooters
-      if (msgverbose) this.log('msg out', bytes)
-      msgsout.put(bytes)
+    if(this.isConnectedTo){
+      if (!msgsout.io && outmsgbuffer.length < 1) {
+        // str8 shooters
+        if (msgverbose) this.log('msg out', bytes)
+        msgsout.put(bytes)
+      } else {
+        // gotta buffer
+        outmsgbuffer.push(bytes)
+        if (msgverbose) this.log('MGR OUTBUFFER LEN', outmsgbuffer.length)
+      }
     } else {
-      // gotta buffer
-      outmsgbuffer.push(bytes)
-      this.log('MGR OUTBUFFER LEN', outmsgbuffer.length)
+      console.log('mgr tossing message', bytes)
     }
   }
 
diff --git a/hunks/template.js b/hunks/template.js
index b42afbba5b30c55ce299f3ff19ff4ef021664f16..a4f55e5da8ce87e9650777d025dd1566e5764ba3 100644
--- a/hunks/template.js
+++ b/hunks/template.js
@@ -20,7 +20,7 @@ function Name() {
     this.outputs.push(outB)
 
     let stateItem = new State('type', 'name')
-    this.state.push(stateItem)
+    this.states.push(stateItem)
 
     this.init = () => {
         // manager calls this once
diff --git a/hunks/view.js b/hunks/view.js
index c64a1d878fcf63dcccc1ecc5cc254488f64d0313..3ba9e1e3c5522ec2918e0d6fe064eb60f19f0fd7 100644
--- a/hunks/view.js
+++ b/hunks/view.js
@@ -26,6 +26,9 @@ import {
   MSGS // messaging
 } from '../typeset.js'
 
+// yonder def, the ui mirror on hunks
+import HunkDefinition from '../view/vdef.js'
+
 // to file-organize view.js, a monster
 import DomTools from '../view/vdom.js'
 import BezierTools from '../view/vbzt.js'
@@ -33,13 +36,13 @@ import MessageBox from '../view/vmsg.js'
 import PatchSet from '../view/vptch.js'
 
 function View() {
-  Hunkify(this, 'View')
+  Hunkify(this)
 
-  let verbose = true
-  let msgverbose = true
+  let verbose = false
+  let msgverbose = false
 
-  let msgsin = new Input('byteArray', 'msgs')
-  let msgsout = new Output('byteArray', 'msgs')
+  let msgsin = new Input('byteArray', 'msgs', this)
+  let msgsout = new Output('byteArray', 'msgs', this)
 
   this.inputs.push(msgsin)
   this.outputs.push(msgsout)
@@ -50,10 +53,18 @@ function View() {
   // the plane, one layer beneath, is where divs live
   this.plane = {}
 
+  // we have a list of definitions,
+  let defs = new Array()
+  // #ref, sloppy
+  this.defs = defs
+
   // tools to write dom-representations of hunks,
   let dt = new DomTools(this)
   // a handy box, for stuff
   let msgbox = new MessageBox(this)
+  this.msgbox = msgbox
+  this.interpreterName = null
+  this.interpreterVersion = null
   // and tools for the links,
   let bzt = new BezierTools(this)
   // and for program (patch) management
@@ -112,28 +123,30 @@ function View() {
 
     // key listeners
     // keys are global, so ... idk how to unfoof this yet, but
-    if (this.id === 'TLView') {
-      document.addEventListener('keydown', (evt) => {
-        if (evt.key === 'l') {
-          //writeMessage('addhunk', 'link')
-        } else if (evt.key === 'c') {
-          //writeMessage('addprogram', 'ntlink')
-        } else if (evt.key === 'v') {
-          //writeMessage('addprogram', 'llink')
-        } else if (evt.keyCode === 27) {
-          // escapekey
-          $(this.plane).children('.contextmenu').remove()
-          // also find floaters ...
-        }
-      })
-    }
+    document.addEventListener('keydown', (evt) => {
+      if (evt.key === 'l') {
+        //writeMessage('addhunk', 'link')
+      } else if (evt.key === 'c') {
+        //writeMessage('addprogram', 'ntlink')
+      } else if (evt.key === 'v') {
+        //writeMessage('addprogram', 'llink')
+      } else if (evt.keyCode === 27) {
+        // escapekey
+        console.log('escape!')
+        $(this.dom).find('.contextmenu').remove()
+        // also find floaters ...
+      }
+    })
   }
   // END INIT CODE
 
   this.refresh = () => {
     // wipe ya docs, and ask yonder manager for a complete description
     // everything is friggen jquery, so check it out
-    $(this.plane).children('.block').remove()
+    console.log("REFRESHING THE VIEW")
+    $(this.plane).children('.def').remove()
+    // also,
+    defs.length = 0
     // and then say hello,
     writeMessage([MK.REQDESCRIBESELF])
     // that's fine, we can wait for a response, but we have to track and setup the next move
@@ -176,18 +189,6 @@ function View() {
     ct.y += evt.movementY
     dt.writeTransform(this.plane, ct)
     dt.writeBackgroundTransform(this.dom, ct)
-
-    /*
-    this.pan.x += evt.movementX
-    this.pan.y += evt.movementY
-    this.plane.style.backgroundPosition = `${this.pan.x}px ${this.pan.y}px`
-    $(this.plane).children().each((index, div) => {
-        let tf = dt.readTransform(div)
-        tf.x += evt.movementX
-        tf.y += evt.movementY
-        dt.writeTransform(div, tf)
-    })
-    */
   }
 
   let canvasUpListener = (evt) => {
@@ -197,33 +198,22 @@ function View() {
 
   // CONTEXT MENU
   let onContextMenu = (evt) => {
-    $(this.plane).find('.contextmenu').remove()
+    $(this.dom).find('.contextmenu').remove()
     //console.log(evt)
     evt.preventDefault()
     evt.stopPropagation()
     // more like
-    /*
-     -> add a hunk
-     -> load a program
-     -> save this program
-     -> reload this view
-     -> heartbeat checkin
-    */
     console.log('context...', evt)
     // make the menu,
     let menu = $('<div>').addClass('contextmenu').get(0)
-    // and place,
-    let pt = dt.readTransform(this.plane)
-    console.log('plane transform', pt)
-    // HERE: there's still some mess, not landing in the right place,
     // (and there's compounding scale issues on dragging the canvas)
     dt.writeTransform(menu, {
       s: 1,
-      x: ((evt.clientX - pt.x) / pt.s), // (pt.s + -0.1 * (pt.s-1))),
-      y: ((evt.clientY - pt.y) / pt.s) // + -0.1 * (pt.s-1)))
+      x: evt.layerX, // (pt.s + -0.1 * (pt.s-1))),
+      y: evt.layerY // + -0.1 * (pt.s-1)))
     })
     //
-    $(this.plane).append(menu)
+    $(this.dom).append(menu)
     // hmmm
     this.changeContextTitle('you can... ')
     // on of the options will ...
@@ -239,58 +229,24 @@ function View() {
     })
 
     this.addContextOption('save this patch', (evt) => {
-      patchset.saveCurrent(evt, true)
+      patchset.saveCurrent(evt, defs, true)
     })
     // writeMessage([MK.REQLISTAVAIL])
   }
 
   // takes 'under' argument
   this.addContextOption = (text, click) => {
-    $(this.plane).find('.contextmenu').get(0).append($('<li>' + text + '</li>').click((click)).get(0))
+    $(this.dom).find('.contextmenu').get(0).append($('<li>' + text + '</li>').click((click)).get(0))
   }
 
   this.changeContextTitle = (text) => {
     // clear,
-    $(this.plane).find('.contextmenu').children().remove()
+    $(this.dom).find('.contextmenu').children().remove()
     // overkill, but fun
-    let menu = $(this.plane).find('.contextmenu').get(0)
+    let menu = $(this.dom).find('.contextmenu').get(0)
     let title = $(`<div>${text}</div>`).addClass('contextTitle').get(0)
-    title.onmousedown = (evt) => {
-      evt.preventDefault()
-      evt.stopPropagation()
-      let domElemMouseMove = (evt) => {
-        // TRANSFORMS here to move div about on drag
-        evt.preventDefault()
-        evt.stopPropagation()
-        let ct = dt.readTransform(menu)
-        let pt = dt.readTransform(menu.parentElement) // think that's just this.plane ?
-        ct.x += evt.movementX / pt.s
-        ct.y += evt.movementY / pt.s
-        dt.writeTransform(menu, ct)
-        this.drawLinks()
-      }
-
-      function rmOnMouseUp(evt) {
-        document.removeEventListener('mousemove', domElemMouseMove)
-        document.removeEventListener('mouseup', rmOnMouseUp)
-      }
-      document.addEventListener('mousemove', domElemMouseMove)
-      document.addEventListener('mouseup', rmOnMouseUp)
-    }
-    $(this.plane).find('.contextmenu').append(title)
-  }
-
-  /*
-  this.changeContextTitle('list of available:')
-  for(let item of list){
-    this.addContextOption(item, (evt) => {
-      let msg = [MK.REQADDHUNK]
-      MSGS.writeTo(msg, item, 'string')
-      writeMessage(msg)
-      $(evt.target).append(' > requested ... ')
-    })
+    $(this.dom).find('.contextmenu').append(title)
   }
-  */
 
   /* ---------------------------    ---------------------------- */
   /* ---------------------- FORCE LAYOUT ----------------------- */
@@ -501,31 +457,18 @@ function View() {
   // here is where you rm'd drawing & moving
 
   this.drawLinks = () => {
-    // from within the div
-    let outputs = $(this.plane).children('.block').children('.outputs').children('.output')
-    // clear all links
+    // drawing from scratch every time ! could be faster, probably
     bzt.clear(this.plane)
-    // and draw new ones
-    for (let output of outputs) {
-      // finding the children to hookup to
-      for (let conn of output.connectedTo) {
-        // find looks down *all* branches of the dom tree
-        // with children().children() we can reduce that tree
-        let hookup = $(this.plane).find(conn)
-        if (hookup.length !== 1) {
-          // this can happen when a dependent is not loaded yet
-          console.log('mismatched connection', hookup.length, conn)
-        } else {
-          let hk = hookup.get(0)
-          let head = bzt.getRightHandle(output)
-          let tail
-          if (hk.id === 'floater') {
-            tail = bzt.getFloaterHandle(hk)
-          } else {
-            tail = bzt.getLeftHandle(hk)
-          }
-          // a bit many arguments, but
-          bzt.drawLink(head, tail, output, hk, conn)
+    // draw 'em all
+    for (let def of defs) {
+      for (let output of def.outputs) {
+        for (let input of output.connections) {
+          bzt.drawLink(output, input)
+        }
+        if (output.hasFloater) {
+          let head = bzt.getRightHandle(output.de)
+          let tail = bzt.getFloaterHandle(output.floater)
+          bzt.writeBezier(head, tail)
         }
       }
     }
@@ -545,97 +488,97 @@ function View() {
     return nameresp.increment + typeresp.increment
   }
 
-  let defBySerial = (bytes, start) => {
+  let specBySerial = (bytes, start, debug) => {
     // deserialize
-    let def = {}
+    let spec = {
+      ind: null,
+      name: null
+    }
     // inputs, outputs, state
-    def.inputs = new Array()
-    def.outputs = new Array()
-    def.state = new Array()
+    spec.inputs = new Array()
+    spec.outputs = new Array()
+    spec.states = new Array()
     // hold,
     let temp
     // starting at 2, msgs[0] is 'hnkalive'
     let i = start
+    // lets write a goddang real structure an object (spec) with mirror type dom and access fn's ...
+    // this will make building better and better code mucho bueno
     // ripperoni,
     outer: while (i < bytes.length) {
       switch (bytes[i]) {
-        case HK.ID:
+        case HK.IND:
           i += 1
-          temp = MSGS.readFrom(bytes, i, 'string')
-          def.id = temp.item
+          temp = MSGS.readFrom(bytes, i, 'uint16')
+          spec.ind = temp.item
           i += temp.increment
           break
         case HK.NAME:
           i += 1
           temp = MSGS.readFrom(bytes, i, 'string')
-          def.name = temp.item
+          spec.name = temp.item
           i += temp.increment
           break
         case HK.INPUT:
           i += 1
           // expecting two strings here, name and then type
-          i += deserializeNameType(def.inputs, bytes, i)
+          i += deserializeNameType(spec.inputs, bytes, i)
           break
         case HK.OUTPUT:
           i += 1
-          i += deserializeNameType(def.outputs, bytes, i)
+          i += deserializeNameType(spec.outputs, bytes, i)
           break
         case HK.STATE:
           i += 1
-          i += deserializeNameType(def.state, bytes, i)
+          i += deserializeNameType(spec.states, bytes, i)
           // ok, and the value should trail
           // we don't *need* to know the type, could just read by the key, but,
-          temp = MSGS.readFrom(bytes, i, def.state[def.state.length - 1].type)
-
-          def.state[def.state.length - 1].value = temp.item
+          temp = MSGS.readFrom(bytes, i, spec.states[spec.states.length - 1].type)
+          spec.states[spec.states.length - 1].value = temp.item
           i += temp.increment
           break
         default:
-          throw new Error(`unexpected key encountered in hunk deserialization at ${i}: ${bytes[i]}`)
+          throw new Error(`unexpected key encountered during hunk deserialization at position ${i}: ${bytes[i]}`)
           break outer
       }
     }
     // a check,
-    console.log(`broke outer, len at ${bytes.length}, i at ${i}`)
+    if (debug) console.log(`broke outer, len at ${bytes.length}, i at ${i}`)
     // we should be able to kind of pick-thru and append based on,
-    console.log('def apres deserialize', def)
+    if (debug) console.log('spec apres deserialize', spec)
     // we gucc ?
-    return def
+    return spec
   }
 
   /* ---------------------------    ---------------------------- */
   /* ------------------- SERIAL -> HOTMESSES ------------------- */
   /* ---------------------------    ---------------------------- */
 
-  let putDef = (def) => {
-    // hmmm ok,
-    if (verbose) console.log('ready write', def.id)
-    if (verbose) console.log('the def', def)
+  let newDef = (spec) => {
+    // hmmm ok, we have checked that this is new, not an update,
+    if (verbose) console.log('ready write new spec to def', spec)
     // do we have this id already? could be an update;
+    let def = new HunkDefinition(spec, this, dt, false)
+
+    // ...
     let mt = {}
-    let match = $(this.plane).find('#' + def.id).get(0)
     let menu = $(this.plane).children('.contextmenu').get(0)
-    if (match) {
-      // we have one already, we are likely updating it
-      // we need to be more careful about this
-      msgbox.write(`received new definition for the hunk with id "${def.id}", replacing that...`)
-      // need to carefully walk outputs to replace,
-      mt = dt.readTransform(match)
-    } else if (menu !== undefined) {
+    if (menu !== undefined) {
       mt = dt.readTransform(menu)
-    } else if (def.id === "NROL39_0") { // TEMPORARY until better management with force layout
+      $(menu).remove()
+    } else if (def.ind === 0 && def.name === 'manager') { // TEMPORARY until better management with force layout
       mt = {
         s: 1,
         x: 100,
         y: 100
       }
-    } else if (def.id === "TLView") { // TEMPORARY until better management with force layout
+    } else if (def.ind === 1 && def.name === 'view') { // TEMPORARY until better management with force layout
       mt = {
         s: 1,
         x: 100,
         y: 200
       }
-    } else { // also, initial placement could be done better
+    } else { // also, initial placement should be determined by force layout
       mt = {
         s: 1,
         x: Math.random() * 1000,
@@ -643,115 +586,131 @@ function View() {
       }
     }
 
-    // write the def dom
-    let de = dt.writeDefDom(def, true)
-
-    // later, we can walk for similar outputs, to maintain those links
-    if (match) {
-      // poll new outputs, replace with old outputs (these contain link information, should retain)
-      let newOtps = $(de).children('.outputs').children('.output')
-      for(let notp of newOtps){
-        let equiv = $(match).children('.outputs').children('#' + notp.id).get(0)
-        if(equiv){
-          msgbox.write(`maintaining output for ${equiv.id}`)
-          $(de).children('.outputs').children('#' + notp.id).replaceWith(equiv)
-        } else {
-          msgbox.write(`no equivalent output for ${equiv.id}, adding that`)
-        }
-      }
-      $(match).remove()
-    } else {
-      // shouldn't have to do this for refreshing descriptions...
-      // if it's in the ref-to-add
-      let native = cuttlefishHunkRef.find((hnk) => {
-        return hnk.id === def.id
-      })
-
-      if (native !== undefined && native !== null) {
-        console.log("trying to add native hunk's dom: native:", native)
-        try {
-          $(de).append($(native.dom).addClass('cuttlefishhunkdom'))
-          if ($(native.dom).is('.view')) {
-            de.style.height = '800px'
-            de.style.width = '1200px'
-            // leader on starting to reize these ...
-            $(de).append($('<div>').addClass('rsHandle').on('mousedown', (evt) => {
-              console.log('rshandle down')
-            }))
-          }
-        } catch (err) {
-          msgbox.write(`native hunk attach fails ${err}`)
+    // if it's in the ref-to-add *this is confusing*
+    let native = cuttlefishHunkRef.find((hunk) => {
+      return hunk.ind === def.ind
+    })
+
+    if (native !== undefined && native !== null) {
+      console.log("trying to add native hunk's dom: native:", native)
+      try { // try to add the dom element to the def's domelement
+        $(def.de).append($(native.dom).addClass('cuttlefishhunkdom'))
+        if ($(native.dom).is('.view')) {
+          def.de.style.height = '800px'
+          def.de.style.width = '1200px'
+          // leader on starting to reize these ...
+          /*
+          $(de).append($('<div>').addClass('rsHandle').on('mousedown', (evt) => {
+            console.log('rshandle down')
+          }))*/
         }
+      } catch (err) {
+        msgbox.write(`native hunk attach fails ${err}`)
       }
     }
-
-    //
-    dt.writeTransform(de, mt)
-    // rm menu if it's around
-    if (menu !== undefined) $(menu).remove()
-
-    // add the def to the view
-    $(this.plane).append(de)
-
-    // for the sim, add an x and y
-    // and we keep a list, but maybe don't need to?
-    blocks.push(de)
-
-    // AS Policy, since this thing *is* a stateful view,
-    // we keep state in the view. no mirror, def is a throwaway
+    // ok, ready to place and append,
+    dt.writeTransform(def.de, mt)
+    // add the def's domelement to the view,
+    $(this.plane).append(def.de)
+    // and add it to our list
+    defs.push(def)
     // i.e. we won't return it: it contains everything we need
     this.drawLinks()
+    // occasionally useful,
+    return def
+  }
 
-    // here is an OK place to do the sorting ...
-    // TODO: add to D3
-    updateForceLoop()
+  let replaceDef = (spec) => {
+    // the old boy,
+    let od = defs[spec.ind]
+    // as a rule, when we replace defs, we unhook everything.
+    // the manager (in its wisdom) is responsible for following up by sending us
+    // links that are still alive,
+    console.log('the od', od)
+    // so first rm those links (this won't properly be tested until program loading, i'd bet)
+    for (let ip in od.inputs) {
+      od.inputs[ip].disconnectAll()
+    }
+    for (let op in od.outputs) {
+      od.outputs[op].disconnectAll()
+    }
+    // that was considerate of the others, but this whole thing is just going to get rm'd, so outputs don't matter
+    let mt = dt.readTransform(od.de)
+    // now we can *eliminate it*
+    $(od.de).remove()
+    defs[spec.ind] = null
+    // and replace it,
+    let nd = new HunkDefinition(spec, this, dt, false)
+    // write-over and cut all connections, we'll receive new ones
+    // ok, ready to place and append,
+    dt.writeTransform(nd.de, mt)
+    // add the def's domelement to the view,
+    $(this.plane).append(nd.de)
+    // and replace it in the list,
+    defs[spec.ind] = nd
+    // and re-render
+    this.drawLinks()
+    // occasionally useful,
+    return nd
   }
 
+  // for cuttlefish hunks,
   let cuttlefishHunkRef = new Array()
 
-  // for cuttlefish hunks,
   this.take = (hunk) => {
     cuttlefishHunkRef.push(hunk)
   }
 
-  let removeDef = (id) => {
-    // get the inputs that we'll have to watch removal for
-    let inpts = $(this.plane).children('#' + id).children('.inputs').children('.input')
-    // remove the def / block
-    if ($(this.plane).children('#' + id).length === 0) throw new Error('trouble on remove, cannot find block with given id')
-    // remove it,
-    $(this.plane).children('#' + id).remove()
-    // we have to walk over the other outputs and disconnect them,
-    let otps = $(this.plane).find('.output')
-    for (let otp of otps) {
-      for (let inp of inpts) {
-        if (otp.connectedTo.includes('#' + inp.id)) {
-          otp.connectedTo.splice(otp.connectedTo.indexOf('#' + inp.id))
-        }
+  let removeDef = (index) => {
+    // ok ok ok
+    let od = defs[index]
+    if (od === undefined) throw new Error('no hunk to delete!')
+    // else,
+    for (let ip in od.inputs) {
+      od.inputs[ip].disconnectAll()
+    }
+    for (let op in od.outputs) {
+      od.outputs[op].disconnectAll()
+    }
+    // ok ...
+    defs.splice(index, 1)
+    // ordering
+    onDefReorder()
+    // and x2thegrave
+    $(od.de).remove()
+  }
+
+  let onDefReorder = () => {
+    for (let ind in defs) {
+      if (defs[ind].ind !== parseInt(ind)) {
+        console.log(`swapping ${defs[ind].ind} for ${parseInt(ind)}`)
+        defs[ind].newInd(parseInt(ind))
       }
     }
-    this.drawLinks()
-    updateForceLoop()
   }
 
-  let putLink = (outId, outName, inId, inName) => {
+  let putLink = (outInd, outputInd, inInd, inputInd) => {
     try {
-      let outp = $(this.plane).children('.block').children('.outputs').children('#' + outId + '_output_' + outName).get(0)
-      outp.connectedTo.push('#' + inId + '_input_' + inName)
+      let outputdef = defs[outInd].outputs[outputInd]
+      let inputdef = defs[inInd].inputs[inputInd]
+      outputdef.connect(inputdef)
       this.drawLinks()
       updateForceLoop()
     } catch (err) {
       console.log('ERR at putlink', err)
-      msgbox.write('ERR at putlink' + err)
+      msgbox.write('ERR at putlink: ' + err)
+
       return false
     }
     return true
   }
 
-  let removeLink = (outId, outName, inId, inName) => {
+  let cutLink = (outInd, outputInd, inInd, inputInd) => {
     try {
-      let outp = $(this.plane).children('.block').children('.outputs').children('#' + outId + '_output_' + outName).get(0)
-      outp.connectedTo.splice(outp.connectedTo.indexOf('#' + inId + '_input_' + inName), 1)
+      let outputdef = defs[outInd].outputs[outputInd]
+      let inputdef = defs[inInd].inputs[inputInd]
+      console.log('to disconn', outputdef, 'from', inputdef)
+      outputdef.disconnect(inputdef)
       this.drawLinks()
     } catch (err) {
       console.log('ERR at rmlink', err)
@@ -773,42 +732,58 @@ function View() {
     writeMessage([MK.HELLO])
   }
 
-  this.requestAddHunk = (name, id) => {
+  this.requestAddHunk = (name, states) => {
     let msg = [MK.REQADDHUNK]
     MSGS.writeTo(msg, name, 'string')
-    if (id) MSGS.writeTo(msg, id, 'string')
+    // probably loading from a program 'state' object:
+    for (let st of states) {
+      //console.log('VIEW REQ STATE ON ADD', st)
+      msg.push(HK.STATE)
+      MSGS.writeTo(msg, st.ind, 'uint8')
+      MSGS.writeTo(msg, st.value, st.type)
+    }
     writeMessage(msg)
   }
 
-  this.requestRemoveHunk = (id) => {
+  this.requestRemoveHunk = (ind) => {
     let msg = [MK.REQRMHUNK]
-    MSGS.writeTo(msg, id, 'string')
+    MSGS.writeTo(msg, ind, 'uint16')
+    writeMessage(msg)
+  }
+
+  this.requestAddLink = (output, input) => {
+    let msg = [MK.REQADDLINK]
+    MSGS.writeTo(msg, output.parent.ind, 'uint16')
+    MSGS.writeTo(msg, output.ind, 'uint8')
+    MSGS.writeTo(msg, input.parent.ind, 'uint16')
+    MSGS.writeTo(msg, input.ind, 'uint8')
     writeMessage(msg)
   }
 
-  this.requestAddLink = (outId, outputName, inId, inputName) => {
+  this.requestAddLinkLikeACaveman = (outInd, outputInd, inInd, inputInd) => {
     let msg = [MK.REQADDLINK]
-    MSGS.writeTo(msg, outId, 'string')
-    MSGS.writeTo(msg, outputName, 'string')
-    MSGS.writeTo(msg, inId, 'string')
-    MSGS.writeTo(msg, inputName, 'string')
+    MSGS.writeTo(msg, outInd, 'uint16')
+    MSGS.writeTo(msg, outputInd, 'uint8')
+    MSGS.writeTo(msg, inInd, 'uint16')
+    MSGS.writeTo(msg, inputInd, 'uint8')
     writeMessage(msg)
   }
 
-  this.requestRemoveLink = (outId, outputName, inId, inputName) => {
+  this.requestRemoveLink = (output, input) => {
     let msg = [MK.REQRMLINK]
-    MSGS.writeTo(msg, outId, 'string')
-    MSGS.writeTo(msg, outputName, 'string')
-    MSGS.writeTo(msg, inId, 'string')
-    MSGS.writeTo(msg, inputName, 'string')
+    MSGS.writeTo(msg, output.parent.ind, 'uint16')
+    MSGS.writeTo(msg, output.ind, 'uint8')
+    MSGS.writeTo(msg, input.parent.ind, 'uint16')
+    MSGS.writeTo(msg, input.ind, 'uint8')
     writeMessage(msg)
   }
 
-  this.requestStateChange = (parentId, state, value) => {
-    // ok then,
+  // , numoot (number)
+  this.requestStateChange = (state, value) => {
+    // ok then, THISNOW
     let msg = [MK.REQSTATECHANGE]
-    MSGS.writeTo(msg, parentId, 'string')
-    MSGS.writeTo(msg, state.name, 'string')
+    MSGS.writeTo(msg, state.parent.ind, 'uint16')
+    MSGS.writeTo(msg, state.ind, 'uint8')
     // not unlikely mess here,
     try {
       MSGS.writeTo(msg, value, state.type)
@@ -819,53 +794,6 @@ function View() {
     }
   }
 
-  // responses (change state / add link)
-
-  let receiveStateChange = (parentId, name, bytes, index) => {
-    let blkstate = $(this.plane).find('#' + parentId + '_state_' + name)
-    if (blkstate !== null && blkstate !== undefined) {
-      // the blkstate is the div element, inside of a <li> it has (type)
-      // we pick that out of the string *like a monkey* because truth is what we see
-      let li = $(blkstate).children().get(0).innerText
-      let tString = li.substring(li.indexOf('(') + 1, li.indexOf(')'))
-      // ok,
-      let val
-      try {
-        val = MSGS.readFrom(bytes, index, tString)
-      } catch (err) {
-        writeErrMessage('no good type matching at view reception of state change')
-        console.log(err)
-      }
-      // assuming that went well, it's a system type. we don't need to know which type apart from:
-      if (Object.keys(val).includes('item') && Object.keys(val).includes('increment')) {
-        val = val.item
-      }
-      // and finally, update the dom
-      switch (typeof val) {
-        case 'string':
-          let strinput = $(blkstate).children('input').get(0)
-          strinput.value = val
-          break
-        case 'number':
-          let numput = $(blkstate).children('input').get(0)
-          numput.value = val.toString(10)
-          break
-        case 'boolean':
-          if (val) {
-            $(blkstate).children('span').text('true')
-          } else {
-            $(blkstate).children('span').text('false')
-          }
-          break
-        default:
-          throw new Error('state type no bueno wyd?')
-          break
-      }
-    } else {
-      writeErrMessage("couldn't find the requested state item on a received-state-change message")
-    }
-  }
-
   /* ---------------------------    ---------------------------- */
   /* --------------------- MESSAGES OUTPUT --------------------- */
   /* ---------------------------    ---------------------------- */
@@ -895,40 +823,46 @@ function View() {
     if (msgsin.io) {
       let msg = msgsin.get()
       // at view, read in and deserialize list
-      if (msgverbose) console.log('VIEW MSG:', msg)
+      if (msgverbose) console.log('VIEW RX MSG:', msg)
       if (!Array.isArray(msg)) throw new Error(`view throwing object message, having header ${msg.header}`)
-
+      // for item, increment pulls
+      let temp
       // ok,
       switch (msg[0]) {
         case MK.ERR:
+          if (msgverbose) console.log('VIEW MSG is an error')
           msgbox.write(MSGS.readFrom(msg, 1, 'string').item)
           break
         case MK.HELLO:
+          if (msgverbose) console.log('VIEW MSG is hello')
           msgbox.write(`manager says hello, took ${performance.now() - helloTime}ms`)
           break
         case MK.BRIEF:
+          if (msgverbose) console.log('VIEW MSG is a manager brief')
           // title, name of manager, lsit of unloaded hunks ?
           msgbox.write('manger sends program brief, will begin loading...')
           // serial -> js, by procedure du jakhey
           let brief = {}
           let bi = 1
           // reading strings returns item, increment
-          let id = MSGS.readFrom(msg, bi, 'string')
-          bi += id.increment
-          brief.interpreterId = id.item
-          let intrprtrnm = MSGS.readFrom(msg, bi, 'string')
-          bi += intrprtrnm.increment
-          brief.interpreterName = intrprtrnm.item
-          let intrprtrv = MSGS.readFrom(msg, bi, 'string')
-          bi += intrprtrv.increment
-          brief.interpreterVersion = intrprtrv.item
-          brief.numHunks = MSGS.readFrom(msg, bi, 'uint32')
-          brief.numLinks = MSGS.readFrom(msg, bi + 5, 'uint32')
+          temp = MSGS.readFrom(msg, bi, 'string')
+          bi += temp.increment
+          brief.interpreterName = temp.item
+          temp = MSGS.readFrom(msg, bi, 'string')
+          bi += temp.increment
+          brief.interpreterVersion = temp.item
+          temp = MSGS.readFrom(msg, bi, 'uint16')
+          bi += temp.increment
+          brief.numHunks = temp.item
+          brief.numLinks = MSGS.readFrom(msg, bi, 'uint16').item
+          // set local,
           this.interpreterName = brief.interpreterName
           this.interpreterVersion = brief.interpreterVersion
+          // and write it down
           msgbox.briefState.setFromBrief(brief)
           break
         case MK.LISTOFAVAIL:
+          if (msgverbose) console.log('VIEW MSG is a list of available items')
           let stringlist = MSGS.readListFrom(msg, 1, 'string')
           this.changeContextTitle('available hunks:')
           for (let item of stringlist) {
@@ -941,36 +875,67 @@ function View() {
           }
           break
         case MK.HUNKALIVE:
-          console.log('hunk alive, going to deserialize')
-          let def = defBySerial(msg, 1)
-          putDef(def)
-          patchset.onHunkLoaded(def)
+          // this can refer to new hunks, and modified hunk descriptions
+          // i.e. changing a list of outputs and inputs
+          if (msgverbose) console.log('VIEW MSG is a new hunk')
+          let spec = specBySerial(msg, 1, false)
+          // so first we check for an existing hunk,
+          if (defs[spec.ind] === undefined) {
+            let nd = newDef(spec)
+            msgbox.briefState.decrementHunks()
+            msgbox.write(`added a new hunk: ${spec.name}`)
+            patchset.onHunkLoaded(nd)
+            $(this.dom).find('.contextmenu').remove()
+          } else {
+            if(verbose) console.log('replacing hunk at', spec.ind)
+            let nd = replaceDef(spec)
+            msgbox.write(`replaced ${spec.name}_${spec.ind} with a new definition`)
+            patchset.onHunkLoaded(nd)
+          }
+          // hmmm ...
+          //
           // bfstate should mixin to vptches
-          msgbox.briefState.decrementHunks()
           break
         case MK.HUNKSTATECHANGE:
-          let stchinc = 1
-          let stChId = MSGS.readFrom(msg, stchinc, 'string')
-          stchinc += stChId.increment
-          stChId = stChId.item
-          let stChName = MSGS.readFrom(msg, stchinc, 'string')
-          stchinc += stChName.increment
-          stChName = stChName.item
-          receiveStateChange(stChId, stChName, msg, stchinc)
+          if (msgverbose) console.log('VIEW MSG is a state change')
+          let stchHnkInd = MSGS.readFrom(msg, 1, 'uint16').item
+          let stchStInd = MSGS.readFrom(msg, 4, 'uint8').item
+          let stDef = defs[stchHnkInd].states[stchStInd]
+          let stValUpdate = MSGS.readFrom(msg, 6, stDef.type).item
+          stDef.set(stValUpdate)
+          patchset.onStateChanged(stDef)
+          msgbox.write(`changed state at ${stchHnkInd} ${stDef.name} to ${stValUpdate}`)
           break
         case MK.HUNKREMOVED:
-          let rmid = MSGS.readFrom(msg, 1, 'string').item
+          if (msgverbose) console.log('VIEW MSG is a hunk to remove')
+          let rmid = MSGS.readFrom(msg, 1, 'uint16').item
           removeDef(rmid)
+          msgbox.write(`removed hunk #${rmid}`)
           break
         case MK.LINKALIVE:
-          let alal = MSGS.readListFrom(msg, 1, 'string')
-          putLink(alal[0], alal[1], alal[2], alal[3])
-          patchset.onLinkLoaded()
-          msgbox.briefState.decrementLinks()
+          if (msgverbose) console.log('VIEW MSG is a link to put')
+          let addOutInd = MSGS.readFrom(msg, 1, 'uint16').item
+          let addOutputInd = MSGS.readFrom(msg, 4, 'uint8').item
+          let addInInd = MSGS.readFrom(msg, 6, 'uint16').item
+          let addInputInd = MSGS.readFrom(msg, 9, 'uint8').item
+          if(putLink(addOutInd, addOutputInd, addInInd, addInputInd)){
+            //patchset.onLinkLoaded()
+            msgbox.write(`added a link`)
+            msgbox.briefState.decrementLinks()
+            patchset.onLinkLoaded(addOutInd, addOutputInd, addInInd, addInputInd)
+          }
           break
         case MK.LINKREMOVED:
-          let rmal = MSGS.readListFrom(msg, 1, 'string')
-          removeLink(rmal[0], rmal[1], rmal[2], rmal[3])
+          if (msgverbose) console.log('VIEW MSG is a link to cut')
+          let rmOutInd = MSGS.readFrom(msg, 1, 'uint16').item
+          let rmOutputInt = MSGS.readFrom(msg, 4, 'uint8').item
+          let rmInInd = MSGS.readFrom(msg, 6, 'uint16').item
+          let rmInputInd = MSGS.readFrom(msg, 9, 'uint8').item
+          if(cutLink(rmOutInd, rmOutputInt, rmInInd, rmInputInd)){
+            msgbox.write(`removed a link`)
+          } else {
+            throw new Error('error during link cut')
+          }
           break
         default:
           throw new Error(`view receives message with no switch: ${msg[0]}`)
diff --git a/programs/cuttlefish/wstst.json b/programs/cuttlefish/wstst.json
new file mode 100644
index 0000000000000000000000000000000000000000..f87cc4f78ec507ba75541c10e214b076fcb95665
--- /dev/null
+++ b/programs/cuttlefish/wstst.json
@@ -0,0 +1,81 @@
+{
+  "interpreterName": "cuttlefish",
+  "interpreterVersion": "v0.1",
+  "hunks": [{
+    "name": "manager",
+    "states": []
+  }, {
+    "name": "view",
+    "states": []
+  }, {
+    "name": "link",
+    "states": [{
+      "ind": 0,
+      "type": "string",
+      "value": "mgrMsgs (byteArray), numtype (number)"
+    }, {
+      "ind": 1,
+      "type": "string",
+      "value": "mgrMsgs (byteArray), numoot (number)"
+    }]
+  }, {
+    "name": "view",
+    "states": []
+  }, {
+    "name": "interface/number",
+    "states": [{
+      "ind": 0,
+      "type": "number",
+      "value": 12
+    }]
+  }, {
+    "name": "comm/websocketclient",
+    "states": [{
+      "ind": 0,
+      "type": "string",
+      "value": "closed"
+    }, {
+      "ind": 1,
+      "type": "number",
+      "value": 3
+    }, {
+      "ind": 2,
+      "type": "boolean",
+      "value": false
+    }, {
+      "ind": 3,
+      "type": "string",
+      "value": "127.0.0.1"
+    }, {
+      "ind": 4,
+      "type": "number",
+      "value": 2042
+    }]
+  }],
+  "links": [{
+    "outInd": 2,
+    "outputInd": 0,
+    "inInd": 5,
+    "inputInd": 0
+  }, {
+    "outInd": 2,
+    "outputInd": 1,
+    "inInd": 3,
+    "inputInd": 0
+  }, {
+    "outInd": 3,
+    "outputInd": 0,
+    "inInd": 2,
+    "inputInd": 1
+  }, {
+    "outInd": 4,
+    "outputInd": 0,
+    "inInd": 2,
+    "inputInd": 2
+  }, {
+    "outInd": 5,
+    "outputInd": 0,
+    "inInd": 2,
+    "inputInd": 0
+  }]
+}
diff --git a/programs/nautilus/ntThru.json b/programs/nautilus/ntThru.json
new file mode 100644
index 0000000000000000000000000000000000000000..ba12aaf896ccbc4f04319c1ad73e5a419d1aac25
--- /dev/null
+++ b/programs/nautilus/ntThru.json
@@ -0,0 +1 @@
+{"interpreterName":"nautilus","interpreterVersion":"v0.1","hunks":[{"name":"manager","states":[]},{"name":"link","states":[{"ind":0,"type":"string","value":"mgrMsgs (byteArray), numtoview (number)"},{"ind":1,"type":"string","value":"mgrMsgs (byteArray), numfromview (number)"}]},{"name":"comm/websocketserver","states":[{"ind":0,"type":"string","value":"connected"},{"ind":1,"type":"number","value":2042}]},{"name":"comm/cobserial","states":[{"ind":0,"type":"string","value":"closed"},{"ind":1,"type":"string","value":"8022"},{"ind":2,"type":"boolean","value":false}]},{"name":"link","states":[{"ind":0,"type":"string","value":"mgrMsgs (byteArray), numthru (number)"},{"ind":1,"type":"string","value":"mgrMsgs (byteArray), numback (number)"}]}],"links":[{"outInd":0,"outputInd":0,"inInd":1,"inputInd":1},{"outInd":1,"outputInd":0,"inInd":2,"inputInd":0},{"outInd":1,"outputInd":1,"inInd":0,"inputInd":0},{"outInd":1,"outputInd":2,"inInd":4,"inputInd":2},{"outInd":2,"outputInd":0,"inInd":1,"inputInd":0},{"outInd":3,"outputInd":0,"inInd":4,"inputInd":0},{"outInd":4,"outputInd":0,"inInd":3,"inputInd":0},{"outInd":4,"outputInd":2,"inInd":1,"inputInd":2}]}
\ No newline at end of file
diff --git a/programs/nautilus/ntsave.json b/programs/nautilus/ntsave.json
new file mode 100644
index 0000000000000000000000000000000000000000..3522a987f2fe42b7905e1f28b6d7ba4e6cde2aa1
--- /dev/null
+++ b/programs/nautilus/ntsave.json
@@ -0,0 +1,22 @@
+{
+  "interpreterName": "cuttlefish",
+  "interpreterVersion": "v0.1",
+  "hunks": [{
+    "name": "comm/websocketserver",
+    "states": [{
+      "ind": 0,
+      "type": "string",
+      "value": "connected"
+    }, {
+      "ind": 1,
+      "type": "number",
+      "value": 2042
+    }]
+  }],
+  "links": [{
+    "outInd": 2,
+    "outputInd": 0,
+    "inInd": 1,
+    "inputInd": 0
+  }]
+}
diff --git a/programs/ptest.json b/programs/ptest.json
deleted file mode 100644
index bd114b60d46c9b0ce922bee3e161857b163db932..0000000000000000000000000000000000000000
--- a/programs/ptest.json
+++ /dev/null
@@ -1 +0,0 @@
-{"interpreterName":"cuttlefish","interpreterVersion":"v0.1","hunks":[{"id":"NROL39_0","name":"manager"},{"id":"TLView","name":"view"},{"id":"hnk_3","name":"view"},{"id":"hnk_2","name":"link","state":[{"name":"inputList","type":"string","value":"mgrMsgs (byteArray), num (number)"},{"name":"outputList","type":"string","value":"mgrMsgs (byteArray)"}]}],"links":[{"outhunk":"NROL39_0","outname":"msgs","inhunk":"TLView","inname":"msgs"},{"outhunk":"TLView","outname":"msgs","inhunk":"NROL39_0","inname":"msgs"},{"outhunk":"hnk_3","outname":"msgs","inhunk":"hnk_2","inname":"data"},{"outhunk":"hnk_2","outname":"data","inhunk":"hnk_3","inname":"msgs"}]}
\ No newline at end of file
diff --git a/style.css b/style.css
index 10a89ccae33cf02157f645de6ed021b200f0d7ca..efe1d8af719fc96308b45e50776fe1c7b2a9ab7f 100644
--- a/style.css
+++ b/style.css
@@ -97,15 +97,6 @@ body {
 	cursor: se-resize;
 }
 
-.contextmenu {
-	position: absolute;
-	overflow: hidden;
-	width: 245px;
-	padding: 10px;
-    background-color: #303030;
-    color: #eee;
-}
-
 #programMenu {
 	position: absolute;
 	width: 245px;
@@ -136,7 +127,7 @@ body {
 	color: #eee;
 }
 
-.block {
+.def {
 	width: 500px;
 	overflow: hidden;
 	position: absolute;
@@ -149,7 +140,7 @@ body {
 	background-color: #4d4c4c;
 }
 
-.blockid {
+.deftitle {
 	font-size: 15px;
 	font-weight: bold;
 	font-style: italic;
@@ -160,12 +151,12 @@ body {
 	color: #eee;
 }
 
-.blockid:hover{
+.deftitle:hover{
 	background-color: #969696;
 	cursor: grab;
 }
 
-.blockid:active{
+.deftitle:active{
 	cursor: grabbing;
 }
 
@@ -196,12 +187,12 @@ body {
 	cursor: grab;
 }
 
-.state {
+.states {
 	padding: 0 123px 0 123px;
 	color: #eee;
 }
 
-.stateItem {
+.state {
 	font-size: 11px;
 	padding: 3px;
 }
@@ -224,17 +215,38 @@ textarea {
 }
 */
 
-.state input {
+.stateItem {
+	margin: 3px;
+}
+
+.stateItem input {
 	background-color: #1a1a1a;
 	color: #fcd17b;
 	font-size: 12px;
 	width: 70%;
 	margin-bottom: 2px;
-	float: right;
+	margin-top: 4px;
+	padding: 2px;
 	border: 1px solid black;
 	border-radius: 3px;
 }
 
+.stateNumInput input {
+	float: right;
+	clear: both;
+	align: right;
+}
+
+.stateBooleanItem{
+	padding-top: 8px;
+	padding-bottom: 8px;
+}
+
+.stateBooleanItem:hover{
+	background-color: #1a1a1a;
+	cursor: pointer;
+}
+
 .dg.a {
 	margin-right: 0px;
 }
@@ -278,16 +290,39 @@ li:active{
 	padding: 7px 5px 6px 5px;
 }
 
+
+/*
 .contextTitle:hover {
 	background-color: #969696;
 	cursor: grab;
 }
+*/
 
 .contextTitle:active {
 	background-color: #d1d1d1;
 	cursor: grabbing;
 }
 
+.contextmenu {
+	position: absolute;
+	overflow: hidden;
+	width: 245px;
+	padding: 10px;
+    background-color: #303030;
+    color: #eee;
+}
+
+.contextmenu input {
+	background-color: #1a1a1a;
+	color: #fcd17b;
+	font-size: 12px;
+	width: 70%;
+	margin-bottom: 2px;
+	padding: 2px;
+	border: 1px solid black;
+	border-radius: 3px;
+}
+
 /* USING THESE WITHIN BOYOS */
 
 .cuttlefishhunkdom {
diff --git a/typeset.js b/typeset.js
index d82b473248624c16f387604538da854d77a1d669..f7ada08d0f7f2f5c50435f613979ba7f4d8bcfc3 100644
--- a/typeset.js
+++ b/typeset.js
@@ -1,62 +1,67 @@
-// as an array, to use .find((candidate) => {})
-
+// typeset: functional types -> bytes for js -> embedded sys
 // bless up @ modern js https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
 
-const MSGKEY_ACK = 254
 
-/*
-const MSGKEY_ACK = 254
-// counting down from
-const MSGKEY_OBJECT = 249
-// hmmm ....
-const MSGKEY_NUMBER = 248
-const MSGKEY_UINT64 = 247
+let tsdebug = false
+
+// oy,
+
+const checkKey = (type, arr, start) => {
+  if (arr[start] !== type.key) throw new Error(`mismatched key on phy read: for ${type.name}, find ${arr[start]} instead of ${type.key} ... at ${start} index`)
+}
+
+const checkBoolean = (value) => {
+  if (typeof value !== 'boolean') throw new Error('cannot cast non-boolean to bool at phy')
+}
 
-MSGKEY_BYTEARRAY: 33,
-MSGKEY_UINT8: 34,
-MSGKEY_UINT8ARRAY: 35,
-MSGKEY_INT8: 36,
-MSGKEY_INT8ARRAY: 37,
-MSGKEY_DOUBLEFLOAT: 33
-*/
+const checkNumber = (value) => {
+  if (typeof value !== 'number') throw new Error(`for uint8 cannot cast non-number into physical world "${value}", ${typeof value}`)
+}
+
+const checkString = (value) => {
+  if (typeof value !== 'string') throw new Error(`cannot cast non-string to string at phy! "${value}", "${typeof value}"`)
+}
+
+const checkArray = (thing) => {
+  if (!Array.isArray(thing)) throw new Error('this thing is not an array!')
+}
+
+const checkUnsigned = (value, bits) => {
+  if(value > Math.pow(2, bits)) throw new Error('value out of byte bounds')
+}
+
+const checkSigned = (value, bits) => {
+  let comparator = Math.pow(2, bits-1)
+  if(value > comparator || value < -comparator) throw new Error('value out of byte bounds')
+}
 
 const findPhy = (type) => {
   let phy = TSET.find((cand) => {
     return cand.name === type
   })
-  if(phy === undefined) throw new Error(`could not find phy for datatype: ${type}`)
+  if (phy === undefined) throw new Error(`could not find phy for datatype: ${type}`)
   return phy
 }
 
 const TSET = [{
-    name: 'byte',
+    name: 'boolean',
     key: 32,
     write: function(value) {
-      // convert to,
-    },
-    read: function(arr) {
-      // retun number
-    }
-  },
-  {
-    name: 'boolean',
-    key: 33,
-    write: function(value){
-      if (typeof value !== 'boolean') throw new Error('cannot cast non-boolean to bool at phy')
+      checkBoolean(value)
       let rtarr = [this.key]
-      if(value){
+      if (value) {
         rtarr.push(1)
-      }else{
+      } else {
         rtarr.push(0)
       }
       return rtarr
     },
-    read: function(arr, start){
-      if(arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`)
+    read: function(arr, start) {
+      checkKey(this, arr, start)
       let item
-      if(arr[start + 1] === 1){
+      if (arr[start + 1] === 1) {
         item = true
-      } else if(arr[start + 1] === 0){
+      } else if (arr[start + 1] === 0) {
         item = false
       } else {
         throw new Error(`non std boolean byte, ${arr[start+1]}`)
@@ -66,45 +71,134 @@ const TSET = [{
         increment: 2
       }
     }
+  }, // booleanArray: 33,
+  {
+    name: 'byte',
+    key: 34,
+    write: function(value) {
+      checkNumber(value)
+      // truncate or error ?
+      checkUnsigned(value, 8)
+      return [this.key, value]
+    },
+    read: function(arr, start) {
+      checkKey(this, arr, start)
+      return {
+        item: arr[start + 1],
+        increment: 2
+      }
+    }
   },
+  {
+    name: 'byteArray',
+    key: 35,
+    write: function(value) {
+      // assume justice has already been served,
+      checkArray(value)
+      let rtarr = writeLenBytes(value.length).concat(value)
+      rtarr.unshift(this.key)
+      if(tsdebug) console.log('byteArray sanity check:', value, 'written as:', rtarr)
+      return rtarr
+    },
+    read: function(arr, start) {
+      checkKey(this, arr, start)
+      let lb = readLenBytes(arr, start + 1)
+      // okey
+      let narr = new Array()
+      for(let i = 0; i < lb.len; i++){
+        narr.push(arr[start + 1 + lb.numBytes + i])
+      }
+      return {
+        item: narr,
+        increment: lb.len + lb.numBytes + 1
+      }
+    }
+  }, // char 36, string 37,
   {
     name: 'string',
-    key: 38,
-    write: function(str){
-      if (typeof str !== 'string') throw new Error('cannot cast non-string to string at phy')
+    key: 37,
+    write: function(str) {
+      checkString(str)
       let rtarr = new Array()
-      for(let i = 0; i < str.length; i ++){
+      for (let i = 0; i < str.length; i++) {
         rtarr.push(str.charCodeAt(i))
       }
       // length bytes are 7-bit 'msb for continue' numbers ...
+      // the -1 because we are not counting the length of the key
       let lb = writeLenBytes(rtarr.length)
       rtarr = lb.concat(rtarr)
-      // key always
       rtarr.unshift(this.key)
       return rtarr
     },
     read: function(arr, start) {
-      if(arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`)
+      checkKey(this, arr, start)
       let lb = readLenBytes(arr, start + 1)
       //console.log('lenbytes', lb)
       let str = new String()
-      for(let i = 0; i < lb.len; i ++){
+      for (let i = 0; i < lb.len; i++) {
         str += String.fromCharCode(arr[start + 1 + lb.numBytes + i])
       }
-      // TODO: it would be *super handy* if I could pass in an i to increment ... maybe I pass in an object,
-      // containing that incrementer ?
-      // this could be optional for all?
-      // more complex types, we need to know upstream how far to increment counter as well,
-      // the +1 here is assuming incrementing over the leading key as well, so that at arr[start + increment] we find a next key,
       return {
         item: str,
         increment: lb.len + lb.numBytes + 1
       }
     }
   },
+  {
+    name: 'uint8',
+    key: 38,
+    write: function(value) {
+      checkNumber(value)
+      checkUnsigned(value, 8)
+      if (value > 255 || value < 0) throw new Error('num too large to represent with cast type, will contencate')
+      // dont' need to type-buffer this,
+      let rtarr = [this.key, value]
+      return rtarr
+    },
+    read: function(arr, start) {
+      // assume we're reading out of an array
+      // start[] should === key
+      if (arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`)
+      if (arr[start + 1] > 255 || arr[start + 1] < 0) throw new Error('whaky read-in on uint8')
+      return {
+        item: arr[start + 1],
+        increment: 2
+      }
+    }
+  }, // uint8Array 39
+  {
+    name: 'uint16',
+    key: 40,
+    write: function(value) {
+      if (typeof value !== 'number') throw new Error(`cannot cast non-number into physical world "${value}"`)
+      if (value > 65536 || value < 0) throw new Error('num too large to represent with cast type, will contencate')
+      let tparr = new Uint16Array(1)
+      tparr[0] = value
+      let btarr = new Uint8Array(tparr.buffer)
+      //place
+      let rtarr = Array.from(btarr).reverse()
+      rtarr.unshift(this.key)
+      return rtarr
+    },
+    read: function(arr, start) {
+      // assume we're reading out of an array
+      // start[] should === key
+      if (arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`)
+      let rdarr = arr.slice(start + 1, start + 3).reverse()
+      let btarr = Uint8Array.from(rdarr)
+      if (tsdebug) console.log('bytes on read of uint16 (little eadian)', btarr)
+      // now make uint32 view on this ...
+      let vlarr = new Uint16Array(btarr.buffer)
+      if (tsdebug) console.log('vlarr', vlarr)
+      return {
+        item: vlarr[0],
+        increment: 3
+      }
+    }
+  }, // uint16 array 41
   {
     name: 'uint32',
-    key: 39,
+    key: 42,
     write: function(value) {
       if (typeof value !== 'number') throw new Error('cannot cast non-number into physical world')
       if (value > 4294967296) throw new Error('num too large to represent with cast type, will contencate')
@@ -119,23 +213,32 @@ const TSET = [{
     read: function(arr, start) {
       // assume we're reading out of an array
       // start[] should === key
-      if(arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`)
+      if (arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`)
       let rdarr = arr.slice(start + 1, start + 5).reverse()
       let btarr = Uint8Array.from(rdarr)
-      console.log('bts on read of uint32', btarr)
+      if (tsdebug) console.log('bts on read of uint32', btarr)
       // now make uint32 view on this ...
       let vlarr = new Uint32Array(btarr.buffer)
-      console.log('vlarr', vlarr)
+      if (tsdebug) console.log('vlarr', vlarr)
       return {
         item: vlarr[0],
         increment: 5
       }
     }
-  },
+  }, // uint32array 43,
+  /*
+  uint64 44, uint64array 45,
+  int8 46, int8array 47,
+  int16 48, int16array 49,
+  int32 50, int32array 50,
+  int64 52, int64array 53,
+  float32 54, float32array 55,
+  float64 56, float64array 57 (these are === javascript 'numbers') ... how to alias ?
+  */
   {
     name: 'number',
-    key: 40,
-    write: function(value){
+    key: 56,
+    write: function(value) {
       if (typeof value !== 'number') throw new Error('cannot cast non-number into physical world')
       let tparr = new Float64Array(1)
       tparr[0] = value
@@ -145,13 +248,13 @@ const TSET = [{
       rtarr.unshift(this.key)
       return rtarr
     },
-    read: function(arr, start){
-      if(arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`)
+    read: function(arr, start) {
+      if (arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`)
       let rdarr = arr.slice(start + 1, start + 9).reverse()
       let btarr = Uint8Array.from(rdarr)
-      console.log('bts on read of float64', btarr)
+      if (tsdebug) console.log('bts on read of float64', btarr)
       let vlarr = new Float64Array(btarr.buffer)
-      console.log('vlarr', vlarr)
+      if (tsdebug) console.log('vlarr', vlarr)
       return {
         item: vlarr[0],
         increment: 9
@@ -164,19 +267,19 @@ const TSET = [{
 const writeLenBytes = (len) => {
   // return array of len bytes for this number
   let bts = new Array()
-  for(let i = 0; i < 3; i ++){
+  for (let i = 0; i < 3; i++) {
     // chonk,
-    let sevenup = (len >>> (7 * i)) & 127
+    let sevenup = (len >> (7 * i)) & 127
     // and if any are remaining,
-    if((len >>> (7 * i)) > 127){
+    if ((len >> (7 * i)) > 127) {
       // drop a 1 in the front, (128 == 1000000)
-      sevenup = sevenup & 128
+      sevenup = sevenup | 128
       bts.push(sevenup)
     } else {
       bts.push(sevenup)
       break
     }
-    if(i > 2) throw new Error('suspiciously long len cast', bts)
+    if (i > 2) throw new Error('suspiciously long len cast', bts)
   }
   //console.log(`for len ${len}, wrote bytes`, bts)
   return bts
@@ -188,17 +291,17 @@ const readLenBytes = (arr, start) => {
   // there is at least one,
   let nb = 0
   // carefully, and no more than four
-  for(let i = 0; i < 3; i ++){
+  for (let i = 0; i < 3; i++) {
     // bitwise operations assume (?) that numbers are 32 bit signed integers,
     // place the nth in position,
     len = len | ((arr[start + nb] & 127) << (7 * nb))
     // if this byte was < 127, there was no 1 in the MSB, that was the last len byte,
-    nb ++
+    nb++
     // go forth, go back
-    if(arr[start + nb - 1] < 127) break
+    if (arr[start + nb - 1] < 127) break
     // otherwise there is a trailing len byte, continue this for
     // if we grow past 4 len bytes, we have a size > 268 million, more than likely some mistakes were made
-    if(nb > 4) throw new Error('nb > 4 while reading lenBytes')
+    if (nb > 4) throw new Error('nb > 4 while reading lenBytes')
   }
   // need 2 know how many to increment as well,
   return {
@@ -209,37 +312,37 @@ const readLenBytes = (arr, start) => {
 
 // heavy mixin of functional programming
 const MSGS = {
-  writeTo: function(bytes, thing, type, debug){
+  writeTo: function(bytes, thing, type, debug) {
     let phy = findPhy(type)
     let block = phy.write(thing)
-    if(debug) console.log(`writing for type ${type} and thing '${thing}' the following block of bytes`, block)
+    if (debug) console.log(`writing for type ${type} and thing '${thing}' the following block of bytes`, block)
     // write-in to msg like this
     block.forEach((byte) => {
       bytes.push(byte)
     })
   },
-  readFrom: function(bytes, place, type){
+  readFrom: function(bytes, place, type) {
     let phy = findPhy(type)
     // check that type exists at place, rip it oot and return it
     return phy.read(bytes, place)
   },
-  readListFrom: function(bytes, place, type){
+  readListFrom: function(bytes, place, type) {
     // using this where I expect a lit of values, i.e. the addLink(str,str,str,str) arguments,
     // plucks thru, continuing to pull values as long as the next in the serialized list is of
     // the right type
     let phy = findPhy(type)
     // the list of items,
     let list = new Array()
-    while(place < bytes.length){
+    while (place < bytes.length) {
       let res = phy.read(bytes, place)
       list.push(res.item)
       place += res.increment
-      if(bytes[place] !== phy.key) break
+      if (bytes[place] !== phy.key) break
       // this could throw us into infinite loops, so
-      if(res.increment < 1) throw new Error('dangerous increment while reading list')
+      if (res.increment < 1) throw new Error('dangerous increment while reading list')
     }
-    if(list.length < 1) throw new Error('reading list, found no items...')
-    console.log('read list as', list)
+    if (list.length < 1) throw new Error('reading list, found no items...')
+    if (tsdebug) console.log('read list as', list)
     return list
   }
 }
@@ -248,41 +351,50 @@ const MSGS = {
 // manager keys
 const MK = {
   // bzzt
-  ERR: 254,           // (str) message
+  ERR: 254, // (str) message
   // heartbeats, wakeup
-  HELLO: 253,         // (eom)
+  HELLO: 253, // (eom)
   // request a top-level description
-  REQDESCRIBESELF: 251,  // (eom)
-  BRIEF: 250,         // (str) name of interpreter, # hunks, # links (and then begin firing list back)
+  REQDESCRIBESELF: 251, // (eom)
+  BRIEF: 250, // (str) name of interpreter, # hunks, # links (and then begin firing list back)
   // please show what is available
-  REQLISTAVAIL: 249,  // (eom)
-  LISTOFAVAIL: 248,   // (list)(str) names 'dirs/like/this' (includes programs ?) (this might be multiple packets?)
+  REQLISTAVAIL: 249, // (eom)
+  LISTOFAVAIL: 248, // (list)(str) names 'dirs/like/this' (includes programs ?) (this might be multiple packets?)
   // business ... we should be able to centralize all control w/i view.js if we can write these
-  REQADDHUNK: 247,    // (str) name
-  HUNKALIVE: 246,     // (hunkdescription): name, id, inputlist, outputlist, statelist
+  REQADDHUNK: 247, // (str) name
+  HUNKALIVE: 246, // (hunkdescription): name, id, inputlist, outputlist, statelist
   REQSTATECHANGE: 245,
   HUNKSTATECHANGE: 244,
-  REQRMHUNK: 243,     // (str) id
-  HUNKREMOVED: 242,   // (str) id
-  REQADDLINK: 241,    // (str) id, (str) outname, (str) id, (str) inname
-  LINKALIVE: 240,     // (str) id, (str) outname, (str) id, (str) inname
-  REQRMLINK: 239,     // (str) id, (str) outname, (str) id, (str) inname
-  LINKREMOVED: 238,   // (str) id, (str) outname, (str) id, (str) inname
+  REQRMHUNK: 243, // (str) id
+  HUNKREMOVED: 242, // (str) id
+  REQADDLINK: 241, // (str) id, (str) outname, (str) id, (str) inname
+  LINKALIVE: 240, // (str) id, (str) outname, (str) id, (str) inname
+  REQRMLINK: 239, // (str) id, (str) outname, (str) id, (str) inname
+  LINKREMOVED: 238, // (str) id, (str) outname, (str) id, (str) inname
 }
 
 // hunk description keys,
 const HK = {
   NAME: 253,
-  ID: 252,
+  IND: 252,
   DESCR: 251,
   INPUT: 249,
   OUTPUT: 247,
   STATE: 245,
 }
 
+// link keys,
+const LK = {
+  ACK: 254
+}
+
 // should write out as list of pairs ?
 // or write fn to do key(stringtype)
 
 export {
-  TSET, MSGKEY_ACK, MK, HK, MSGS
+  TSET,
+  MK, // manager keys
+  HK, // hunk def keys
+  LK, // link keys
+  MSGS
 }
diff --git a/view/vbzt.js b/view/vbzt.js
index ae817b983feb6fecfeb66798be3fbe4c66564893..b9fb4fc6752bfa90cd7007d2619939c8841902ed 100644
--- a/view/vbzt.js
+++ b/view/vbzt.js
@@ -62,7 +62,7 @@ function BezierTools(View) {
     return bz
   }
 
-  this.writeBezier = (head, tail, id) => {
+  this.writeBezier = (head, tail) => {
     let svg = document.createElementNS(svgns, 'svg')
     svg.style.position = 'absolute'
     svg.style.left = head.x + 'px'
@@ -72,15 +72,18 @@ function BezierTools(View) {
     svg.setAttribute('width', 12)
     svg.setAttribute('height', 12)
     svg.setAttribute('class', 'svg')
-    svg.setAttribute('id', 'svg' + '_' + id)
+    //svg.setAttribute('id', 'svg' + '_' + id)
     let bz = newBezier(head, tail, 7)
     svg.appendChild(bz.elem)
     view.plane.append(svg)
     return bz.elem
   }
 
-  this.drawLink = (head, tail, outdiv, hk, conn) => {
-    let bz = this.writeBezier(head, tail, outdiv.id + '_to_' + hk.id)
+  // these are 'def' objects
+  this.drawLink = (output, input) => {
+    let head = this.getRightHandle(output.de)
+    let tail = this.getLeftHandle(input.de)
+    let bz = this.writeBezier(head, tail)
     bz.addEventListener('mouseenter', (evt) => {
       bz.style.stroke = '#2889af'
     })
@@ -91,12 +94,7 @@ function BezierTools(View) {
       evt.preventDefault()
       evt.stopPropagation()
       // nice
-      let outId = outdiv.id.substring(0, outdiv.id.indexOf('_output_'))
-      let outName = outdiv.id.substring(outdiv.id.indexOf('_output_') + 8)
-      let inId = conn.substring(1, conn.indexOf('_input_'))
-      let inName = conn.substring(conn.indexOf('_input_') + 7)
-      // and the serialized message via the view, nice
-      view.requestRemoveLink(outId, outName, inId, inName)
+      view.requestRemoveLink(output, input)
     })
   }
 }
diff --git a/view/vdef.js b/view/vdef.js
new file mode 100644
index 0000000000000000000000000000000000000000..edc368ab0c3733ae5fcd013ed7e13fe5fbf7b56f
--- /dev/null
+++ b/view/vdef.js
@@ -0,0 +1,341 @@
+// a def is not a hunk, it's a definition of a hunk - the mirror image
+
+// new this -
+function HunkDefinition(spec, view, dt, debug) {
+  // the basics,
+  this.ind = spec.ind
+  this.name = spec.name
+  this.inputs = new Array()
+  this.outputs = new Array()
+  this.states = new Array()
+
+  // dom element
+  this.de = $('<div>').addClass('def').attr('id', `${this.name}_${this.ind}`).get(0)
+  let title = $(`<div>${this.name}_${this.ind}</div>`).addClass('deftitle').get(0)
+
+  // title right-click handler
+  title.oncontextmenu = (evt) => {
+    evt.preventDefault()
+    evt.stopPropagation()
+    // write menu for requesting delete and copy
+    let menu = $('<div>').addClass('contextmenu').get(0)
+    // title.offsetWidth is 400
+    // de.style.left, de.style.top, de.clientWidth,
+    let ct = dt.readTransform(this.de)
+    let x = ct.x + 500 + 10 + 'px'
+    dt.writeTransform(menu, {
+      s: 1,
+      x: ct.x + ((500 + 10)),
+      y: ct.y
+    })
+    $(view.plane).append(menu)
+    $(menu).append($('<li>remove hunk</li>').on('click', (evt) => {
+      view.requestRemoveHunk(this.ind)
+      $(menu).remove()
+    }))
+    $(menu).append($('<li>copy hunk</li>').on('click', (evt) => {
+      view.requestAddHunk(this.name)
+      $(menu).remove()
+    }))
+  }
+
+  // title drag handler,
+  title.onmousedown = (evt) => {
+    evt.preventDefault()
+    evt.stopPropagation()
+
+    let domElemMouseMove = (evt) => {
+      // TRANSFORMS here to move div about on drag
+      evt.preventDefault()
+      evt.stopPropagation()
+      let ct = dt.readTransform(this.de)
+      let pt = dt.readTransform(view.plane)
+      //console.log(ct, pt)
+      ct.x += evt.movementX / pt.s
+      ct.y += evt.movementY / pt.s
+      dt.writeTransform(this.de, ct)
+      view.drawLinks()
+    }
+
+    function rmOnMouseUp(evt) {
+      document.removeEventListener('mousemove', domElemMouseMove)
+      document.removeEventListener('mouseup', rmOnMouseUp)
+    }
+
+    document.addEventListener('mousemove', domElemMouseMove)
+    document.addEventListener('mouseup', rmOnMouseUp)
+  }
+
+  $(this.de).append(title)
+
+  // write inputs
+  if (spec.inputs.length > 0) {
+    let idom = $('<div>').addClass('inputs')
+    for (let ip in spec.inputs) {
+      let input = new InputDefinition(spec.inputs[ip], ip, this, debug)
+      this.inputs.push(input)
+      $(idom).append(input.de)
+    }
+    $(this.de).append(idom)
+  }
+  // write outputs,
+  if (spec.outputs.length > 0) {
+    let odom = $('<div>').addClass('outputs')
+    for (let op in spec.outputs) {
+      let output = new OutputDefinition(spec.outputs[op], op, this, view, dt, debug)
+      this.outputs.push(output)
+      $(odom).append(output.de)
+    }
+    $(this.de).append(odom)
+  }
+
+  if (spec.states.length > 0) {
+    let sdom = $('<div>').addClass('states')
+    for (let st in spec.states) {
+      let state = new StateDefinition(spec.states[st], st, this, view, debug)
+      this.states.push(state)
+      $(sdom).append(state.de)
+    }
+    $(this.de).append(sdom)
+  }
+
+  this.newInd = (ind) => {
+    this.ind = ind
+    // and those titles, and ids ...
+    $(this.de).attr('id', `${this.name}_${this.ind}`)
+    $(title).text(`${this.name}_${this.ind}`)
+    for(let ip of this.inputs){
+      ip.newParentInd()
+    }
+    for(let op of this.outputs){
+      op.newParentInd()
+    }
+    for(let st of this.states){
+      st.newParentInd()
+    }
+  }
+
+  if (debug) console.log('HunkDefinition', this)
+}
+
+function InputDefinition(ipspec, ind, def, debug) {
+  // keep track of name and type,
+  this.name = ipspec.name
+  this.type = ipspec.type
+  this.parent = def
+  this.ind = parseInt(ind)
+  // a dom element
+  this.de = $(`<li>${this.name} (${this.type})</li>`).addClass('input').get(0)
+  this.de.id = `${this.parent.name}_${this.parent.ind}_input_${this.name}`
+  this.newParentInd = () => {
+    this.de.id = `${this.parent.name}_${this.parent.ind}_input_${this.name}`
+  }
+  // we also keep a list,
+  this.connections = new Array()
+  this.disconnect = (output) => {
+    let index = this.connections.findIndex((cand) => {
+      return (cand.parent.ind === output.parent.ind && cand.name === output.name && cand.type === output.type)
+    })
+    if(index === -1) throw new Error('during output disconnect, input cannot find output...')
+    this.connections.splice(index, 1)
+  }
+  this.disconnectAll = () => {
+    for(let op of this.connections){
+      op.disconnect(this)
+    }
+    this.connections.length = 0
+  }
+  // to get this object via the dom, circular... apparently that is fine ?
+  this.de.hookup = this
+}
+
+function OutputDefinition(opspec, ind, def, view, dt, debug) {
+  // keep track of name and type,
+  this.parent = def
+  this.name = opspec.name
+  this.type = opspec.type
+  this.ind = parseInt(ind)
+  // a dom element
+  this.de = $(`<li>(${this.type}) ${this.name}</li>`).addClass('output').get(0)
+  this.de.id = `${this.parent.name}_${this.parent.ind}_output_${this.name}`
+  this.newParentInd = () => {
+    this.de.id = `${this.parent.name}_${this.parent.ind}_output_${this.name}`
+  }
+  // outputs handle all of the dragging-etc
+  this.connections = new Array() // of inputdefs, !
+  this.connect = (inputdef) => {
+    inputdef.connections.push(this)
+    this.connections.push(inputdef)
+  }
+  this.disconnect = (inputdef) => {
+    inputdef.disconnect(this)
+    let iof = this.connections.findIndex((cand) => {
+      return (cand.name === inputdef.name && cand.parent.ind === inputdef.parent.ind)
+    })
+    if(iof === -1) throw new Error('could not find input to disconnect')
+    this.connections.splice(iof, 1)
+    return true
+  }
+  this.disconnectAll = () => {
+    for(let ip of this.connections){
+      ip.disconnect(this)
+    }
+    this.connections.length = 0
+  }
+  // the dragging
+  this.floater = {}
+  this.hasFloater = false
+  // ondrag, attached later
+  let evtDrag = (evt) => {
+    // jake wants dead reckoning
+    evt.preventDefault()
+    evt.stopPropagation()
+    //let cp = this.readTransform(floater)
+    let pt = dt.readTransform(view.plane)
+    let thet = {}
+    // put it there ...
+    thet.s = 1
+    //console.log(pt.s)
+    // ...
+    let fltheight = this.floater.clientHeight
+    let fltwidth = this.floater.clientWidth
+    //console.log('mouse', evt.clientY, 'pt', pt.y, 'height', fltheight)
+    //console.log(fltheight, fltwidth)
+    thet.x = (evt.clientX - pt.x) / pt.s - ((fltwidth + 5) / pt.s)
+    thet.y = (evt.clientY - pt.y) / pt.s - (fltheight + (pt.s - 1) * (-5)) / pt.s // - ((fltheight * pt.s) / 2) / pt.s
+    dt.writeTransform(this.floater, thet)
+    view.drawLinks()
+  }
+  // to remove the below
+  let dragMouseUp = (evt) => {
+    if(debug) console.log('MOUSEUP ON', evt.target.id)
+    // 1st, make sure it's an input
+    if ($(evt.target).is('.input')) {
+      // HERE: searcheth by input id text? or
+      let hk = evt.target.hookup
+      if(!hk) throw new Error('missing some data at this input...')
+      // use a dom data flag, to find that input and output id?
+      view.requestAddLink(this, hk)
+      // do things to conn, then
+    }
+    // cleanup
+    document.removeEventListener('mouseup', dragMouseUp)
+    document.removeEventListener('mousemove', evtDrag)
+    // remove the floater flag
+    this.hasFloater = false
+    // remove the floater itself
+    $(view.plane).find('#floater').remove()
+    view.drawLinks()
+  }
+  // eeeeehntry
+  this.de.onmousedown = (evt) => {
+    evt.stopPropagation()
+    evt.preventDefault()
+    if (debug) console.log('mousedown for', this)
+    // this and that flag will be read-in on drawlinks, to draw that link
+    this.floater = $('<div>').attr('id', 'floater').append(this.type).get(0)
+    this.hasFloater = true
+    this.floater.style.zIndex = '1'
+    // the plane position
+    let pt = dt.readTransform(view.plane)
+    // plonk: have to do this now or else clientHeight / width are 0
+    view.plane.appendChild(this.floater)
+    // init out floater position, and put it in the dom
+    dt.writeTransform(this.floater, {
+      s: 1,
+      x: (evt.clientX - pt.x) / pt.s - ((this.floater.clientWidth + 5) / pt.s),
+      y: (evt.clientY - pt.y) / pt.s - (this.floater.clientHeight + (pt.s - 1) * (-5)) / pt.s // - ((fltheight * pt.s) / 2) / pt.s
+    })
+    // handlers to drag, and remove
+    document.addEventListener('mousemove', evtDrag)
+    // and delete / act when mouse comes up
+    document.addEventListener('mouseup', dragMouseUp)
+  }
+}
+
+function StateDefinition(stspec, ind, def, view, debug){
+  this.parent = def
+  this.name = stspec.name
+  this.type = stspec.type
+  this.ind = parseInt(ind)
+  // business,
+  this.value = stspec.value
+  // ok,
+  this.de = $('<div>' + this.name + " (" + this.type + ")" + '</div>').addClass('stateItem').get(0)
+  this.de.id = `${this.parent.name}_${this.parent.ind}_state_${this.name}`
+  this.newParentInd = () => {
+    this.de.id = `${this.parent.name}_${this.parent.ind}_state_${this.name}`
+  }
+  // ui for these ... we can just cover the basics of js types because yonder serializations
+  // etc will throw errors for other types. of course, this could help more, but we're in a rush
+  switch (typeof this.value) {
+      case 'string':
+        //dom.append($('<br>').get(0))
+        let strinput = $('<input>').attr('type', 'text').attr('size', 32).attr('value', this.value).css('width', '240px').get(0)
+        strinput.addEventListener('change', (evt) => {
+          // ask for a change,
+          // TODO HERE NOW: this is the state change request you want to write
+          // do it like writeMessage() instead
+          // requestStateChange(def.id, state, strinput.value)
+          // but assert that we don't change the definition unless
+          view.requestStateChange(this, strinput.value)
+          strinput.value = this.value
+        })
+        this.de.append(strinput)
+        this.set = (value) => {
+          if(typeof value === 'string'){
+            strinput.value = value
+            this.value = value
+          } else {
+            throw new Error('bad type put into state dom')
+          }
+        }
+        break // end string types
+      case 'number':
+        let ninput = $('<input>').addClass('stateNumInput').attr('type', 'text').attr('size', 24).attr('value', this.value.toString()).css('width', '100px').get(0)
+        ninput.addEventListener('change', (evt) => {
+          // ask for a change,
+          view.requestStateChange(this, parseFloat(ninput.value))
+          // but assert that we don't change the definition unless
+          ninput.value = this.value
+        })
+        this.de.append(ninput)
+        this.set = (value) => {
+          if(typeof value === 'number'){
+            // quite sure js does this conversion no problem
+            ninput.value = value
+            this.value = value
+          } else {
+            throw new Error('bad type put into state dom')
+          }
+        }
+        break // end numnber type
+      case 'boolean':
+        let span = $('<span style="float:right;">' + this.value.toString() + '</span>').get(0)
+        $(this.de).addClass('stateBooleanItem')
+        this.de.append(span)
+        this.de.addEventListener('click', (evt) => {
+          // read the current 'state' (as written) and send the opposite
+          let txt = $(span).text()
+          if (txt === 'true') {
+            view.requestStateChange(this, false)
+          } else {
+            view.requestStateChange(this, true)
+          }
+        })
+        this.set = (value) => {
+          if(typeof value === boolean){
+            $(span).text(value.toString())
+            this.value = value
+          } else {
+            throw new Error('bad type put into state dom')
+          }
+        }
+        break// end boolean type
+      default:
+        console.error(`unaccounted for type at input pull for state change, ${typeof state.value}`)
+        break
+    }
+}
+
+export default HunkDefinition
diff --git a/view/vdom.js b/view/vdom.js
index 0fa53fd438de640942e5048fedfb658f28c2939c..c1f97c6ca4ccc1a274523c40ccb36ac9b0feed20 100644
--- a/view/vdom.js
+++ b/view/vdom.js
@@ -63,101 +63,6 @@ function DomTools(View) {
   /* ---------------------- WRITING DEFS ----------------------- */
   /* ---------------------------    ---------------------------- */
 
-  // write *the* dom element (.block)
-  this.writeDefDom = (def, debug) => {
-    // debug
-    if (debug) console.log('writing for def', def)
-    // a div to locate it
-    let de = document.createElement('div')
-    $(de).addClass('block').attr('id', def.id)
-
-    // more html: the title
-    $(de).append($('<div>' + de.id + '</div>').addClass('blockid').append('<span style="float:right;">(' + def.name + ')</span>'))
-
-    let title = $(de).children('.blockid').get(0)
-
-    title.oncontextmenu = (evt) => {
-      evt.preventDefault()
-      evt.stopPropagation()
-      // write menu for requesting delete and copy
-      let menu = $('<div>').addClass('contextmenu').get(0)
-      // title.offsetWidth is 400
-      // de.style.left, de.style.top, de.clientWidth,
-      let ct = this.readTransform(de)
-      let x = ct.x + 500 + 10 + 'px'
-      this.writeTransform(menu, {
-        s: 1,
-        x: ct.x + ((500 + 10)),
-        y: ct.y
-      })
-      $(view.plane).append(menu)
-      $(menu).append($('<li>remove hunk</li>').on('click', (evt) => {
-        view.requestRemoveHunk(def.id)
-        $(menu).remove()
-      }))
-      $(menu).append($('<li>copy hunk</li>').on('click', (evt) => {
-        view.requestAddHunk(def.name)
-        $(menu).remove()
-      }))
-    }
-
-    // drag title
-    title.onmousedown = (evt) => {
-      evt.preventDefault()
-      evt.stopPropagation()
-
-      let domElemMouseMove = (evt) => {
-        // TRANSFORMS here to move div about on drag
-        evt.preventDefault()
-        evt.stopPropagation()
-        let ct = this.readTransform(de)
-        let pt = this.readTransform(de.parentElement)
-        ct.x += evt.movementX / pt.s
-        ct.y += evt.movementY / pt.s
-        this.writeTransform(de, ct)
-        view.drawLinks()
-      }
-
-      function rmOnMouseUp(evt) {
-        // would do save of position state here
-        // TODO /\
-        document.removeEventListener('mousemove', domElemMouseMove)
-        document.removeEventListener('mouseup', rmOnMouseUp)
-        // atm this doesn't work because update looks for changes in list size
-        //updateForceLoop()
-      }
-
-      document.addEventListener('mousemove', domElemMouseMove)
-      document.addEventListener('mouseup', rmOnMouseUp)
-    }
-
-    if (def.inputs.length > 0) {
-      let idom = $('<div>').addClass('inputs')
-      for (let ip of def.inputs) {
-        $(idom).append(writePortDom(ip, def, 'input', debug))
-      }
-      $(de).append(idom)
-    }
-
-    if (def.outputs.length > 0) {
-      let odom = $('<div>').addClass('outputs')
-      for (let op of def.outputs) {
-        $(odom).append(writePortDom(op, def, 'output', debug))
-      }
-      $(de).append(odom)
-    }
-
-    if (def.state.length > 0) {
-      let sdom = $('<div>').addClass('state')
-      for (let st of def.state) {
-        $(sdom).append(writeStateDom(st, def, debug))
-      }
-      $(de).append(sdom)
-    }
-
-    return de
-  } // END writeDefDom
-
   // write the ports: inputs, outputs
   let writePortDom = (port, def, inout, debug) => {
     if (debug) console.log('port dom', port, def.id, inout)
diff --git a/view/vmsg.js b/view/vmsg.js
index 418cfcec6df3d21885d10c8213d251d846941170..da952e56623d9d8c3d80708609c63e31ba43598d 100644
--- a/view/vmsg.js
+++ b/view/vmsg.js
@@ -7,18 +7,26 @@ function MessageBox(View) {
 
   // tracking a load,
   this.briefState = {
-    recipId: '',
     recipName: '',
+    recipVersion: '',
     numHunksLeft: 0,
     numLinksLeft: 0,
+    isStateHappenning: false,
     setFromBrief: function(brief) {
-      this.recipId = brief.interpreterId
       this.recipVer = brief.interpreterVersion
       this.recipName = brief.interpreterName
       this.numHunksLeft = brief.numHunks
       this.numLinksLeft = brief.numLinks
       this.postToDom()
     },
+    stateIsHappening: function() {
+      this.isStateHappenning = true
+      this.postToDom()
+    },
+    stateIsNotHappening: function() {
+      this.isStateHappenning = false
+      this.postToDom()
+    },
     decrementHunks: function() {
       this.numHunksLeft--
       this.postToDom()
@@ -31,16 +39,18 @@ function MessageBox(View) {
       this.numLinksLeft--
       this.postToDom()
     },
-    incrementHunks: function() {
+    incrementLinks: function() {
       this.numLinksLeft++
       this.postToDom()
     },
     postToDom: function() {
       let str
-      if (this.numHunksLeft > 0 || this.numLinksLeft > 0) {
-        str = `manager id: ${this.recipId} <br>interpreter: ${this.recipName} ${this.recipVer} <br> awaiting ${this.numHunksLeft} hunks and ${this.numLinksLeft} links`
+      if(this.stateIsHappening){
+        str = `manager interpreter: ${this.recipName} ${this.recipVer} <br> awaiting state ...`
+      } else if (this.numHunksLeft > 0 || this.numLinksLeft > 0) {
+        str = `manager interpreter: ${this.recipName} ${this.recipVer} <br> awaiting ${this.numHunksLeft} hunks and ${this.numLinksLeft} links`
       } else {
-        str = `manager id: ${this.recipId} <br>interpreter: ${this.recipName} ${this.recipVer} <br> all loaded OK`
+        str = `manager interpreter: ${this.recipName} ${this.recipVer} <br> all loaded OK`
       }
       $(themsgbox).find('#titleBox').html(str)
     }
@@ -53,7 +63,7 @@ function MessageBox(View) {
   /* ---------------------------    ---------------------------- */
 
   this.init = () => {
-    view.log('message box alive')
+    //view.log('message box alive')
     // a box,
     themsgbox = $('<div>').addClass('msgbox').get(0)
     // the title, and id of your manager
@@ -64,6 +74,7 @@ function MessageBox(View) {
     }).get(0))
     // a refresh button
     themsgbox.append($('<div>').addClass('msgboxbutton').addClass('msgboxmsg').append('~ refresh view ~').click((evt) => {
+      evt.preventDefault()
       view.refresh()
     }).get(0))
     // zoom extents object,
@@ -100,11 +111,11 @@ function MessageBox(View) {
     // if too tall, remove
     let ch = themsgbox.clientHeight
     if (heightcheck() > ch) {
-      console.log('rm 1', heightcheck(), ch)
+      //console.log('rm 1', heightcheck(), ch)
       $(themsgbox).children().get(4).remove()
       // two at most, sloppy but fast
       if (heightcheck() > ch) {
-        console.log('rm 2', heightcheck(), ch)
+        //console.log('rm 2', heightcheck(), ch)
         $(themsgbox).children().get(4).remove()
       }
     }
diff --git a/view/vptch.js b/view/vptch.js
index 514bdd49fc478b0629eec552e93a1ab64e13495d..894d4b321068e6494e0d8e7fd83c72bfc5116116 100644
--- a/view/vptch.js
+++ b/view/vptch.js
@@ -14,8 +14,12 @@ function PatchSet(View, MsgBox) {
   // load from server should be assumed, just rip that *baybie*
   this.findPatches = (evt) => {
     // and then,
+    if (!(view.interpreterName)) {
+      msgbox.write('view on unknown interpeter, cannot save ... refresh view first')
+      return false
+    }
     $(evt.target).append(' > loading a list ...')
-    gg.recursivePathSearch('programs', '.json', true).then((list) => {
+    gg.recursivePathSearch('programs/' + view.interpreterName + '/', '.json', true).then((list) => {
       console.log('returns list', list)
       // title, and options
       view.changeContextTitle('available patches:')
@@ -27,82 +31,146 @@ function PatchSet(View, MsgBox) {
           } catch (err) {
             msgbox.write('caught an error while starting program load')
           }
-          $(view.plane).find('.contextmenu').remove()
+          $(view.dom).find('.contextmenu').remove()
         })
       }
     })
   }
 
-  let lastPatch = {}
+  let patchStep = 0
+  let linkLoadingStarted = false
   let unloadedHunks = []
-  let unloadedStates = []
+  let awaitStates = []
   let unloadedLinks = []
 
   let reqNextHunk = () => {
-    // from 0th position in array
-    view.requestAddHunk(unloadedHunks[0].name, unloadedHunks[0].id)
+    // patchStep is the expected current place in an array of hunks, if
+    if (view.defs[patchStep] !== undefined) { // have one of these already,
+      if (view.defs[patchStep].name === unloadedHunks[0].name) {
+        msgbox.write(`found write-over for ${unloadedHunks[0].name}, checking for req change`)
+        // look at each state,
+        if (view.defs[patchStep].states.length < 1) {
+          unloadedHunks.shift()
+          patchStep ++
+          reqNextHunk() // recursive? pretty sure this is fn completion
+        } else {
+          for (let st in view.defs[patchStep].states) {
+            // might be a few of these, and there might be none
+            if (view.defs[patchStep].states[st].value !== unloadedHunks[0].states[st].value) {
+              view.requestStateChange(view.defs[patchStep].states[st], unloadedHunks[0].states[st].value)
+              // we have to track this ...
+              msgbox.briefState.stateIsHappening()
+              awaitStates.push({
+                defname: view.defs[patchStep].name,
+                defind: view.defs[patchStep].ind,
+                statename: view.defs[patchStep].states[st].name
+              })
+            }
+          }
+        }
+      } else {
+        // an error, the in-place hunk doesn't exist here
+        // this is a hack for now ... we are assuming all contexts are starting from bootstrap,
+        // and that exactly that bootstrap is running already
+        msgbox.write('lost bootstrap, or existing program, while loading a patch')
+        console.error(`lost bootstrap, or existing program, while loading a patch: ${patchStep}, ulh, ${unloadedHunks[0].name}, defs, ${view.defs[patchStep].name}`);
+      }
+    } else {
+      // regular ops,
+      msgbox.briefState.incrementHunks()
+      console.log('loading hunk from', unloadedHunks[0])
+      view.requestAddHunk(unloadedHunks[0].name, unloadedHunks[0].states)
+    }
   }
 
-  // callbacks,
-  this.onHunkLoaded = (def) => {
-    // not interested,
-    if(unloadedHunks.length < 1) return true
-    // find in list, rm
-    let place = unloadedHunks.findIndex((cand) => {
-      return (cand.id === def.id && cand.name === def.name)
+  this.onStateChanged = (stateDef) => {
+    if(awaitStates.length < 1) return true
+    let indOf = awaitStates.findIndex((cand) => {
+      return (cand.statename === stateDef.name)
     })
-    if(place !== -1) {
-      if(place !== 0) console.error("watch out of order loading for programs... shouldn't be like that but it do")
-      unloadedHunks.shift()
-      msgbox.write(`patchset placed ${def.id}, ${unloadedHunks.length} hunks remaining`)
-      if(unloadedHunks.length < 1){
-        msgbox.write(`patchset loaded all hunks, now updating state`)
-        startStateRefresh()
-      } else {
+    if(indOf === -1){
+      console.error(`misplaced state: ${stateDef.name}`)
+    } else {
+      awaitStates.splice(indOf, 1)
+      console.log('splicing state item', stateDef)
+      if(awaitStates.length < 0){
+        msgbox.briefState.stateIsNotHappening()
+        unloadedHunks.shift()
         reqNextHunk()
       }
-    } else {
-      console.error(`hunk not found in unloaded hunks, ${def.id}`)
     }
-    // if place, else bad news ...
-    // HERE
-    // ...
-    // and when complete, load first link
   }
 
-  // BRRRRT nevermind, making state-before-init change. 
-  let startStateRefresh = () => {
-    // so, we have a list of hunks each with some state
-    msgbox.write(`beginning state sweep`)
-    // at this point, they should all be loaded into the dom, so we should be able to find them all
-    for(let hnk of $(view.plane).children('.block')){
-      // we can compare each one to the patch
-      let loaded = lastPatch.hunks.find((cand) => {
-        return cand.id === hnk.id
-      })
-      if(loaded){
-        console.log('for state search over this hunk', hnk, 'w/r/t', loaded)
-        if(loaded.state){
-          // check for differences, and add an item to the list if we need to // id, name, value
-        }
+  // callbacks,
+  // this happens *also* when we update some link state, yikes,
+  this.onHunkLoaded = (def) => {
+    // not interested,
+    if (unloadedHunks.length < 1) return true
+    // ok, is it something we were asking for a state change on ?
+    // we *also* receive a state update message, which is nice,
+    let iopossible = awaitStates.findIndex((cand) => {
+      return (cand.defname === def.name && cand.defind === def.ind)
+    })
+    if(iopossible !== -1) return true
+    // ur loaded,
+    patchStep++
+    // ok ...
+    // find in list, rm
+    console.log('checking', def, 'against', unloadedHunks[0])
+    // check that we *are* receiving in order
+    let checksOut = true
+    if (def.name !== unloadedHunks[0].name) checksOut = false
+    // on a state update case, we might have different states ... for now, avoiding this problem
+    for (let st in def.states) {
+      if (def.states[st].value !== unloadedHunks[0].states[st].value) checksOut = false
+    }
+    if (!checksOut) {
+      console.error('find error while loading hunks from a patch: bad state, or bad name')
+    } else {
+      unloadedHunks.shift()
+      if (unloadedHunks.length < 1) {
+        msgbox.write(`patchset loaded all hunks`)
+        reqNextLink()
+        linkLoadingStarted = true
       } else {
-        msgbox.write(`ignoring patch-exterior hunk ${hnk.id}`)
+        msgbox.write(`patchset placed ${def.name}_${def.ind}, ${unloadedHunks.length} hunks remaining`)
+        reqNextHunk()
       }
     }
   }
 
   // try for a one-at-a-time cycle,
-  this.loadHunkList = (list) => {
-
+  let reqNextLink = () => {
+    msgbox.briefState.incrementLinks()
+    console.log('loading link from', unloadedLinks[0])
+    let lnk = unloadedLinks[0]
+    view.requestAddLinkLikeACaveman(lnk.outInd, lnk.outputInd, lnk.inInd, lnk.inputInd)
   }
 
-  this.onLinkLoaded = (outId, outName, inId, inName) => {
+  this.onLinkLoaded = (addOutInd, addOutputInd, addInInd, addInputInd) => {
+    // not interested in this
+    if (!linkLoadingStarted) return true
+    if (unloadedLinks.length < 1) return true
     // find in list, rm,
+    let lnk = unloadedLinks[0]
+    // this is exhausting, arrays would be nice
+    if (lnk.outInd !== addOutInd || lnk.outputInd !== addOutputInd || lnk.inInd !== addInInd || lnk.inputInd !== addInputInd) {
+      console.error('unexpected link notification while loading program')
+    } else {
+      unloadedLinks.shift()
+      if (unloadedLinks.length < 1) {
+        msgbox.write(`patchset loaded all links, FIN DU LOAD`)
+        linkLoadingStarted = false
+      } else {
+        msgbox.write(`patchset placed a link, ${unloadedLinks.length} links remaining`)
+        reqNextLink()
+      }
+    }
   }
 
   this.loadPatch = (name) => {
     msgbox.write(`ok, loading a patch from: ${name}`)
-    gg.getJson('/programs/' + name + '.json').then((patch) => {
+    gg.getJson('/programs/' + view.interpreterName + '/' + name + '.json').then((patch) => {
       console.log('the patch', patch)
       if (patch.interpreterName !== view.interpreterName) {
         msgbox.write(`WARN: loading patch built in a different interpreter... some hunks may not exist: patch for: "${patch.interpreterName}", but view is connected to "${view.interpreterName}"`)
@@ -113,7 +181,6 @@ function PatchSet(View, MsgBox) {
       // new so that we don't shift out of the original list,
       unloadedHunks = JSON.parse(JSON.stringify(patch.hunks))
       unloadedLinks = JSON.parse(JSON.stringify(patch.links))
-      lastPatch = patch
       // kick it off by sending this message,
       reqNextHunk()
       // continue loading ... write a bootload of messages, in queu, waiting for each response?
@@ -123,78 +190,55 @@ function PatchSet(View, MsgBox) {
     })
   }
 
-  this.saveCurrent = (evt, debug) => {
+  this.saveCurrent = (evt, defs, debug) => {
     if (debug) console.log('saving ...')
-    // riperoni ok
+    // riperoni ok, save them all
     let patch = {
-      interpreterName: gg.interpreterName,
-      interpreterVersion: gg.interpreterVersion,
+      // cerntakt
+      interpreterName: view.interpreterName,
+      interpreterVersion: view.interpreterVersion,
       hunks: [],
       links: []
+      // links added later
     }
-    // js, u wyld
-    for (let hnk of $(view.plane).children('.block')) {
-      // dom is truth
-      if (debug) console.log('hnk', hnk)
-      let name = $(hnk).children('.blockid').find('span').text()
-      name = name.substring(1, name.length - 1)
-      let phnk = {
-        id: hnk.id,
-        name: name
-      }
-      let state = []
-      for (let st of $(hnk).children('.state').children('.stateItem')) {
-        // text is faithful,
-        let text = $(st).find('p').text()
-        let name = text.substring(0, text.indexOf(' '))
-        let type = text.substring(text.indexOf('(') + 1, text.indexOf(')'))
-        if (debug) console.log('state: name', `"${name}"`, 'type', `"${type}"`)
-        // the value... (typing on program saves? not if we JSON ...)
-        let value
-        if (type === 'boolean') {
-          let vstring = $(st).find('span').text()
-          vstring = vstring.substring(vstring.indexOf('(') + 1, vstring.indexOf(')'))
-          if (vstring === 'true') {
-            value = true
-          } else if (vstring === 'false') {
-            value = false
-          } else {
-            console.error('error saving boolean value, setting to false')
-            value = false
-          }
-        } else if (type === 'string') {
-          value = $(st).find('input').val()
-        } else {
-          // must be some kind of number,
-          value = parseFloat($(st).find('input').val())
-        } // end if-on-types sequence
-        state.push({
-          name: name,
-          type: type,
-          value: value
-        })
-      } // end roll over states,
-      if (state.length > 0) {
-        phnk.state = state
+    // the hunks,
+    for (let df of defs) {
+      // we save them all,
+      // on load, compare to existing in same position
+      console.log('writing prep for', df)
+      // in order, u c
+      let prep = {
+        name: df.name,
+        states: []
       }
-      patch.hunks.push(phnk)
-      // now roll over links in the hunk, to write outputs
-      for (let otp of $(hnk).children('.outputs').children('.output')) {
-        if (debug) console.log('and output', otp)
-        let outId = otp.id.substring(0, otp.id.indexOf('_output_'))
-        let outName = otp.id.substring(otp.id.indexOf('_output_') + 8)
-        for (let conn of otp.connectedTo) {
-          let inId = conn.substring(1, conn.indexOf('_input_'))
-          let inName = conn.substring(conn.indexOf('_input_') + 7)
-          patch.links.push({
-            outhunk: outId,
-            outname: outName,
-            inhunk: inId,
-            inname: inName
+      // HERE: we save state just with the index / value ?
+      if (df.states !== undefined) {
+        for (let st of df.states) {
+          prep.states.push({
+            ind: st.ind,
+            type: st.type,
+            value: st.value
           })
         }
-      } // end loop over outputs, for links ...
-    } // end loop over hunks
+      }
+      // roll for links,
+      // outputs
+      if (df.outputs !== undefined) {
+        for (let otp in df.outputs) {
+          for (let cn in df.outputs[otp].connections) {
+            patch.links.push({
+              outInd: df.ind, // truth in index
+              outputInd: parseInt(otp), // a num,
+              inInd: df.outputs[otp].connections[cn].parent.ind,
+              inputInd: df.outputs[otp].connections[cn].ind
+            })
+          }
+        }
+      }
+      //
+      console.log('wrote ', prep)
+      patch.hunks.push(prep)
+    }
     // we have this now,
     if (debug) console.log('a patch', patch)
     // prompt for name? ... via the (evt) on the callback ??
@@ -218,7 +262,7 @@ function PatchSet(View, MsgBox) {
         $(evt.target).append(anchor)
         anchor.click()
         // finally, rip
-        $(view.plane).find('.contextmenu').remove()
+        $(view.dom).find('.contextmenu').remove()
         //saveAs(bleb, 'file.json')
       }
     })