Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                ._audio
.l
.p3d{"@mousemove" => "colorPicker($event)"}
    .p3d_colorPicker{"v-if" => "picker.active", ":style" => "`background: #${picker.color};left: ${picker.x}px; top: ${picker.y}px;`", "@click" => "picker.active = !picker.active, picker.color = '#25273E'"}
    .p3d_loader
        .p3d_loader__inner
            %img{:src => 'https://assets.codepen.io/217233/p3d_logoLoading_2.svg'}
            .b
            .f
    .p3d_main
        .p3d_overlay{":class" => "{open : modalOpen}", "@click" => "closeModals()"}
        .p3d_load.modal{":class" => "{open : modalOpen && modal == 'share'}"}
            .p3d_load__inner.modal
                .close{"@click" => "closeModals(), enJin.audioController.play('pop6')"}
                    X
                %h1{"v-if" => "submitted"} Creation shared!
                %h1{"v-if" => "!submitted"} Share your creation
                .wrap{"v-if" => "submitted"}
                    %p Amazing! Thanks for being part of the community. If your VoCSSel is approved, everyone will be able to view it in the community section. I really hope you enjoyed using VoCSSels!
                .wrap{"v-if" => "!submitted"}
                    %p Want other people to be able to load in your VoCSSel? If approved, your VoCSSel will be added to our community section.
                    .row
                        .row-half
                            %label{:for => 'name'} VoCSSel name
                            %input#name{":value" => "exportSettings.name", "v-model" => "exportSettings.name", :type => 'text'}
                        .row-half
                            %label{:for => 'name'} Author name
                            %input#name{":value" => "author", "v-model" => "author", :type => 'text'}
                .b{"v-if" => "!submitted"}
                    %button{"@click" => "shareModel()", ":class" => "{submitting : submitting}"} 
                        %img.loader{:src => 'https://assets.codepen.io/217233/Dual+Ring-1s-200px.gif', :draggable => 'false'}
                        Share it
                    %button{"@click" => "closeModals(), enJin.audioController.play('pop6')"} No thanks
        .p3d_load.modal.community{":class" => "{open : modalOpen && modal == 'community'}"}
            .p3d_load__inner.modal
                .close{"@click" => "closeModals(), enJin.audioController.play('pop6')"}
                    X
                %h1 Community content
                %p Take a look at some of the incredible VoCSSels people have made
                .s-wrap
                    .x-wrap
                        .p3d_load__model.empty{"v-if" => "communityContent.length == 0"}
                            %h4 Sorry, we seem to be having a problem loading content. Please try again later
                        .p3d_load__model{":key" => "model", "v-for" => "(model, index) in communityContent", "@click" => "load(model, true), closeModals(), enJin.audioController.play('pop6')"}
                            .m_image{":style" => "`background: url(${model.image})`"}
                            .m_details
                                %p.date {{model.date}}
                                %p.name {{model.name}}
                                %p.author by {{model.author}}
                                %p.voxels 
                                    %span 
                                        {{model.voxels}}
                                    voxels | 
                                    %span
                                        {{model.vertices}}
                                    vertices
        .p3d_load.modal{":class" => "{open : modalOpen && modal == 'load'}"}
            .p3d_load__inner.modal
                .close{"@click" => "closeModals(), enJin.audioController.play('pop6')"}
                    X
                %h1 Load a VoCSSel
                %p Select or manage your saved VoCSSels
                .s-wrap
                    .p3d_load__model.empty{"v-if" => "savedModelsMeta.length == 0"}
                        %h4 You don't have any VoCSSels saved. Go and make one first
                    .p3d_load__model{":key" => "model", "v-for" => "(model, index) in savedModelsMeta", "@click" => "load(index, false), closeModals(), enJin.audioController.play('pop6')"}
                        .m_image{":style" => "`background: url(${getMetaData('image', model)})`"}
                        .m_details
                            %p.date {{getMetaData('date', model)}}
                            %p.name {{getMetaData('name', model)}} 
                            %p.author by {{getMetaData('author', model)}} 
                            %p.voxels 
                                %span 
                                    {{getMetaData('voxels', model)}} 
                                voxels | 
                                %span
                                    {{getMetaData('vertices', model)}} 
                                vertices
                            .delete{"@click" => "deleteModel(index), enJin.audioController.play('pop5')"} Delete
            
        .p3d_main__header
            .header_left
                %img{:src => 'https://assets.codepen.io/217233/p3d_logo_new.svg', :draggable => 'false'}
            .header_right
                .name
                    %input{":value" => "exportSettings.name", "v-model" => "exportSettings.name"}
                .buttons
                    .save.button{"@click" => "newModel(), enJin.audioController.play('pop6')"}
                        %img{:src => 'https://assets.codepen.io/217233/p3d_load_1.svg', :draggable => 'false', ":class" => "{saving : saving}"}
                            .tooltip
                                New
                    .save.button{"@click" => "save(), enJin.audioController.play('pop6')"}
                        %img.icon{:src => 'https://assets.codepen.io/217233/p3d_save_1.svg', :draggable => 'false', ":class" => "{saving : saving}"}
                        %img.loader{:src => 'https://assets.codepen.io/217233/Dual+Ring-1s-200px.gif', :draggable => 'false', ":class" => "{saving : saving}"}
                            .tooltip
                                Save
                    .load.button{"@click" => "openModal('load'), enJin.audioController.play('pop6')"}
                        %img{:src => 'https://assets.codepen.io/217233/p3d_new.svg', :draggable => 'false'}
                            .tooltip
                                Load
                    .community.button{"@click" => "openModal('community'), enJin.audioController.play('pop6')"}
                        Community
                .options
                    .button{"@click" => "toggleAudio()", ":class" => "{active : muted}"}
                        %img.icon{:src => 'https://assets.codepen.io/217233/p3d_mute.svg', :draggable => 'false'}
                            .tooltip
                                Audio
                    .button{"@click" => "toggleMotion()", ":class" => "{active : !motion}"}
                        %img{:src => 'https://assets.codepen.io/217233/p3d_nomotion.svg', :draggable => 'false'}
                            .tooltip
                                Motion
        .p3d_main__editor
            .editor_left
                .editor_left__header{":class" => "{export : mode == 'export'}"}
                    .e_buttons{":class" => "{hide : mode != 'drawing'}"}
                        .button{":class" => "{active : symMode == ''}", "@click" => "symMode = ''"}
                            %img{:src => 'https://assets.codepen.io/217233/p3d_sym_none_1.svg', :draggable => 'false'}
                            .tooltip
                                No Symmetry
                        .button{":class" => "{active : symMode == 'x'}", "@click" => "symMode = 'x'"}
                            %img{:src => 'https://assets.codepen.io/217233/p3d_sym_x_1.svg', :draggable => 'false'}
                            .tooltip
                                X Symmetry
                        .button{":class" => "{active : symMode == 'y'}", "@click" => "symMode = 'y'"}
                            %img{:src => 'https://assets.codepen.io/217233/p3d_sym_y_1.svg', :draggable => 'false'}
                            .tooltip
                                Y Symmetry
                        .button{":class" => "{active : symMode == 'xy'}", "@click" => "symMode = 'xy'"}
                            %img{:src => 'https://assets.codepen.io/217233/p3d_sym_xy_1.svg', :draggable => 'false'}
                            .tooltip
                                XY Symmetry
                    .e_tabs
                        .e_tabs__tab.button{"@click" => "swapMode('drawing'), drawMode = 'draw', exportSettings.scale = 0.8, updateOrientation(0, 90, 0, false)", ":class" => "{active : mode == 'drawing'}"}
                            Draw
                            .tooltip
                                Draw pixel art
                        .e_tabs__tab.button{"@click" => "swapMode('extrude'), drawMode = 'extrude', exportSettings.scale = 0.8, updateOrientation(-30, 140, 0, false)", ":class" => "{active : mode == 'extrude'}"}
                            Extrude
                            .tooltip
                                Give depth
                        .e_tabs__tab.button{"@click" => "swapMode('paint'), drawMode = 'draw', exportSettings.scale = 0.8, updateOrientation(0, 90, 0, false), orientationButton = 'front'", ":class" => "{active : mode == 'paint'}"}
                            Paint
                            .tooltip
                                Paint voxels
                        .e_tabs__tab.button{"@click" => "swapMode('export'), updateOrientation(0, 90, 0, true)", ":class" => "{active : mode == 'export'}"}
                            Export
                            .tooltip
                                Export for web
                    .e_sym
                .editor_left__main{"@mouseleave" => "picker.active = false"}
                    .m_palette{":class" => "{hide : mode == 'extrude'}"}
                        .buttons
                            .button.draw{"@click" => "drawMode = 'draw', enJin.audioController.play('pop6')", ":class" => "{active : drawMode == 'draw'}"}
                                %img{:src => 'https://assets.codepen.io/217233/p3d_pencil.svg', :draggable => 'false'}
                                .tooltip
                                    Draw
                            .button.erase{"v-if" => "mode != 'paint'", "@click" => "picker.active = false, drawMode = 'erase', enJin.audioController.play('pop6')", ":class" => "{active : drawMode == 'erase'}"}
                                %img{:src => 'https://assets.codepen.io/217233/p3d_eraser_2.svg', :draggable => 'false'}
                                .tooltip
                                    Erase
                        
                        .cPicker{"@click" => "picker.active = !picker.active", ":class" => "{active : picker.active}"}
                            %svg{:fill => "none", :height => "18", :viewbox => "0 0 18 18", :width => "18", :xmlns => "http://www.w3.org/2000/svg"}
                                %path{:d => "M16.3 0.75C15.3 -0.25 13.7 -0.25 12.7 0.75L10.9 2.55L10.2 1.85C9.8 1.45 9.2 1.45 8.8 1.85L8 2.55C7.6 2.95 7.6 3.55 8 3.95L13 8.95C13.4 9.35 14 9.35 14.4 8.95L15.1 8.25C15.5 7.85 15.5 7.25 15.1 6.85L14.5 6.15L16.3 4.35C17.3 3.35 17.3 1.75 16.3 0.75V0.75ZM2.9 10.55C0.7 12.75 2 13.75 0 16.35L0.7 17.05C3.3 15.05 4.3 16.35 6.5 14.15L11.6 9.05L8 5.45L2.9 10.55Z", :fill => "black"}
                        #colorPicker             
                    .m_palette.palette--depth{":class" => "{hide : mode != 'extrude'}"}
                        .buttons
                            .button.erase{"@click" => "drawMode = 'extrude', enJin.audioController.play('pop6')", ":class" => "{active : drawMode == 'extrude'}"}
                                %img{:src => 'https://assets.codepen.io/217233/p3d_extrude.svg?x=ghfh', :draggable => 'false'}
                                .tooltip
                                    Extrude 
                            .button.erase{"@click" => "drawMode = 'hollow', enJin.audioController.play('pop6')", ":class" => "{active : drawMode == 'hollow'}"}
                                %img{:src => 'https://assets.codepen.io/217233/p3d_hollow.svg?x=ghfh', :draggable => 'false', :draggable => 'false'}
                                .tooltip
                                    Shell 
                        .dp-outer
                            .hollowTip{":class" => "{hide : drawMode == 'extrude'}"}
                                .help
                                    Shell a group
                                    %img.icon{:src => 'https://assets.codepen.io/217233/p3d_help.svg', :draggable => 'false'}
                                    .gif
                                        .desc
                                            %h4 Shell tool
                                            Use the shell toggle to remove the voxels between the first and last in the row. Handy for optimising your model and removing voxels that cannot be seen. Also great for creating legs.
                                        %img{:src => 'https://assets.codepen.io/217233/shell.gif', :draggable => 'false'}
                                .button{"@click" => "shell = true, enJin.audioController.play('pop6')", ":class" => "{active : shell}"}
                                    On
                                .button{"@click" => "shell = false, enJin.audioController.play('pop6')", ":class" => "{active : !shell}"}
                                    Off
                            .dpgrid{":class" => "{hide : drawMode == 'hollow'}"}
                                .help
                                    Select a depth
                                    %img.icon{:src => 'https://assets.codepen.io/217233/p3d_help.svg', :draggable => 'false'}
                                    .gif
                                        .desc
                                            %h4 Extrude tool
                                            Select a level of depth, then click on any pixel to extrude by that amount. New voxels will be created along the z axis which can be individually painted.
                                        %img{:src => 'https://assets.codepen.io/217233/depth.gif', :draggable => 'false'}
                                -(1..9).each do | index |
                                    .dp{':data-depth' => index, "@click" => "setDepth($event), enJin.audioController.play('pop6')", ":class" => "{active : currentDepth == #{index}}"} #{index}
                    .m_grid{"@mousedown" => "drawing = true", "@mouseup" => "drawing = false", "@mouseup.right" => "handleRightClick()", "@mouseleave" => "drawing = false", ":class" => "{hide : mode == 'paint', loading : loading}"}
                        .helper-x{":class" => "{active : symMode == 'x' || symMode == 'xy'}"}
                        .helper-y{":class" => "{active : symMode == 'y' || symMode == 'xy'}"}
                        %img.loader{:src => 'https://assets.codepen.io/217233/Dual+Ring-1s-200px.gif', :draggable => 'false', ":class" => "{saving : saving}"}
                        .m_grid__pixel{":data-index" => "index", ":data-y" => "Math.floor(`${index / canvasSize + 1}`)", ":data-x" => "Math.ceil(`${index % canvasSize}`)", "@click" => "selectColor()", "@mouseenter" => "drawPixel($event)", "@mousedown" => "drawPixel($event)", "@contextmenu.prevent" => '', ":key" => "voxel.x", "v-for" => "(voxel, index) in voxels", ":style" => ""}
                            .p{"v-if" => "voxel.c", ":style" => "`background: #${voxel.c[0][1]}`"}
                            .d{":class" => "{show : mode == 'extrude' && drawMode == 'extrude'}"}{{voxel.d}}
                            .d{":class" => "{show : mode == 'extrude' && drawMode == 'hollow' && voxel.h}"} S
                            
            .editor_right
                .editor_right__export{":class" => "{show : mode == 'export'}"}
                    %h3 Export settings
                    %p.sub Export your VoCSSel for web, or as a png based on the current view
                    .form
                    .row
                        .row-half
                            %label{:for => 'name'} VoCSSel name
                            %input#name{":value" => "exportSettings.name", "v-model" => "exportSettings.name", :type => 'text'}
                        .row-half
                            %label{:for => 'name'} Author name
                            %input#name{":value" => "author", "v-model" => "author", :type => 'text'}
                        .save.button{"@click" => "save(), enJin.audioController.play('pop6')"}
                            %img.icon{:src => 'https://assets.codepen.io/217233/p3d_save_1.svg', :draggable => 'false', ":class" => "{saving : saving}"}
                            %img.loader{:src => 'https://assets.codepen.io/217233/Dual+Ring-1s-200px.gif', :draggable => 'false', ":class" => "{saving : saving}"}
                                .tooltip
                                    Save
                    %br
                    .row
                        %label{:for => 'exportBg'} Background color
                        %input#exportBg
                        %img{:src => 'https://assets.codepen.io/217233/p3d_resetColour.svg', :draggable => 'false', "@click" => "resetBgColor()"}
                    .row
                        %label{:for => 'perspective'} 
                            Perspective: 
                            %span {{exportSettings.perspective}}px
                        %input#perspective{":value" => "exportSettings.perspective", :min => 100, :max => 3000, :type => 'range', "v-model" => "exportSettings.perspective"}
                    .row
                        %label{:for => 'animate'} 
                            Animate 
                            %span 
                                %span Turn off for viewport control
                        %input#animate{":value" => "exportSettings.animate", :type => 'checkbox', "v-model" => "exportSettings.animate"}
                    .row{"v-if" => "exportSettings.animate"}
                        %label{:for => 'speed'} 
                            Speed: 
                            %span {{exportSettings.spinSpeed}}s
                        %input#speed{":value" => "exportSettings.spinSpeed", :type => 'range', :min => 0.1, :max => 20, :step => 0.1, "v-model" => "exportSettings.spinSpeed"}
                    .row{"v-if" => "!exportSettings.animate"}
                        .row-half
                            %label{:for => 'rotateX'} 
                                Rotate X: 
                                %span {{exportSettings.x}}deg
                            %input#rotateX{":value" => "exportSettings.x", :type => 'range', :min => -180, :max => 180, :step => 10, "v-model" => "exportSettings.x"}
                        .row-half
                            %label{:for => 'rotateY'} 
                                Rotate Y: 
                                %span {{exportSettings.y}}deg
                            %input#rotateY{":value" => "exportSettings.y", :type => 'range', :min => -180, :max => 180, :step => 10, "v-model" => "exportSettings.y"}

                    .row{"v-if" => "!exportSettings.animate"}
                        .row-half
                            %label{:for => 'rotateZ'} 
                                Rotate Z: 
                                %span {{exportSettings.z}}deg
                            %input#rotateZ{":value" => "exportSettings.z", :type => 'range', :min => -180, :max => 180, :step => 10, "v-model" => "exportSettings.z"}
                        .row-half
                            %label{:for => 'scale'} 
                                Scale: 
                                %span {{exportSettings.scale}}
                            %input#scale{":value" => "exportSettings.scale", :type => 'range', :min => 0.01, :max => 3, :step => 0.01, "v-model" => "exportSettings.scale"}
                    .buttons
                        %button{"@click" => "openModal('share'), enJin.audioController.play('pop6')"} Share with community
                        %button.cp{"@click" => "processForExport()", ":class" => "{exporting : exporting}"}
                            %img.loader{:src => 'https://assets.codepen.io/217233/Dual+Ring-1s-200px.gif', :draggable => 'false', ":class" => "{saving : saving}"}
                            Export to CodePen
                %p{":class" => "{hide : mode == 'export' || mode == 'paint'}"} HTML / CSS Output
                %img{:src => 'https://assets.codepen.io/217233/p3d_resetColour.svg', :draggable => 'false', "@click" => "resetBgColor()", ":class" => "{hide : mode == 'export'}"}
                %input#colorBg{":class" => "{hide : mode == 'export'}"}
                .editor_right__preview{":class" => "{export : mode == 'export', paint : mode == 'paint'}"}
                    .p_inner#model{":style" => "`background: ${exportSettings.bgColor};`"}
                        .button.zooms.first{"@click" => "handleZoom(0.05), enJin.audioController.play('pop6')", ":class" => "{hide : mode == 'export'}"}
                            %img{:src => 'https://assets.codepen.io/217233/p3d_zoomIn.svg', :draggable => 'false'}
                        .button.zooms{"@click" => "handleZoom(-0.05), enJin.audioController.play('pop6')", ":class" => "{hide : mode == 'export'}"}
                            %img{:src => 'https://assets.codepen.io/217233/p3d_zoomOut.svg', :draggable => 'false'}
                        .button.zooms{"@click" => "zoomLevel = .8, enJin.audioController.play('pop6')", ":class" => "{hide : mode == 'export'}"}
                            %img{:src => 'https://assets.codepen.io/217233/p3d_resetZoom.svg', :draggable => 'false'}
                        .views{":class" => "{show : mode == 'paint'}"}
                            .button{"@click" => "updateOrientation(0, 90, 0, false), orientationButton = 'front'", ":class" => "{active : orientationButton == 'front'}"} Front
                            .button{"@click" => "updateOrientation(0, -90, 0, false), orientationButton = 'back'", ":class" => "{active : orientationButton == 'back'}"} Back
                            .button{"@click" => "updateOrientation(0, 180, 0, false), orientationButton = 'left'", ":class" => "{active : orientationButton == 'left'}"} Left
                            .button{"@click" => "updateOrientation(0, 0, 0, false), orientationButton = 'right'", ":class" => "{active : orientationButton == 'right'}"} Right
                            .button{"@click" => "updateOrientation(-90, 0, 0, false), orientationButton = 'top'", ":class" => "{active : orientationButton == 'top'}"} Top
                            .button{"@click" => "updateOrientation(90, 0, 0, false), orientationButton = 'bottom'", ":class" => "{active : orientationButton == 'bottom'}"} Bottom
                            .button{"@click" => "updateOrientation(-30, 50, 0, false), orientationButton = 'iso1'", ":class" => "{active : orientationButton == 'iso1'}"} Isometric 1
                            .button{"@click" => "updateOrientation(-30, 140, 0, false), orientationButton = 'iso2'", ":class" => "{active : orientationButton == 'iso2'}"} Isometric 2
                            .button{"@click" => "updateOrientation(-30, 230, 0, false), orientationButton = 'iso3'", ":class" => "{active : orientationButton == 'iso3'}"} Isometric 3
                            .button{"@click" => "updateOrientation(-30, 310, 0, false), orientationButton = 'iso4'", ":class" => "{active : orientationButton == 'iso4'}"} Isometric 4
                        .zoom{"@wheel" => "zoom($event)", ":style" => "`transform: scale(${zoomLevel})`"}
                            .exportWrap
                                .model{"v-if" => "voxels", ":class" => "{extrude : mode == 'extrude', spin : mode == 'export' && exportSettings.animate, export : mode == 'export', paint : mode == 'paint'}", ":style" => "`transform: scale(${exportSettings.scale}) rotateZ(${exportSettings.z}deg) rotateX(${exportSettings.x}deg) rotateY(${exportSettings.y}deg); animation-duration: ${exportSettings.spinSpeed}s`"}
                                    .voxel-group{"v-if" => "voxelGroup.length != 0", ":key" => "voxelGroup.x", "v-for" => "(voxelGroup, index) in voxels", "stagger" => "50", ":class" => "`g-${voxelGroup.d}`", ":data-index" => "`${voxelGroup.index}`"}
                                        .voxel{"v-if" => "voxelGroup.c", ":key" => "index", "v-for" => "(voxel, index) in voxelGroup.d", ":class" => "`d-${index}`"}
                                            .v{"v-if" => "voxelGroup.c[index] != ''", ":class" => "`x-${voxelGroup.x} y-${voxelGroup.y}`", ":data-index" => "`${index}`"}
                                                .f.f--f{"v-if" => "voxelGroup?.c?.[index]?.[0]", ":data-vertex"  => "0" ,":style" => "[voxelGroup.c ? { background: `#${voxelGroup.c[index][0]}` } : null]", ":class" => "{paintable : mode == 'paint'}", "@click" => "paint($event)"}
                                                .f.f--ba{"v-if" => "voxelGroup?.c?.[index]?.[0]", ":data-vertex" => "1" ,":style" => "[voxelGroup.c ? { background: `#${voxelGroup.c[index][1]}` } : null]", ":class" => "{paintable : mode == 'paint'}", "@click" => "paint($event)"}
                                                .f.f--t{"v-if" => "voxelGroup?.c?.[index]?.[0]", ":data-vertex"  => "2" ,":style" => "[voxelGroup.c ? { background: `#${voxelGroup.c[index][2]}` } : null]", ":class" => "{paintable : mode == 'paint'}", "@click" => "paint($event)"}
                                                .f.f--b{"v-if" => "voxelGroup?.c?.[index]?.[0]", ":data-vertex"  => "3" ,":style" => "[voxelGroup.c ? { background: `#${voxelGroup.c[index][3]}` } : null]", ":class" => "{paintable : mode == 'paint'}", "@click" => "paint($event)"}
                                                .f.f--l{"v-if" => "voxelGroup?.c?.[index]?.[0]", ":data-vertex"  => "4" ,":style" => "[voxelGroup.c ? { background: `#${voxelGroup.c[index][4]}` } : null]", ":class" => "{paintable : mode == 'paint'}", "@click" => "paint($event)"}
                                                .f.f--r{"v-if" => "voxelGroup?.c?.[index]?.[0]", ":data-vertex"  => "5" ,":style" => "[voxelGroup.c ? { background: `#${voxelGroup.c[index][5]}` } : null]", ":class" => "{paintable : mode == 'paint'}", "@click" => "paint($event)"}
                %p.voxelCount{":class" => "{hide : mode == 'export' || mode == 'paint'}"} 
                    %span 
                        {{getVoxelsCount()}} 
                    Voxels | 
                    %span
                        {{getVerticesCount() - 1}} 
                    Vertices
                    %span.block{":class" => "{show : getVerticesCount() > 750}"}
                        %img.icon{:src => 'https://assets.codepen.io/217233/p3d_warning.svg', :draggable => 'false'}
                        Performance will decrease as the vertices count increases. Make sure to shell out any unused voxels for maximum performance.
        .p3d_main_footer
            %p 
                Made with love by 
                %a{:href => 'https://www.codepen.io/jcoulterdesign', :target => "_blank"} Jamie Coulter
              
            
