diff --git a/core/scope.js b/core/scope.js
index bb38f4b13ba1f0808a8326b6b1df8ce3756f05e5..8f20ddc5d2e327aab1275e0c4805b5799dceb153 100644
--- a/core/scope.js
+++ b/core/scope.js
@@ -289,14 +289,101 @@ export default function Scope(wrapper, tlv) {
     }
   }
 
+  let open = (context) => {
+    // new plane every time!
+    context.plane = $('<div>').addClass('subplane').addClass('block').attr('id', `${def.name}_plane`).get(0)
+    context.plane.position = () => {
+      return { x: 0, y: blocks.getBlockStackHeight(def.blocks) }
+    }
+    if (!context.size) context.size = { x: 800, y: 600 }
+    dt.writeContainerSize(context.size)
+    // blocks should have handles,
+    context.plane.handle = context // this is a throwaway ... and maybe ah bugfarm
+    // the context should be .within an ldef, we want this block to carry the plane around,
+    let ldef = context.within
+    ldef.blocks.push(context.plane)
+    ldef.blocks[0].take(context.plane) // 'parent' block, for positioning, kind of awkward
+    // existence
+    $(ldef.context.plane).append(context.plane)
+    // handle resize,
+    dt.addResizeHandle(context.plane)
+    context.plane.onresize = (deltas) => {
+      let size = dt.readContainerSize(context.plane)
+      size.x += deltas.x
+      size.y += deltas.y
+      dt.writeContainerSize(context.plane, size)
+      repositionDef(def)
+      // reposition all defs in the downstream: we might be squishing them about:
+      for (let dsdef of context.defs) {
+        repositionDef(dsdef)
+      }
+    } // end onresize,
+    // place,
+    repositionDef(def)
+    // toggle button state,
+    $(squid).html('<i class="em em-shell"></i> collapse link')
+    $(squid).one('click', close)
+    /*
+    if (def.states[0].value) { // if is-connecting,
+      context.refresh().then(() => {
+        // ?
+      }).catch((err) => {
+        console.error(err)
+      })
+    }
+    */
+  }
+
+
+  let close = (context) => {
+    console.error('nah')
+    /*
+    // 'ldef.contains' is a ptr to the context (view) that is w i t h i n the link, accoring
+    // to our earlier piping, ldef.contains = view returned here
+    wipeContext(ldef.contains)
+    $(ldef.contains.plane).remove()
+    // arduous: rm from ldef, and from titleblock,
+    let bi = ldef.blocks.findIndex((cand) => {
+      return (cand === ldef.contains.plane)
+    })
+    if (bi >= 0) {
+      ldef.blocks.splice(bi, 1)
+    } else {
+      console.error('lost plane block ... ')
+    }
+    titleblock.remove(ldef.contains.plane)
+    delete ldef.contains.plane
+    // . then->
+
+    $(squid).html('<i class="em em-squid"></i> expand link')
+    $(squid).one('click', open)
+    repositionDef(ldef)
+    */
+  }
+
   this.check = () => {
     // check levels recursively,
-    let recursor = (view) => {
-      checkView(view)
-      for (let def of view.defs) {
-        if (def.contains) {
-          if (!def.contains.plane) continue
-          recursor(def.contains)
+    let recursor = (context) => {
+      checkView(context)
+      for (let def of context.defs) {
+        if (def.type == 'link') {
+          // find the context it's connected to,
+          def.context.getLinkContext(def).then((nc) => { // next context,
+            if (nc.open && !nc.plane) { // open, no plane, so we build one:
+              console.log('opening')
+              console.log(nc.plane) // nc / linkcontext maybe not what you think it is ?
+              here you are 
+              open(nc)
+            }
+            if (nc.plane && !nc.open) { // exist, but should be closed, run that
+              close(nc)
+            }
+            if (nc.plane) { // if plane still up, we passed the last if, recurse down
+              recursor(nc)
+            }
+          }).catch(() => {
+            // noop, no context,
+          })
         }
       }
     }
diff --git a/hunks/view.js b/hunks/view.js
index 4357872e8d2e6a73c5969321e6b672b332d64c0a..3b3e12cf09cb3abf695fd708273216f227ac4eb7 100644
--- a/hunks/view.js
+++ b/hunks/view.js
@@ -42,6 +42,21 @@ function View() {
   let defs = new Array
   this.defs = defs
 
+  // some global state for the remote interpreter:
+  this.interpreterName = null
+  this.interpreterVersion = null
+
+  /*
+  views have some persistent state, and we link them to one another, so this is nice to know,
+  views have this shape: {
+    defs: [<ptrs to defs>],           // objects, see below
+    interpreterName: <string>,        // name of df world we are talking to,
+    interpreterVersion: <string>,     // of the same,
+    within: <ptr to link-def>,        // if exists, we are nested inside of this link
+    size: {w: <number>, h: <number>}, // if exists, render this. size to render at.
+  }
+  */
+
   /*
   the view maintains this list of definitions to match state of remote dataflow environments
   defs have this shape: {
@@ -49,6 +64,10 @@ function View() {
     name: <string>,             // the name of the thing,
     ind: <number>,              // own index of the def, in this array (and the managers),
     context: <ptr to view>,     // so def.context.defs[def.ind] is circular,
+    // LINK-specific:
+    contains: <ptr to view>,    // ~ potentially ~ exists, if this is a link piped to a view (per upper level connectivity!)
+    downstream: <ptr to link>,  // ~ potentially ~ exists, meaning this bridges to that link, and that link is 'down' one level
+    upstream: <ptr to link>,    // ~ potentially ~ exists, meaning that this link bridge to that link, that link is 'up' one level
     inputs: [                   // a list of inputs, each of which:
       {
         type: <string>,             // the type, types are strings 4 js
@@ -95,10 +114,6 @@ function View() {
   /* -------------------- RENDER INTERFACE --------------------- */
   /* ---------------------------    ---------------------------- */
 
-  // some global state for the remote interpreter:
-  this.interpreterName = null
-  this.interpreterVersion = null
-
   // we interface to the UI by setting these flags...
   // when we make big changes, just nuke 'em
   // mostly, this is useful for any deleted hunks, or the refresh
@@ -305,7 +320,9 @@ function View() {
     // rm everything ...
     for (let key in def) {
       if (def.hasOwnProperty(key)) {
-        if (key == 'type' || key == 'name' || key == 'ind' || key == 'context' || key == 'inputs' || key == 'outputs' || key == 'states') {
+        if (key == 'type' || key == 'name' || key == 'ind' ||
+            key == 'context' || key == 'inputs' || key == 'outputs' || key == 'states' ||
+            key == 'contains' || key == 'downstream' || key == 'upstream') {
           // these we keep,
         } else {
           delete def[key]
@@ -731,6 +748,17 @@ function View() {
   // with recepies, we take the atomic units above and do larger order operations
 
   // wipes current state from remote, polls from zero
+  /*
+  so, at the moment the replaceDef that occurs when we go to build a route
+  manages to wipe some of the state out of the route - probably we are
+  cleaning defs in our view, that is erasing graph knowledge. this means
+  we should probably prune the cleanup, and try to make some careful sense of what's going on
+  when we run the redrawing op as well ...
+  ... yeah, recall that expanding / contracting w/e is stateful at the button. this is indeed
+  a new days' can of worms
+  ... perhaps the way to do this is to set a global .norefresh flag, see if the route building alone works
+  and then handle etcs afterwards, i.e. probably just cleaning up .clean() (ha)
+  */
   this.refresh = () => {
     console.log('REFRESH')
     // well, I won't say it's clean or beautiful, but we are interested in keeping the
@@ -1064,36 +1092,41 @@ function View() {
     }
   }
 
+  this.makeLinkContext = (ldef) => {
+    return new Promise((resolve, reject) => {
+      this.getLinkContext(ldef).then((context) => {
+        resolve(context)
+      }).catch(async () => {
+        // none, make one,
+        try {
+          let vdef = await window.tlv.requestAddHunk('view')
+          await this.buildRoute(vdef.outputs[0], ldef.inputs[1])
+          await this.buildRoute(ldef.outputs[1], vdef.inputs[0])
+          let view = vdef.hunk // views are always toplevel hunks, so they always have these handles
+          resolve(view)
+        } catch (err) {
+          console.error(err)
+          reject()
+        }
+      })
+    })
+  }
+
   // for any link, find / build a route up to a view, from its' 1st input / output - that are assumed to be manager
   // message ports to the manager within that link...
   this.getLinkContext = (ldef) => {
-    // oof async so nice
-    return new Promise(async (resolve, reject) => {
-      // ok,
-      let view
+    return new Promise((resolve, reject) => {
       let tr = this.trace(ldef.outputs[1])
       if (tr) {
         if (tr.parent.type == 'view') {
-          // keep our ptrs together
-          view = tr.parent.hunk
+          tr.parent.hunk.within = ldef
+          ldef.contains = tr.parent.hunk
+          resolve(tr.parent.hunk)
         } else {
-          console.error('need to write case for this, likely that we are link->link here')
-          reject('no link traversing trace yet, pls write')
+          reject('looking for context, traces to non-view... ')
         }
       } else {
-        try {
-          let vdef = await window.tlv.requestAddHunk('view')
-          await this.requestAddLink(vdef.outputs[0], ldef.inputs[1])
-          await this.requestAddLink(ldef.inputs[1], vdef.outputs[0])
-          view = vdef.hunk // views are always toplevel hunks, so they always have these handles
-        } catch (err) {
-          reject(err)
-        }
-      }
-      if (view) {
-        view.within = ldef
-        ldef.contains = view
-        resolve(view)
+        reject()
       }
     })
   }
@@ -1196,8 +1229,8 @@ function View() {
           let porthole = route[route.length - 1].exit
           let portlist = porthole.states[3].value
           portlist += `, at_${porthole.outputs.length} (${type})`
-          await ipdef.context.requestStateChange(porthole.states[3], portlist)
-          await ipdef.context.requestAddLink(porthole.outputs[porthole.outputs.length - 1], ipdef)
+          await ipdef.parent.context.requestStateChange(porthole.states[3], portlist)
+          await ipdef.parent.context.requestAddLink(porthole.outputs[porthole.outputs.length - 1], ipdef)
           // to avoid piping data into the void, we can do this last ->
           await gateway.context.requestAddLink(opdef, gateway.inputs[gateway.inputs.length - 1])
           resolve()
diff --git a/style.css b/style.css
index 13671b999293646834a980d3540b21437c415afa..fd42f433b651f61733596b640a0aba7c21e374ad 100644
--- a/style.css
+++ b/style.css
@@ -127,6 +127,7 @@ body {
 /* is title and state */
 .defcore {
 	width: 275px;
+	height: 20px;
 	font-size: 15px;
 	font-weight: bold;
 	font-style: italic;
@@ -149,19 +150,10 @@ body {
 	position: absolute;
 }
 
-.inputs {
-	position:absolute;
-	width: 117px;
-	float: left;
-	margin-left: 2px;
-	font-size: 11px;
-	background-color: #1a1a1a;
-	color: #eee;
-}
-
 .input {
 	position:absolute;
 	width: 100px;
+	height: 20px;
 	text-align: left;
 	font-size: 11px;
 	background-color: #1a1a1a;
@@ -177,20 +169,10 @@ body {
 	padding: 2px;
 }
 
-.outputs {
-	position: absolute;
-	width: 117px;
-	float: right;
-	margin-right: 2px;
-	text-align: right;
-	font-size: 11px;
-	background-color: #1a1a1a;
-	color: #eee;
-}
-
 .output {
 	position: absolute;
 	width: 100px;
+	height: 20px;
 	text-align: right;
 	font-size: 11px;
 	background-color: #1a1a1a;
diff --git a/view/blocks.js b/view/blocks.js
index 98a9e77a6bf7bc44705d6c51a5dd46257c92e256..7f8556cdcd8beb5c14375195956f2e0c20dda133 100644
--- a/view/blocks.js
+++ b/view/blocks.js
@@ -84,63 +84,12 @@ let makeLink = (ldef, titleblock) => {
     titleblock.take(squid)
     ldef.blocks.push(squid)
     let open = (evt) => {
-      // returns the view that connects to this link,
-      ldef.context.getLinkContext(ldef).then((view) => {
-        // oh lawd
-        view.plane = $('<div>').addClass('subplane').addClass('block').attr('id', `${ldef.name}_plane`).get(0)
-        view.plane.position = () => {
-          return { x: 0, y: getBlockStackHeight(ldef.blocks) }
-        }
-        view.plane.handle = view // this is a throwaway ... and maybe ah bugfarm
-        ldef.blocks.push(view.plane)
-        titleblock.take(view.plane)
-        $(window.tlv.plane).append(view.plane)
-        dt.addResizeHandle(view.plane)
-        view.plane.onresize = (deltas) => {
-          let size = dt.readContainerSize(view.plane)
-          size.x += deltas.x
-          size.y += deltas.y
-          dt.writeContainerSize(view.plane, size)
-          repositionDef(ldef)
-          // reposition all defs in the downstream: we might be squishing them about:
-          for(let dsdef of ldef.downstream.context.defs){
-            repositionDef(dsdef)
-          }
-        }
-        // and,
-        repositionDef(ldef)
-        // toggle button state,
-        $(squid).html('<i class="em em-shell"></i> collapse link')
-        $(squid).one('click', close)
-        view.refresh().then(() => {
-          // ?
-        }).catch((err) => {
-          console.error(err)
-        })
-      }).catch((err) => {
-        console.error(err)
+      ldef.context.makeLinkContext(ldef).then((context) => {
+        context.open = true
       })
     }
     let close = (evt) => {
-      // 'ldef.contains' is a ptr to the context (view) that is w i t h i n the link, accoring
-      // to our earlier piping, ldef.contains = view returned here
-      wipeContext(ldef.contains)
-      $(ldef.contains.plane).remove()
-      // arduous: rm from ldef, and from titleblock,
-      let bi = ldef.blocks.findIndex((cand) => {
-        return (cand === ldef.contains.plane)
-      })
-      if (bi >= 0) {
-        ldef.blocks.splice(bi, 1)
-      } else {
-        console.error('lost plane block ... ')
-      }
-      titleblock.remove(ldef.contains.plane)
-      delete ldef.contains.plane
-      // . then->
-      $(squid).html('<i class="em em-squid"></i> expand link')
-      $(squid).one('click', open)
-      repositionDef(ldef)
+      ldef.contains.open = false
     }
     $(squid).html('<i class="em em-squid"></i> expand link')
     $(squid).one('click', open)
@@ -148,8 +97,8 @@ let makeLink = (ldef, titleblock) => {
     // static title,
     titleblock.position = () => {
       let y = 0;
-      for(let ipd of ldef.inputs){
-        y += ipd.block.clientHeight + 5
+      for(let opd of ldef.outputs){
+        y += opd.block.clientHeight + 5
       }
       return { x: 0, y: y }
     }
@@ -353,10 +302,12 @@ let rebuildDef = (def, position) => {
     inputblock.position = () => {
       // is this hella dollars?
       if (def.contains && def.contains.plane) {
+        // draw wrap-around,
         // I wonder if this is going to bog us down,
         // ideally redrawing would be list-based, with longer trees of offsetparents ...
         return { x: -inputblock.clientWidth - 5, y: getBlockStackHeight(def.blocks) + (inputblock.clientHeight + 5) * i }
       } else if (def.upstream) {
+        // draw wrap-within,
         // we have an upstream link, i.e. we are the unwrapped thing,
         // inputs go right,
         return {