diff --git a/src/components/bit-line-mode/bit-line-mode.jsx b/src/components/bit-line-mode/bit-line-mode.jsx
index 57921fba..75f50761 100644
--- a/src/components/bit-line-mode/bit-line-mode.jsx
+++ b/src/components/bit-line-mode/bit-line-mode.jsx
@@ -1,27 +1,25 @@
 import React from 'react';
-
-import {ComingSoonTooltip} from '../coming-soon/coming-soon.jsx';
+import PropTypes from 'prop-types';
 import ToolSelectComponent from '../tool-select-base/tool-select-base.jsx';
 
 import lineIcon from './line.svg';
 
-const BitLineComponent = () => (
-    <ComingSoonTooltip
-        place="right"
-        tooltipId="bit-line-mode"
-    >
-        <ToolSelectComponent
-            disabled
-            imgDescriptor={{
-                defaultMessage: 'Line',
-                description: 'Label for the line tool, which draws straight line segments',
-                id: 'paint.lineMode.line'
-            }}
-            imgSrc={lineIcon}
-            isSelected={false}
-            onMouseDown={function () {}} // eslint-disable-line react/jsx-no-bind
-        />
-    </ComingSoonTooltip>
+const BitLineComponent = props => (
+    <ToolSelectComponent
+        imgDescriptor={{
+            defaultMessage: 'Line',
+            description: 'Label for the line tool, which draws straight line segments',
+            id: 'paint.lineMode.line'
+        }}
+        imgSrc={lineIcon}
+        isSelected={props.isSelected}
+        onMouseDown={props.onMouseDown}
+    />
 );
 
+BitLineComponent.propTypes = {
+    isSelected: PropTypes.bool.isRequired,
+    onMouseDown: PropTypes.func.isRequired
+};
+
 export default BitLineComponent;
diff --git a/src/components/mode-tools/mode-tools.jsx b/src/components/mode-tools/mode-tools.jsx
index 6356f9de..80523e06 100644
--- a/src/components/mode-tools/mode-tools.jsx
+++ b/src/components/mode-tools/mode-tools.jsx
@@ -15,14 +15,15 @@ import InputGroup from '../input-group/input-group.jsx';
 import LabeledIconButton from '../labeled-icon-button/labeled-icon-button.jsx';
 import Modes from '../../lib/modes';
 import Formats from '../../lib/format';
-import {isBitmap} from '../../lib/format';
+import {isBitmap, isVector} from '../../lib/format';
 import styles from './mode-tools.css';
 
 import copyIcon from './icons/copy.svg';
 import pasteIcon from './icons/paste.svg';
 
-import brushIcon from '../brush-mode/brush.svg';
 import bitBrushIcon from '../bit-brush-mode/brush.svg';
+import bitLineIcon from '../bit-line-mode/line.svg';
+import brushIcon from '../brush-mode/brush.svg';
 import curvedPointIcon from './icons/curved-point.svg';
 import eraserIcon from '../eraser-mode/eraser.svg';
 import flipHorizontalIcon from './icons/flip-horizontal.svg';
@@ -39,6 +40,11 @@ const ModeToolsComponent = props => {
             description: 'Label for the brush size input',
             id: 'paint.modeTools.brushSize'
         },
+        lineSize: {
+            defaultMessage: 'Line size',
+            description: 'Label for the line size input',
+            id: 'paint.modeTools.lineSize'
+        },
         eraserSize: {
             defaultMessage: 'Eraser size',
             description: 'Label for the eraser size input',
@@ -80,18 +86,22 @@ const ModeToolsComponent = props => {
     case Modes.BRUSH:
         /* falls through */
     case Modes.BIT_BRUSH:
+        /* falls through */
+    case Modes.BIT_LINE:
     {
-        const currentBrushIcon = isBitmap(props.format) ? bitBrushIcon : brushIcon;
+        const currentIcon = isVector(props.format) ? brushIcon :
+            props.mode === Modes.BIT_LINE ? bitLineIcon : bitBrushIcon;
         const currentBrushValue = isBitmap(props.format) ? props.bitBrushSize : props.brushValue;
         const changeFunction = isBitmap(props.format) ? props.onBitBrushSliderChange : props.onBrushSliderChange;
+        const currentMessage = props.mode === Modes.BIT_LINE ? messages.lineSize : messages.brushSize;
         return (
             <div className={classNames(props.className, styles.modeTools)}>
                 <div>
                     <img
-                        alt={props.intl.formatMessage(messages.brushSize)}
+                        alt={props.intl.formatMessage(currentMessage)}
                         className={styles.modeToolsIcon}
                         draggable={false}
-                        src={currentBrushIcon}
+                        src={currentIcon}
                     />
                 </div>
                 <LiveInput
diff --git a/src/components/paint-editor/paint-editor.jsx b/src/components/paint-editor/paint-editor.jsx
index eb715312..3fff3bd7 100644
--- a/src/components/paint-editor/paint-editor.jsx
+++ b/src/components/paint-editor/paint-editor.jsx
@@ -11,7 +11,7 @@ import {shouldShowGroup, shouldShowUngroup} from '../../helper/group';
 import {shouldShowBringForward, shouldShowSendBackward} from '../../helper/order';
 
 import BitBrushMode from '../../containers/bit-brush-mode.jsx';
-import BitLineMode from '../../components/bit-line-mode/bit-line-mode.jsx';
+import BitLineMode from '../../containers/bit-line-mode.jsx';
 import BitOvalMode from '../../components/bit-oval-mode/bit-oval-mode.jsx';
 import BitRectMode from '../../components/bit-rect-mode/bit-rect-mode.jsx';
 import BitTextMode from '../../components/bit-text-mode/bit-text-mode.jsx';
@@ -410,7 +410,9 @@ const PaintEditorComponent = props => {
                         <BitBrushMode
                             onUpdateSvg={props.onUpdateSvg}
                         />
-                        <BitLineMode />
+                        <BitLineMode
+                            onUpdateSvg={props.onUpdateSvg}
+                        />
                         <BitOvalMode />
                         <BitRectMode />
                         <BitTextMode />
diff --git a/src/containers/bit-line-mode.jsx b/src/containers/bit-line-mode.jsx
new file mode 100644
index 00000000..dc2bfd54
--- /dev/null
+++ b/src/containers/bit-line-mode.jsx
@@ -0,0 +1,107 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import {connect} from 'react-redux';
+import bindAll from 'lodash.bindall';
+import Modes from '../lib/modes';
+import {MIXED} from '../helper/style-path';
+
+import {changeFillColor, DEFAULT_COLOR} from '../reducers/fill-color';
+import {changeMode} from '../reducers/modes';
+import {clearSelectedItems} from '../reducers/selected-items';
+import {clearSelection} from '../helper/selection';
+
+import BitLineModeComponent from '../components/bit-line-mode/bit-line-mode.jsx';
+import BitLineTool from '../helper/bit-tools/line-tool';
+
+class BitLineMode extends React.Component {
+    constructor (props) {
+        super(props);
+        bindAll(this, [
+            'activateTool',
+            'deactivateTool'
+        ]);
+    }
+    componentDidMount () {
+        if (this.props.isBitLineModeActive) {
+            this.activateTool(this.props);
+        }
+    }
+    componentWillReceiveProps (nextProps) {
+        if (this.tool && nextProps.color !== this.props.color) {
+            this.tool.setColor(nextProps.color);
+        }
+        if (this.tool && nextProps.bitBrushSize !== this.props.bitBrushSize) {
+            this.tool.setLineSize(nextProps.bitBrushSize);
+        }
+        
+        if (nextProps.isBitLineModeActive && !this.props.isBitLineModeActive) {
+            this.activateTool();
+        } else if (!nextProps.isBitLineModeActive && this.props.isBitLineModeActive) {
+            this.deactivateTool();
+        }
+    }
+    shouldComponentUpdate (nextProps) {
+        return nextProps.isBitLineModeActive !== this.props.isBitLineModeActive;
+    }
+    activateTool () {
+        clearSelection(this.props.clearSelectedItems);
+        // Force the default line color if fill is MIXED or transparent
+        let color = this.props.color;
+        if (!color || color === MIXED) {
+            this.props.onChangeFillColor(DEFAULT_COLOR);
+            color = DEFAULT_COLOR;
+        }
+        this.tool = new BitLineTool(
+            this.props.onUpdateSvg
+        );
+        this.tool.setColor(color);
+        this.tool.setLineSize(this.props.bitBrushSize);
+
+        this.tool.activate();
+    }
+    deactivateTool () {
+        this.tool.deactivateTool();
+        this.tool.remove();
+        this.tool = null;
+    }
+    render () {
+        return (
+            <BitLineModeComponent
+                isSelected={this.props.isBitLineModeActive}
+                onMouseDown={this.props.handleMouseDown}
+            />
+        );
+    }
+}
+
+BitLineMode.propTypes = {
+    bitBrushSize: PropTypes.number.isRequired,
+    clearSelectedItems: PropTypes.func.isRequired,
+    color: PropTypes.string,
+    handleMouseDown: PropTypes.func.isRequired,
+    isBitLineModeActive: PropTypes.bool.isRequired,
+    onChangeFillColor: PropTypes.func.isRequired,
+    onUpdateSvg: PropTypes.func.isRequired
+};
+
+const mapStateToProps = state => ({
+    bitBrushSize: state.scratchPaint.bitBrushSize,
+    color: state.scratchPaint.color.fillColor,
+    isBitLineModeActive: state.scratchPaint.mode === Modes.BIT_LINE
+});
+const mapDispatchToProps = dispatch => ({
+    clearSelectedItems: () => {
+        dispatch(clearSelectedItems());
+    },
+    handleMouseDown: () => {
+        dispatch(changeMode(Modes.BIT_LINE));
+    },
+    onChangeFillColor: fillColor => {
+        dispatch(changeFillColor(fillColor));
+    }
+});
+
+export default connect(
+    mapStateToProps,
+    mapDispatchToProps
+)(BitLineMode);
diff --git a/src/containers/paint-editor.jsx b/src/containers/paint-editor.jsx
index 07354966..659b8336 100644
--- a/src/containers/paint-editor.jsx
+++ b/src/containers/paint-editor.jsx
@@ -49,6 +49,7 @@ class PaintEditor extends React.Component {
             'handleZoomReset',
             'canRedo',
             'canUndo',
+            'switchMode',
             'onMouseDown',
             'setCanvas',
             'setTextArea',
@@ -81,11 +82,9 @@ class PaintEditor extends React.Component {
             this.stopEyeDroppingLoop();
         }
 
-        // @todo move to correct corresponding tool
-        if (isVector(this.props.format) && isBitmap(prevProps.format)) {
-            this.props.changeMode(Modes.BRUSH);
-        } else if (isVector(prevProps.format) && isBitmap(this.props.format)) {
-            this.props.changeMode(Modes.BIT_BRUSH);
+        if ((isVector(this.props.format) && isBitmap(prevProps.format)) ||
+            (isVector(prevProps.format) && isBitmap(this.props.format))) {
+            this.switchMode(this.props.format);
         }
     }
     componentWillUnmount () {
@@ -94,6 +93,31 @@ class PaintEditor extends React.Component {
         document.removeEventListener('mousedown', this.onMouseDown);
         document.removeEventListener('touchstart', this.onMouseDown);
     }
+    switchMode (newFormat) {
+        if (isVector(newFormat)) {
+            switch (this.props.mode) {
+            case Modes.BIT_BRUSH:
+                this.props.changeMode(Modes.BRUSH);
+                break;
+            case Modes.BIT_LINE:
+                this.props.changeMode(Modes.LINE);
+                break;
+            default:
+                this.props.changeMode(Modes.BRUSH);
+            }
+        } else if (isBitmap(newFormat)) {
+            switch (this.props.mode) {
+            case Modes.BRUSH:
+                this.props.changeMode(Modes.BIT_BRUSH);
+                break;
+            case Modes.LINE:
+                this.props.changeMode(Modes.BIT_LINE);
+                break;
+            default:
+                this.props.changeMode(Modes.BIT_BRUSH);
+            }
+        }
+    }
     handleUpdateSvg (skipSnapshot) {
         // Store the zoom/pan and restore it after snapshotting
         // TODO Only doing this because snapshotting at zoom/pan makes export wrong
@@ -300,6 +324,7 @@ PaintEditor.propTypes = {
     handleSwitchToBitmap: PropTypes.func.isRequired,
     handleSwitchToVector: PropTypes.func.isRequired,
     isEyeDropping: PropTypes.bool,
+    mode: PropTypes.oneOf(Object.keys(Modes)).isRequired,
     name: PropTypes.string,
     onDeactivateEyeDropper: PropTypes.func.isRequired,
     onKeyPress: PropTypes.func.isRequired,
@@ -331,6 +356,7 @@ const mapStateToProps = state => ({
     clipboardItems: state.scratchPaint.clipboard.items,
     format: state.scratchPaint.format,
     isEyeDropping: state.scratchPaint.color.eyeDropper.active,
+    mode: state.scratchPaint.mode,
     pasteOffset: state.scratchPaint.clipboard.pasteOffset,
     previousTool: state.scratchPaint.color.eyeDropper.previousTool,
     selectedItems: state.scratchPaint.selectedItems,
diff --git a/src/helper/bit-tools/brush-tool.js b/src/helper/bit-tools/brush-tool.js
index da173899..8802996e 100644
--- a/src/helper/bit-tools/brush-tool.js
+++ b/src/helper/bit-tools/brush-tool.js
@@ -96,10 +96,6 @@ class BrushTool extends paper.Tool {
     handleMouseDrag (event) {
         if (event.event.button > 0 || !this.active) return; // only first mouse button
 
-        if (this.isBoundingBoxMode) {
-            this.boundingBoxTool.onMouseDrag(event);
-            return;
-        }
         forEachLinePoint(this.lastPoint, event.point, this.draw.bind(this));
         this.lastPoint = event.point;
     }
diff --git a/src/helper/bit-tools/line-tool.js b/src/helper/bit-tools/line-tool.js
new file mode 100644
index 00000000..b150e947
--- /dev/null
+++ b/src/helper/bit-tools/line-tool.js
@@ -0,0 +1,142 @@
+import paper from '@scratch/paper';
+import {getRaster} from '../layer';
+import {forEachLinePoint, fillEllipse} from '../bitmap';
+import {getGuideLayer} from '../layer';
+import {ART_BOARD_WIDTH, ART_BOARD_HEIGHT} from '../view';
+
+/**
+ * Tool for drawing lines with the bitmap brush.
+ */
+class LineTool extends paper.Tool {
+    /**
+     * @param {!function} onUpdateSvg A callback to call when the image visibly changes
+     */
+    constructor (onUpdateSvg) {
+        super();
+        this.onUpdateSvg = onUpdateSvg;
+        
+        // We have to set these functions instead of just declaring them because
+        // paper.js tools hook up the listeners in the setter functions.
+        this.onMouseMove = this.handleMouseMove;
+        this.onMouseDown = this.handleMouseDown;
+        this.onMouseDrag = this.handleMouseDrag;
+        this.onMouseUp = this.handleMouseUp;
+
+        this.colorState = null;
+        this.active = false;
+        this.startPoint = null;
+        this.cursorPreview = null;
+        // Raster to which to draw
+        this.drawTarget = null;
+    }
+    setColor (color) {
+        this.color = color;
+    }
+    setLineSize (size) {
+        // For performance, make sure this is an integer
+        this.size = Math.max(1, ~~size);
+    }
+    // Draw a brush mark at the given point
+    draw (x, y) {
+        const roundedUpRadius = Math.ceil(this.size / 2);
+        this.drawTarget.drawImage(this.tmpCanvas, new paper.Point(~~x - roundedUpRadius, ~~y - roundedUpRadius));
+    }
+    updateCursorIfNeeded () {
+        if (!this.size) {
+            return;
+        }
+        // The cursor preview was unattached from the view by an outside process,
+        // such as changing costumes or undo.
+        if (this.cursorPreview && !this.cursorPreview.parent) {
+            this.cursorPreview = null;
+        }
+
+        if (!this.cursorPreview || !(this.lastSize === this.size && this.lastColor === this.color)) {
+            if (this.cursorPreview) {
+                this.cursorPreview.remove();
+            }
+
+            this.tmpCanvas = document.createElement('canvas');
+            const roundedUpRadius = Math.ceil(this.size / 2);
+            this.tmpCanvas.width = roundedUpRadius * 2;
+            this.tmpCanvas.height = roundedUpRadius * 2;
+            const context = this.tmpCanvas.getContext('2d');
+            context.imageSmoothingEnabled = false;
+            context.fillStyle = this.color;
+            // Small squares for pixel artists
+            if (this.size <= 5) {
+                if (this.size % 2) {
+                    context.fillRect(1, 1, this.size, this.size);
+                } else {
+                    context.fillRect(0, 0, this.size, this.size);
+                }
+            } else {
+                const roundedDownRadius = ~~(this.size / 2);
+                fillEllipse(roundedDownRadius, roundedDownRadius, roundedDownRadius, roundedDownRadius, context);
+            }
+
+            this.cursorPreview = new paper.Raster(this.tmpCanvas);
+            this.cursorPreview.guide = true;
+            this.cursorPreview.parent = getGuideLayer();
+            this.cursorPreview.data.isHelperItem = true;
+        }
+        this.lastSize = this.size;
+        this.lastColor = this.color;
+    }
+    handleMouseMove (event) {
+        this.updateCursorIfNeeded();
+        this.cursorPreview.position = new paper.Point(~~event.point.x, ~~event.point.y);
+    }
+    handleMouseDown (event) {
+        if (event.event.button > 0) return; // only first mouse button
+        this.active = true;
+        
+        this.cursorPreview.remove();
+
+        const tmpCanvas = document.createElement('canvas');
+        tmpCanvas.width = ART_BOARD_WIDTH;
+        tmpCanvas.height = ART_BOARD_HEIGHT;
+        this.drawTarget = new paper.Raster(tmpCanvas);
+        this.drawTarget.parent = getGuideLayer();
+        this.drawTarget.guide = true;
+        this.drawTarget.locked = true;
+        this.drawTarget.position = getRaster().position;
+
+        this.draw(event.point.x, event.point.y);
+        this.startPoint = event.point;
+    }
+    handleMouseDrag (event) {
+        if (event.event.button > 0 || !this.active) return; // only first mouse button
+
+        // Clear
+        const context = this.drawTarget.canvas.getContext('2d');
+        context.clearRect(0, 0, ART_BOARD_WIDTH, ART_BOARD_HEIGHT);
+
+        forEachLinePoint(this.startPoint, event.point, this.draw.bind(this));
+    }
+    handleMouseUp (event) {
+        if (event.event.button > 0 || !this.active) return; // only first mouse button
+        
+        this.drawTarget.remove();
+        this.drawTarget = getRaster();
+        forEachLinePoint(this.startPoint, event.point, this.draw.bind(this));
+        this.drawTarget = null;
+        this.onUpdateSvg();
+
+        this.lastPoint = null;
+        this.active = false;
+
+        this.updateCursorIfNeeded();
+        this.cursorPreview.position = new paper.Point(~~event.point.x, ~~event.point.y);
+    }
+    deactivateTool () {
+        this.active = false;
+        this.tmpCanvas = null;
+        if (this.cursorPreview) {
+            this.cursorPreview.remove();
+            this.cursorPreview = null;
+        }
+    }
+}
+
+export default LineTool;
diff --git a/src/lib/modes.js b/src/lib/modes.js
index 4eafc6b5..332558cd 100644
--- a/src/lib/modes.js
+++ b/src/lib/modes.js
@@ -2,6 +2,7 @@ import keyMirror from 'keymirror';
 
 const Modes = keyMirror({
     BIT_BRUSH: null,
+    BIT_LINE: null,
     BRUSH: null,
     ERASER: null,
     LINE: null,