diff --git a/src/components/audio-trimmer/audio-trimmer.css b/src/components/audio-trimmer/audio-trimmer.css
index fe276c3819eed948b33d34cde90da60f19bca77f..3d9fa65a190ee08844f2079730346973e9bfd54a 100644
--- a/src/components/audio-trimmer/audio-trimmer.css
+++ b/src/components/audio-trimmer/audio-trimmer.css
@@ -12,6 +12,9 @@ $hover-scale: 2;
     left: 0;
     width: 100%;
     height: 100%;
+
+    /* Force the browser to paint separately to avoid composite cost with waveform */
+    transform: translateZ(0);
 }
 
 .trim-background {
@@ -51,7 +54,15 @@ $hover-scale: 2;
 }
 
 .playhead {
-    border: 1px solid $motion-primary;
+    /*
+        Even though playhead is just a line, it is 100% width (the width of the waveform)
+        so that we can use transform: translateX() using percentages.
+    */
+    width: 100%;
+    border-left: 1px solid $motion-primary;
+    border-top: none;
+    border-bottom: none;
+    border-right: none;
 }
 
 .start-trim-line {
diff --git a/src/components/audio-trimmer/audio-trimmer.jsx b/src/components/audio-trimmer/audio-trimmer.jsx
index d1b21c92664cebc586212c9833629ba90da8f701..e2ad295fc09ff22c5725eb0285234f5f419a212f 100644
--- a/src/components/audio-trimmer/audio-trimmer.jsx
+++ b/src/components/audio-trimmer/audio-trimmer.jsx
@@ -35,7 +35,7 @@ const AudioTrimmer = props => (
             <Box
                 className={classNames(styles.trimLine, styles.playhead)}
                 style={{
-                    left: `${100 * props.playhead}%`
+                    transform: `translateX(${100 * props.playhead}%)`
                 }}
             />
         ) : null}
diff --git a/src/components/waveform/waveform.jsx b/src/components/waveform/waveform.jsx
index 1b2abe96ebf5ed306bde9e3ba9d54a202dd846be..48a0a4935c376995624e4cf4c41c194539b27ec8 100644
--- a/src/components/waveform/waveform.jsx
+++ b/src/components/waveform/waveform.jsx
@@ -2,52 +2,65 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import styles from './waveform.css';
 
-const Waveform = props => {
-    const {
-        width,
-        height,
-        data
-    } = props;
-
-    const cappedData = [0, ...data, 0];
-
-    const points = [
-        ...cappedData.map((v, i) =>
-            [width * i / cappedData.length, height * v / 2]
-        ),
-        ...cappedData.reverse().map((v, i) =>
-            [width * (cappedData.length - i - 1) / cappedData.length, -height * v / 2]
-        )
-    ];
-
-    const pathComponents = points.map(([x, y], i) => {
-        const [nx, ny] = points[i < points.length - 1 ? i + 1 : 0];
-        return `Q${x} ${y} ${(x + nx) / 2} ${(y + ny) / 2}`;
-    });
-
-    return (
-        <svg
-            className={styles.container}
-            viewBox={`-1 0 ${width} ${height}`}
-        >
-            <line
-                className={styles.baseline}
-                x1={-1}
-                x2={width}
-                y1={height / 2}
-                y2={height / 2}
-            />
-            <g transform={`scale(1, -1) translate(0, -${height / 2})`}>
-                <path
-                    className={styles.waveformPath}
-                    d={`M0 0${pathComponents.join(' ')}Z`}
-                    strokeLinejoin={'round'}
-                    strokeWidth={1}
+// Waveform is expensive to compute, make sure it only updates when data does
+// by using PureComponent. In future can be changed back to function with React.memo
+// eslint-disable-next-line react/prefer-stateless-function
+class Waveform extends React.PureComponent {
+    render () {
+        const {
+            width,
+            height,
+            data
+        } = this.props;
+
+        // Never want a density of points higher than the number of pixels
+        // This is very conservative, could be far fewer points because of curve smoothing.
+        // Drawing too many points seems to cause an explosion in browser
+        // composite time when animating the playhead
+        const takeEveryN = Math.ceil(data.length / width);
+
+        const filteredData = takeEveryN === 1 ? data :
+            data.filter((_, i) => i % takeEveryN === 0);
+
+        const cappedData = [0, ...filteredData, 0];
+
+        const points = [
+            ...cappedData.map((v, i) =>
+                [width * i / cappedData.length, height * v / 2]
+            ),
+            ...cappedData.reverse().map((v, i) =>
+                [width * (cappedData.length - i - 1) / cappedData.length, -height * v / 2]
+            )
+        ];
+        const pathComponents = points.map(([x, y], i) => {
+            const [nx, ny] = points[i < points.length - 1 ? i + 1 : 0];
+            return `Q${x} ${y} ${(x + nx) / 2} ${(y + ny) / 2}`;
+        });
+
+        return (
+            <svg
+                className={styles.container}
+                viewBox={`-1 0 ${width} ${height}`}
+            >
+                <line
+                    className={styles.baseline}
+                    x1={-1}
+                    x2={width}
+                    y1={height / 2}
+                    y2={height / 2}
                 />
-            </g>
-        </svg>
-    );
-};
+                <g transform={`scale(1, -1) translate(0, -${height / 2})`}>
+                    <path
+                        className={styles.waveformPath}
+                        d={`M0 0${pathComponents.join(' ')}Z`}
+                        strokeLinejoin={'round'}
+                        strokeWidth={1}
+                    />
+                </g>
+            </svg>
+        );
+    }
+}
 
 Waveform.propTypes = {
     data: PropTypes.arrayOf(PropTypes.number),
diff --git a/test/unit/components/__snapshots__/sound-editor.test.jsx.snap b/test/unit/components/__snapshots__/sound-editor.test.jsx.snap
index 93ebc2cf68c794ad31bbf93e6f61b6ec5ac440b5..77df3c54966667bf29f37063ce62d857ed95c2c9 100644
--- a/test/unit/components/__snapshots__/sound-editor.test.jsx.snap
+++ b/test/unit/components/__snapshots__/sound-editor.test.jsx.snap
@@ -224,7 +224,7 @@ exports[`Sound Editor Component matches snapshot 1`] = `
               "flexWrap": undefined,
               "height": undefined,
               "justifyContent": undefined,
-              "left": "50%",
+              "transform": "translateX(50%)",
               "width": undefined,
             }
           }