diff --git a/src/containers/costume-tab.jsx b/src/containers/costume-tab.jsx
index 5df459150509e96d746bf03aec3fd1671fa6ee6a..2b71975c4e366a58ae876d67fe0cce479c40475b 100644
--- a/src/containers/costume-tab.jsx
+++ b/src/containers/costume-tab.jsx
@@ -13,6 +13,8 @@ import errorBoundaryHOC from '../lib/error-boundary-hoc.jsx';
 import DragConstants from '../lib/drag-constants';
 import {emptyCostume} from '../lib/empty-assets';
 import sharedMessages from '../lib/shared-messages';
+import download from '../lib/download-url';
+import getCostumeUrl from '../lib/get-costume-url';
 
 import {
     closeCameraCapture,
@@ -86,6 +88,7 @@ class CostumeTab extends React.Component {
             'handleSelectCostume',
             'handleDeleteCostume',
             'handleDuplicateCostume',
+            'handleExportCostume',
             'handleNewCostume',
             'handleNewBlankCostume',
             'handleSurpriseCostume',
@@ -136,6 +139,12 @@ class CostumeTab extends React.Component {
             this.setState({selectedCostumeIndex: target.currentCostume});
         }
     }
+    getCostumeData (costumeItem) {
+        if (costumeItem.url) return costumeItem.url;
+        if (!costumeItem.asset) return null;
+
+        return getCostumeUrl(costumeItem.asset);
+    }
     handleSelectCostume (costumeIndex) {
         this.props.vm.editingTarget.setCostume(costumeIndex);
         this.setState({selectedCostumeIndex: costumeIndex});
@@ -150,6 +159,10 @@ class CostumeTab extends React.Component {
     handleDuplicateCostume (costumeIndex) {
         this.props.vm.duplicateCostume(costumeIndex);
     }
+    handleExportCostume (costumeIndex) {
+        const item = this.props.vm.editingTarget.sprite.costumes[costumeIndex];
+        download(`${item.name}.${item.asset.dataFormat}`, this.getCostumeData(item));
+    }
     handleNewCostume (costume, fromCostumeLibrary) {
         if (fromCostumeLibrary) {
             this.props.vm.addCostumeFromLibrary(costume.md5, costume);
@@ -312,6 +325,7 @@ class CostumeTab extends React.Component {
                     this.handleDeleteCostume : null}
                 onDrop={this.handleDrop}
                 onDuplicateClick={this.handleDuplicateCostume}
+                onExportClick={this.handleExportCostume}
                 onItemClick={this.handleSelectCostume}
             >
                 {target.costumes ?
diff --git a/src/containers/monitor.jsx b/src/containers/monitor.jsx
index e2c88222018d94c35d1c9ef31af8f6e8ec23b018..039fa060d616d2df878f75eff8140fcbdcb51ecb 100644
--- a/src/containers/monitor.jsx
+++ b/src/containers/monitor.jsx
@@ -8,7 +8,7 @@ import MonitorComponent, {monitorModes} from '../components/monitor/monitor.jsx'
 import {addMonitorRect, getInitialPosition, resizeMonitorRect, removeMonitorRect} from '../reducers/monitor-layout';
 import {getVariable, setVariableValue} from '../lib/variable-utils';
 import importCSV from '../lib/import-csv';
-import downloadText from '../lib/download-text';
+import download from '../lib/download-url';
 
 import {connect} from 'react-redux';
 import {Map} from 'immutable';
@@ -155,7 +155,8 @@ class Monitor extends React.Component {
     handleExport () {
         const {vm, targetId, id: variableId} = this.props;
         const variable = getVariable(vm, targetId, variableId);
-        downloadText(`${variable.name}.txt`, variable.value.join('\r\n'));
+        const text = variable.value.join('\r\n');
+        download(`${variable.name}.txt`, `data:text/plain;charset=utf-8,${encodeURIComponent(text)}`);
     }
     render () {
         const monitorProps = monitorAdapter(this.props);
diff --git a/src/containers/sound-tab.jsx b/src/containers/sound-tab.jsx
index 3df93b1f6039e0945f73d9e804d73b9c11368df1..40e08dfb737321de558b278c011c4a2e9e980142 100644
--- a/src/containers/sound-tab.jsx
+++ b/src/containers/sound-tab.jsx
@@ -21,6 +21,7 @@ import soundLibraryContent from '../lib/libraries/sounds.json';
 import {handleFileUpload, soundUpload} from '../lib/file-uploader.js';
 import errorBoundaryHOC from '../lib/error-boundary-hoc.jsx';
 import DragConstants from '../lib/drag-constants';
+import download from '../lib/download-url';
 
 import {connect} from 'react-redux';
 
@@ -44,6 +45,7 @@ class SoundTab extends React.Component {
             'handleSelectSound',
             'handleDeleteSound',
             'handleDuplicateSound',
+            'handleExportSound',
             'handleNewSound',
             'handleSurpriseSound',
             'handleFileUploadClick',
@@ -86,6 +88,12 @@ class SoundTab extends React.Component {
         this.props.dispatchUpdateRestore({restoreFun, deletedItem: 'Sound'});
     }
 
+    handleExportSound (soundIndex) {
+        const item = this.props.vm.editingTarget.sprite.sounds[soundIndex];
+        const soundDataURL = item.asset.encodeDataURI();
+        download(`${item.name}.${item.asset.dataFormat}`, soundDataURL);
+    }
+
     handleDuplicateSound (soundIndex) {
         this.props.vm.duplicateSound(soundIndex).then(() => {
             this.setState({selectedSoundIndex: soundIndex + 1});
@@ -236,6 +244,7 @@ class SoundTab extends React.Component {
                 onDeleteClick={this.handleDeleteSound}
                 onDrop={this.handleDrop}
                 onDuplicateClick={this.handleDuplicateSound}
+                onExportClick={this.handleExportSound}
                 onItemClick={this.handleSelectSound}
             >
                 {sprite.sounds && sprite.sounds[this.state.selectedSoundIndex] ? (
diff --git a/src/lib/download-text.js b/src/lib/download-url.js
similarity index 70%
rename from src/lib/download-text.js
rename to src/lib/download-url.js
index 2c0bc91a511b6f6d20011dbbc23a71d4cf0fdd1a..e01cb1f0890bf103d704c661b0795bce721418bd 100644
--- a/src/lib/download-text.js
+++ b/src/lib/download-url.js
@@ -1,6 +1,6 @@
-export default (filename, text) => {
+export default (filename, url) => {
     const pom = document.createElement('a');
-    pom.setAttribute('href', `data:text/plain;charset=utf-8,${encodeURIComponent(text)}`);
+    pom.setAttribute('href', url);
     pom.setAttribute('download', filename);
 
     if (document.createEvent) {