diff --git a/routes/_actions/timeline.js b/routes/_actions/timeline.js
index e788553..9f01023 100644
--- a/routes/_actions/timeline.js
+++ b/routes/_actions/timeline.js
@@ -78,11 +78,11 @@ export async function setupTimeline() {
   if (statusStream) {
     statusStream.close()
   }
-  statusStream = new StatusStream(instanceInfo.urls.streaming_api, accessToken, timelineName, {
+  /*statusStream = new StatusStream(instanceInfo.urls.streaming_api, accessToken, timelineName, {
     onMessage(message) {
       console.log('message', message)
     }
-  })
+  })*/
   stop('addStatuses')
 }
 
diff --git a/routes/_components/pseudoVirtualList/PseudoVirtualList.html b/routes/_components/pseudoVirtualList/PseudoVirtualList.html
new file mode 100644
index 0000000..796ca0a
--- /dev/null
+++ b/routes/_components/pseudoVirtualList/PseudoVirtualList.html
@@ -0,0 +1,65 @@
+<div class="pseudo-virtual-list {{shown ? '' : 'hidden'}}" on:initializedVisibleItems>
+  {{#each wrappedItems as wrappedItem, i @item}}
+    <PseudoVirtualListLazyItem
+      component="{{component}}"
+      index="{{i}}"
+      length="{{items.length}}"
+      makeProps="{{makeProps}}"
+      key="{{wrappedItem.item}}"
+      scrollToThisItem="{{wrappedItem.item === scrollToItem}}"
+      on:scrollToPosition="onScrollToPosition(event)"
+      on:renderedListItem="onRenderedListItem()"
+    />
+  {{/each}}
+</div>
+<style>
+  .pseudo-virtual-list {
+    position: relative;
+    transition: opacity 0.25s linear;
+  }
+</style>
+<script>
+
+  import PseudoVirtualListLazyItem from './PseudoVirtualListLazyItem.html'
+
+  export default {
+    oncreate() {
+      this.observe('numRenderedListItems', numRenderedListItems => {
+        let items = this.get('items')
+        if (items.length && items.length === numRenderedListItems && !this.get('initialized')) {
+          this.set({initialized: true})
+          console.log('fire initialized')
+          this.fire('initializedVisibleItems')
+        }
+      })
+    },
+    methods: {
+      onScrollToPosition(rect) {
+        console.log('onScrollToPosition', rect)
+        // TODO: there should be some cleaner way to grab the container element
+        let container = document.querySelector('.container')
+        if (!container) {
+          return
+        }
+        let containerRect = container.getBoundingClientRect()
+        let scrollTop = rect.top - containerRect.top
+        if (scrollTop !== 0) {
+          requestAnimationFrame(() => {
+            console.log('setting scrollTop to ', scrollTop)
+            container.scrollTop = scrollTop
+          })
+        }
+      },
+      onRenderedListItem() {
+        let numRenderedListItems = this.get('numRenderedListItems') || 0
+        this.set({numRenderedListItems: numRenderedListItems + 1})
+      }
+    },
+    computed: {
+      wrappedItems: (items) => items.map(item => ({item: item}))
+    },
+    components: {
+      PseudoVirtualListLazyItem
+    }
+  }
+</script>
\ No newline at end of file
diff --git a/routes/_components/pseudoVirtualList/PseudoVirtualListItem.html b/routes/_components/pseudoVirtualList/PseudoVirtualListItem.html
new file mode 100644
index 0000000..3295787
--- /dev/null
+++ b/routes/_components/pseudoVirtualList/PseudoVirtualListItem.html
@@ -0,0 +1,32 @@
+<div class="pseudo-virtual-list-item" pseudo-virtual-list-key="{{index}}" ref:node>
+  <:Component {component}
+              virtualProps="{{props}}"
+              virtualIndex="{{index}}"
+              virtualLength="{length}}"
+              on:renderedListItem
+              on:scrollToPosition
+  />
+</div>
+<script>
+
+  import { AsyncLayout } from '../../_utils/AsyncLayout'
+
+  export default {
+    oncreate() {
+      this.fire('renderedListItem')
+      if (this.get('scrollToThisItem')) {
+        if (this.get('firedScrollToPosition')) {
+          return
+        }
+        this.set({firedScrollToPosition: true})
+        let node = this.refs.node
+        let asyncLayout = new AsyncLayout(node => node.getAttribute('pseudo-virtual-list-key'))
+        let key = this.get('index')
+        asyncLayout.observe(key, this.refs.node, (rect) => {
+          asyncLayout.disconnect()
+          this.fire('scrollToPosition', rect)
+        })
+      }
+    }
+  }
+</script>
diff --git a/routes/_components/pseudoVirtualList/PseudoVirtualListLazyItem.html b/routes/_components/pseudoVirtualList/PseudoVirtualListLazyItem.html
new file mode 100644
index 0000000..eddce33
--- /dev/null
+++ b/routes/_components/pseudoVirtualList/PseudoVirtualListLazyItem.html
@@ -0,0 +1,24 @@
+{{#if props}}
+  <PseudoVirtualListItem :component
+                         :props
+                         :key
+                         :index
+                         :scrollToThisItem
+                         on:renderedListItem
+                         on:scrollToPosition
+  />
+{{/if}}
+<script>
+  import PseudoVirtualListItem from './PseudoVirtualListItem.html'
+  export default {
+    async oncreate() {
+      let makeProps = this.get('makeProps')
+      let key = this.get('key')
+      let props = await makeProps(key)
+      this.set({ props: props })
+    },
+    components: {
+      PseudoVirtualListItem
+    }
+  }
+</script>
\ No newline at end of file
diff --git a/routes/_components/timeline/StatusListItem.html b/routes/_components/timeline/StatusVirtualListItem.html
similarity index 100%
rename from routes/_components/timeline/StatusListItem.html
rename to routes/_components/timeline/StatusVirtualListItem.html
diff --git a/routes/_components/timeline/Timeline.html b/routes/_components/timeline/Timeline.html
index 803dd3f..98b26e7 100644
--- a/routes/_components/timeline/Timeline.html
+++ b/routes/_components/timeline/Timeline.html
@@ -1,14 +1,26 @@
 <div class="timeline" role="feed" aria-label="{{label}}">
-  <VirtualList component="{{StatusListItem}}"
-               :makeProps
-               items="{{$statusIds}}"
-               on:scrollToBottom="onScrollToBottom()"
-               shown="{{$initialized}}"
-               footerComponent="{{LoadingFooter}}"
-               showFooter="{{$initialized && $runningUpdate}}"
-               realm="{{$currentInstance + '/' + timeline}}"
-               on:initializedVisibleItems="initialize()"
-  />
+  {{#if virtual}}
+    <VirtualList component="{{StatusVirtualListItem}}"
+                 :makeProps
+                 items="{{$statusIds}}"
+                 on:scrollToBottom="onScrollToBottom()"
+                 shown="{{$initialized}}"
+                 footerComponent="{{LoadingFooter}}"
+                 showFooter="{{$initialized && $runningUpdate}}"
+                 realm="{{$currentInstance + '/' + timeline}}"
+                 on:initializedVisibleItems="initialize()"
+    />
+  {{else}}
+    <!-- if this is a status thread, it's easier to just render the
+         whole thing rather than use a virtual list -->
+    <PseudoVirtualList component="{{StatusVirtualListItem}}"
+                       :makeProps
+                       items="{{$statusIds}}"
+                       shown="{{$initialized}}"
+                       on:initializedVisibleItems="initialize()"
+                       scrollToItem="{{timelineValue}}"
+    />
+  {{/if}}
 </div>
 <style>
   .timeline {
@@ -17,7 +29,9 @@
 </style>
 <script>
   import { store } from '../../_store/store'
-  import StatusListItem from './StatusListItem.html'
+  import StatusVirtualListItem from './StatusVirtualListItem.html'
+  import Status from '../status/Status.html'
+  import PseudoVirtualList from '../pseudoVirtualList/PseudoVirtualList.html'
   import LoadingFooter from './LoadingFooter.html'
   import VirtualList from '../virtualList/VirtualList.html'
   import { timelines } from '../../_static/timelines'
@@ -26,11 +40,13 @@
 
   export default {
     async oncreate() {
+      console.log('timeline oncreate()')
       setupTimeline()
     },
     data: () => ({
-      StatusListItem: StatusListItem,
-      LoadingFooter: LoadingFooter
+      StatusVirtualListItem,
+      LoadingFooter,
+      Status
     }),
     computed: {
       makeProps: ($currentInstance, timelineType) => async (statusId) => ({
@@ -56,17 +72,22 @@
       },
       timelineValue: (timeline) => {
         return timeline.split('/').slice(-1)[0]
-      }
+      },
+      // for threads, it's simpler to just render all items due to need to scroll to the right item
+      // TODO: this can be optimized to use a virtual list
+      virtual: (timelineType) => timelineType !=='status'
     },
     store: () => store,
     components: {
-      VirtualList
+      VirtualList,
+      PseudoVirtualList
     },
     methods: {
       initialize() {
         if (this.store.get('initialized') || !this.store.get('statusIds') || !this.store.get('statusIds').length) {
           return
         }
+        console.log('timeline initialize()')
         initializeTimeline()
       },
       onScrollToBottom() {
diff --git a/routes/statuses/[statusId].html b/routes/statuses/[statusId].html
index 7fc0e31..b53be51 100644
--- a/routes/statuses/[statusId].html
+++ b/routes/statuses/[statusId].html
@@ -3,8 +3,6 @@
 </:Head>
 
 <Layout page='statuses'
-        virtual="true"
-        virtualRealm='status/{{params.statusId}}'
         dynamicPage="Status"
         dynamicHref="/statuses/{{params.statusId}}"
         dynamicLabel="Status"