!

CSS

              
                @import url('https://fonts.googleapis.com/css2?family=Baloo+2:wght@400;500;600;700&display=swap');

$primary: #25273E;
$secondary: #E5513A;
$borderRadius: 14px;

$voxelSize: 26; // We want to work as 1 unit is 1 voxel occupying one space. So here we are setting the the amount of pixels a voxel takes. This will need to be the same as the voxel size in the vue data object.
$shadingMixTolerance: 4; // How agressive the SASS mix is on each side of the voxel. Lower is less noticeable.
$maximumDepth: 15;
$maxX: 40;
$maxY: 40;

* {
    user-select: none;
}

body {
    background: $primary;
    color: white;
    font-family: 'Baloo 2', cursive;
    margin: 0;
    padding: 0;
    overflow: hidden;
    height: 100vh;

    .l {
        position: fixed;
        width: 50px;
        height: 10px;
        background: red;
        right: 358px;
        top: -10px;
        box-shadow: 0 0 20px 1px #f44336;
        animation: love 2s infinite;
    }

    @keyframes love {
        0%{box-shadow: 0 0 20px 1px #f44336;}
        50%{box-shadow: 0 0 26px 3px #f44336;}
        100%{box-shadow: 0 0 20px 1px #f44336;}
    }

    .noMotion {
        transition-duration: 0s !important;

        div {
            transition-duration: 0s !important;
        }
    }

    .hide {
        pointer-events: none;
    }

    // Spectrum

    .sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner,
    .sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner {
        background-image: none;
    }

    .sp-flat {
        z-index: 0;
    }

    .sp-input {
        font-size: 12px !important;
        border: 1px inset;
        padding: 8px 10px;
        margin: -20px 0 0 0;
        width: calc(100% - 56px);
        background: rgba(0, 0, 0, 0.3);
        border-radius: 8px;
        font-family: "Baloo 2", cursive;
        font-weight: 700;
        color: white;
        position: relative;
        top: -11px;
        left: 2px;
        border: 0 !important;
        outline: none !important;

        &:focus {
            box-shadow: 0 0 0 3px $secondary inset;
        }
    }

    .sp-container {
        background: transparent;
        border: 0;
        width: 170px;
        margin-left: 6px;
        margin-top: 22px;
    }

    .sp-container.bg {
        border: 0;
        height: 130px;
        border-radius: 10px;
        width: 170px;
        margin-left: 6px;
        margin-top: 22px;
        transform: translate(-363px, 12px) !important;
    }

    .sp-thumb-el {
        border-radius: 10px;
        transition: all .2s;

        &:hover {
            transform: scale(1.1);
        }
    }

    .sp-thumb-inner {
        box-shadow: 0 0 0 0 inset white;
        transition: all .3s;
        background: none;
    }

    .sp-thumb-active .sp-thumb-inner {
        background: none;
        box-shadow: 0 0 0 3px inset white;
    }

    .sp-top-inner {
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        width: 140px;
        height: 110px;
        right: 0;
    }

    .sp-palette .sp-thumb-inner {
        background-position: 50% 50%;
        background-repeat: no-repeat;
        border-radius: 10px;
    }

    .sp-color, 
    .sp-hue, 
    .sp-clear {
        border: 0;
    }

    .sp-palette-container {
        border: 0;
    }

    .sp-palette .sp-thumb-el {
        width: 40px;
        height: 40px;
        margin: 5px;
        border: 0;
        background: transparent;
    }

    .sp-hue {
        width: 10px;
        border-radius: 10px;
        margin-left: 11px;
    }

    .sp-slider, .sp-dragger {
        position: absolute;
        top: 0;
        cursor: pointer;
        height: 10px;
        width: 10px;
        transform: translate(4px, 4px);
        left: -6px;
        top: 4px;
        border-radius: 16px;
        border: 2px solid #fff;
        background: transparent;
        opacity: 1;
    }

    .sp-button-container.sp-cf {
        display: none;
    }

    .sp-picker-container {
        width: 172px;
        border-left: solid 0px #fff;

    }

    .sp-val {
        box-shadow: 0 0 0 3px inset white;
        border-radius: 10px;
        padding: 10px;
    }

    .sp-color {
        border-radius: 10px;
        overflow: hidden;
    }

    .sp-top {
        margin-left: 4px;
    }

    .p3d {
        height: 100vh;
        width: 100vw;

        &_colorPicker {
            width: 40px;
            height: 40px;
            background: red;
            position: absolute;
            z-index: 2;
            border-radius: 30px;
            transform: translate(-20px, -20px);
            pointer-events: none;
            transition: background .1s;
            border: 3px solid white;
        }

        &_loader {
            position: fixed;
            background: $primary;
            width: 100%;
            height: 100%;
            z-index: 1000;
            &__inner {
                position: absolute;
                left: 0;
                right: 0;
                margin: auto;
                top: 50%;
                transform: translateY(-50%) scale(0);
                width: 100px;
                animation: loadIn 2.75s 1s cubic-bezier(0.035, 1.495, 0.625, 0.890) forwards;

                .b, .f {
                    position: absolute;
                    width: 45px;
                    height: 45px;
                    background: #0000001c;
                    border-radius: 10px;
                    top: -13px;
                    left: 30px;
                    z-index: -1;
                }

                .f {
                    background: $secondary;
                    animation: load 1.5s 1.5s forwards;
                    clip-path: polygon(0 100%, 100% 100%, 100% 100%, 0 100%);
                }

                @keyframes load {
                    from {clip-path: polygon(0 100%, 100% 100%, 100% 100%, 0 100%);}
                    to {clip-path: polygon(0 100%, 100% 100%, 100% 0, 0 0);}
                }

                @keyframes loadIn {
                    0%{transform: translateY(-50%) scale(0); opacity: 1}
                    10%{transform: translateY(-50%) scale(1); opacity: 1}
                    90%{transform: translateY(-50%) scale(1); opacity: 1}
                    100%{transform: translateY(-50%) scale(0); opacity: 0}
                }
            }
        }

        &_overlay {
            background: rgb(16 14 29 / 80%);
            position: fixed;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            z-index: 1;
            opacity: 0;
            transition: all .2s .2s;
            pointer-events: none;

            &.open {
                opacity: 1;
                pointer-events: all;
                transition: all .2s 0s;
            }
        }

        .modal {
            .row {
                padding: 10px;

                &-half {
                    margin-bottom: 10px;
                    width: 50%;
                    float: left;
                }

                label {
                    font-size: 14px;
                    margin-bottom: 6px;
                    display: block;
                }
            }

            input[type=text] {
                padding: 14px 20px;
                font-weight: 600;
                width: calc(100% - 50px);
                border-radius: 10px;
                color: white;
                border: none;
                font-family: "Baloo 2", cursive;
                background: #00000024;
                outline: none;
                box-shadow: 0 0 0 0px #ffc215 inset;
                transition: all 0.3s;

                &:focus {
                    box-shadow: 0 0 0 3px #ffc215 inset;
                }
            }

            .b {
                padding: 11px;
                margin-top: 10px;
                clear: both;
                float: left;

                button {
                    color: #6d581e;
                    background: #f3c032;
                    border: 0;
                    border-radius: 10px;
                    font-size: 14px;
                    padding: 16px 24px;
                    font-weight: 700;
                    outline: none;
                    font-family: "Baloo 2", cursive;
                    position: relative;
                    float: left;
                    transition: all 0.3s;
                    cursor: pointer;

                    img {
                        mix-blend-mode: luminosity;
                    }

                    &.submitting {
                        padding-left: 46px;

                        img {
                            transform: scale(1);
                        }
                    }

                    &:nth-of-type(1) {
                        margin-right: 16px;

                        &:hover {
                            transform: scale(1.1);
                        }
                    }

                    &:nth-of-type(2) {
                        margin-right: 16px;
                        color: #ffffff;
                        background: transparent;
                        box-shadow: 0 0 0 3px inset white;

                        &:hover {
                            background: white;
                            color: $primary;
                        }
                    }

                    img {
                        transform: scale(0);
                        position: absolute;
                        left: 13px;
                        top: 13px;
                        height: 26px;
                        transition: all 0.3s 0.1s;
                    }
                }
            }
        }

        &_load {
            position: fixed;
            left: 0;
            right: 0;
            margin: auto;
            z-index: 10;
            transform: scale(0);
            height: 100%;
            width: 0;
            pointer-events: none;
            transition: all .3s 0s cubic-bezier(0.035, 1.495, 0.625, 0.890);


            &.open {
                transform: scale(1);
                pointer-events: all;
                transition: all .3s .2s cubic-bezier(0.035, 1.495, 0.625, 0.890);
            }

            h4 {
                color: $secondary;
            }

            .close {
                position: absolute;
                right: -24px;
                top: -24px;
                background: $primary;
                border-radius: 100px;
                width: 40px;
                height: 40px;
                line-height: 42px;
                text-align: center;
                border: 3px solid white;
                cursor: pointer;
                transition: all .3s;

                &:hover {
                    background: white;
                    color:  $primary;
                }
            }
            &__inner {
                position: fixed;
                left: 0;
                right: 0;
                margin: auto;
                z-index: 10;
                background: $primary;
                border: 3px solid white;
                width: 440px;
                border-radius: 20px;
                padding: 40px;
                font-weight: 600;
                top: 50%;
                transform: translateY(-50%) translateX(-50%);

                h1 {
                    margin: -10px 0px 0px 10px;
                }

                p {
                    margin: 0 0 20px 10px;
                }

                .delete,
                .load {
                    cursor: pointer;
                }

                .delete {
                    color: $secondary;
                }

                .s-wrap {
                    max-height: 315px;
                    overflow-x: hidden;
                    padding-right: 10px;
                    overflow-y: scroll;

                    /* width */
                    &::-webkit-scrollbar {
                        width: 4px;
                        border-radius: 10px;
                    }

                    /* Track */
                    &::-webkit-scrollbar-track {
                        background: rgba(0, 0, 0, 0.2); 
                    }

                    /* Handle */
                    &::-webkit-scrollbar-thumb {
                        background: $secondary; 
                        border-radius: 10px;
                    }

                    /* Handle on hover */
                    &::-webkit-scrollbar-thumb:hover {
                        //background: #555; 
                    }
                }

                .p3d_load__model {
                    overflow: hidden;
                    background: transparent;
                    border-radius: 10px;
                    padding: 10px;
                    transition: all .3s;
                    position: relative;

                    &:last-child {
                        &:not(.empty) {
                            margin-bottom: 0;
                        }
                    }

                    &:not(.empty) {
                        cursor: pointer;
                        &:hover {
                            background: rgba(0, 0, 0, 0.2);

                            .delete {
                                opacity: 1;
                                top: 0;
                            }
                        }
                    }

                    .m_image {
                        width: 35%;
                        float: left;
                        height: 142px;
                        overflow: hidden;
                        box-sizing: border-box;
                        border: 3px solid white;
                        border-radius: 10px;
                        background-size: 190% !important;
                        background-position: center center !important;

                        img {
                            width: 100%;
                            border-radius: 10px;
                            display: block;
                        }    
                    }

                    .m_details {
                        width: 50%;
                        float: left;
                        padding-left: 15px;
                        padding-top: 14px;

                        .load {
                            margin: 10px;
                            background: #ffc720;
                            position: absolute;
                            right: 10px;
                            top: 50%;
                            width: 40px;
                            height: 40px;
                            cursor: pointer;
                            transition: all .3s;
                            border-radius: 40px;
                            transform: scale(1);

                            &:hover {
                                transform: scale(1.1);
                            }

                            img {
                                position: relative;
                                left: 12px;
                                top: 8px;
                                opacity: 0.5;

                            }
                        }

                        .delete {
                            font-size: 14px;
                            opacity: 0;
                            transition: all .2s;
                            margin-top: 16px;
                            position: absolute;
                            right: 20px;
                            top: 10px;

                            &:hover {
                                text-decoration: underline;
                            }
                        }

                        p.name {
                            margin-bottom: 0px;
                            font-size: 22px;
                            margin-top: 8px;
                            text-transform: capitalize;
                        }

                        p.date {
                            margin-bottom: -6px;
                            font-size: 12px;
                            opacity: 0.3;
                            margin-top: 10px;
                        }

                        p.author {
                            font-size: 12px;
                            margin: -7px 0 7px 10px;
                        }

                        p.voxels {
                            margin-bottom: 0px;
                            font-size: 12px;

                            span {
                                color: $secondary;
                            }
                        }
                    }
                }
            }


            &.community {
                .p3d_load__inner {
                    width: 800px;
                }
                .p3d_load__model {
                    overflow: hidden;
                    background: transparent;
                    border-radius: 10px;
                    padding: 10px;
                    float: left;
                    transition: all 0.3s;
                    width: 244px;
                    position: relative;
                }

                .p_name {
                    margin-bottom: 1px;
                    font-size: 22px;
                    margin-top: 6px;
                    text-transform: capitalize;
                }
                .m_image {
                    width: 100%;
                    float: left;
                    height: 220px;
                }

                .m_details {
                    width: 100%;
                    float: left;
                    padding-left: 0;
                    padding-top: 24px;
                    margin-left: -10px;
                }

                .x-wrap {
                    width: 10000px;
                }

                .s-wrap {
                    max-height: 390px;
                    overflow-x: hidden;
                    padding-right: 0;
                    overflow-y: hidden;
                    overflow-x: scroll;
                    padding-bottom: 20px;
                }
            }
        }

        &_main {
            &_footer {
                position: absolute;
                bottom: 0;
                padding: 0 0 20px 50px;
                font-size: 12px;

                a {
                    color: $secondary;
                    font-weight: 700;
                }

                span {
                    opacity: 0.4;
                }
            }
            .help {
                font-size: 16px;
                font-weight: 700;
                margin-bottom: 14px;

                .icon {
                    width: 8px;
                    border: 2px solid white;
                    padding: 4px 6px;
                    border-radius: 20px;
                    transform: scale(0.7);
                    cursor: pointer;

                    &:hover {
                        & + div {
                            opacity: 1;
                            transform: translateY(0px);
                        }
                    }
                }

                .gif {
                    transition: transform 0.3s 0.2s cubic-bezier(0.035, 1.495, 0.625, 0.89), opacity 0.2s 0.2s;
                    opacity: 0;
                    position: absolute;
                    pointer-events: none;
                    width: 740px;
                    transform: translateY(20px);
                    z-index: 3;
                    top: 48px;
                    border: 3px solid white;
                    border-radius: 10px;
                    padding: 16px;
                    background: #151c29;

                    .desc {
                        width: 200px;
                        float: left;
                        padding: 30px;
                        line-height: 20px;


                        h4 {
                            margin: 0;
                            font-size: 20px;
                            margin-bottom: 10px;
                        }
                    }

                    img {
                        width: 480px;
                        display: block;
                        border-radius: 10px;
                        float: right;
                    }

                }
            }
            .button {
                line-height: 42px;
                border-radius: 10px;
                cursor: pointer;
                transition: all .3s;
                font-weight: 800;
                position: relative;
                height: 40px;



                img.icon {
                    transform: scale(1);
                    transition: all .1s .1s;

                    &.saving {
                        transition: all .1s 0s;
                        transform: scale(0);
                    }
                }

                img.loader {
                    transition: all .1s 0s;
                    position: absolute;
                    left: -4px;
                    height: 28px;
                    top: -3px;
                    transform: scale(0);

                    &.saving {
                        transition: all .1s .1s;
                        transform: scale(1);
                    }
                }

                &:hover {
                    & > .tooltip {
                        opacity: 1; 
                        top: -54px;

                        transition: all .3s .2s;
                    }
                }

                img {
                    margin: 9px 10px;
                    height: 20px;
                }

                & > .tooltip {
                    transition: all .23s 0s;
                    left: 0;
                    opacity: 0;
                    pointer-events: none;
                    top: -50px;
                    color: #25273E;
                    border-radius: 10px;
                    position: absolute;
                    background: white;
                    width: 140px;
                    font-size: 14px;
                    text-align: center;

                    &:after {
                        position: absolute;
                        width: 10px;
                        height: 10px;
                        background: white;
                        content: "";
                        margin: auto;
                        display: block;
                        left: 0;
                        bottom: -3px;
                        right: 0;
                        transform: rotate(45deg);
                    }
                }

                &:after,
                &:before {
                    border-radius: 10px;
                    position: absolute;
                    content: "";
                    width: 100%;
                    height: 100%;
                    background: rgb(0 0 0 / 30%);
                    top: 0;
                    left: 0;
                    z-index: -1;
                    transform: scale(0);
                    transition: all 0.3s cubic-bezier(0.035, 1.495, 0.625, 0.89);
                }

                &:before {
                    background: $secondary;
                }

                &.active {
                    &:before {
                        transform: scale(1);
                    }
                }

                &:not(.active):hover {
                    color: $secondary;

                    &:after {
                        transform: scale(1);
                    }
                }
            }

            &__header {
                padding: 40px;

                .header_left,
                .header_right {
                    width: 50%;
                    float: left;
                }

                .header_left {
                    width: 200px;
                }

                .header_right {
                    margin-top: 6px;
                    text-align: left;
                    width: calc(100% - 200px);
                    float: right;

                    .button {
                        width: 40px;
                        text-align: center;

                        &::before {
                            display: block;
                            content: "";
                            position: absolute;
                            height: 3px;
                            width: 0px;
                            background: $secondary;
                            z-index: 1;
                            left: 5px;
                            border-radius: 10px;
                            top: 17px;
                            transform: scale(1);
                        }

                        &.active {
                            img {
                                opacity: 0.5;
                            }
                            &::before {
                                width: 30px;
                            }
                        }
                    }

                    @keyframes pulse {
                        from {box-shadow: 0 0 0 0 rgba(243, 192, 50, 1)}
                        to {box-shadow: 0 0 0 12px rgba(243, 192, 50, 0)}
                    }

                    .buttons {
                        float: left;

                        .community {
                            background: #f3c032;
                            width: 120px;
                            position: relative;
                            font-size: 15px;
                            height: 44px;
                            line-height: 46px;
                            top: -14px;
                            color: #504014;
                            margin-left: 10px;
                            transform: scale(1);
                            transition: all .3s;

                            animation: pulse 1.3s infinite;

                            &::after,
                            &::before {
                                display: none;
                            }
                            &:hover {
                                background: #ffbc00;
                                transform: scale(1.05);
                            }
                        }
                    }

                    .options {
                        float: right;
                    }

                    input {
                        float: left;
                        width: 300px;
                        font-family: 'Baloo 2', cursive;
                        background: transparent;
                        font-weight: 700;
                        color: white;
                        border: 0;
                        border-bottom: 2px solid white;
                        outline: none;
                        padding: 0 0 8px 0;
                        margin-right: 16px;
                    }

                    .button {
                        display: inline-block;

                        &:hover {
                            .tooltip {
                                bottom: -50px;
                            }
                        }

                        .tooltip {
                            left: -20px;
                            width: 80px;
                            top: auto;
                            bottom: -44px;

                            &:after {
                                bottom: auto;
                                top: -3px;
                            }
                        }


                    }
                }
            }

            &__editor {
                height: 100px;
                width: 1300px;
                margin: 0 auto;
                position: absolute;
                left: 0;
                right: 0;
                top: 50%;
                transform: translateY(-50%) scale(1);
                height: 600px;

                @for $i from 1 through 40 {
                 @media only screen and (max-height: #{970 - ($i * 8)}px) {
                     transform: translateY(-50%) scale(calc(1 - (0.007 * #{$i})));
                   }
                 }

                .editor {
                    &_right {
                        width: 35%;
                        float: right;
                        position: relative;

                        &__export {
                            opacity: 0;
                            pointer-events: none;
                            float: left;
                            position: absolute;
                            padding-left: 70px;
                            padding-top: 70px;
                            transition: all .1s 0s;

                            .buttons {
                                clear: both;
                                float: left;
                                margin-top: 30px;
                            }

                            input[type="text"] {
                                padding: 14px 20px;
                                font-weight: 600;
                                border-radius: 10px;
                                color: white;
                                border: none;
                                font-family: 'Baloo 2', cursive;
                                background: #00000024;
                                outline: none;
                                box-shadow: 0 0 0 0px #ffc215 inset;
                                transition: all .3s;

                                &:focus {
                                    box-shadow: 0 0 0 3px #ffc215 inset
                                }
                            }

                            input {
                                margin-top: 8px;
                            }

                            p.sub {
                                margin: -17px 0 16px 0px;
                                font-size: 14px;
                                line-height: 20px;
                                font-weight: 500;
                                opacity: 0.5;
                            }

                            button
                            {
                                color: #6d581e;
                                background: #f3c032;
                                border: 0;
                                border-radius: 10px;
                                font-size: 14px;
                                padding: 16px 19px;
                                font-weight: 700;
                                outline: none;
                                font-family: "Baloo 2", cursive;
                                float: left;
                                transition: all .3s;
                                cursor: pointer;
                                animation: pulse 1.3s infinite;

                                &:hover {
                                    background: #ffbc00;
                                }
                            }

                            input[type="submit"] {
                                opacity: 0;
                                position: absolute;
                                left: -10000px;
                                top: -1000000px;
                            }

                            button.cp {
                                margin-top: 0px;
                                margin-left: 16px;
                                background: #694a7d;
                                color: #fff;
                                position: relative;
                                animation: none;

                                img {
                                    transform: scale(0);
                                    position: absolute;
                                    left: 13px;
                                    top: 13px;
                                    height: 26px;
                                    transition: all .3s .1s;
                                }

                                &.exporting {
                                    padding-left: 46px;

                                    img {
                                        transform: scale(1);
                                    }
                                }

                                &:hover {
                                    background: #8f4db9;
                                }
                            }

                            .row {
                                margin-bottom: 8px;
                                position: relative;
                                clear: both;
                                float: left;
                                transition: all .3s;

                                &.inactive {
                                    opacity: 0.4;
                                    pointer-events: none;
                                }

                                .sp-replacer + img {
                                    height: 15px;
                                    opacity: 0.2;
                                    cursor: pointer;
                                    position: relative;
                                    transition: all 0.3s;
                                    top: 5px;

                                    &.hide {
                                        opacity: 0;   
                                    }

                                    &:hover {
                                        opacity: 1;
                                    }
                                }

                                &-half {
                                    float: left;
                                    width: 50%;


                                    input {
                                        width: calc(100% - 50px);
                                    }

                                    input[type='range'] {
                                        width: calc(100% - 22px) !important;
                                    }

                                    & + .save {
                                        position: absolute;
                                        right: -50px;
                                        top: 44px;
                                        width: 40px;

                                        .tooltip {
                                            left: -19px;
                                            width: 80px;
                                        }
                                    }
                                }

                                input[type='checkbox'] {
                                    margin-top: 8px;
                                    appearance: none;
                                    width: 20px;
                                    height: 20px;
                                    margin-left: -1px;
                                    border-radius: 7px;
                                    border: 3px solid white;
                                    outline: none;
                                    cursor: pointer;
                                    overflow: hidden;
                                    position: relative;

                                    &::after {
                                        display: block;
                                        content: "";
                                        width: 8px;
                                        height: 8px;
                                        left: 3px;
                                        top: 3px;
                                        border-radius: 2px;
                                        background: #E5513A;
                                        position: absolute;
                                        transition: all 0.3s cubic-bezier(0.035, 1.495, 0.625, 0.89);
                                        transform: scale(0);
                                    }

                                    &:checked {
                                        &::after {
                                            transform: scale(1);
                                        }
                                    }
                                }

                                input[type='range'] {
                                    overflow: hidden;
                                    height: 6px;
                                    border-radius: 10px;
                                    outline: none;
                                    width: 200px;
                                    -webkit-appearance: none;
                                    background-color: rgba(0, 0, 0,  0.3);
                                }

                                input[type='range']::-webkit-slider-runnable-track {
                                    height: 10px;
                                    -webkit-appearance: none;
                                    color: #13bba4;
                                    margin-top: -1px;
                                }

                                input[type='range']::-webkit-slider-thumb {
                                    width: 10px;
                                    -webkit-appearance: none;
                                    height: 10px;
                                    cursor: ew-resize;
                                    background: #fff;
                                    box-shadow: -180px 0 0 180px $secondary;
                                }


                                label {
                                    display: block;
                                    font-weight: 700;
                                    font-size: 14px;
                                    display: block;
                                    margin-top: 10px;

                                    span {
                                        // color: $secondary;
                                        font-weight: 700;

                                        span {
                                            font-size: 12px;
                                            font-weight: 500;
                                            opacity: 0.3;
                                        }

                                    }
                                }
                            }

                            &.show {
                                opacity: 1;
                                pointer-events: all;
                                transition: all .3s .2s;
                            }
                        }

                        #colorBg {
                            & + div {
                                opacity: 1;
                                transition: all .29s;
                            }

                            &.hide {

                                & + div {
                                    opacity: 0;
                                    pointer-events: none;
                                }
                            }
                        }
                        p {
                            font-weight: 700;
                            margin: 10px 0px 20px 40px;
                            opacity: 1;
                            transition: all .2s;
                            transform: translateY(0px);


                            &.hide {
                                transform: translateY(-12px);
                                opacity: 0;
                            }
                            & + img {
                                position: absolute;
                                right: 59px;
                                top: 19px;
                                height: 15px;
                                opacity: 0.2;
                                cursor: pointer;
                                transition: all .3s;

                                &.hide {
                                    opacity: 0;   
                                }

                                &:hover {
                                    opacity: 1;
                                }
                            }
                        }

                        p.voxelCount {
                            clear: both;
                            float: right;
                            position: absolute;
                            top: 476px;
                            left: 0px;
                            font-size: 14px;
                            transform: translateY(0px);
                            transition: all .2s .2s;

                            &.hide {
                                transition: all .002s;
                                pointer-events: none;
                            }

                            span {
                                color: $secondary;

                                &.block {
                                    opacity: 0;
                                    color: rgba(255, 255, 255, 0.5);
                                    font-size: 12px;
                                    display: block;
                                    font-weight: 400;
                                    margin-top: 10px;

                                    &.show {
                                        opacity: 1;
                                    }

                                    img {
                                        width: 16px;
                                        margin-top: -1px;
                                        margin-right: 9px;
                                        position: relative;
                                        top: 3px;
                                        margin-bottom: 13px;
                                        float: left;

                                    }
                                }
                            }
                        }



                        #colorBg + div ,
                        #exportBg + div {
                            position: absolute;
                            right: -6px;
                            top: 10px;
                            border: 0;
                            background: transparent;

                            .sp-preview {
                                position: relative;
                                width: 25px;
                                height: 20px;
                                border: solid 3px #fff;
                                margin-right: 8px;
                                border-radius: 6px;
                                float: left;
                                z-index: 0;
                            }

                            .sp-preview-inner {
                                border-radius: 3px;
                            }

                            .sp-dd {
                                padding: 6px 0;
                                height: 20px;
                                line-height: 12px;
                                float: left;
                                color: white;
                                font-size: 10px;
                                transform: scaleY(.6);
                            }
                        }

                        #exportBg + div {
                            margin-top: 8px;
                            position: static   
                        }

                        &__preview {
                            box-shadow: 0 0 0 3px inset white;
                            background: $primary;
                            height: 415px;
                            width: 415px;
                            left: calc(65% + 40px);
                            float: right;
                            border-radius: 14px;
                            z-index: 1;
                            position: fixed;
                            transition: all .3s cubic-bezier(0.035, 1.495, 0.625, 0.890);



                            &.export {
                                position: fixed;
                                width: calc(100% - 460px);
                                left: 20px;
                                height: calc(100% + 34px);
                            }

                            &.paint {
                                position: fixed;
                                width: calc(100% - 210px);
                                left: 210px;
                                height: calc(100% + 34px);
                            }

                            // Return the true px size of a voxel based on the passed unit.
                            @function getVoxelSize($size, $operator) {
                                @return unquote($operator + $size * $voxelSize + px);    
                            }

                            // Function to set the orientation of a side
                            @function setFaceOrientation($tx, $ty, $tz, $sx, $sy, $rx, $ry, $rz) {
                                @return rotateX($rx + deg) rotateY($ry + deg) rotateZ($rz + deg) scaleX($sx) scaleY($sy) translate3d(unquote($tx + ',' + $ty + ',' + $tz)); 
                            }

                            .p_inner {
                                position: absolute;
                                left: 3px;
                                top: 3px;
                                overflow: hidden;
                                width: calc(100% - 6px);
                                height: calc(100% - 6px);
                                border-radius: 10px;

                                .button.zooms {
                                    background: #25273E;
                                    display: block;
                                    color: #fff;
                                    border: 0;
                                    float: right;
                                    margin: 4px 18px;
                                    width: 30px;
                                    clear: both;
                                    text-align: center;
                                    height: 30px;
                                    line-height: 28px;
                                    position: relative;
                                    z-index: 2;
                                    transform: scale(1);
                                    transition: all 0.2s;

                                    img {
                                        margin: 5px 1px;
                                        width: 16px;
                                    }

                                    &.hide {
                                        opacity: 0;
                                        pointer-events: none;
                                    }

                                    &:hover {
                                        transform: scale(1.1);
                                    }

                                    &:after,
                                    &:before {
                                        display: none;
                                    }

                                    &.first {
                                        margin-top: 19px;
                                    }
                                }

                                .views {
                                    position: absolute;
                                    top: 12px;
                                    left: 15px;
                                    z-index: 1;
                                    padding: 0 4px;

                                    &.show {
                                        background: $primary;
                                        border-radius: 10px;

                                        .button {
                                            opacity: 1;
                                            transform: translateY(0px);



                                            @for $i from 1 through 14 {
                                                &:nth-of-type(#{$i}) {
                                                    transition:  color .3s, transform .5s ($i - 1) / 20 + .2s, opacity .5s ($i - 1) / 20 + .2s;

                                                }
                                            }
                                        }
                                    }

                                    .button {
                                        font-size: 15px;
                                        display: inline-block;
                                        margin: 0 10px;
                                        transition: all .3s;
                                        opacity: 0;
                                        transform: translateY(16px);

                                        @for $i from 1 through 14 {
                                            &:nth-of-type(#{$i}) {
                                                transition: color .3s, transform .0s ($i - 1) / 1222 + 0s, opacity .0s ($i - 1) / 1222 + 0s;

                                            }
                                        }

                                        &.active {
                                            color: $secondary;
                                        }

                                        &:after,
                                        &:before {
                                            display: none;
                                        }

                                    }
                                }

                                .resetZoom {
                                    position: absolute;
                                    z-index: 1;
                                    right: 10px;
                                    top: 8px;
                                }

                                .spin {
                                    position: absolute;
                                    z-index: 1;
                                    right: 10px;
                                    bottom: 8px;
                                }

                                .exportWrap {
                                    height: 100%;
                                    transform-origin: 50% 365px;
                                    transform-style: preserve-3d;
                                }

                                .zoom {
                                    transform: scale(1);
                                    transform-origin: 50% calc(50% + -60px);
                                    height: 415px;
                                    transition: all .3s;

                                }

                                .model {
                                    position: absolute;
                                    left: -3px;
                                    top: -96px;
                                    width: 415px;
                                    height: 140px;
                                    transform-style: preserve-3d;
                                    transition: all .3s cubic-bezier(0.035, 1.495, 0.625, 0.890);
                                    transform: rotateY(90deg) rotateZ(0) rotatex(0deg);
                                    transform-origin: 50% calc(905px / 2) calc(370px / 2);

                                    .f {
                                        @for $v from 1 through 6 {
                                            $width: 1;
                                            $height: 1;
                                            $depth: 1;

                                            &--f {
                                                transform: setFaceOrientation(0, 0, getVoxelSize($depth / 2, ''), $height, $width, 0, 90, 0);
                                            }

                                            &--ba {
                                                transform: setFaceOrientation(0, 0, getVoxelSize($depth / 2, '-'), $height, $width, 0, 90, 0);
                                            }

                                            &--t {
                                                transform: setFaceOrientation(0, 0, getVoxelSize($height / 2, ''), $depth, $width, 0, 0, 0);
                                            }

                                            &--b {
                                                transform: setFaceOrientation(0, 0, getVoxelSize($height / 2, '-'), $depth, $width, 0, 0, 0);
                                            }

                                            &--l {
                                                transform: setFaceOrientation(0, 0, getVoxelSize($width / 2, ''), $depth, $height, 90, 0, 0);
                                            }

                                            &--r {
                                                transform: setFaceOrientation(0, 0, getVoxelSize($width / 2, '-'), $depth, $height, 90, 0, 0);
                                            }
                                        }

                                        &.paintable {
                                            cursor: pointer;
                                            box-shadow: 0 0 0 0px $secondary inset;
                                            transition: all .3s;

                                            &:hover {
                                                box-shadow: 0 0 0 4px $secondary inset;
                                            }
                                        }
                                    }

                                    &.export,
                                    &.paint {
                                        position: fixed;
                                        width: calc(100% + -60px);
                                        left: 0;
                                        height: calc(100% + 10px);
                                    }

                                    &.export {
                                        width: calc(100%);
                                    }

                                    &.spin {
                                        animation: spin 6s infinite linear;
                                    }

                                    &.extrude {
                                        transform: scale(.8) rotateX(-30deg) rotateY(140deg) rotateZ(0deg);
                                        top: -144px;
                                    }

                                    @keyframes spin {
                                        from { transform: scale(1) rotateY(140deg) rotateZ(0deg) rotatex(0deg);}
                                        to { transform: scale(1) rotateY(500deg) rotateZ(0deg) rotatex(0deg);}
                                    }

                                    %voxel {
                                        position: absolute;
                                        top: 50%;
                                        transform-style: preserve-3d;
                                        left: 0;
                                        right: 0;
                                        margin: auto;
                                        width: 10px;
                                    }

                                    %face {
                                        width: $voxelSize + px;
                                        height: $voxelSize + px;
                                        position: absolute;
                                        transform-style: preserve-3d;
                                        transform-origin: 50% 50%;
                                        background: transparent; // Default color
                                    }

                                    .voxel,
                                    .voxel-group {
                                        @extend %voxel;
                                    }

                                    .v {

                                        @extend %voxel;
                                        & .f {
                                            @extend %face;
                                        }
                                    }

                                    // Utility classes

                                    // Colors
                                    $colors: [#de2b14, #d5713f, #ffda25, #2c4c35, #503d1f];

                                    @each $color in $colors {
                                        $class: #{$color};
                                        $class: unquote(str_slice($class, 2));

                                        .c-#{$class} {
                                            .f {
                                                @for $i from 1 through 6 {
                                                    &:nth-of-type(#{$i}) {
                                                        background-color: mix(white, $color, ($i - 1) * $shadingMixTolerance);
                                                    }
                                                }
                                            }
                                        }
                                    }

                                    @for $x from 0 through $maxX {
                                        @for $y from 0 through $maxY {
                                            .x-#{$x}.y-#{$y} {
                                                transform: translateZ(getVoxelSize($x - 1, '')) translateY(getVoxelSize($y - 1, ''));
                                            }
                                        }
                                    }

                                    // Depths
                                    // This can be done on a normal loop as depth will be limited



                                    @for $i from 1 through $maximumDepth {
                                        .d-#{$i} {
                                            transform: translateX(23px * $i)
                                        }

                                        .g-#{$i} {
                                            transform: translateX(-23px * ($i / 2))
                                        }
                                    }
                                }
                            }
                        }
                    }

                    &_left {
                        width: 65%;
                        float: left;

                        &__header {
                            width: 634px;
                            transition: all .3s 0s;
                            float: right;
                            position: relative;
                            left: 0;

                            &.export {

                                left: -196px;
                                z-index: 2;
                            }

                            .e_buttons {
                                float: right;
                                position: relative;
                                display: block;

                                &.hide {
                                    .button {
                                        opacity: 0;
                                        transform: translateY(0px);

                                        @for $i from 1 through 5 {
                                            &:nth-of-type(#{$i}) {
                                                transition: transform .3s ($i - 1) / 30 + 0s, opacity .2s ($i - 1) / 30 + 0s;
                                                transform: translateY(-30px);
                                            }
                                        }
                                    }
                                }

                                .button {
                                    display: inline-block;
                                    width: 40px;

                                    img {
                                        width: 20px;
                                        position: relative;
                                        top: 1px;
                                        left: 1px;
                                    }

                                    &:nth-of-type(1) {
                                        img {
                                            top: 0px;
                                            left: 0px;
                                        }
                                    }

                                    .tooltip {
                                        left: -50px;
                                    }

                                    @for $i from 1 through 5 {
                                        &:nth-of-type(#{$i}) {
                                            transition: transform .3s ($i - 1) / 30 + .3s, opacity .2s ($i - 1) / 30 + .3s;
                                        }
                                    }
                                }
                            }

                            .e_tabs {
                                float: left;

                                &__tab {
                                    display: inline-block;
                                    margin-bottom: 16px;
                                    margin-right: 8px;
                                    padding-left: 12px;
                                    padding-right: 12px;
                                    width: 64px;
                                    text-align: center;

                                    .tooltip {
                                        left: -25px;
                                    }
                                }
                            }
                        }

                        &__main {
                            .m {
                                &_palette {
                                    float: left;
                                    width: 211px;
                                    transform: translateX(0px);
                                    position: relative;
                                    z-index: 1;
                                    transition: transform .3s .2s cubic-bezier(0.035, 1.495, 0.625, 0.890), opacity .2s .2s;

                                    .cPicker {
                                        position: absolute;
                                        border: 3px solid white;
                                        border-radius: 7px;
                                        height: 24px;
                                        width: 24px;
                                        line-height: 30px;
                                        right: 42px;
                                        cursor: pointer;
                                        z-index:1;
                                        text-align: center;
                                        bottom: 36px;

                                        svg {
                                            height: 14px;
                                        }

                                        &.active {
                                            svg path {
                                                fill: $secondary;
                                            }
                                        }

                                        svg path {
                                            fill: white;
                                        }    
                                    }

                                    .buttons {
                                        margin: 51px 0 10px 16px;
                                    }

                                    .button {
                                        display: inline-block;
                                        margin: 5px;

                                        .tooltip {
                                            left: -50px;
                                        }
                                    }

                                    &.palette--depth {
                                        .hollowTip {
                                            position: absolute;
                                            width: 140px;

                                            .button {
                                                width: 40px;
                                                text-align: center;
                                            }

                                            p {
                                                font-size: 13px;
                                                color: $secondary;
                                                margin: 10px 0 0 6px;
                                            }
                                        }

                                        .dpgrid,
                                        .hollowTip{
                                            opacity: 1;
                                            transform: translateY(0);
                                            transition: transform .3s 0s cubic-bezier(0.035, 1.495, 0.625, 0.890), opacity .2s 0s;

                                            &.hide {
                                                transform: translateY(20px);
                                                opacity: 0;
                                                pointer-events: none;
                                            }
                                        }

                                        .hollowTip {
                                            transition: transform .3s .2s cubic-bezier(0.035, 1.495, 0.625, 0.890), opacity .2s .2s;

                                            &.hide {
                                                transition: transform 0s 0s cubic-bezier(0.035, 1.495, 0.625, 0.890), opacity 0s 0s;
                                            }
                                        }

                                        .dp-outer {
                                            width: 150px;
                                            padding-left: 15px;
                                            margin-top: 52px;
                                        }

                                        .dp {
                                            width: 40px;
                                            height: 40px;
                                            margin: 5px;
                                            border-radius: 10px;
                                            box-shadow: 0 0 0 3px white inset;
                                            text-align: center;
                                            float: left;
                                            position: relative;
                                            cursor: pointer;
                                            line-height: 42px;
                                            font-weight: 700;
                                            transition: all .2s;

                                            &:not(.active):hover {
                                                transform: scale(1.1);
                                                color: $primary;
                                                background: white;
                                            }

                                            &.active {
                                                color: $primary;
                                                background: white;
                                            }
                                        }
                                    }

                                    &.hide {
                                        opacity: 0;
                                        pointer-events: none;
                                        transform: translateX(-40px);
                                        position: absolute;
                                        transition: transform .3s 0s cubic-bezier(0.035, 1.495, 0.625, 0.890), opacity .2s 0s;
                                    }


                                }

                                &_grid {
                                    width: 634px;
                                    box-shadow: 0 0 0 3px inset white;
                                    border-radius: $borderRadius;
                                    overflow: hidden;
                                    transition: opacity 0.3s .1s;
                                    opacity: 1;
                                    position: relative;

                                    .helper-x {
                                        width: 316px;
                                        height: 640px;
                                        border-right: 2px dashed rgb(255 255 255 / 8%);
                                        position: absolute;
                                        pointer-events: none;
                                        transition: all .3s;
                                        z-index: 1;

                                        &.active {
                                            border-right: 2px dashed $secondary;
                                        }
                                    }

                                    .helper-y {
                                        width: 640px;
                                        height: 316px;
                                        border-bottom: 2px dashed rgb(255 255 255 / 8%);
                                        position: absolute;
                                        pointer-events: none;
                                        transition: all .3s;
                                        z-index: 1;

                                        &.active {
                                            border-bottom: 2px dashed $secondary;
                                        }
                                    }

                                    &.loading {
                                        width: 633px;
                                        height: 633px;

                                        img.loader {
                                            transform: translateY(-50%) scale(1);
                                        }
                                    }

                                    img.loader {
                                        position: absolute;
                                        left: 0;
                                        right: 0;
                                        margin: auto;
                                        width: 30px;
                                        z-index: 1;
                                        top: 50%;
                                        transform: translateY(-50%) scale(0);
                                        transition: all 0.3s 0s cubic-bezier(0.035, 1.495, 0.625, 0.89);

                                    }

                                    &.hide {
                                        opacity: 0;
                                        transition: opacity 0.3s 0s;
                                    }

                                    &__pixel {
                                        box-shadow: 0 0 0 1px inset rgba(255, 255, 255, 0.1);
                                        float: left;
                                        position: relative;
                                        cursor: pointer;
                                        width: 37.2px;
                                        height: 37.2px;
                                        
                                        &:after {
                                            display: block;
                                            content: '';
                                            position: absolute;
                                            width: 100%;
                                            height: 100%;
                                            box-shadow: 0 0 0 3px #fff;
                                            border-radius: 5px;
                                            z-index: 2;
                                            pointer-events: none;
                                            opacity: 0;
                                            transition: all .01s;
                                        }

                                        &:hover {
                                            &:after {
                                                opacity: 1;
                                            }
                                        }

                                        .p {
                                            position: absolute;
                                            pointer-events: none;
                                            width: 100%;
                                            height: 100%;
                                            left: 0;
                                            top: 0;
                                        }

                                        .d {
                                            position: absolute;
                                            width: 100%;
                                            text-align: center;
                                            top: 50%;
                                            transform: translateY(-50%);
                                            display: none;
                                            color: black;
                                            font-weight: 700;
                                            font-size: 16px;
                                            pointer-events: none;



                                            &.show {
                                                display: block;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
              
            
!

JS

              
                /*
    Dependencies
    https://codepen.io/jcoulterdesign/pen/1e3ed378fed68f1a43bc4f73f9964945
    https://codepen.io/jcoulterdesign/pen/6c44bfdc74442457826e062bc719c586
    https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js
    https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js
    https://cdnjs.cloudflare.com/ajax/libs/spectrum/1.8.1/spectrum.js
    https://cdnjs.cloudflare.com/ajax/libs/dom-to-image/2.6.0/dom-to-image.min.js
*/

// Master audio array. This is for audio that will not be manipulated by any HTML5 filters.
// For audio needing low, high pass effects, add them to the _specialAudio array.
const _masterAudio = [
    {
        'name'   : 'pop1',
        'source' : 'https://assets.codepen.io/217233/p3d_pop1_t.mp3',
        'stack' : 15
    },
    {
        'name'   : 'pop2',
        'source' : 'https://assets.codepen.io/217233/p3d_pop2_t.mp3',
        'stack' : 15
    },
    {
        'name'   : 'pop3',
        'source' : 'https://assets.codepen.io/217233/p3d_pop3_t.mp3',
        'stack' : 3
    },
    {
        'name'   : 'pop4',
        'source' : 'https://assets.codepen.io/217233/p3d_pop4_t.mp3',
    },

    {
        'name'   : 'pop5',
        'source' : 'https://assets.codepen.io/217233/p3d_pop5_t.mp3',
    },

    {
        'name'   : 'pop6',
        'source' : 'https://assets.codepen.io/217233/p3d_pop7.mp3',
    },
    {
        'name'   : 'save',
        'source' : 'https://assets.codepen.io/217233/p3d_save.wav',
    }
];

const enJin = new EnJin();

// Create audio controller
enJin.createAudioController();
enJin.audioController.load(_masterAudio);

// Voxel
// Class containing all our volxel data including its position and vertex information
// This technically represents a voxel group as well, as vue renders out a voxel for each entry in the colors array
class Voxel {
    constructor(x, y, depth, color, index) {
        this.x = x;
        this.y = y;
        this.d = depth;
        this.h = false;
        this.c = [ // Color array for each side of the voxel
            {
                0: lightenDarkenColor(color, 0),
                1: lightenDarkenColor(color, -5),
                2: lightenDarkenColor(color, -10),
                3: lightenDarkenColor(color, -15),
                4: lightenDarkenColor(color, -20),
                5: lightenDarkenColor(color, -25)
            }
        ]
        this.index = index;
    }
}

// Lighten darken any hex color by amt
function lightenDarkenColor(col, amt) {
    col = col.replace(/^#/, '')
    if (col.length === 3) col = col[0] + col[0] + col[1] + col[1] + col[2] + col[2]
    let [r, g, b] = col.match(/.{2}/g);
    ([r, g, b] = [parseInt(r, 16) + amt, parseInt(g, 16) + amt, parseInt(b, 16) + amt])
    r = Math.max(Math.min(255, r), 0).toString(16)
    g = Math.max(Math.min(255, g), 0).toString(16)
    b = Math.max(Math.min(255, b), 0).toString(16)
    const rr = (r.length < 2 ? '0' : '') + r
    const gg = (g.length < 2 ? '0' : '') + g
    const bb = (b.length < 2 ? '0' : '') + b

    return `${rr}${gg}${bb}`
}

// Rot13 function. Not critical to ser but used as a way of tracking what has been made with the tool
// If I added a unique string to this CodePen, which then passes it on to the exported pen, I could use the search to find all the models exported with this tool. The
// issue ofcourse is that the string would also exist on this pen, and so i would be supplied with all the forks. Doing it with a simple rot13 means the string will
// appear only on the exported pen.
function rot13(str) {
    var input     = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    var output    = 'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm';
    var index     = x => input.indexOf(x);
    var translate = x => index(x) > -1 ? output[index(x)] : x;
    return str.split('').map(translate).join('');
}

// Vue app
new Vue({
    el: '.p3d',

    data() {
        return {
            gridElement       : '.m_grid',
            voxelElement      : '.m_grid__pixel',
            canvasSize        : 17, // In voxel units
            voxels            : [],
            currentColor      : 'fff',
            currentDepth      : 1,
            mode              : 'drawing',
            drawMode          : 'draw',
            drawing           : false,
            author            : 'VoCSSels',
            zoomLevel         : .8, // Initial zoom level of our models preview
            maxZoom           : 3, // The maximum you can zoom in 
            minZoom           : .3, // The maximum you can zoom out
            orientation       : '',
            orientationButton : 'front',
            savedModels       : '',
            savedModelsMeta   : '',
            loading           : false,
            saving            : false,
            shell             : true,
            exporting         : false,
            motion            : true,
            muted             : false,
            exportSettings: {
                'name'        : 'My VoCSSel model',
                'perspective' : 3000,
                'bgColor'     : '#25273E',
                'scale'       : 1,
                'uid'         : 'madewithvocssels',
                'spinSpeed'   : 10,
                'animate'     : true,
                'x'           : 0,
                'y'           : 90,
                'z'           : 0
            },
            metaPrefix        : 'p3d_metadata_',
            modelPrefix       : 'p3d_modeldata_',
            modal             : '',
            modalOpen         : false,
            symMode           : '',
            picker: {
                'x'      : 0,
                'y'      : 0,
                'active' : false,
                'color'  : 'ffffff'
            },
            submitting       : false,
            submitted        : false,
            communityContent : []
        }
    },

    methods: {
        // Main draw function. Name is deceiving. Handles all interaction with pixels such as colour depth and shell
        // debounced
        drawPixel: _.debounce(function(event) {

            event.stopPropagation();

            let target = event.target;
            let data = $(target).data(); // Get pixel data
            let x = data.x; // Get pixel column
            let y = data.y; // Get pixel row
            let index = data.index; // Get index of pixel

            if(event.which == 3 && this.mode == "drawing") {
                this.drawMode = 'erase'
            }

            var v = _.get(this.voxels[index], 'c[0][0]', 'undefined');

            if(v != 'undefined') {
                this.picker.color = this.voxels[index].c[0][0]
            }

            // Fire when in drawing mode and not picking a colour
            if(this.mode == 'drawing' && this.drawing && !this.picker.active) {

                // Set colorpicker to current color
                $("#colorPicker").spectrum("set", this.currentColor);

                // Create a new voxel instance
                if(this.drawMode == 'draw') {

                    // If the user is currently in draw mode using draw
                    var v = _.isEmpty(this.voxels[index].c);
                    if(v) {
                        // If no voxel, make one and store in array
                        var voxel = new Voxel(x, y, 1, this.currentColor, index);   

                        // Vue set to keep reactive
                        Vue.set(this.voxels, index, voxel);

                        // Play audio
                        enJin.audioController.play('pop1');
                    } else {

                        // If the pixel we clicked on already has a voxel associated with it
                        // Firstly, set the color array to empty
                        let v = _.get(this.voxels[index], 'c', 'undefined');

                        if(v != 'undefined') {
                            this.voxels[index].h = false
                            _.omit(this.voxels[index], 'd')




                            // Generate each voxel (colour group)
                            this.generateColors(index);

                            // Only play a sound if the colour is different

                            enJin.audioController.play('pop1')
                        }

                    }
                } else {
                    // If not in draw mode, then we must be in erase mode
                    if(this.voxels[index].c != []) { // No point deleting nothing
                        // Set the voxel back to an empty array
                        Vue.set(this.voxels, index, []);

                        // Play audio
                        enJin.audioController.play('pop2');
                    }
                }
                // If we are not in drawing mode, then check if in extrude mode
            } else if(this.mode == 'extrude' && this.drawing) {

                // Check if extruding and not shelling
                if(this.drawMode == 'extrude') {

                    // Check to make sure the selected extrusion is not on a voxel that doesnt exist
                    var v = _.get(this.voxels[index], 'c', 'undefined');

                    if(v != 'undefined') {
                        // Start extrude
                        // Set the d property of the voxel to the selected depth
                        this.voxels[index].d = this.currentDepth;

                        // Reset any shell props on the voxel
                        this.voxels[index].h = false;

                        // Generate each voxel (colour group)
                        this.generateColors(index);

                        // play audio
                        enJin.audioController.play('pop2')
                    }
                } else {
                    // If not extrude, then must be hollow
                    var v = _.get(this.voxels[index], 'c', 'undefined');

                    if(v != 'undefined') {

                        // If shell is on
                        if(this.shell == true) {
                            // Check to make sure the selected extrusion is not on a voxel that doesnt exist
                            var v = _.get(this.voxels[index], 'c', 'undefined');

                            if(v != 'undefined') {
                                // set the voxels hollow prop to true
                                this.voxels[index].h = true;

                                // Get ctx
                                that = this;    

                                var length = this.voxels[index].c.length;
                                let color = this.voxels[index].c[0][0];

                                let shelledColors = [];

                                for(let i = 0; i < length; i++) {
                                    if(i == 0 || i == (length - 1)) {

                                        var s = {
                                            0: lightenDarkenColor(color, 0),
                                            1: lightenDarkenColor(color, -5),
                                            2: lightenDarkenColor(color, -10),
                                            3: lightenDarkenColor(color, -15),
                                            4: lightenDarkenColor(color, -20),
                                            5: lightenDarkenColor(color, -25)
                                        }

                                        } else {
                                            var s = '';
                                        }

                                    shelledColors.push(s)   
                                }

                                Vue.set(this.voxels[index], 'c', shelledColors);
                            }

                        } else {
                            // If shell is off
                            // Check to make sure the selected extrusion is not on a voxel that doesnt exist
                            var v = _.get(this.voxels[index], 'c', 'undefined');

                            if(v != 'undefined') {
                                // set the voxels hollow prop to false
                                this.voxels[index].h = false

                                // Generate each voxel (colour group)
                                this.generateColors(index);
                            }

                        }

                        // Play audio only if the voxel is shelled
                        if(this.voxels[index].h) {
                            enJin.audioController.play('pop4') ;
                        }
                    }
                }
            }
        }, 1),

        generateColors(voxel) {

            var v = _.get(this.voxels[voxel], 'c[0][0]', 'undefined');

            if(v != 'undefined') {

                if(this.mode == 'extrude') {
                    var color = this.voxels[voxel].c[0][0];
                } else {
                    var color = this.currentColor;
                }

                // Then set all colours to [].
                this.voxels[voxel].c = [];

                // Now create an empty object for our colours
                let newColours = [];

                // Loop through and create colours for each voxel
                for(let i = 0; i < this.currentDepth; i++) {
                    let colours = {
                        0: lightenDarkenColor(color, 0),
                        1: lightenDarkenColor(color, -5),
                        2: lightenDarkenColor(color, -10),
                        3: lightenDarkenColor(color, -15),
                        4: lightenDarkenColor(color, -20),
                        5: lightenDarkenColor(color, -25)
                    }
                    // Add colours to array
                    newColours.push(colours);
                }

                // Push this array to the voxel
                Vue.set(this.voxels[voxel], 'c', newColours);
            }
        },

        paint: _.debounce(function(event) {
            let target = event.target;
            let index = $(target).closest('.voxel-group').data().index // Get index of pixel
            let voxelIndex = $(target).parent().data().index // Get index of pixel
            let vertexIndex = $(target).data().vertex // Get index of pixel

            enJin.audioController.play('pop1');
            Vue.set(this.voxels[index].c[voxelIndex], vertexIndex, this.currentColor);
        }, 15),

        swapMode(mode) {
            this.orientation = {}
            this.zoomLevel = .8;
            this.mode = mode;

            enJin.audioController.play('pop3')
        },

        setDepth(event) {
            let target = event.target;
            let depth = $(target).data().depth;
            this.currentDepth = depth;

        },

        handleZoom(amount) {

            if(amount > 0) {
                // in
                if(this.zoomLevel < this.maxZoom) {
                    this.zoomLevel += amount;
                } else {
                    this.zoomLevel = this.maxZoom;
                }
            } else {
                // out
                if(this.zoomLevel > this.minZoom) {
                    this.zoomLevel += amount;
                } else {
                    this.zoomLevel = this.minZoom;
                }
            }
        },


        zoom(event) {
            if(this.mode != 'export') {
                const deltaY = event.deltaY;
                if(deltaY < 0) {
                    this.handleZoom(0.03);
                } else {
                    this.handleZoom(-0.03);
                }      
            }
        },

        updateOrientation(x, y, z, exp) {

            enJin.audioController.play('pop4')

            this.exportSettings.x = x;
            this.exportSettings.y = y;
            this.exportSettings.z = z;
        },

        processForExport() {

            enJin.audioController.play('pop6');
            this.exporting = true;
            var hamlArray = '- @voxels = [';

            that.voxels.forEach(function(v) {
                if(v.length != 0) {
                    let colors = '[';
                    v.c.forEach(function(c) {
                        let colourString = '{'
                        for (let key of Object.keys(c)) {
                            let col = c[key];
                            let index = key;
                            var comma;
                            if(key != 0) {
                                comma = ','
                            } else {
                                comma = ''
                            }
                            colourString = `${colourString} ${comma} ${index} => '${col}'`
                        }
                        colourString = colourString + '}'
                        colors = colors + colourString + ','
                    })
                    let haml = `{:x => ${v.x}, :y => ${v.y}, :d => ${v.d}, :c => ${colors}]},`
                    hamlArray += haml
                }
            })

            const data = {
                title : `${this.exportSettings.name} - A 3D Pure CSS & HTML Model Made With VoCSSels`,
                css : `$voxelSize: 26; // We want to work as 1 unit is 1 voxel occupying one space. So here we are setting the the amount of pixels a voxel takes. This will need to be the same as the voxel size in the vue data object.
$maxDepth: 17;
$spinSpeed: ${this.exportSettings.spinSpeed}s;
$uid: ${rot13(this.exportSettings.uid)};

// Return the true px size of a voxel based on the passed unit.
@function getVoxelSize($size, $operator) {
    @return unquote($operator + $size * $voxelSize + px);    
}

// Function to set the orientation of a side
@function setFaceOrientation($tx, $ty, $tz, $sx, $sy, $rx, $ry, $rz) {
    @return rotateX($rx + deg) rotateY($ry + deg) rotateZ($rz + deg) scaleX($sx) scaleY($sy) translate3d(unquote($tx + ',' + $ty + ',' + $tz)); 
}

%voxel {
    position: absolute;
    top: 50%;
    transform-style: preserve-3d;
    left: 0;
    right: 0;
    margin: auto;
    width: 10px;
}

%face {
    width: $voxelSize + px;
    height: $voxelSize + px;
    position: absolute;
    transform-style: preserve-3d;
    transform-origin: 50% 50%;
}

body {
    height: 100vh;
    overflow: hidden;
    background: ${this.exportSettings.bgColor};

    .p3d_playground {
        height: 100vh;
        perspective: ${this.exportSettings.perspective}px;
        transform: scale(${this.exportSettings.scale});

        .model {
            height: 100vh;
            transform-style: preserve-3d;
            ${this.exportSettings.animate ? 'animation: spin $spinSpeed infinite linear;' : ''}
            transform-origin: 50% 50% getVoxelSize($maxDepth / 2, '');
            transform: scale(.6) rotateZ(${this.exportSettings.z}deg) rotatex(${this.exportSettings.x}deg) rotateY(-${this.exportSettings.y}deg) translateY(getVoxelSize($maxDepth / 2, '-'));
            transition: all .3s;

            @media only screen and (max-width: 700px) {
               transform: scale(.5) rotateZ(${this.exportSettings.z}deg) rotatex(${this.exportSettings.x}deg) rotateY(-${this.exportSettings.y}deg) translateY(getVoxelSize($maxDepth / 2, '-'));
            }

            @keyframes spin {
                from { transform: scale(1) rotateY(0deg) rotateZ(0deg) rotatex(0deg) translateY(getVoxelSize($maxDepth / 2, '-'));}
                to { transform: scale(1) rotateY(360deg) rotateZ(0deg) rotatex(0deg) translateY(getVoxelSize($maxDepth / 2, '-'));}
            }

            .voxel,
            .voxel-group,
            .v {
                @extend %voxel;
            }

            .f {
                @extend %face;
            }

            // Utility classes
            @for $x from 0 through 20 {
                @for $y from 0 through 20 {
                    .x-#{$x}.y-#{$y} {
                        transform: translateZ(getVoxelSize($x - 0.1, '')) translateY(getVoxelSize($y - 0.1, ''));
                    }
                }
            }

            // Depths
            // This can be done on a normal loop as depth will be limited
            .f {
                @for $v from 1 through 6 {
                    &:nth-of-type(#{$v}) {
                        $operator: if($v % 2 == 0, '', '-');
                        @if $v == 1 or $v == 2 {
                            transform: setFaceOrientation(0, 0, getVoxelSize(1 / 2, $operator), 1, 1, 0, 90, 0);
                        }
                        @if $v == 3 or $v == 4 {
                            transform: setFaceOrientation(0, 0, getVoxelSize(1 / 2, $operator),1 , 1, 0, 0, 0);
                        }
                        @if $v == 5 or $v == 6 {
                            transform: setFaceOrientation(0, 0, getVoxelSize(1 / 2, $operator), 1, 1, 90, 0, 0);
                        }
                    }
                }
            }

            @for $i from 0 through 14 {
                .d-#{$i} {
                    transform: translateX(23px * $i);
                }
                .g-#{$i} {
                    transform: translateX(-23px * ($i / 2));
                }
            }
        }
    }
}`,
                css_pre_processor : "scss",
                html_pre_processor : "haml",
                html : `${hamlArray}] 
-# Created using VoCSSels by Jamie Coulter https://codepen.io/jcoulterdesign/pen/vYyzZdo
.p3d_playground
    .model
        - @voxels.each do | voxel |
            .voxel-group{:class => "g-#{voxel[:d]}"}
                -(1..voxel[:d]).each do | index |
                    .voxel{:class => "d-#{index}"}
                        .v{:class => "x-#{voxel[:x]} y-#{voxel[:y]}"}
                            -(1..6).each do | v |
                                .f.f--t{:style => "background-color: ##{voxel[:c][index - 1][v]}"}`
            };

            const JSONstring = JSON.stringify(data).replace(/"/g, "&quot;").replace(/'/g, "&apos;");
            const form = `<form class="export" action="https://codepen.io/pen/define" method="POST" target="_blank"><input class="change" type="hidden" name="data" value='${JSONstring}'><input type="submit" width="40" height="40" value="Export to new pen"></form>`;
            $('.editor_right__export .form').html('');
            $('.editor_right__export .form').append(form);
            that = this;
            setTimeout(function() {
                that.exporting = false;
                $('.export').submit();
            }, 1500)

        },

        /* -------------------------------------------------------------------------

        Save model to local storage

        ------------------------------------------------------------------------- */

        save() {
            // Work out todays date
            let today = new Date();
            let dd = String(today.getDate()).padStart(2, '0');
            let mm = String(today.getMonth() + 1).padStart(2, '0');
            let yyyy = today.getFullYear();

            let date = mm + '.' + dd + '.' + yyyy;

            // Save model to local storage
            // Start by creating a metadata object for our models information
            let metaData = {
                'date'     : date,
                'author'   : this.author,
                'name'     : this.exportSettings.name,      // Get the model name
                'voxels'   : $('.v').length, // Get the total voxels in the model
                'vertices' : $('.f').length, // Get the total vertices in the model
                'image'    : '',             // Set a blank string for the base64 image data
                'bgColor'  : this.exportSettings.bgColor
            }

            // Set a new item in local storage for the model data and assing the JSON to it
            window.localStorage.setItem(this.modelPrefix + this.exportSettings.name.toLowerCase().replace(/\s/g, ''), JSON.stringify(this.voxels));

            // Set saving flag to show saving icon
            this.saving = !this.saving;

            // Reset the zoom level for the snap shot
            this.zoomLevel = 0.8;

            // Take snapshop of model node
            const node = document.getElementById('model');

            // Hide preview buttons
            $('.zooms').hide();

            domtoimage.toPng(node)
                .then(function (dataUrl) {

                var that = this; // Get context
                var img = new Image(); 

                // Set image in meta data to data url
                metaData.image = dataUrl; 

                // Set local storage item to metadata
                window.localStorage.setItem(that.metaPrefix + that.exportSettings.name.toLowerCase().replace(/\s/g, ''), JSON.stringify(metaData));



                // Set saving flag back to false after a reasonable delay
                setTimeout(function() {
                    // Show preview buttons
                    $('.zooms').show();

                    // Reset saving flag
                    that.saving = !that.saving;

                    // Update the saved models arrays so they are accessible in the modal straight away
                    that.getSavedModels();

                    // Play sound feedback
                    enJin.audioController.play('save')
                }, 1000)

            }.bind(this)); 
        },

        handleRightClick() {

            if(this.drawMode == 'erase') {
                this.drawMode = 'draw'
            }  

        },
        shareModel() {
            // Work out todays date
            let today = new Date();
            let dd = String(today.getDate()).padStart(2, '0');
            let mm = String(today.getMonth() + 1).padStart(2, '0');
            let yyyy = today.getFullYear();

            let date = mm + '.' + dd + '.' + yyyy;

            let metaData = {
                'date'     : date,
                'author'   : this.author,
                'name'     : this.exportSettings.name,      // Get the model name
                'voxels'   : $('.v').length, // Get the total voxels in the model
                'vertices' : $('.f').length, // Get the total vertices in the model
                'image'    : '',             // Set a blank string for the base64 image data
                'bgColor'  : this.exportSettings.bgColor
            }

            metaData.modelData = [this.voxels];

            // Reset the zoom level for the snap shot
            this.zoomLevel = 0.8;

            // Take snapshop of model node
            const node = document.getElementById('model');

            // Hide preview buttons
            $('.zooms').hide();

            this.submitting = !this.submitting;

            domtoimage.toPng(node)
                .then(function (dataUrl) {

                var that = this; // Get context
                var img = new Image(); 

                // Set image in meta data to data url
                metaData.image = dataUrl; 

                // Set local storage item to metadata
                window.localStorage.setItem(that.metaPrefix + that.exportSettings.name.toLowerCase().replace(/\s/g, ''), JSON.stringify(metaData));
                if(that.submitting == false) {
                    // Set saving flag back to false after a reasonable delay
                    setTimeout(function() {
                        // Show preview buttons
                        $('.zooms').show();

                        // Post data to zapier webhook
                        var xhr = new XMLHttpRequest();
                        xhr.open("POST", 'https://hooks.zapier.com/hooks/catch/708069/onctccu', true);
                        xhr.send(JSON.stringify(metaData));



                        setTimeout(function() {
                            that.submitted = true;
                            that.submitting = false;
                            enJin.audioController.play('save')
                        }, 2000)
                    }, 1000)
                }

            }.bind(this));


        },
        /* -------------------------------------------------------------------------

        Get models from local storage

        ------------------------------------------------------------------------- */

        getSavedModels() {

            // First, clear any data from the saved models and meta arrays
            let savedModels = [];
            let savedModelsMeta = [];

            // Iterate over localStorage and insert the keys that meet the condition into arr
            for (let i = 0; i < window.localStorage.length; i++) {
                // Check for p3d_modeldata prefix
                if (window.localStorage.key(i).substring(0, this.modelPrefix.length) == this.modelPrefix) {
                    savedModels.push(window.localStorage.key(i));
                }
                // Check for p3d_modeldata prefix
                if (window.localStorage.key(i).substring(0, this.metaPrefix.length) == this.metaPrefix) {
                    savedModelsMeta.push(window.localStorage.key(i));
                }
            }

            // Set the arrays to the model data and meta keys. This will then update vue loop in the load modal
            let meta = savedModelsMeta.sort();
            let data = savedModels.sort();

            this.savedModelsMeta = meta;
            this.savedModels = data;
        },

        /* -------------------------------------------------------------------------

        Get meta data entry for saved model

        ------------------------------------------------------------------------- */

        getMetaData(key, index) {
            let data = JSON.parse(window.localStorage.getItem(index));
            let metaData = data[key];
            return metaData;
        },

        /* -------------------------------------------------------------------------

        Load model from local storage

        ------------------------------------------------------------------------- */

        load(model, community) {

            if(!community) {

                var target = this.savedModels[model];
                var metaTarget = this.savedModelsMeta[model];

                var modelData = window.localStorage.getItem(target);
                var metaData = JSON.parse(window.localStorage.getItem(metaTarget));


            } else {
                var metaData = model
                var modelData = model.modelData[0];
            }




            // Remove all voxel information
            this.voxels = [];
            this.exportSettings.name = metaData.name;
            this.mode = 'drawing';

            // Re get context
            that = this;
            this.loading = !this.loading;

            setTimeout(function() {

                $("#colorBg, #exportBg").spectrum("set", metaData.bgColor);
                that.exportSettings.bgColor = metaData.bgColor;

                if(!community) {
                    that.voxels = JSON.parse(modelData);
                } else {
                    that.voxels = modelData;
                }

                that.loading = !that.loading;
            }, 1000)
        },

        newModel() {
            this.voxels = [];
            this.mode = 'drawing';
            $("#colorBg, #exportBg").spectrum("set", '#25273E');
            $("#colorPicker").spectrum("set", '#ffffff');
            that.exportSettings.bgColor = '#25273E';

            for(let i = 0; i < Math.pow(this.canvasSize, 2); i++) {
                this.voxels.push([]);
            }
        },

        /* -------------------------------------------------------------------------

        Open modal

        ------------------------------------------------------------------------- */

        openModal(modal) {
            this.modalOpen = true;
            this.modal = modal;
        },

        /* -------------------------------------------------------------------------

        Close modals

        ------------------------------------------------------------------------- */

        closeModals() {
            this.modalOpen = false;


            this.modal = '';
            that = this;

            setTimeout(function() {
                that.submitted = false;
            }, 1000)
        },

        /* -------------------------------------------------------------------------

        Open modal

        ------------------------------------------------------------------------- */

        colorPicker(event) {
            this.picker.x = event.clientX;
            this.picker.y = event.clientY;
        },

        selectColor: _.debounce(function() {
            if(this.picker.active) {
                this.picker.active = !this.picker.active;
                this.currentColor = this.picker.color;
                $("#colorPicker").spectrum("set", this.picker.color);
            }
        }, 10),

        /* -------------------------------------------------------------------------

        Reset all of the colour pickers to their default values

        ------------------------------------------------------------------------- */

        getVoxelsCount(model) {
            return $('.v').length;
        },

        /* -------------------------------------------------------------------------

        Reset all of the colour pickers to their default values

        ------------------------------------------------------------------------- */

        getVerticesCount(model) {
            return $('.f').length;
        },

        /* -------------------------------------------------------------------------

        Reset all of the colour pickers to their default values

        ------------------------------------------------------------------------- */

        resetBgColor() {
            $("#colorBg, #exportBg").spectrum("set", '#25273E');
            this.exportSettings.bgColor = '#25273E';
        },

        /* -------------------------------------------------------------------------

        Get all community models from GitHub gists

        ------------------------------------------------------------------------- */

        getCommunityModels() {
            let xhr = new XMLHttpRequest();

            xhr.open('GET', 'https://api.github.com/users/jcoulterdesign/gists');
            xhr.send();

            // Store contenxt
            that = this;

            xhr.onload = function() {
                if (xhr.status == 200) { 
                    let gists = JSON.parse(xhr.response);
                    let urls = []; // Raw urls array

                    gists.forEach(function(g) {
                        let files = g.files;

                        for (let key of Object.keys(files)) {
                            let raw_url = files[key].raw_url;
                            urls.push(raw_url);
                        }
                    })

                    // Now we have a list of all approved gists. Loop through and get the content of each one and
                    // store to our vue instance

                    var xhrReq = [];

                    urls.forEach(function(u, i) {
                        xhrReq[i] = new XMLHttpRequest();
                        xhrReq[i].open('GET', u);
                        xhrReq[i].send();

                        ctx = that;
                        xhrReq[i].onload = function() {
                            if (xhrReq[i].status == 200) {
                                ctx.communityContent.push(JSON.parse(xhrReq[i].response));
                            }
                        }
                    })

                    $('.community .x-wrap').width(urls.length * 265 + 'px')
                }
            };
        },

        /* -------------------------------------------------------------------------

        Delete model from local storage

        ------------------------------------------------------------------------- */

        deleteModel(model) {
            // Get the relevant entry in storage
            let target = this.savedModels[model];
            let targetMeta = this.savedModelsMeta[model];

            // Remove both the meta and the model data
            window.localStorage.removeItem(target);
            window.localStorage.removeItem(targetMeta);

            // Update the UI by updating models array
            this.getSavedModels();
        },

        /* -------------------------------------------------------------------------

        Toggle the audio controller muted prop

        ------------------------------------------------------------------------- */

        toggleAudio() {
            enJin.audioController.play('pop6');
            enJin.audioController.muted = !enJin.audioController.muted;
            this.muted = !this.muted
        },

        /* -------------------------------------------------------------------------

        Quick and dirty way to reduce motion in the app. Add a class to everything that
        has transition-duration 0

        ------------------------------------------------------------------------- */

        toggleMotion() {
            enJin.audioController.play('pop6');
            this.motion = !this.motion;
            if(this.motion) {
                $('*').removeClass('noMotion');
            } else {
                $('*').addClass('noMotion');
            }
        }
    },

    mounted() {

        // Get all the community VoCSSels for github gists
        this.getCommunityModels();

        // Get all saved models from local storage
        this.getSavedModels();

        // Prepare an empty voxels array
        for(let i = 0; i < Math.pow(this.canvasSize, 2); i++) {
            this.voxels.push([]);
        }

        /* -------------------------------------------------------------------------

        Set up our spectrums

        ------------------------------------------------------------------------- */

        // Main colour selector
        $("#colorPicker").spectrum({
            color: "ffffff",
            preferredFormat: "hex",
            flat: true,
            showInput: true,
            showPalette: true,
            palette: [],
            showSelectionPalette: true, // true by default
            selectionPalette: [],
            clickoutFiresChange: true,
            maxSelectionSize: 15,
            move(color) {
                that.currentColor = color.toHexString().substring(1); // #ff0000

            }
        });

        // Auto switch to draw when selecting a colour
        $('#colorPicker').on("dragstart.spectrum", function(e, color) {
            that.drawMode = 'draw'
        });

        // Auto switch to draw when selecting a colour
        $('#colorPicker').on("move.spectrum", function(e, color) {
            that.drawMode = 'draw'
        });

        // Background color selectors for preview panel and export
        $("#colorBg, #exportBg").spectrum({
            color: "25273E",
            containerClassName: 'bg',
            move(color) {
                that.bgColor = color.toHexString(); // #ff0000
                that.exportSettings.bgColor = color.toHexString();
                $("#colorBg, #exportBg").spectrum("set", color.toHexString());
            }
        });

        // Make sure the first palette entry is selected
        $('.sp-thumb-inner').click();

        // Simple preloader
        setTimeout(function() {
            $('.p3d_loader').fadeOut();
        }, 4000)
    }
});

// Symmetry
// Fix intermittent bug
// Optimize

              
            
!
999px

Console