chrmoritz/Troxel

View on GitHub
index.jade

Summary

Maintainability
Test Coverage
doctype html
html
  head
    title Troxel
    meta(name='viewport', content='width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0')
    if deploy
      link(rel='canonical', href='https://troxel.js.org')
      script.
        if (window.location.protocol !== 'https:' && window.location.hostname === 'troxel.js.org') window.location.protocol = 'https';
      link(rel='stylesheet', href='troxel.min.css')

  body(style='background-color: #888888;')
    .navbar.navbar-inverse.navbar-fixed-top(role='navigation', style='margin-bottom: 0px;')
      .container-fluid
        .navbar-header
          a.navbar-brand(onclick='javascript:window.location.href=window.location.href.split("#")[0];') Troxel
        .collapse.navbar-collapse
          ul.nav.navbar-nav
            li.dropdown
              a.dropdown-toggle(data-toggle='dropdown', data-tag='#ulSavedModels') My models (save / open)
                span.caret
              ul#ulSavedModels.dropdown-menu(role='menu')
                li.dropdown-header Current Model:
                li.disabled: a untitled/unsaved
                li(style='display: none;'): a Save
                li: a#SavedModelsAdd(data-toggle='modal', data-target='#saveModal') Save as ...
                li(style='display: none;'): a Remove
                li.divider
                li.dropdown-header Saved Models:
                li.disabled: a No saved models
          button.btn.btn-primary.navbar-btn(style='margin-left: 50px;', data-toggle='modal', data-target='#openModal') Open model from file ...
          button#btnExport.btn.btn-default.navbar-btn(style='margin-left: 5px; display: none;', data-toggle='modal', data-target='#exportModal') Export model as ...
          a#btnExportPng.btn.btn-default.navbar-btn(style='margin-left: 5px; display: none;', download='Model.png') Open current view as png
          ul.nav.navbar-nav.navbar-right
            li: p.navbar-text Mode:
            li.active: a#modeView View
            li: a#modeEdit Edit

    #openModal.modal.fade(tabindex='-1', role='dialog')
      .modal-dialog.modal-lg
        .modal-content
          .modal-header
            button.close(data-dismiss='modal'): span ×
            h4.modal-title Open model from file ...
          .modal-body
            ul#filetabs.nav.nav-tabs(role='tablist', style='margin-bottom: 15px;')
              li.active: a(href='#tabqb', data-toggle='tab') Qubicle (.qb)
              li: a(href='#tabzox', data-toggle='tab') Zoxel (.zox)
              li: a(href='#tabvox', data-toggle='tab') Magica (.vox)
              li: a(href='#tabjson', data-toggle='tab') JSON
              li: a#dragTab(href='#tabdrag', data-toggle='tab') Drag & Drop
              li: a#openTroveTab(href='#tabtrove', data-toggle='tab') Trove-Blueprint
              li: a(href='#tabnew', data-toggle='tab') empty Model (new)
            .tab-content
              #tabqb.tab-pane.fade.in.active
                .form-horizontal
                  .form-group
                    label.col-sm-3.control-label(for='fqb') Main mesh (*.qb):
                    .col-sm-9: input#fqb(type='file', accept='.qb', style='margin-top: 5px;', multiple)
                  .form-group
                    label.col-sm-3.control-label(for='fqba') Alpha map (*_a.qb):
                    .col-sm-9: input#fqba(type='file', accept='.qb', style='margin-top: 5px;', multiple)
                  .form-group
                    label.col-sm-3.control-label(for='fqbt') Type map (*_t.qb):
                    .col-sm-9: input#fqbt(type='file', accept='.qb', style='margin-top: 5px;', multiple)
                  .form-group
                    label.col-sm-3.control-label(for='fqbs') Specular map (*_s.qb):
                    .col-sm-9: input#fqbs(type='file', accept='.qb', style='margin-top: 5px;', multiple)
                  span.help-block Alpha, Type and Specular map are optional (only the main mesh is required)
              #tabzox.tab-pane.fade
                .form-horizontal
                  .form-group
                    label.col-sm-3.control-label(for='fzox') Zoxel file (*.zox):
                    .col-sm-9: input#fzox(type='file', accept='.zox', style='margin-top: 5px;', multiple)
              #tabvox.tab-pane.fade
                .form-horizontal
                  .form-group
                    label.col-sm-3.control-label(for='fvox') Magica Voxel file (*.vox):
                    .col-sm-9: input#fvox(type='file', accept='.vox', style='margin-top: 5px;', multiple)
              #tabjson.tab-pane.fade
                .form-horizontal
                  .form-group
                    label.col-sm-1.control-label(for='sjson') JSON:
                    .col-sm-11: textarea#sjson.form-control(rows=7, style='resize: vertical; min-height: 100px;')
              #tabdrag.tab-pane.fade
                .dropZone Drag files anywhere to this modal to select them
                h4 Selected files:
                ul.list-unstyled
                  li: span.help-block No files selected
              #tabtrove.tab-pane.fade
                .form-horizontal
                  .form-group
                    label.col-sm-3.control-label(for='sbtag') Tag (date of patch release):
                    .col-sm-5
                      select#cbbtag.form-control
                        option(value='latest') latest (default)
                    .col-sm-4: button.btn.btn-default.form-control#bbmanageTags Manage Blueprint DB (installed tags)...
                  .form-group
                    label.col-sm-2.control-label(for='sbtrove') Blueprint id:
                    .col-sm-10: input#sbtrove.form-control(type='text')
                  span.help-block All rights for the here listed voxel models belongs to Trion Worlds and or their respective voxel model authors.
                  span.help-block
                    | Hint: Check out 
                    a(href='https://www.trovesaurus.com/', target='_blank') Trovesaurus
                    |  for a categorized but more outdated list of Trove items with metatdata.
              #tabnew.tab-pane.fade
                .form-horizontal
                  .form-group
                    label.col-sm-2.control-label(for='cbnewTP') Trove presets:
                    .col-sm-10: select#cbnewTP.form-control
                      option custom - choose your options below
                  .form-group
                    label.col-sm-2.control-label Dimensions:
                    .col-sm-10: .input-group
                      span.input-group-addon x:
                      input#snewX.form-control(type='number', value='20')
                      span.input-group-addon y:
                      input#snewY.form-control(type='number', value='20')
                      span.input-group-addon z:
                      input#snewZ.form-control(type='number', value='20')
                  .form-group
                    label.col-sm-2.control-label(for='cbnewAp') attachment Point:
                    .col-sm-10: .input-group
                      span.input-group-addon
                        input#cbnewAp(type='checkbox', style='margin-right: 3px;')
                        |  add at position:
                      span.input-group-addon x:
                      input#snewApX.snewApPos.form-control(type='number', value='10', disabled)
                      span.input-group-addon y:
                      input#snewApY.snewApPos.form-control(type='number', value='10', disabled)
                      span.input-group-addon z:
                      input#snewApZ.snewApPos.form-control(type='number', value='10', disabled)
            .form-inline
              .checkbox: label
                input#ImportRestorAP(type='checkbox', style='margin-bottom: 10px; margin-right: 5px;')
                | try to restore the attachment point position from the qb's mete data for models exported from Trove
              .checkbox: label
                input#ImportMerge(type='checkbox', style='margin-right: 5px;')
                | merge model into existing model with offset:
              .form-group(style='margin-left: 10px;'): .input-group
                span.input-group-addon x:
                input#QbMergeOffX.form-control.QbMergeOff(type='number', value='0', style='width: 67px;', disabled)
                span.input-group-addon y:
                input#QbMergeOffY.form-control.QbMergeOff(type='number', value='0', style='width: 67px;', disabled)
                span.input-group-addon z:
                input#QbMergeOffZ.form-control.QbMergeOff(type='number', value='0', style='width: 67px;', disabled)
                span.input-group-addon
                  input#ImportAPrelativeOffsets.QbMergeOff(type='checkbox', style='margin-right: 3px;', disabled)
                  |  relative from attachment point:
          .modal-footer
            button.btn.btn-default(data-dismiss='modal') Close
            button#open.btn.btn-primary Open model

    #exportModal.modal.fade(tabindex='-1', role='dialog')
      .modal-dialog
        .modal-content
          .modal-header
            button.close(data-dismiss='modal'): span ×
            h4.modal-title Export model as ...
          .modal-body
            ul.nav.nav-tabs(role='tablist', style='margin-bottom: 15px;')
              li.active: a(href='#tabexqb', data-toggle='tab') Qubicle maps (.qb)
              li: a(href='#tabexzox', data-toggle='tab') Zoxel (.zox)
              li: a(href='#tabexvox', data-toggle='tab') Magica (.vox)
              li: a(href='#tabexbase64', data-toggle='tab') Link (share)
              li: a(href='#tabexjson', data-toggle='tab') JSON
            .tab-content
              #tabexqb.tab-pane.fade.in.active
                .form-horizontal
                  .form-group
                    label.col-sm-3.control-label(for='exportFilenameQb') File name:
                    .col-sm-9: .input-group
                      input#exportFilenameQb.form-control(type='text', value='Model')
                      span.input-group-addon .qb
                  .form-group
                    label.col-sm-3.control-label(for='exportQbComp') Qb-Options:
                    .col-sm-9: .checkbox
                      label
                        input#exportQbComp(type='checkbox', checked)
                        | compressed (incompatible with some 3rd party apps)
                  .form-group
                    label.col-sm-3.control-label(for='exportQbComp') Zip-Options:
                    .col-sm-9: .checkbox
                      label
                        input#exportQbZipComp(type='checkbox', checked)
                        | deflate / compress zip (may lower performance for large files)
                a#exportQbzip.btn.btn-primary.btn-lg.btn-block(download='Model.zip') Export as material map archive (.zip: 4x .qb) ...
                p.help-block or alternatively download each material map file separately:
                a#exportQb.exportQb.btn.btn-info.btn-block(download='Model.qb') Export as Qubicle (*.qb, main map) ...
                a#exportQba.exportQb.btn.btn-default.btn-block(download='Model_a.qb') Export as alpha material map (*_a.qb) ...
                a#exportQbt.exportQb.btn.btn-default.btn-block(download='Model_t.qb') Export as type material map (*_t.qb) ...
                a#exportQbs.exportQb.btn.btn-default.btn-block(download='Model_s.qb') Export as specular material map (*_s.qb) ...
              #tabexzox.tab-pane.fade
                .form-horizontal
                  .form-group
                    label.col-sm-3.control-label(for='exportFilenameZox') File name:
                    .col-sm-9: .input-group
                      input#exportFilenameZox.form-control(type='text', value='Model')
                      span.input-group-addon .zox
                a#exportZox.btn.btn-primary.btn-lg.btn-block(download='Model.zox') Export as Zoxel (.zox) ...
              #tabexvox.tab-pane.fade
                .form-horizontal
                  .form-group
                    label.col-sm-3.control-label(for='exportFilenameVox') File name:
                    .col-sm-9: .input-group
                      input#exportFilenameVox.form-control(type='text', value='Model')
                      span.input-group-addon .vox
                a#exportVox.btn.btn-primary.btn-lg.btn-block(download='Model.vox') Export as Magica Voxel (.vox) ...
              #tabexbase64.tab-pane.fade
                .checkbox
                  label(data-toggle='tooltip', data-placement='right', data-container='body', title='disables exports and edits of your voxel model if checked')
                    input#exportBase64Ro(type='checkbox')
                    | readonly
                  label(data-toggle='tooltip', data-placement='right', data-container='body', title='enables color palette compression for reducing link length (highly recommended for lairs and dungeons)', style="margin-left: 10px;")
                    input#exportBase64V2(type='checkbox', checked)
                    | color palette compression (highly recommended for lairs and dungeons)
                  label(data-toggle='tooltip', data-placement='right', data-container='body', title='resize the modal to its minimal bounding box (removes empty voxel space around the model)')
                    input#exportBase64Rbb(type='checkbox', checked)
                    | resize to bounding box
                  label(data-toggle='tooltip', data-placement='right', data-container='body', title='use Trovesaurus link shortener for getting a shorturl redirecting to your model', style="margin-left: 10px;")
                    input#exportBase64Tsl(type='checkbox')
                    | use Trovesaurus link shortener (shorturl)
                button#exportBase64.btn.btn-primary.btn-lg.btn-block Export as Troxel Link
                textarea#exportBase64Ta.form-control(rows=7, style='resize: vertical; min-height: 100px; display: none; margin-top: 5px;')
              #tabexjson.tab-pane.fade
                .checkbox
                  label
                    input#exportJsonPret(type='checkbox', checked)
                    | pretty
                button#exportJson.btn.btn-primary.btn-lg.btn-block Export as Troxel (json)
                textarea#exportJsonTa.form-control(rows=7, style='resize: vertical; min-height: 100px; display: none; margin-top: 5px;')
          .modal-footer
            button.btn.btn-default(data-dismiss='modal') Close

    #saveModal.modal.fade(tabindex='-1', role='dialog')
      .modal-dialog
        .modal-content
          .modal-header
            button.close(data-dismiss='modal'): span ×
            h4.modal-title Save model locally as ...
          .modal-body
            .form-horizontal
              .form-group
                label.col-sm-2.control-label(for='saveModelName') Name:
                .col-sm-10: input#saveModelName.form-control(type='text')
          .modal-footer
            button.btn.btn-default(data-dismiss='modal') Close
            button#saveModelAs.btn.btn-primary Save model locally

    #resizeModal.modal.fade(tabindex='-1', role='dialog')
      .modal-dialog
        .modal-content
          .modal-header
            button.close(data-dismiss='modal'): span ×
            h4.modal-title Resize voxel model ...
          .modal-body
            .form-inline: .form-group
              label new dimensions (size):
              .input-group
                span.input-group-addon x:
                input#resizeX.resizeDim.form-control(type='number')
                span.input-group-addon y:
                input#resizeY.resizeDim.form-control(type='number')
                span.input-group-addon z:
                input#resizeZ.resizeDim.form-control(type='number')
            .form-inline: .form-group
              label resize offsets:
              .input-group
                span.input-group-addon x:
                input#resizeOffX.resizeDim.form-control(type='number', value='0')
                span.input-group-addon y:
                input#resizeOffY.resizeDim.form-control(type='number', value='0')
                span.input-group-addon z:
                input#resizeOffZ.resizeDim.form-control(type='number', value='0')
            p.help-block resizing will be done to the cube defined by the origin point (bottom back right point in default camera position), the offsets (positive or negative integers) and the new dimensions
            button#resizeCalcBBb.btn.btn-default.btn-block calculate bounding box
            p.help-block this will move and resize your voxel model to the smallest possible dimension without erasing voxels
          .modal-footer
            button.btn.btn-default(data-dismiss='modal') Close
            button#resizeBtn.btn.btn-primary Resize voxel model

    #updateModal.modal.fade(tabindex='-1', role='dialog')
      .modal-dialog.modal-lg
        .modal-content
          .modal-header
            button.close(data-dismiss='modal'): span ×
            h4.modal-title A new version of Troxel is available!
          .modal-body
            #recentChangesDiv
            i Do you want to reload this page now to update and continue your work in the new version? (you can manually reload the page later to update too)
          .modal-footer.form-inline
            button#updateLater.btn.btn-default Close and remind me in:
            select#remindUpdateTime.form-control(style="margin: 0px 10px 0px 3px;")
              option(value=600000) 10 minutes
              option(value=1800000) 30 minutes
              option(value=3600000) 1 hour
              option(value=7200000) 2 hours
            button(onclick="javascript:location.reload();").btn.btn-primary Update now
      
    #TroveCreationLinterModal.modal.fade(tabindex='-1', role='dialog')
      .modal-dialog.modal-lg
        .modal-content
          .modal-header
            button.close(data-dismiss='modal'): span ×
            h3.modal-title Trove Creation linting results and export to Reddit link
          .modal-body
            #TroveCreationsLintingResults
            #TroveCreationsExportDiv
              h3 Export as Reddit Link
              p#TroveCreationsLintingCount.text-danger
              .checkbox
                label(data-toggle='tooltip', data-placement='right', data-container='body', title='disables exports and edits of your voxel model if checked')
                  input#TroveCreationsReadonly(type='checkbox')
                  | readonly (allow no edits and export)
                label(data-toggle='tooltip', data-placement='right', data-container='body', title='use Trovesaurus link shortener for getting a shorturl redirecting to your model', style="margin-left: 10px;")
                  input#TroveCreationsTsl(type='checkbox')
                  | use Trovesaurus link shortener (shorturl, recommended for lairs / dungeons)
                button#TroveCreationsExport.btn.btn-primary.btn-lg.btn-block(style="margin-top: 5px;") Export as Reddit Link
                textarea#TroveCreationsExportLink.form-control(rows=7, style='resize: vertical; min-height: 100px; display: none; margin-top: 5px;')
          .modal-footer
            button.btn.btn-default(data-dismiss='modal') Close

    #WebGlContainer(style='position: fixed; right: 220px; left: 0px; top: 50px; bottom: 0px;')
    div(style='position: fixed; right: 0px; width: 220px; top: 50px; bottom: 0px; overflow: auto;')
      #addPanel.panel.panel-default(style='display: none;')
        .panel-heading
          button.btn.btn-default.btn-sm.pull-right(style='margin-top: -6px;'): span.glyphicon.glyphicon-minus
          h3.panel-title Editing options
        .panel-body
          .form-horizontal
            .form-group(style='margin-bottom: 0px;')
              label.col-sm-3.control-label(for='editTool', style='padding-top: 0px;') Tool:
              .col-sm-9(style='padding-right: 0px;'): .btn-group.btn-group-xs(data-toggle='buttons', style='margin-bottom: 5px;')
                label.btn.btn-info.active(data-toggle='tooltip', data-container='body', data-placement='left', title='LMB = add voxel | RMB = remove voxel | MMB = pick voxel')
                  input.editTool(type='radio', name='editTool', data-edittool=0, checked)
                  | add/remove
                label.btn.btn-info(data-toggle='tooltip', data-container='body', data-placement='left', title='LMB = fill single voxel | RMB = fill connected voxels | MMB = pick voxel')
                  input.editTool(type='radio', name='editTool', data-edittool=1)
                  | fill mode
            #fillSameColorDiv.form-group(style='margin-bottom: 0px; display: none;')
              .col-sm-offset-3.col-sm-9: .checkbox(style='padding-top: 0px;')
                label(data-toggle='tooltip', data-container='body', data-placement='left', title='Enable this to fill only voxels with the same color or disable it to fill all connected voxels (rightclick)')
                  input#fillSameColor(type='checkbox', checked)
                  | same color only
            .form-group(style='margin-bottom: 10px;')
              label.col-sm-4.control-label(for='addVoxColor') Color:
              .col-sm-8: .input-group.input-group-sm
                input#addVoxColor.form-control.input-sm(type='color', value='#ffb248')
                span.input-group-btn: button#addVoxAP.btn.btn-default(data-toggle='tooltip', data-container='body', data-placement='left', title='adds an attachment point') AP
            .form-group(style='margin-bottom: 0px;')
              label.col-sm-6.control-label(for='editVoxNoiseBright', style='padding-top: 0px; padding-right: 0px;') Noise-bright.:
              .col-sm-6
                input#editVoxNoiseBright(type='range', min=0, max=0.3, step=0.01, value=0, data-toggle='tooltip', data-container='body', data-placement='left', title='Brightness noise of the color (R/G/B multiplied by the same random number)')
            .form-group(style='margin-bottom: 0px;')
              label.col-sm-6.control-label(for='editVoxNoiseHSL', style='padding-top: 0px;') Noise-HSL:
              .col-sm-6
                input#editVoxNoiseHSL(type='range', min=0, max=0.3, step=0.01, value=0, data-toggle='tooltip', data-container='body', data-placement='left', title='HSL noise of the color (hue/saturation/lightness multiplied by different random number)')
            .form-group(style='margin-bottom: 0px;')
              label.col-sm-4.control-label(for='addVoxAlpha') Alpha:
              .col-sm-8
                input#addVoxAlpha(type='range', min=16, max=240, step=32, value=112, disabled)
              span.help-block transparent => solid
            .form-group(style='margin-bottom: 10px;')
              label.col-sm-4.control-label(for='addVoxType') Type:
              .col-sm-8
                select#addVoxType.form-control.input-sm
                  option(value=0, selected) solid
                  option(value=1) glass
                  option(value=2) tiled glass
                  option(value=3) glowing solid
                  option(value=4) glowing glass
            .form-group(style='margin-bottom: 0px;')
              label.col-sm-4.control-label(for='addVoxSpecular') Specular:
              .col-sm-8
                select#addVoxSpecular.form-control.input-sm
                  option(value=0, selected) rough
                  option(value=1) metal
                  option(value=2) water
                  option(value=3) iridescent
                  option(value=4) waxy
      .panel.panel-default
        .panel-heading
          button.btn.btn-default.btn-sm.pull-right(style='margin-top: -6px;'): span.glyphicon.glyphicon-minus
          h3.panel-title Render options
        .panel-body(style='padding: 5px 15px 0px;')
          .form-horizontal
            .form-group(style='margin-bottom: 5px;')
              label.col-sm-5.control-label(for='renderMode', style='padding-left: 10px') Rend.mode:
              .col-sm-7(style='padding-right: 5px;')
                select#renderMode.form-control.input-sm
                  option(value=0, selected) pretty (default)
                  option(value=1) Color only
                  option(value=2) Alpha map
                  option(value=3) Type map
                  option(value=4) Specular map
            .form-group(style='margin-bottom: 5px;')
              label.col-sm-5.control-label(for='renderWireframes', style='padding-left: 10px') Wireframes:
              .col-sm-7(style='padding-right: 5px;')
                select#renderWireframes.form-control.input-sm
                  option(value=0, selected) Off (default)
                  option(value=1) Darkgrey
                  option(value=2) Color
                  option(value=3) Alpha
                  option(value=4) Type
                  option(value=5) Specular
                  option(value=6) Linter results
            .form-group(style='margin-bottom: 5px;')
              label.col-sm-5.control-label(for='rendererPostEffect', style='padding-left: 10px') Post-effect:
              .col-sm-7(style='padding-right: 5px;')
                select#rendererPostEffect.form-control.input-sm
                  option(value=0) None
                  option(value=1, selected) MSAA (antialias, default)
                  option(value=2) SSAO + FXAA (experimental)
            .form-group(style='margin-bottom: 5px;')
              label.col-sm-5.control-label(for='renderControls') Controls:
              .col-sm-7(style='padding-right: 5px;')
                select#renderControls.form-control.input-sm
                  option(value=0, selected) Orbital (default)
                  option(value=1) Fly (lair/dungeon)
            .form-group(style='margin-bottom: 10px;')
              label.col-sm-5.control-label(for='renderAutoRotateSpeed') autorotate:
              .col-sm-7
                input#renderAutoRotateSpeed(type='range', min=-10, max=10, step=1, value=0, style='margin-top: 5px;')
            .form-group(style='margin-bottom: 10px;')
              label.col-sm-7.control-label(for='backgroundColor', style='padding-right: 5px;') Background:
              .col-sm-5
                input#backgroundColor.form-control.input-sm(type='color', value='#888888', style='padding: 5px;')
            .form-group(style='margin-bottom: 10px;')
              label.col-sm-7.control-label(for='ambLightColor', style='padding-right: 5px;') Ambient light:
              .col-sm-5
                input#ambLightColor.form-control.input-sm(type='color', value='#606060', style='padding: 5px;')
          .h5: b: u Directional light:
          .form-horizontal
            .form-group(style='margin-bottom: 0px;')
              label.col-sm-4.control-label(for='dirLightColor') Color:
              .col-sm-8
                input#dirLightColor.form-control.input-sm(type='color', value='#ffffff', style='padding: 5px;')
            .form-group(style='margin-bottom: 10px;')
              label.col-sm-4.control-label(for='dirLightIntensity') Intensity:
              .col-sm-8
                input#dirLightIntensity(type='range', min=0, max=1, step=0.01, value=0.3, style='margin-top: 5px;')
          .input-group.input-group-sm(style='margin: 0px -8px 5px;', data-toggle='tooltip', data-container='body', data-placement='left', title='normal vector for the direction of the directional light')
            span.input-group-addon(style='padding: 5px;') x:
            input#dirLightX.form-control(type='text', value='-0.5', style='padding: 5px;')
            span.input-group-addon(style='padding: 5px;') y:
            input#dirLightY.form-control(type='text', value='-0.5', style='padding: 5px;')
            span.input-group-addon(style='padding: 5px;') z:
            input#dirLightZ.form-control(type='text', value='1', style='padding: 5px;')
            span.input-group-btn
              button#dirLightVector.btn.btn-default(style='padding: 5px;') go
          .h5: b: u Point light (camera):
          .form-horizontal
            .form-group(style='margin-bottom: 0px;')
              label.col-sm-4.control-label(for='pointLightColor') Color:
              .col-sm-8
                input#pointLightColor.form-control.input-sm(type='color', value='#ffffff', style='padding: 5px;')
            .form-group(style='margin-bottom: 10px;')
              label.col-sm-4.control-label(for='pointLightIntensity') Intensity:
              .col-sm-8
                input#pointLightIntensity(type='range', min=0, max=3, step=0.01, value=0.7, style='margin-top: 5px;')
      .panel.panel-default
        .panel-heading
          button.btn.btn-default.btn-sm.pull-right(style='margin-top: -6px;'): span.glyphicon.glyphicon-minus
          h3.panel-title Trove Creations
        .form-inline
          select#TroveCreationsType.form-control.input-sm(style='margin-right: 5px; width: 85px;')
            option(value='melee') Melee
            option(value='gun') Gun
            option(value='staff') Staff
            option(value='bow') Bow
            option(value='spear') Spear
            option(value='mask') Mask
            option(value='hat') Hat
            option(value='hair') Hair
            option(value='deco') Deco
            option(value='lair') Lair
            option(value='dungeon') Dungeon
          button#TroveCreationsLint.btn.btn-default.btn-sm(data-toggle='modal', data-target='#TroveCreationLinterModal') lint and export ...
      .panel.panel-default
        .panel-heading
          button.btn.btn-default.btn-sm.pull-right(style='margin-top: -6px;'): span.glyphicon.glyphicon-minus
          h3.panel-title Resize model
        button#openResizeModal.btn.btn-default.btn-sm.btn-block(data-toggle='modal', data-target='#resizeModal') resize voxel model ...
      .panel.panel-default
        .panel-heading
          button.btn.btn-default.btn-sm.pull-right(style='margin-top: -6px;'): span.glyphicon.glyphicon-minus
          h3.panel-title Rotate model
        .panel-body
          .form-horizontal
            .form-group(style='margin-bottom: 10px;')
              label.col-sm-5.control-label x-axis:
              .col-sm-7
                .btn-group.btn-group-sm
                  button.rotateBtn.btn.btn-default(data-rotate='-x', data-toggle='tooltip', data-container='body', data-placement='left', title='rotate the voxel model up') up
                  button.rotateBtn.btn.btn-default(data-rotate='x', data-toggle='tooltip', data-container='body', data-placement='left', title='rotate the voxel model down') down
            .form-group(style='margin-bottom: 10px;')
              label.col-sm-5.control-label y-axis:
              .col-sm-7
                .btn-group.btn-group-sm
                  button.rotateBtn.btn.btn-default(data-rotate='-y', data-toggle='tooltip', data-container='body', data-placement='left', title='rotate the voxel model left') left
                  button.rotateBtn.btn.btn-default(data-rotate='y', data-toggle='tooltip', data-container='body', data-placement='left', title='rotate the voxel model right') right
            .form-group(style='margin-bottom: 0px;')
              label.col-sm-5.control-label z-axis:
              .col-sm-7
                .btn-group.btn-group-sm
                  button.rotateBtn.btn.btn-default(data-rotate='-z', data-toggle='tooltip', data-container='body', data-placement='left', title='rotate the voxel model clockwise') cw
                  button.rotateBtn.btn.btn-default(data-rotate='z', data-toggle='tooltip', data-container='body', data-placement='left', title='rotate the voxel model counterclockwise') ccw
      .panel.panel-default
        .panel-heading
          button.btn.btn-default.btn-sm.pull-right(style='margin-top: -6px;'): span.glyphicon.glyphicon-minus
          h3.panel-title Move model
        .panel-body
          .form-horizontal
            .form-group(style='margin-bottom: 10px;')
              label.col-sm-5.control-label x-axis:
              .col-sm-7
                .btn-group.btn-group-sm
                  button.moveBtn.btn.btn-default(data-move='-x', data-toggle='tooltip', data-container='body', data-placement='left', title='move the voxel model one voxel left') left
                  button.moveBtn.btn.btn-default(data-move='x', data-toggle='tooltip', data-container='body', data-placement='left', title='move the voxel model one voxel right') right
            .form-group(style='margin-bottom: 10px;')
              label.col-sm-5.control-label y-axis:
              .col-sm-7
                .btn-group.btn-group-sm
                  button.moveBtn.btn.btn-default(data-move='-y', data-toggle='tooltip', data-container='body', data-placement='left', title='move the voxel model one voxel up') up
                  button.moveBtn.btn.btn-default(data-move='y', data-toggle='tooltip', data-container='body', data-placement='left', title='move the voxel model one voxel down') down
            .form-group(style='margin-bottom: 0px;')
              label.col-sm-5.control-label z-axis:
              .col-sm-7
                .btn-group.btn-group-sm
                  button.moveBtn.btn.btn-default(data-move='-z', data-toggle='tooltip', data-container='body', data-placement='left', title='move the voxel model one voxel to the front') fw
                  button.moveBtn.btn.btn-default(data-move='z', data-toggle='tooltip', data-container='body', data-placement='left', title='move the voxel model one voxel to the back') back
      .panel.panel-default
        .panel-heading
          button.btn.btn-default.btn-sm.pull-right(style='margin-top: -6px;'): span.glyphicon.glyphicon-minus
          h3.panel-title Mirror model
        .btn-group-vertical.btn-group-sm(style='width: 100%;')
          button.mirrorBtn.btn.btn-default(data-mirror='x', data-toggle='tooltip', data-container='body', data-placement='left', title='mirror the voxel model in x-axis') Mirror x-axis
          button.mirrorBtn.btn.btn-default(data-mirror='y', data-toggle='tooltip', data-container='body', data-placement='left', title='mirror the voxel model in y-axis') Mirror y-axis
          button.mirrorBtn.btn.btn-default(data-mirror='z', data-toggle='tooltip', data-container='body', data-placement='left', title='mirror the voxel model in z-axis') Mirror z-axis

    #UpdateProgress.progress(style='position: fixed; bottom: 0px; width: 100%; margin: 0; display: none;')
      #UpdateProgressBar.progress-bar.progress-bar-info.progress-bar-striped.active(style='width: 0%;') updating local Trove Blueprint Datebase ...
    
    if deploy
      script(src='troxel.min.js', type='text/javascript')
      script(src='//www.google-analytics.com/analytics.js', type='text/javascript', async)
      script.
        window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;ga('create','UA-54717865-2','auto',{'storage':'none','clientId':localStorage.getItem('_ga_id')});ga(function(t){localStorage.setItem('_ga_id',t.get('clientId'));});ga('send','pageview');
    else
      script(src='jspm_packages/system.js', type='text/javascript')
      script(src='jspm.browser.js', type='text/javascript')
      script(src='jspm.config.js', type='text/javascript')
      script.
        System.import('troxel/Main.coffee').catch(function(e){console.warn(e);});