diff --git a/client/bvh.js b/client/bvh.js
index c913a6f..c499c55 100644
--- a/client/bvh.js
+++ b/client/bvh.js
@@ -1,5 +1,3 @@
-// TODO: get rid of node_count
-//
 function bvh_make_leaf(bvh, index, stroke) {
     const leaf = {
         'stroke_index': index,
@@ -100,15 +98,12 @@ function bvh_rotate(bvh, index) {
 function bvh_add_stroke(bvh, index, stroke) {
     const leaf_index = bvh_make_leaf(bvh, index, stroke);
 
-    if (bvh.node_count === 0) {
+    if (bvh.nodes.length === 1) {
         bvh.root = leaf_index;
-        bvh.node_count++;
         return;
     }
 
-    bvh.node_count++;
-
-    if (bvh.pqueue.capacity < Math.ceil(bvh.node_count * 1.2)) {
+    if (bvh.pqueue.capacity < Math.ceil(bvh.nodes.length * 1.2)) {
         bvh.pqueue = new MinQueue(bvh.pqueue.capacity * 2);        
     }
 
@@ -152,8 +147,6 @@ function bvh_add_stroke(bvh, index, stroke) {
     bvh.nodes[new_parent].bbox = new_bbox;
     bvh.nodes[new_parent].area = (new_bbox.x2 - new_bbox.x1) * (new_bbox.y2 - new_bbox.y1);   
 
-    bvh.node_count++;
-
     // 3. Refit and rotate
     let refit_index = bvh.nodes[leaf_index].parent_index;
     while (refit_index !== null) {
@@ -195,18 +188,8 @@ function bvh_intersect_quad(bvh, quad) {
 }
 
 function bvh_clip(state, context) {
-    if (state.onscreen_segments === null) {       
-        let total_points = 0;
-
-        for (const event of state.events) {
-            if (event.type === EVENT.STROKE && !event.deleted && event.points.length > 0) {
-                total_points += event.points.length - 1;
-            }
-        }
-    
-        if (total_points > 0) {
-            state.onscreen_segments = new Uint32Array(total_points * 6);
-        }
+    if (state.onscreen_segments.length < Math.ceil(state.total_points * 6 * 1.2)) {       
+        state.onscreen_segments = new Uint32Array(state.total_points * 6 * 2);
     }
 
     let at = 0;
diff --git a/client/client_recv.js b/client/client_recv.js
index 6df8d55..f82d77a 100644
--- a/client/client_recv.js
+++ b/client/client_recv.js
@@ -170,10 +170,12 @@ function handle_event(state, context, event, options = {}) {
         }
 
         case EVENT.STROKE: {
-            if (event.user_id != state.me) {
+            // TODO: @speed do proper local prediction, it's not that hard
+            
+            //if (event.user_id != state.me) {
                 geometry_clear_player(state, context, event.user_id);
                 need_draw = true;
-            }
+            //}
             
             event.index = state.events.length;
             event.starting_index = state.starting_index;
@@ -182,6 +184,8 @@ function handle_event(state, context, event, options = {}) {
                 state.starting_index += (event.points.length - 1) * 4;
             }
 
+            state.total_points += event.points.length;
+
             geometry_add_stroke(state, context, event, state.events.length, options.skip_bvh === true);
 
             state.stroke_count++;
@@ -368,6 +372,8 @@ async function handle_message(state, context, d) {
                 }
             }
 
+            state.sn = event_count;
+
             bvh_construct(state);
 
             document.getElementById('debug-render-from').max = state.stroke_count;
diff --git a/client/index.html b/client/index.html
index 97c8c3f..f1c1760 100644
--- a/client/index.html
+++ b/client/index.html
@@ -41,7 +41,6 @@
 
             
             
-            
             
 
             
diff --git a/client/index.js b/client/index.js
index 317936b..5fb5ae2 100644
--- a/client/index.js
+++ b/client/index.js
@@ -1,6 +1,8 @@
 // NEXT: pan with m3, place dot, cursor size and color, YELLOW and gray, show user cursor, background styles,
 // view desks, undo, eraser, ruler, images (movable), quadtree for clipping, f5 without redownload, progress bar
 //
+// use returning ID on insert intead of (COLLIDING!) rand_32
+// look into using u64 for point coordinates? fix bad drawings on zoomout
 
 document.addEventListener('DOMContentLoaded', main);
 
@@ -165,10 +167,10 @@ function main() {
         'events': [],
         'stroke_count': 0,
         'starting_index': 0,
+        'total_points': 0,
 
         'bvh': {
             'nodes': [],
-            'node_count': 0,
             'root': null,
             'pqueue': new MinQueue(1024),
         },
@@ -189,7 +191,7 @@ function main() {
         },
 
         'players': {},
-        'onscreen_segments': null,
+        'onscreen_segments': new Uint32Array(1024),
 
         'debug': {
             'red': false,
@@ -198,7 +200,6 @@ function main() {
             'limit_to': false,
             'render_from': 0,
             'render_to': 0,
-            'force_clip_off': false,
             'draw_bvh': false,
         }
     };
diff --git a/client/webgl_draw.js b/client/webgl_draw.js
index 56183ce..5e3979c 100644
--- a/client/webgl_draw.js
+++ b/client/webgl_draw.js
@@ -57,7 +57,7 @@ function draw(state, context) {
     gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
 
     let index_count;
-    const do_clip = !state.debug.force_clip_off; //(state.canvas.zoom > config.clip_zoom_threshold); 
+    const do_clip = true;//(state.canvas.zoom > config.clip_zoom_threshold); 
 
     if (do_clip) {
         context.need_index_upload = true;
@@ -137,6 +137,7 @@ function draw(state, context) {
             gl.uniform2f(locations['u_translation'], state.canvas.offset.x, state.canvas.offset.y);
             gl.uniform1i(locations['u_stroke_count'], state.stroke_count);
             gl.uniform1i(locations['u_debug_mode'], state.debug.red);
+            gl.uniform1i(locations['u_shrink'], 1);
 
             gl.enableVertexAttribArray(locations['a_pos']);
             gl.enableVertexAttribArray(locations['a_line']);
@@ -160,6 +161,34 @@ function draw(state, context) {
         }
     }
 
+    // Dynamic data (stroke previews that are currently in progress)
+    const dynamic_points = context.dynamic_serializer.offset / config.bytes_per_point;
+
+    if (dynamic_points > 0) {
+        gl.clear(gl.DEPTH_BUFFER_BIT);
+        gl.bindBuffer(gl.ARRAY_BUFFER, buffers['b_packed_dynamic']);
+
+        gl.enableVertexAttribArray(locations['a_pos']);
+        gl.enableVertexAttribArray(locations['a_line']);
+        gl.enableVertexAttribArray(locations['a_color']);
+        gl.enableVertexAttribArray(locations['a_stroke_id']);
+
+        gl.vertexAttribPointer(locations['a_pos'],        3, gl.FLOAT,         false, config.bytes_per_point, 0);
+        gl.vertexAttribPointer(locations['a_line'],       4, gl.FLOAT,         false, config.bytes_per_point, 4 * 3);
+        gl.vertexAttribPointer(locations['a_color'],      3, gl.UNSIGNED_BYTE, true,  config.bytes_per_point, 4 * 3 + 4 * 4);
+        gl.vertexAttribIPointer(locations['a_stroke_id'], 1, gl.INT,                  config.bytes_per_point, 4 * 3 + 4 * 4 + 4);
+
+        gl.uniform1i(locations['u_shrink'], 0);
+
+        if (context.need_dynamic_upload) {
+            gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(context.dynamic_serializer.buffer, 0, context.dynamic_serializer.offset), gl.DYNAMIC_DRAW);
+            context.need_dynamic_upload = false;
+        }
+
+        gl.drawArrays(gl.TRIANGLES, 0, dynamic_points);
+    }
+
+
     if (state.debug.draw_bvh) {
         const points = new Float32Array(state.bvh.nodes.length * 6 * 2);
 
@@ -195,32 +224,10 @@ function draw(state, context) {
         gl.vertexAttribPointer(locations['a_pos'], 2, gl.FLOAT, false, 8, 0);
        
         gl.clear(gl.DEPTH_BUFFER_BIT);
-
         gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
         gl.drawArrays(gl.TRIANGLES, 0, points.length / 2);
     }
-
-    /*
-    if (dynamic_points > 0) {
-        gl.bindBuffer(gl.ARRAY_BUFFER, buffers['b_packed_dynamic']);
-
-        gl.enableVertexAttribArray(locations['a_pos']);
-        gl.enableVertexAttribArray(locations['a_line']);
-        gl.enableVertexAttribArray(locations['a_color']);
-
-        gl.vertexAttribPointer(locations['a_pos'],   3, gl.FLOAT,         false, config.bytes_per_point, 0);
-        gl.vertexAttribPointer(locations['a_line'],  4, gl.FLOAT,         false, config.bytes_per_point, 4 * 3);
-        gl.vertexAttribPointer(locations['a_color'], 3, gl.UNSIGNED_BYTE, true,  config.bytes_per_point, 4 * 3 + 4 * 4);
-
-        if (context.need_dynamic_upload) {
-            gl.bufferData(gl.ARRAY_BUFFER, new Uint8Array(context.dynamic_serializer.buffer, 0, context.dynamic_serializer.offset), gl.STATIC_DRAW);
-            context.need_dynamic_upload = false;
-        }
-
-        gl.drawArrays(gl.TRIANGLES, 0, dynamic_points);
-    }
-    */
-
+ 
     if (context.gpu_timer_ext) {
         gl.endQuery(context.gpu_timer_ext.TIME_ELAPSED_EXT);
 
diff --git a/client/webgl_geometry.js b/client/webgl_geometry.js
index 33fd2dc..4b56b39 100644
--- a/client/webgl_geometry.js
+++ b/client/webgl_geometry.js
@@ -13,18 +13,23 @@ function push_point(s, x, y, ax, ay, bx, by, thickness, r, g, b, stroke_id) {
     ser_u32(s, stroke_id);
 }
 
-function push_quad(s, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y, ax, ay, bx, by, thickness, r, g, b, stroke_id) {
-    push_point(s, p1x, p1y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
-    push_point(s, p2x, p2y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
-    push_point(s, p3x, p3y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
-    push_point(s, p4x, p4y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
+function push_quad(s, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y, ax, ay, bx, by, thickness, r, g, b, stroke_id, indexed = true) {
+    if (indexed) {
+        push_point(s, p1x, p1y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
+        push_point(s, p2x, p2y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
+        push_point(s, p3x, p3y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
+        push_point(s, p4x, p4y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
+    } else {
+        push_point(s, p1x, p1y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
+        push_point(s, p2x, p2y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
+        push_point(s, p3x, p3y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
+        push_point(s, p4x, p4y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
+        push_point(s, p3x, p3y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
+        push_point(s, p2x, p2y, ax, ay, bx, by, thickness, r, g, b, stroke_id);
+    }
 }
 
-function push_stroke(s, stroke, stroke_index) {
-    // if (stroke.stroke_id !== 1123776468) {
-        // return;
-    // }
-
+function push_stroke(s, stroke, stroke_index, indexed = true) {
     const stroke_width = stroke.width;
     const points = stroke.points;
     const color_u32 = stroke.color;
@@ -73,7 +78,8 @@ function push_stroke(s, stroke, stroke_index) {
             to.x, to.y, 
             stroke_width, 
             r, g, b,
-            stroke_index
+            stroke_index,
+            indexed
         );
     }
 }
@@ -97,7 +103,7 @@ function geometry_prepare_stroke(state) {
     };
 }
 
-function geometry_add_stroke(state, context, stroke, stroke_index, skip_bvh) {
+function geometry_add_stroke(state, context, stroke, stroke_index, skip_bvh = false) {
     if (!state.online || !stroke || stroke.points.length === 0) return;
 
     stroke.bbox = stroke_bbox(stroke);
@@ -157,8 +163,8 @@ function recompute_dynamic_data(state, context) {
     for (const player_id in state.players) {
         // player has the same data as their current stroke: points, color, width
         const player = state.players[player_id];
-        if (player.points.length > 0) {
-            push_stroke(context.dynamic_serializer, player, 0); // TODO: stroke index ??
+        if (player.points.length > 1) {
+            push_stroke(context.dynamic_serializer, player, 0, false);
         }
     }
 
diff --git a/client/webgl_listeners.js b/client/webgl_listeners.js
index 3d23714..387fe59 100644
--- a/client/webgl_listeners.js
+++ b/client/webgl_listeners.js
@@ -26,7 +26,6 @@ function debug_panel_init(state, context) {
     document.getElementById('debug-do-prepass').checked = state.debug.do_prepass;
     document.getElementById('debug-limit-from').checked = state.debug.limit_from;
     document.getElementById('debug-limit-to').checked = state.debug.limit_to;
-    document.getElementById('debug-force-clip-off').checked = state.debug.force_clip_off;
     document.getElementById('debug-draw-bvh').checked = state.debug.draw_bvh;
 
     document.getElementById('debug-draw-bvh').addEventListener('change', (e) => {
@@ -34,11 +33,6 @@ function debug_panel_init(state, context) {
         schedule_draw(state, context);
     });
 
-    document.getElementById('debug-force-clip-off').addEventListener('change', (e) => {
-        state.debug.force_clip_off = e.target.checked;
-        schedule_draw(state, context);
-    });
-
     document.getElementById('debug-red').addEventListener('change', (e) => {
         state.debug.red = e.target.checked;
         schedule_draw(state, context);
@@ -257,9 +251,9 @@ function mouseup(e, state, context) {
         const stroke = geometry_prepare_stroke(state);
 
         if (stroke) {
-            geometry_add_stroke(state, context, stroke, 0); // TODO: stroke index?
+            //geometry_add_stroke(state, context, stroke, 0); // TODO: stroke index?
             queue_event(state, stroke_event(state));
-            geometry_clear_player(state, context, state.me);
+            //geometry_clear_player(state, context, state.me);
             schedule_draw(state, context);
         }
 
diff --git a/client/webgl_shaders.js b/client/webgl_shaders.js
index 8790c39..d615e36 100644
--- a/client/webgl_shaders.js
+++ b/client/webgl_shaders.js
@@ -113,6 +113,7 @@ const sdf_vs_src = `#version 300 es
     uniform vec2 u_translation;
 
     uniform int u_stroke_count;
+    uniform int u_shrink;
 
     out vec4 v_line;
     out vec2 v_texcoord;
@@ -123,31 +124,35 @@ const sdf_vs_src = `#version 300 es
     void main() {
         vec2 screen01 = (a_pos.xy * u_scale + u_translation) / u_res;
         vec2 screen02 = screen01 * 2.0;
-
-        // Inflate quad by 1 pixel
-        float apron = 2.0;
-        vec2 line_dir = normalize(a_line.zw - a_line.xy);
-        vec2 up_dir = vec2(line_dir.y, -line_dir.x);
-        vec2 pixel = vec2(2.0) / u_res * apron;
-
-        int vertex_index = gl_VertexID % 4;
-
-        if (vertex_index == 0) {
-            // "top left" aka "p1"
-            screen02 += up_dir * pixel - line_dir * pixel;
-            v_texcoord = a_pos.xy + up_dir * 1.0 / u_scale - line_dir * 1.0 / u_scale;
-        } else if (vertex_index == 1) {
-            // "top right" aka "p2"
-            screen02 += up_dir * pixel + line_dir * pixel;
-            v_texcoord = a_pos.xy + up_dir * 1.0 / u_scale + line_dir * 1.0 / u_scale;
-        } else if (vertex_index == 2) {
-            // "bottom left" aka "p3"
-            screen02 += -up_dir * pixel - line_dir * pixel;
-            v_texcoord = a_pos.xy - up_dir * 1.0 / u_scale - line_dir * 1.0 / u_scale;
+        
+        if (u_shrink == 1) {
+            // Inflate quad by 2 pixels (change to 1 when I figure out how to fix the prepass shit)
+            float apron = 2.0;
+            vec2 line_dir = normalize(a_line.zw - a_line.xy);
+            vec2 up_dir = vec2(line_dir.y, -line_dir.x);
+            vec2 pixel = vec2(2.0) / u_res * apron;
+
+            int vertex_index = gl_VertexID % 4;
+
+            if (vertex_index == 0) {
+                // "top left" aka "p1"
+                screen02 += up_dir * pixel - line_dir * pixel;
+                v_texcoord = a_pos.xy + up_dir * 1.0 / u_scale - line_dir * 1.0 / u_scale;
+            } else if (vertex_index == 1) {
+                // "top right" aka "p2"
+                screen02 += up_dir * pixel + line_dir * pixel;
+                v_texcoord = a_pos.xy + up_dir * 1.0 / u_scale + line_dir * 1.0 / u_scale;
+            } else if (vertex_index == 2) {
+                // "bottom left" aka "p3"
+                screen02 += -up_dir * pixel - line_dir * pixel;
+                v_texcoord = a_pos.xy - up_dir * 1.0 / u_scale - line_dir * 1.0 / u_scale;
+            } else {
+                // "bottom right" aka "p4"
+                screen02 += -up_dir * pixel + line_dir * pixel;
+                v_texcoord = a_pos.xy - up_dir * 1.0 / u_scale + line_dir * 1.0 / u_scale;
+            }
         } else {
-            // "bottom right" aka "p4"
-            screen02 += -up_dir * pixel + line_dir * pixel;
-            v_texcoord = a_pos.xy - up_dir * 1.0 / u_scale + line_dir * 1.0 / u_scale;
+            v_texcoord = a_pos.xy;
         }
 
         screen02.y = 2.0 - screen02.y;
@@ -303,6 +308,7 @@ function init_webgl(state, context) {
             'u_debug_mode':      gl.getUniformLocation(context.programs['sdf'].main, 'u_debug_mode'),
             'u_tile_size':       gl.getUniformLocation(context.programs['sdf'].main, 'u_tile_size'),
             'u_stroke_count':    gl.getUniformLocation(context.programs['sdf'].main, 'u_stroke_count'),
+            'u_shrink':          gl.getUniformLocation(context.programs['sdf'].main, 'u_shrink'),
         }
     };
 
diff --git a/server/recv.js b/server/recv.js
index d33ea1e..82b2932 100644
--- a/server/recv.js
+++ b/server/recv.js
@@ -52,7 +52,7 @@ async function recv_syn(d, session) {
         '$id': session.id,
         '$lsn': lsn
     });
-
+    
     send.send_ack(session.ws, lsn);
     send.sync_desk(session.desk_id);
 }
diff --git a/server/send.js b/server/send.js
index 829a600..80907b5 100644
--- a/server/send.js
+++ b/server/send.js
@@ -206,7 +206,7 @@ async function sync_session(session_id) {
     }
 
     let size = 1  + 4 + 4; // opcode + sn + event count
-    let count = desk.sn -  session.sn;
+    let count = desk.sn - session.sn;
 
     if (count === 0) {
         if (config.DEBUG_PRINT) console.log('client ACKed all events');