Merge remote-tracking branch 'upstream/master'

This commit is contained in:
unsettledgames 2021-07-07 10:13:31 +02:00
commit a18584ff04
111 changed files with 3225 additions and 3001 deletions

3
.gitignore vendored
View File

@ -3,4 +3,5 @@
routes
build
node_modules
.idea
.idea
.history

View File

@ -1 +0,0 @@
<mxfile host="app.diagrams.net" modified="2021-04-25T14:57:23.836Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36 Edg/90.0.818.46" etag="K3S2uQVQjw_jQCK8DyHB" version="14.6.6" type="device"><diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">7V1bc+K4Ev41VOU8kPI98BjIZGb3MHuyk9nM7KOCBWhiWxxZBJhfv5ItG2zJxgSMsx5XpSq4Jd/0tVqfultyzxz7m48ELBefsQu9nqG5m5551zMMfWAN2D8u2QqJMxSSOUGukO0Ej+gnFEJNSFfIhWGmIsXYo2iZFU5xEMApzcgAIXidrTbDXvauSzCHkuBxCjxZ+g25dBFLB8bNTv4JovkiuTN7wbjEB0ll8SbhArh4vScyP/TMMcGYxr/8zRh6vPWSdvn22/abN3lxPv7+Z/h/8Nfov1//eOrHF7s/5pT0FQgM6Jsv3X+6tz5PHp5mqz/+fnn83+Oy/xX3LUe8G90mDQZd1n7iEBO6wHMcAO/DTjoieBW4kF9WY0e7OhOMl0yoM+EPSOlWKANYUcxEC+p7opS9Btl+Zwd97VpLBX/zC15rw1RwtxG3iI+2+0cPkCAfUkiEMH4N/uw52A+0magX4hWZilN/vszuPz1ZP74vH+7/XGsfb59/74u21Sggc0hLGnRPM1ifgpg9I9myEwn0AEWv2acDQrfnab0dfuyHgFANZ9lTvgJvJe70lfW18DMMVhLO4Rr5Hgg4oDMc0ARy9vAj4KF5wH5PWdvxFh69QkIR61O3ooByoEfTBfLcCdjiFW+RkILpS3I0WmCCfrLLggRzVkyo0AjDydR45GcKHAkMWZ2HBDY9FU1ASEWdKfY8sAzRc/TAvIrPYEHBCFOK/eRCGSVN+250QAl+Sa2BnmpPVWXhrQE3e0jKcItSJ7GCifU0xfF6Z4p0R8gW+2bI0opVRNzuCzOXIJizRkjvZ5i5+1kV72c42dsBjwEfAApHvBlDSTHTV327rpqSrvbF2BBKusqam+7ppQdntFArwyWYomA+iercWTvJF/G6XITZuTMv0ogFcl0YRBpDAQWxUnE1WWIU0Kg97BH7Y6021q7tns0eaMyO9d0x++PVCR3jgCkXQJEWQaaxa8i1tkwZhVnUlFpY2skPa+E2C+6xSnA2s2RJUEsIeyiyRHuDhNxLD8DvMyCj8Ung/TUajfq6pBOmrBOmAn8PPEPvAYeIIsyvT+K6Ob04BH1doNpGNVAHNWFqKzAdcUyhx+wSH3aukPufHtcpU4+1mxczLpir0LKuXhfeTkVLPigZOKoCrqaKg0apIm//faJ4gCSekQ8qW6MqH9SdC/FB5d1tu1HMctTesP8loJlmo6DdNAHae2l7Y9hk2zuNzIffS9s7dpNtL09eH9AGspZGFBMJlm76mp++SlyiqgYVTl9T11fJ9NVQziTMEtr5r5u+qgd2SVv59NXD83CP8/YjQkwpo6R58ZLpBaRhhiBnKsyQB/MngSnvhveIN1rZebHDJyOmO0dQ9jmAxx5QdYYHtpCoTnERYO+5go/bkEK/+Elipg9dRpUpV8O2Uf1jZvUHOmexQTxmVq/ui5pVk8E2pC4gQdzyaX0NqFY1sWeY16vZpwziLzzNsyoyJ91okjnJ/rV4iOgo08UpUz/lLMe6/NOIaXs5k+wz7Ee9lxN8HnrO8QcU3kZ8p5hhxBSluDzmSxNeS8lN2AigKnydbVTi6QJOXyB5xoC4orxjNEeNfdaxjEYdHDPrYjROx2jOjqpe2XNdE6g3ClB5KAIHkXlhFu9KjlPggLXNXnHLOnp9YA+qgW0aNaE9kND+8MreaLSSo8odH6qfDzk5OmQZFa2BrrWeDg2VdIgpmffM1OHXzoJ4i2kanIVdnCMLQj1HlB3cHbs4FdULpkGoQZX9wAmBuIKvkddzvNepZaIBfUTjmh3LqAp6VUZZlkR3Guqy61M9IewoxiVcLo59kGOk3pWMqW9VlqVaU9VplgHwJW+Le9j9EoufUKwWefkET19g/irTJPhT5KNxCVgzMzUGwStQBMleEVwnZS0zj3XzoSKndEkASdVL6nO36F1iaA24qhwuSmBr40RFuaEUz5khjc0HoluF2yWuERsSRfFq6TJr+bBvFXK1WmYialQS2VGjVJKbuhw1tiWhddHcxGtNy4Yar7Ubo9fs0qOSFNJ3H4TUZed5xIm7xUdNZW+92fV20/7sLTkooIwnciG3Hh886HcpTG8YhQrS34/0ydXHQOVwQcdAT4a16YifLnvWY/4I3Dhwr6CWBPpYpAqoFy6tlh6DlJZU8SEboEeQ9V5l8YyNwmwqfOt5ituLQjG1Vj4fn7OnT98yO1SfKlaMR+pl2TenZUmqF2V3lKgBSjSwsxSlqqHSh613FBpyIKPIURg+isTuNs+862ZGRRtFHMmMrNqSu+UQR8eMTob1pmFmZMjhALFsmw8HKo9bqCIjIeu3qsooJ5SSqmLLUZBvFaaFLbMl9alTZXZTlxfPkF34Xzg/4A3Z0ZyGaI6uDd/Ic8z28xx1Evp0RXiTR5rSNvNTO5U5T1p3bU4eQ/ZMd1TmZFibdvIYRXndKJgS1gCQ92UF03BhaXEIIyNwxY1/x0Sqa0NFJuLURkRkn9/D/tLmjoZcnIbktw/op5sT7WvJQMULjNbzkORR8zwEe7iLQJ2TnBTsJ1NCTlQaWZufxVQlEHfk5ERYVX4WFax1kZNkeZMqAjWOuvhV3NOLAlEllXL1uXIA8pEAF7Emi8/QRdY5/20oOA6DZLSdrHwUcARViVhxlTtAXgIY5pOsdhUeAV0RwHWgsMoY+0scxI/mLxW1fD40YtI5fo7RbwXdUum3btXFt0zZk3if7jzTka2Lk61+nmylC+gO6kj7V9qZqozUbpA9ZISK9kE8kjvVNsiq/Dp8SAngmtsiVZhhCYOCohC8wgeCf6jjE3DDm3ivvBupqilJ4tU7pCSOU5OW2LoE1q+8B6op3GYHs4mtgvHmMtnEpuzd+4RCisWlO3ZxYXZh5iJK1b9k0P5tjUw5iTTaiJEAH3ar1o4eT26OJh1KPajNYaNKLu245Imw2hW7d11c0pLdsSKnJXCxMh1XKeYkUoxTHUk8Av2K0aNkt4fzwy97YQWM9yTKgOw4x+U5h2O/kXO0P1s3ceup1i/dse6v2idRbMOcDy5No2W0XeLLW/ZCO893l+y6qIqlyvbsqMqJsKqC2BelKs181GWD6Pe937E7wxZHO2cGP8gsl/6+fxCfpVvmAS9IMwute5JnpPjbTU05RqxGvg5T9sVOXXPeI5pJqvvhL84UZDZdCM9ho3jqDE4ni6c2OOSjfC+985gNSi/07SatUTS16+FwkOud9rvc1MKuiGbRxPFCn4OSafZd7uMn3cQwObjYxNDOfVVXHepWOqPbn1foqDd8E+sbEu2V9Lab6pXPCWJLcLpXuq4op9NtpVYDrE3vLusUfmV3gddJX77ia7RlVzTrdfBAlamHQ3jreUm1sPNZV9eNqutfnJIhp0A52CHBmO4PDAQsF/wTKbzGPw==</diagram></mxfile>

View File

@ -2,57 +2,58 @@ const fs = require('fs');
const path = require('path');
const gulp = require('gulp');
const include = require('gulp-include');
const hb = require('gulp-hb');
const handlebars = require('gulp-hb');
const sass = require('gulp-sass');
const rename = require('gulp-rename');
const hb_svg = require('handlebars-helper-svg');
//const hb_svg = require('handlebars-helper-svg');
const BUILDDIR = process.argv[2] || './build/';
const SLUG = 'pixel-editor';
console.log('Building Pixel Editor');
function copy_images(){
// Icons
gulp.src('./images/*.png').pipe(gulp.dest(path.join(BUILDDIR, SLUG)));
gulp.src('./images/*.png').pipe(gulp.dest(BUILDDIR));
// Splash images
gulp.src('./images/Splash images/*.png').pipe(gulp.dest(path.join(BUILDDIR, SLUG)));
gulp.src('./images/Splash images/*.png').pipe(gulp.dest(BUILDDIR));
// Logs images
gulp.src('./images/Logs/*.gif').pipe(gulp.dest(path.join(BUILDDIR, SLUG)));
gulp.src('./images/Logs/*.gif').pipe(gulp.dest(BUILDDIR));
}
function copy_logs() {
gulp.src('logs/*.html').pipe(gulp.dest(path.join(BUILDDIR, SLUG)));
gulp.src('logs/*.html').pipe(gulp.dest(BUILDDIR));
}
function render_js(){
gulp.src('./js/*.js')
.pipe(include({includePaths: [
'_ext/scripts',
'js',
'!js/_*.js',
]}))
.on('error', console.log)
.pipe(gulp.dest(path.join(BUILDDIR, SLUG)));
.pipe(gulp.dest(BUILDDIR));
}
function render_css(){
gulp.src('css/*.scss')
.pipe(sass({includePaths: ['css', '_ext/sass', '_ext/modules/css']}))
.pipe(gulp.dest(path.join(BUILDDIR, SLUG)));
.pipe(sass({includePaths: ['css']}))
.pipe(gulp.dest(BUILDDIR));
}
function compile_page(){
gulp.src(path.join('./views/', SLUG + '.hbs'))
.pipe(hb({encoding: 'utf8'})
.partials('./_ext/modules/_*.hbs')
.helpers({ svg: hb_svg })
.helpers('./_ext/modules/hbs/helpers/**/*.js')
gulp.src(path.join('./views/index.hbs'))
.pipe(include({includePaths: ['/svg']}))
.pipe(handlebars({encoding: 'utf8', debug: true, bustCache: true})
.partials('./views/[!index]*.hbs')
//.helpers({ svg: hb_svg })
.helpers('./helpers/**/*.js')
.data({
projectSlug: SLUG,
projectSlug: 'pixel-editor',
title: 'Lospec Pixel Editor',
layout: false,
}))

103
css/_canvas.scss Normal file
View File

@ -0,0 +1,103 @@
.drawingCanvas {
cursor: url('/pixel-editor/pencil-tool-cursor.png');
border: solid 1px #fff;
image-rendering: optimizeSpeed;
/* Legal fallback */
image-rendering: -moz-crisp-edges;
/* Firefox */
image-rendering: -o-crisp-edges;
/* Opera */
image-rendering: -webkit-optimize-contrast;
/* Safari */
image-rendering: optimize-contrast;
/* CSS3 Proposed */
image-rendering: crisp-edges;
/* CSS4 Proposed */
image-rendering: pixelated;
/* CSS4 Proposed */
-ms-interpolation-mode: nearest-neighbor;
/* IE8+ */
width: 400px;
height: 400px;
position: fixed;
display: none;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.64);
background-color: transparent;
}
#checkerboard {
z-index: 1;
}
#pixel-canvas {
z-index: 3;
background: transparent;
}
#pixel-grid {
z-index: 5000;
background: transparent;
}
#tmp-canvas {
z-index: 5;
background: transparent;
}
#vfx-canvas {
z-index: -5000;
background: transparent;
}
#eyedropper-preview {
position: absolute;
width: 45px;
height: 45px;
border-radius: 30px;
border: solid 10px red;
z-index: 1200;
display: none;
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.25), inset 0 0 6px 0 rgba(0, 0, 0, 0.2);
pointer-events: none;
&.dark {
box-shadow: 0 0 8px 0 rgba(255, 255, 255, 0.5), inset 0 0 6px 0 rgba(255, 255, 255, 0.5);
}
}
#brush-preview {
position: absolute;
border: solid 1px #fff;
z-index: 1200;
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.5), inset 0 0 2px 0 rgba(0, 0, 0, 0.5);
pointer-events: none;
left: -500px;
&.dark {
border: solid 1px #000;
box-shadow: 0 0 3px 0 rgba(255, 255, 255, 0.8), inset 0 0 3px 0 rgba(255, 255, 255, 0.8);
}
}
#canvas-view {
bottom: 0px;
left: 64px;
right: 48px;
top: 48px;
cursor: default;
position: fixed;
display: block;
}
#canvas-view-shadow {
box-shadow: inset 0px 0px 4px 0px rgba(0, 0, 0, 0.4);
position: fixed;
bottom: 0px;
left: 64px;
right: 48px;
top: 48px;
display: block;
pointer-events: none;
}

196
css/_colors-menu.scss Normal file
View File

@ -0,0 +1,196 @@
#colors-menu {
right: 200px;
width: 48px;
display: flex;
justify-content: flex-start;
flex-direction: column;
list-style-type: none;
top: 48px;
bottom: 0;
padding: 0;
margin: 0;
background-color: $basecolor;
box-sizing: border-box;
position: fixed;
z-index: 1120;
li {
width: 48px;
flex-basis: 48px;
&:not(.noshrink) {
flex-grow: 1;
}
&.noshrink {
flex-grow: 0;
flex-shrink: 0;
}
}
}
//added when the color is a duplicate of another
#duplicate-color-warning {
display: inline-block;
visibility: hidden;
margin-left: 5px;
opacity: 0.75;
cursor: help;
&:hover {
opacity: 0.9;
}
}
//floating button to open jscolor picker
.color-edit-button {
position: absolute;
top: 3px;
left: 0px;
background: $basecolor;
padding: 6px 10px 3px 6px;
border-radius: 4px 0 0 4px;
cursor: pointer;
transition: left 0.25s;
z-index: -1;
box-shadow: 0px 15px 15px 0px rgba(0, 0, 0, 0.2);
path {
fill: $baseicon;
}
&:hover {
background: $basehover;
path {
fill: $basehovericon;
}
} //class added when jscolor is opened
&.hidden {
left: 0px !important;
}
}
#colors-menu li {
position: relative;
}
#colors-menu li:hover .color-edit-button {
display: block;
left: -32px;
}
#colors-menu li.selected:hover .color-edit-button {
display: block;
left: -35px;
}
#colors-menu li button {
height: 100%;
display: block;
}
.color-value {
display: none;
}
#add-color-button {
background: $basecolor;
path {
fill: #6f6873;
}
}
#colors-menu li {
button {
border: none;
width: 100%;
cursor: url('/pixel-editor/eyedropper.png'), auto;
} //white outline
&.selected button::before {
content: "";
display: block;
position: absolute;
top: -3px;
left: -3px;
border: solid 3px #fff;
width: 100%;
height: 100%;
border-radius: 4px;
box-shadow: 0px 0px 0px 3px rgba(0, 0, 0, 0.15);
z-index: 10;
} //inner outline
&.selected button::after {
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
border: solid 1px rgba(0, 0, 0, 0.15);
width: 100%;
height: 100%;
box-sizing: border-box;
}
}
#colors-menu li.noshrink button {
cursor: pointer;
}
#add-color-button:hover {
background: $basehover;
}
.jscolor-picker-bottom {
display: none;
position: absolute;
left: -4px;
right: -4px;
bottom: -7px;
color: $basetext;
span {
margin-left: 5px;
}
input {
width: 64px;
background: $indent;
color: $indenttext;
border-radius: 4px;
border: none;
margin: 0;
padding: 3px 12px;
margin-left: 5px;
}
}
.delete-color-button {
background: none;
padding: 0px;
border: none;
text-align: center;
cursor: pointer;
float: right;
path {
fill: $baseicon;
}
&:hover path {
fill: $basehovericon;
}
&.disabled {
cursor: not-allowed;
& path {
fill: lighten($basecolor, 10%) !important;
}
}
}

59
css/_compatibility.scss Normal file
View File

@ -0,0 +1,59 @@
#compatibility-warning {
display: flex;
justify-content: center;
align-items: center;
visibility: hidden;
z-index: 3000;
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(35, 32, 36, 0.92);
color: $basetext;
div {
position: relative;
width: 100%;
height: 100%;
div {
width: 400px;
background-color: $basecolor;
padding: 20px;
width: 400px;
height: 200px;
position: absolute;
top: 50%;
left: 50%;
margin: -120px 0 0 -220px;
}
}
a {
color: $baselink;
border-bottom: dotted 1px transparent;
text-decoration: none;
&:hover {
border-bottom: dotted 1px $basetext;
}
}
button {
background: $basehover;
border: none;
border-radius: 4px;
color: $basehovertext;
padding: 10px 20px;
cursor: pointer;
margin: 0 auto;
display: block;
&:hover {
background: $baseselected;
}
}
}
#cookies-disabled-warning {
display: none;
color: $basetextweak;
font-style: italic;
}

46
css/_general.scss Normal file
View File

@ -0,0 +1,46 @@
body {
background: darken($basecolor, 6%);
font-family: 'Roboto', sans-serif;
margin: 0;
padding: 0;
color: #fff;
font-size: 14px;
width: 100%;
height: 100%;
overflow: hidden;
-moz-user-select: none;
/* Firefox */
-ms-user-select: none;
/* Internet Explorer */
-khtml-user-select: none;
/* KHTML browsers (e.g. Konqueror) */
-webkit-user-select: none;
/* Chrome, Safari, and Opera */
-webkit-touch-callout: none;
/* Disable Android and iOS callouts*/
}
//don't let svg handle click events, just send to parents
svg {
pointer-events: none;
path {
pointer-events: none;
}
}
//remove blue outline in chrome
*:focus {
outline: 0 !important;
}
.weak {
font-size: 0.8em;
color: $basetextweak;
}
#data-holders, .preload {
display: none;
}

39
css/_help.scss Normal file
View File

@ -0,0 +1,39 @@
#help {
max-height: 500px;
overflow-y:scroll;
li {
margin-top:5px;
}
// Fancy scrollbar
&::-webkit-scrollbar {
background: #232125;
width: 0.5em;
}
&::-webkit-scrollbar-track {
margin-top: -0.125em;
width: 0.5em;
}
&::-webkit-scrollbar-thumb {
background: #332f35;
border-radius: 0.25em;
border: solid 0.125em #232125; //same color as scrollbar back to fake padding
}
&::-webkit-scrollbar-corner {
background: #232125;
}
}
.keyboard-key {
background: lighten($basecolor, 20%);
box-shadow: 0 3px 0 2px lighten($basecolor, 12%);
padding: 0 4px;
border-radius: 2px;
margin: 6px;
display: inline-block;
color: #c0bfc1;
}

210
css/_layers.scss Normal file
View File

@ -0,0 +1,210 @@
#layer-properties-menu {
visibility: hidden;
margin: 0;
padding: 0;
top: 0;
right: 0;
width: 120px;
text-align: center;
margin-right: 200px;
/*border:1px solid $basetext;*/
list-style: none;
position: relative;
z-index: 1200;
list-style-type: none;
background-color: $basecolor;
position: fixed;
overflow: visible;
li button {
color: $basetext;
height: 100%;
padding: 10px;
background: none;
border: none;
cursor: pointer;
width: 100%;
}
li button:hover {
background-color: $basehover;
}
}
.preview-canvas {
image-rendering: optimizeSpeed;
/* Legal fallback */
image-rendering: -moz-crisp-edges;
/* Firefox */
image-rendering: -o-crisp-edges;
/* Opera */
image-rendering: -webkit-optimize-contrast;
/* Safari */
image-rendering: optimize-contrast;
/* CSS3 Proposed */
image-rendering: crisp-edges;
/* CSS4 Proposed */
image-rendering: pixelated;
/* CSS4 Proposed */
-ms-interpolation-mode: nearest-neighbor;
/* IE8+ */
}
#layers-menu {
&::-webkit-scrollbar {
background: #232125;
width: 1em;
}
&::-webkit-scrollbar-track {
margin-top: -0.125em;
width: 1em;
}
&::-webkit-scrollbar-thumb {
background: #332f35;
border-radius: 0.25em;
border: solid 0.125em #232125; //same color as scrollbar back to fake padding
}
&::-webkit-scrollbar-corner {
background: #232125;
}
scrollbar-color: #332f35 #232125;
scroll-behavior: smooth;
width:200px;
top: 48px;
bottom: 0;
right:0;
padding: 0;
margin: 0;
background-color: $basecolor;
box-sizing: border-box;
position: fixed;
z-index: 1120;
list-style-type: none;
overflow-y:scroll;
overflow-x:hidden;
#add-layer-button {
path {
fill: $baseicon;
}
svg {
position: relative;
margin-right: 10px;
}
position:relative;
justify-content: center;
display:flex;
align-items:center;
margin-top:2px;
font-size: 1.2em;
color: $basetext;
height: 100%;
width: 100%;
padding: 17px;
background: none;
border: none;
cursor: pointer;
}
#add-layer-button:hover {
color: $basehovertext;
background-color: $basehover;
}
}
.selected-layer {
ul.layer-buttons li.layer-button {
visibility: visible;
button svg path {
fill: $baseselectedicon;
}
&:hover button svg path {
fill: $baseselectediconhover;
}
}
color: $baseselectedtext;
background-color: $baseselected !important;
}
.layerdragover {
margin-top: 5px;
border-top: 3px solid $basehovertext;
}
.layers-menu-entry {
cursor: pointer;
margin-bottom: 2px;
font-size: 1em;
color: $basetext;
background-color: lighten($basecolor, 4%);
display: inline-block;
height: 50px;
width: 100%;
display: flex;
align-items: center;
ul.layer-buttons {
top: 0;
left: 0;
margin: 0;
padding: 0;
box-sizing: border-box;
position: relative;
height: 100%;
list-style: none;
path {
fill: $basehovericon;
}
li:hover {
path {
fill: $basehovericonhover;
}
}
.layer-button {
visibility: hidden;
height: 50%;
}
}
.lock-layer-button,
.hide-layer-button {
background: none;
border: none;
cursor: pointer;
height: 100%;
position: relative;
}
canvas {
display: inline-block;
height: 50px;
width: 50px;
background-color: lightgrey;
left: 4px;
}
p {
right: 0;
display: inline-block;
padding-left: 10px;
height: 18px;
overflow: hidden;
position: relative;
}
}
.layers-menu-entry:hover {
ul.layer-buttons li {
visibility: visible !important;
}
color: $basehovertext;
background-color: $basehover;
}

85
css/_main-menu.scss Normal file
View File

@ -0,0 +1,85 @@
#main-menu {
height: 48px;
left: 0;
right: 0;
list-style-type: none;
margin: 0;
padding: 0;
background-color: $basecolor;
position: fixed;
z-index: 1110;
overflow: visible;
&>li {
float: left;
height: 100%;
}
li button,
li a {
color: $basetext;
height: 100%;
padding: 17px;
background: none;
border: none;
cursor: pointer;
}
li.selected {
background-color: $basehover;
&>button {
color: $basehovertext;
}
ul {
display: block;
}
}
li ul {
display: none;
position: absolute;
top: 48px;
list-style-type: none;
padding: 0;
margin: 0;
background-color: $basehover;
box-shadow: 0px 2px 2px 0px rgba(0, 0, 0, 0.5);
padding-bottom: 2px;
li {
width: 100%;
button,
a {
width: 100%;
text-align: left;
padding: 8px 32px 8px 16px;
font-size: 1em;
&:hover {
background-color: $baseselected;
color: $baseselectedtext;
}
}
a {
display: block;
text-decoration: none;
box-sizing: border-box;
}
}
}
.disabled {
color: #6f6e70 !important;
}
}
/*app title*/
.logo {
color: lighten($basecolor, 20%);
text-transform: uppercase;
font-weight: bold;
padding: 17px 10px 0;
cursor: default;
box-sizing: border-box;
}
#main-menu li.open, #main-menu li button:hover {
background: $basehover;
}

28
css/_new-pixel.scss Normal file
View File

@ -0,0 +1,28 @@
#new-pixel-warning {
display: none;
text-align: center;
margin: 20px 0 0;
font-style: italic;
}
.dimentions-x {
margin: -2px 7px;
path {
fill: $baseicon
}
}
#no-palette-button {
display: none;
}
#editor-mode-info {
font-style: italic;
}
#editor-mode {
display: none;
}

315
css/_palette-editor.scss Normal file
View File

@ -0,0 +1,315 @@
/***********************COLOUR PICKER*****************************/
#colour-picker {
background-color:$basecolor;
width:250px;
height:350px;
position:absolute;
display:inline-block;
input[type=text] {
background-color:$basetext;
color:$basecolor;
box-shadow:none;
border:none;
}
input[type=range] {
width: 100%;
margin: 2.2px 0;
background-color: transparent;
-webkit-appearance: none;
}
input[type=range]::-webkit-slider-runnable-track {
background: #484d4d;
border: 0;
width: 100%;
height: 25.6px;
cursor: pointer;
}
input[type=range]::-webkit-slider-thumb {
margin-top: -2.2px;
width: 18px;
height: 30px;
background: $basetext;
border: 0;
cursor: pointer;
-webkit-appearance: none;
}
input[type=range]::-moz-range-track {
background: #484d4d;
border: 0;
width: 100%;
height: 25.6px;
cursor: pointer;
}
input[type=range]::-moz-range-thumb {
width: 18px;
height: 30px;
background: $basetextweak;
border: 0;
cursor: pointer;
}
/*TODO: Use one of the selectors from https://stackoverflow.com/a/20541859/7077589 and figure out
how to remove the vertical space around the range input in IE*/
@supports (-ms-ime-align:auto) {
/* Pre-Chromium Edge only styles, selector taken from hhttps://stackoverflow.com/a/32202953/7077589 */
input[type=range].slider {
margin: 0;
/*Edge starts the margin from the thumb, not the track as other browsers do*/
}
}
}
#cp-modes {
margin: 0 0 0 0;
font-size:0;
height:40px;
float:left;
display:flex;
font-family: 'Roboto', sans-serif;
background-color:$basetextweak;
width:100%;
button {
font-size:14px;
left:0;
right:0;
margin:0 0 0 0;
border: none;
border-radius: 0;
height:100%;
width:37x;
background-color:$basehover;
color:$basetext;
cursor:pointer;
}
button:hover {
background-color:$baseicon;
color:$basetext;
}
button.cp-selected-mode {
background-color:$baseicon;
color:$basetext;
}
input {
width:60px;
}
div {
background-color:yellow;
width:100%;
height:100%;
z-index:2;
position:relative;
}
}
#sliders-container {
padding:10px;
}
.cp-slider-entry {
width:100%;
height:30px;
display:flex;
align-items:center;
margin-top:2px;
position:relative;
label {
width: 20px;
font-size:15px;
font-style: bold;
}
input[type=text] {
text-align:center;
width: 30px;
overflow:visible;
margin-left:4px;
}
}
.colour-picker-slider {
width:90%;
}
#cp-minipicker {
width:100%;
height:100px;
position:relative;
margin: 0 0 0 0;
z-index: inherit 2000;
input {
width:100%;
margin: none;
padding: none;
}
.cp-colours-previews {
width:100%;
position:relative;
}
.cp-colour-preview {
width:100%;
position:relative;
background-color:blue;
color:$basecolor;
float:left;
height:30px;
justify-content: center;
display:flex;
align-items: center;
font-size:12px;
}
#cp-colour-picking-modes {
width:100%;
position:relative;
}
button {
font-size:14px;
left:0;
right:0;
margin:0 0 0 0;
border: none;
border-radius: 0;
height:30px;
width:16.66666%;
float:left;
overflow:hidden;
background-color:$basehover;
color:$basetext;
cursor:pointer;
}
button:hover {
background-color:$baseicon;
color:$basetext;
}
button.cp-selected-mode {
background-color:$baseicon;
color:$basetext;
}
}
#cp-canvas-container {
width:100%;
height:100%;
position:relative;
}
#cp-spectrum {
width:100%;
height:100px;
position:absolute;
background-color: transparent;
}
.cp-picker-icon{
width:16px;
height:16px;
border-radius:100%;
position:absolute;
background-color:white;
z-index:2;
border:2px solid black;
}
/***************PALETTE BLOCK****************/
div#palette-block {
z-index:1000;
position:relative;
resize: horizontal;
margin: 0 0 0 0;
width:600px;
height:400px;
}
div#palette-container {
display:inline-block;
background-color: #232125;
position:absolute;
scrollbar-color: #332f35 #232125;
scroll-behavior: smooth;
left:300px;
width:300px;
height:320px;
overflow-y: scroll;
&::-webkit-scrollbar {
background: #232125;
width: 0.5em;
}
&::-webkit-scrollbar-track {
margin-top: -0.125em;
width: 0.5em;
}
&::-webkit-scrollbar-thumb {
background: #332f35;
border-radius: 0.25em;
border: solid 0.125em #232125; //same color as scrollbar back to fake padding
}
&::-webkit-scrollbar-corner {
background: #232125;
}
}
ul#palette-list {
list-style:none;
margin: 0 0 0 0;
padding: 0 0 0 0;
position:relative;
display:inline-block;
li {
float:left;
width:50px;
height:50px;
border:none;
min-width:20px;
min-height:20px;
max-width:75px;
max-height:75px;
}
}
div#pb-options {
position:relative;
left:280px;
height:30px;
width:300px;
top:300px;
button {
border-radius:none;
position:relative;
float:left;
width:50%;
height:100%;
text-align:center;
cursor: pointer;
font-size:16px;
background-color:$baseicon;
border:none;
}
button:hover {
color: $basehovertext;
background-color: $basehover;
}
}

155
css/_popup-container.scss Normal file
View File

@ -0,0 +1,155 @@
#pop-up-container {
position: fixed;
z-index: 2000;
width: 100%;
height: 100%;
background-color: rgba(35, 32, 36, 0.75);
display: none;
color: $basetext;
cursor: default;
&>div {
background: $basecolor;
border-radius: 3px;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.5);
width: 400px;
padding: 20px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;
}
h1 {
margin: 0 0 10px;
color: lighten($basecolor, 100%);
text-transform: uppercase;
font-size: 1.5em;
}
h2 {
margin: 25px 0 10px;
color: lighten($basecolor, 70%);
text-transform: uppercase;
font-size: 1em;
}
a {
color: $baselink;
border-bottom: dotted 1px transparent;
text-decoration: none;
&:hover {
border-bottom: dotted 1px $basetext;
}
}
.close-button {
width: 32px;
height: 32px;
position: absolute;
right: 0;
top: 0;
background: transparent;
border: none;
color: $baseicon;
font-weight: bold;
font-size: 1em;
cursor: pointer;
border-radius: 0 3px 0 0;
path {
fill: $baseicon;
}
&:hover {
background: $basehover;
path {
fill: $basehovericon;
}
}
}
div.update {
input {
background: $indent;
border: none;
border-radius: 4px;
color: $indenttext;
padding: 10px 20px;
margin: 0;
width: 60px;
text-align: center;
}
}
/*
input {
background: $indent;
border: none;
border-radius: 4px;
color: $indenttext;
padding: 10px 20px;
margin: 0;
width: 60px;
text-align: center;
}
*/
button.default {
background: $basehover;
border: none;
border-radius: 4px;
color: $basehovertext;
padding: 10px 20px;
cursor: pointer;
margin: 20px 0 0 10px;
&:hover {
background: $baseselected;
}
}
.dropdown-button {
background: $basehover url('/pixel-editor/dropdown-arrow.png') right center no-repeat;
border: none;
border-radius: 4px;
color: $basehovertext;
padding: 5px 20px 5px 5px;
cursor: pointer;
margin: 0;
width: 200px;
text-align: left;
&:hover {
background: $baseselected url('/pixel-editor/dropdown-arrow-hover.png') right center no-repeat;
color: $baseselectedtext;
}
&.selected {
border-radius: 4px 4px 0 0;
}
}
.dropdown-menu {
background: $basehover;
border: none;
color: $basehovertext;
padding: 0;
margin: -1px 0 0 0;
width: 200px;
text-align: left;
position: absolute;
border-radius: 0 0 4px 4px;
overflow: hidden;
display: none;
&.selected {
display: block;
}
button {
background: $basehover;
border: none;
color: $basehovertext;
padding: 5px 20px 5px 5px;
cursor: pointer;
margin: 0;
width: 100%;
text-align: left;
&:hover {
background: $baseselected;
}
}
}
}

220
css/_resize-menus.scss Normal file
View File

@ -0,0 +1,220 @@
#resize-canvas,
#resize-sprite {
display: flex;
position: relative;
flex-wrap: wrap;
}
#pivot-menu {
position: relative;
display: inline-flex;
flex-wrap: wrap;
vertical-align: middle;
text-align: center;
width: 130px;
float: left;
button {
margin-right: 10px;
margin-bottom: 10px;
position: relative;
width: 32px;
height: 32px;
background: $basehover;
border: none;
path {
fill: $basehovericon;
}
transition: background 100ms ease-in-out,
transform 100ms ease;
-webkit-appearance: none;
-moz-appearance: none;
}
button:hover,
button:focus,
button.rc-selected-pivot {
cursor: pointer;
background-color: $baseicon;
path {
fill: $basehovericonhover;
}
border: 2px solid color(base, foreground);
}
button:active {
transform: scale(0.95);
}
}
#borders-menu,
#rc-size-menu,
#rs-size-menu,
#rs-percentage-menu {
display: flex;
position: relative;
flex-wrap: wrap;
width: 250px;
font-size: 15px;
left: 10px;
text-align: center;
button {
background: $basehover;
border: none;
color: $basehovericon;
transition: background 100ms ease-in-out,
transform 100ms ease;
-webkit-appearance: none;
-moz-appearance: none;
}
button:hover,
button:focus {
cursor: pointer;
background-color: $baseicon;
color: $basehovericonhover;
border: 2px solid color(base, foreground);
}
button:active {
transform: scale(0.95);
}
input[type=number] {
position: relative;
margin-left: 10px;
height: 15px !important;
width: 40px !important;
padding: 8px !important;
}
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Firefox */
input[type=number] {
-moz-appearance: textfield;
}
span {
padding-right: 10px;
float: left;
position: relative;
vertical-align: middle;
height: 40px;
width: 100px;
display: inline-flex;
align-items: center;
}
}
#rs-percentage-menu {
width: 400px;
span {
width: 150px;
}
}
#rs-size-menu {
width: 400px;
span {
width: 150px;
}
}
#rs-percentage-menu,
#rs-size-menu {
justify-content: center;
div {
float: none;
}
}
#borders-menu {
width: 400px;
justify-content: center;
div {
float: none;
width: 330px;
padding-left: 50px;
span {
padding-right: 20px;
}
}
}
#rs-ratio-div {
width: 400px;
justify-content: center;
padding-left: 20px;
span {
width: 400px;
justify-content: center;
}
select {
height: 30px;
background-color: $basehover;
color: $basehovericon;
border: none;
position: relative;
left: 10px;
option {
background-color: $basehover;
color: $basehovericon;
padding: 5px;
}
option:checked,
option:hover {
box-shadow: 0 0 10px 100px $basehovericon inset;
color: $basehovericonhover;
}
}
}
#rs-keep-ratio {
background: color(button);
border: none;
font-size: 14px;
color: color(button, foreground);
padding: 10px 20px;
margin: 0 auto;
position: relative;
display: block;
}
#resize-canvas-confirm,
#resize-sprite-confirm {
background: color(button);
border: none;
font-size: 18px;
border-radius: 4px;
color: color(button, foreground);
padding: 10px 20px;
cursor: pointer;
margin: 0 auto;
position: relative;
top: 10px;
display: block;
&:hover {
background: color(button, background, hover);
}
}

15
css/_settings.scss Normal file
View File

@ -0,0 +1,15 @@
.settings-entry {
display: flex;
align-items: baseline;
margin-top:10px;
label {
flex: 1;
}
input {
width: 90px !important;
display: block;
box-sizing: border-box;
float:right;
}
}

25
css/_shake.scss Normal file
View File

@ -0,0 +1,25 @@
.shake {
animation: shake 0.82s cubic-bezier(.36, .07, .19, .97) both;
position: relative;
}
@keyframes shake {
10%,
90% {
transform: translate3d(-1px, 0, 0);
}
20%,
80% {
transform: translate3d(1px, 0, 0);
}
30%,
50%,
70% {
transform: translate3d(-2px, 0, 0);
}
40%,
60% {
transform: translate3d(2px, 0, 0);
}
}

320
css/_splash-page.scss Normal file
View File

@ -0,0 +1,320 @@
/********SPLASH PAGE*************/
#splash {
width:100% !important;
height:100%!important;
background-color: #232125 !important;
opacity: 1 !important;
#splash-input {
width:74%;
height:100% !important;
color:$baselink;
#splash-menu {
position:relative;
height:100%;
left:0;
top:0;
}
.splash-menu {
display: flex;
}
#editor-logo {
font-weight:bold;
text-transform:uppercase;
font-size:20px;
height:35vh;
width:100%;
position:relative;
background-image:url('https://cdn.discordapp.com/attachments/506277390050131978/795660870221955082/final.png');
background-size:cover;
background-position:center;
background-repeat:no-repeat;
}
#black {
width:100%;
height:100%;
position:relative;
background-color:rgba(0,0,0,0.2);
}
#sp-coverdata {
padding:20px;
p, a {
font-size:15px;
position:absolute;
text-transform:none;
right:20px;
}
p {
top:0px;
}
a {
font-size:17px;
bottom:20px;
text-decoration:underline;
}
* {
filter: drop-shadow(3px 5px 2px rgba(0, 0, 0, 0.4));
}
}
}
#sp-quickstart-container {
width:70%;
float:right;
padding:40px;
display: flex;
flex-direction: column;
justify-content: space-between;
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box; /* Opera/IE 8+ */
overflow-y: auto;
&::-webkit-scrollbar {
background: #232125;
width: 0.5em;
}
&::-webkit-scrollbar-track {
margin-top: -0.125em;
width: 0.5em;
}
&::-webkit-scrollbar-thumb {
background: #332f35;
border-radius: 0.25em;
border: solid 0.125em #232125; //same color as scrollbar back to fake padding
}
&::-webkit-scrollbar-corner {
background: #232125;
}
.mode-switcher {
margin-top: 2em;
font-size: 1.2em;
color: $basetext;
a {
font-weight: bolder;
color: white;
margin-left: 0.5em;
}
//show the correct info when the .advanced class is added
.advanced {display: none};
&.advanced-mode {
.basic {display: none}
.advanced {display: inline}
}
}
}
#sp-quickstart {
display:flex;
flex-wrap: wrap;
align-content: flex-start;
overflow-y: auto;
min-height: 0;
flex: 1 1 0;
// Fancy scrollbar
&::-webkit-scrollbar {
background: #232125;
width: 0.5em;
}
&::-webkit-scrollbar-track {
margin-top: -0.125em;
width: 0.5em;
}
&::-webkit-scrollbar-thumb {
background: #332f35;
border-radius: 0.25em;
border: solid 0.125em #232125; //same color as scrollbar back to fake padding
}
&::-webkit-scrollbar-corner {
background: #232125;
}
}
#sp-quickstart-title {
font-size:27px;
text-transform: uppercase;
font-weight: bold;
}
.sp-template {
display: flex;
align-items: center;
height: 5em;
min-width: 5em;
text-transform: uppercase;
width:16%;
border-radius:5%;
margin-right:4%;
margin-top:4%;
background-color:$basecolor;
font-size: 18px;
text-align:center;
font-weight: bold;
&:hover {
cursor:pointer;
background-color:$baseselected;
}
p {
span {
display:block;
font-size:14px !important;
margin: 0 0 0 0;
padding: 0 0 0 0;
}
width:100%;
float:left;
position:relative;
}
}
/*
.sp-template:before {
content:'';
float:left;
padding-top:100%;
}*/
#sp-newpixel {
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box; /* Opera/IE 8+ */
display: inline-block;
width: 30% !important;
height:65vh;
padding:20px;
position:relative;
background-color:$basecolor;
#palette-button-splash {
left:5%;
width:90%;
}
.sp-np-entry {
width:100%;
text-align:center;
}
input {
border:none;
background-color: #232125;
color:$basetext;
font-size:14px;
width:40px;
padding:7px;
text-align:center;
}
#create-button {
font-size:18px;
width:150px;
margin-top:40px;
font-weight: bold;
}
#sp-mode-palette {
text-align: center;
position: relative;
float:bottom;
font-size:16px;
font-weight: bold;
div.button-menu {
border:2px solid $basetextweak;
border-radius:5px;
position:relative;
display:inline-block;
padding: 0 0 0 0;
text-align:left;
width:90%;
div {
border:none;
padding:none;
margin:none;
background-color:transparent;
width:50%;
float:left;
text-align: center;
height:25px;
cursor:pointer;
z-index:1;
p {
z-index:0;
-ms-transform: translateY(-60%);
transform: translateY(-60%);
}
}
.sp-interface-selected {
background-color: $basetextweak;
}
}
}
}
#splash-news {
box-sizing: border-box;
width:26%;
height:100%;
background-color:#151516 !important;
float: right;
}
#latest-update {
width:100%;
font-size:15px;
height:90%;
line-height: 1.5;
position:relative;
top:20px;
padding: 0 1.5em;
overflow-y:scroll;
box-sizing: border-box;
img {
width:100%;
}
&::-webkit-scrollbar {
background: #232125;
width: 0.5em;
}
&::-webkit-scrollbar-track {
margin-top: -0.125em;
width: 0.5em;
}
&::-webkit-scrollbar-thumb {
background: #332f35;
border-radius: 0.25em;
border: solid 0.125em #232125; //same color as scrollbar back to fake padding
}
&::-webkit-scrollbar-corner {
background: #232125;
}
}
}

116
css/_tools-menu.scss Normal file
View File

@ -0,0 +1,116 @@
#tools-menu {
left: 0;
width: 64px;
list-style-type: none;
top: 48px;
bottom: 0;
padding: 0;
margin: 0;
background-color: $basecolor;
box-sizing: border-box;
position: fixed;
z-index: 1120;
}
#tools-menu li {
position: relative;
}
#tools-menu li button:first-child {
text-align: center;
border: none;
background: none;
width: 100%;
padding: 0;
cursor: pointer;
height: 64px;
}
#tools-menu li button path {
fill: $baseicon;
}
#tools-menu li:hover button:first-child path {
fill: $basehovericon;
}
#tools-menu li.selected {
background: $baseselected !important;
}
#tools-menu li.selected button:first-child path {
fill: $baseselectedicon;
}
#tools-menu li.selected.expanded {
padding-bottom: 10px;
}
.tools-menu-sub-button {
text-align: center;
border: none;
background: none;
cursor: pointer;
width: 50%;
height: 22px;
display: none;
line-height: 0;
overflow: hidden;
position: absolute;
bottom: 0;
path {
fill: $baseselectedicon !important;
}
&:hover {
background: $baseselectedhover !important;
path {
fill: $baseselectediconhover !important;
}
}
}
#tools-menu li button#pencil-bigger-button,
#tools-menu li button#zoom-in-button,
#tools-menu li button#eraser-bigger-button,
#tools-menu li button#rectangle-bigger-button,
#tools-menu li button#ellipse-bigger-button,
#tools-menu li button#line-bigger-button {
left: 0;
}
#tools-menu li button#pencil-smaller-button,
#tools-menu li button#zoom-out-button,
#tools-menu li button#eraser-smaller-button,
#tools-menu li button#rectangle-smaller-button,
#tools-menu li button#ellipse-smaller-button,
#tools-menu li button#line-smaller-button {
right: 0;
}
#tools-menu li.selected button#pencil-bigger-button,
#tools-menu li.selected button#pencil-smaller-button,
#tools-menu li.selected button#zoom-in-button,
#tools-menu li.selected button#zoom-out-button,
#tools-menu li.selected button#eraser-bigger-button,
#tools-menu li.selected button#eraser-smaller-button,
#tools-menu li.selected button#rectangle-bigger-button,
#tools-menu li.selected button#rectangle-smaller-button,
#tools-menu li.selected button#ellipse-bigger-button,
#tools-menu li.selected button#ellipse-smaller-button,
#tools-menu li.selected button#line-bigger-button,
#tools-menu li.selected button#line-smaller-button {
display: block;
}
#tools-menu li:hover {
background: $basehover;
}

16
css/_variables.scss Normal file
View File

@ -0,0 +1,16 @@
$basecolor: #332f35; //color(base)
$basetext: lighten($basecolor, 50%); //color(menu, foreground), color(base, foreground, text)
$basetextweak: lighten($basecolor, 30%); //color(menu, foreground), color(base, foreground, text)
$baselink: lighten($basecolor, 100%); //color(menu, foreground), color(base, foreground, text)
$baseicon: lighten($basecolor, 25%); //color(base, foreground)
$basehover: lighten($basecolor, 6%); //color(base, background, hover), color(button), color(menu), color(menu, background, hover)
$basehovertext: lighten($basecolor, 60%); //color(base, foreground, bold), color(menu, foreground, hover), color(button, foreground)
$basehovericon: lighten($basecolor, 40%); //color(base, foreground, hover)
$basehovericonhover: lighten($basecolor, 60%); //color(base, foreground, hover)
$baseselected: lighten($basecolor, 15%); //color(selectedTool, background), color(button, background, hover)
$baseselectedtext: lighten($basecolor, 80%); //color(base, foreground, bold)
$baseselectedicon: lighten($basecolor, 50%); //color(subbutton, foreground), color(selectedTool, foreground)
$baseselectediconhover: lighten($basecolor, 70%); //color(subbutton, foreground, hover)
$baseselectedhover: lighten($basecolor, 25%); //color(subbutton, background, hover)
$indent: darken($basecolor, 5%); //color(indent)
$indenttext: lighten($basecolor, 50%); //color(indent, foreground)

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
[0114/110029.536:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3)

41
helpers/svg.js Normal file
View File

@ -0,0 +1,41 @@
const fs = require("fs");
const handlebars = require("handlebars");
const ltx = require("ltx");
const resolve = require("resolve");
const path = "../svg/";
const nameToModule = {};
const cache = {};
module.exports = function (name, opts) {
name = path + name;
const mod =
nameToModule[name] ||
(nameToModule[name] = resolve.sync(name, {
extensions: [".svg"],
}));
const content =
cache[name] || (cache[name] = fs.readFileSync(mod, "utf-8"));
const svg = parse(content);
Object.assign(svg.attrs, opts.hash);
return new handlebars.SafeString(svg.root().toString());
};
module.exports.cache = cache;
function parse(xml, mod) {
const svg = ltx.parse(xml);
if (svg.name != "svg") {
throw new TypeError("Input must be an SVG");
}
delete svg.attrs.xmlns;
delete svg.attrs["xmlns:xlink"];
return svg;
}

View File

@ -9,7 +9,7 @@ function create(isSplash) {
var height = getValue('size-height' + splashPostfix);
// If I'm creating from the splash screen, I use the splashMode variable
var mode = isSplash ? splashMode : getValue('editor-mode');
var mode = isSplash ? splashMode : pixelEditorMode;
newPixel(width, height, mode);
@ -29,9 +29,7 @@ function create(isSplash) {
//reset new form
setValue('size-width', 64);
setValue('size-height', 64);
setValue("editor-mode", 'Advanced')
setText('editor-mode-button', 'Choose a mode...');
setText('palette-button', 'Choose a palette...');
setText('preset-button', 'Choose a preset...');
}
@ -43,10 +41,9 @@ on('click', 'create-button', function (){
// Getting the values of the form
var width = getValue('size-width');
var height = getValue('size-height');
var mode = getValue("editor-mode");
// Creating a new pixel with those properties
newPixel(width, height, mode);
newPixel(width, height);
document.getElementById('new-pixel-warning').style.display = 'block';
//get selected palette name
@ -61,9 +58,7 @@ on('click', 'create-button', function (){
//reset new form
setValue('size-width', 64);
setValue('size-height', 64);
setValue("editor-mode", 'Advanced')
setText('editor-mode-button', 'Choose a mode...');
setText('palette-button', 'Choose a palette...');
setText('preset-button', 'Choose a preset...');
});
@ -95,9 +90,7 @@ on('click', 'create-button-splash', function (){
//reset new pixel form
setValue('size-width-splash', 64);
setValue('size-height-splash', 64);
setValue("editor-mode", 'Advanced')
setText('editor-mode-button', 'Choose a mode...');
setText('palette-button', 'Choose a palette...');
setText('preset-button', 'Choose a preset...');
});

View File

@ -7,30 +7,13 @@ let modes = {
}
}
let infoBox = document.getElementById('editor-mode-info');
let currentSplashButton = document.getElementById("sp-mode-palette").children[0].children[1];
function splashMode(mouseEvent, mode) {
if (currentSplashButton == undefined) {
currentSplashButton = mouseEvent.target.parentElement;
}
if (mode !== pixelEditorMode) {
// Remove selected class to old button
currentSplashButton.classList.remove("sp-interface-selected");
// Add selected class to new button
mouseEvent.target.parentElement.classList.add("sp-interface-selected");
// Setting the new mode
pixelEditorMode = mode;
}
// Setting the new selected button
currentSplashButton = mouseEvent.target.parentElement;
}
on('click', 'switch-editor-mode-splash', function (e) {
console.log('switching mode')
switchMode();
});
function switchMode(mustConfirm = true) {
console.log('switching mode', 'current:',pixelEditorMode)
//switch to advanced mode
if (pixelEditorMode == 'Basic') {
// Switch to advanced ez pez lemon squez
@ -41,7 +24,13 @@ function switchMode(mustConfirm = true) {
// Hide the palette menu
document.getElementById('colors-menu').style.right = '200px'
//change splash text
document.querySelector('#sp-quickstart-container .mode-switcher').classList.add('advanced-mode');
pixelEditorMode = 'Advanced';
//turn pixel grid off
togglePixelGrid('off');
}
//switch to basic mode
else {
@ -71,57 +60,15 @@ function switchMode(mustConfirm = true) {
// Move the palette menu
document.getElementById('colors-menu').style.right = '0px';
//change splash text
document.querySelector('#sp-quickstart-container .mode-switcher').classList.remove('advanced-mode');
pixelEditorMode = 'Basic';
togglePixelGrid('on');
}
}
on('click', 'switch-mode-button', function (e) {
switchMode();
});
// Makes the menu open
on('click', 'editor-mode-button', function (e){
//open or close the preset menu
toggle('editor-mode-button');
toggle('editor-mode-menu');
//close the palette menu
deselect('palette-button');
deselect('palette-menu');
//close the preset menu
deselect('preset-button');
deselect('preset-menu');
//stop the click from propogating to the parent element
e.stopPropagation();
});
//populate preset list in new pixel menu
Object.keys(modes).forEach(function(modeName,index) {
var editorModeMenu = document.getElementById('editor-mode-menu');
//create button
var button = document.createElement('button');
button.appendChild(document.createTextNode(modeName));
//insert new element
editorModeMenu.appendChild(button);
//add click event listener
on('click', button, function() {
//change mode on new pixel
setValue('editor-mode', modeName);
// Change description
infoBox.innerHTML = modes[modeName].description;
//hide the dropdown menu
deselect('editor-mode-menu');
deselect('editor-mode-button');
//set the text of the dropdown to the newly selected mode
setText('editor-mode-button', modeName);
});
});

View File

@ -1,15 +0,0 @@
var rawFile = new XMLHttpRequest();
rawFile.open("GET", '/pixel-editor/latestLog.html', false);
rawFile.onreadystatechange = function ()
{
if(rawFile.readyState === 4)
{
if(rawFile.status === 200 || rawFile.status == 0)
{
var allText = rawFile.responseText;
document.getElementById("latest-update").innerHTML = allText;
}
}
}
rawFile.send(null);

View File

@ -103,10 +103,10 @@ function newPixel (width, height, editorMode, fileContent = null) {
// If the user selected a palette and isn't opening a file, I load the selected palette
if (selectedPalette != 'Choose a palette...' && fileContent == null) {
console.log('HELO', selectedPalette, palettes[selectedPalette])
//if this palette isnt the one specified in the url, then reset the url
if (!palettes[selectedPalette].specified)
history.pushState(null, null, '/pixel-editor/app');
history.pushState(null, null, '/pixel-editor');
//fill the palette with specified colours
createColorPalette(palettes[selectedPalette].colors,true);
@ -114,7 +114,7 @@ function newPixel (width, height, editorMode, fileContent = null) {
// Otherwise, I just generate 2 semirandom colours
else if (fileContent == null) {
//this wasn't a specified palette, so reset the url
history.pushState(null, null, '/pixel-editor/app');
history.pushState(null, null, '/pixel-editor');
//generate default colors
var fg = hslToRgb(Math.floor(Math.random()*255), 230,70);

View File

@ -1,17 +1,68 @@
//when the page is done loading, you can get ready to start
window.onload = function () {
featureToggles.onLoad();
currentTool.updateCursor();
//check if there are any url parameters
if (window.location.pathname.replace('/pixel-editor/','').length <= 1) {
console.log('no url parameters were found');
//if the user specified dimensions
if (specifiedDimentions) {
//create a new pixel
newPixel(getValue('size-width'), getValue('size-height'), getValue('editor-mode'));
} else {
//otherwise show the new pixel dialog
showDialogue('splash', false);
}
//show splash screen
showDialogue('splash', false);
}
//url parameters were specified
else {
console.log('loading preset from url parameters', window.location.pathname);
let args = window.location.pathname.split('/');
let paletteSlug = args[2];
let dimentions = args[3];
//fetch palette via lospec palette API
fetch('https://lospec.com/palette-list/'+paletteSlug+'.json')
.then(response => response.json())
.then(data => {
//palette loaded successfully
console.log('loaded palette', data);
palettes[paletteSlug] = data;
palettes[paletteSlug].specified = true;
//refresh list of palettes
document.getElementById('palette-menu-splash').refresh();
//if the dimentions were specified
if (dimentions && dimentions.length >= 3 && dimentions.includes('x')) {
let width = dimentions.split('x')[0];
let height = dimentions.split('x')[1];
console.log('dimentions were specified',width,'x',height)
//firstPixel = false;
//create new document
newPixel(width, height);
}
//dimentions were not specified -- show splash screen with palette preselected
else {
//show splash
showDialogue('new-pixel', false);
}
})
//error fetching url (either palette doesn't exist, or lospec is down)
.catch((error) => {
console.warn('failed to load palette "'+paletteSlug+'"', error);
//proceed to splash screen
showDialogue('splash', false);
});
}
};

View File

@ -1,3 +1,59 @@
palettes = {
"Endesga 32": {
colors: "be4a2f,d77643,ead4aa,e4a672,b86f50,733e39,3e2731,a22633,e43b44,f77622,feae34,fee761,63c74d,3e8948,265c42,193c3e,124e89,0099db,2ce8f5,ffffff,c0cbdc,8b9bb4,5a6988,3a4466,262b44,181425,ff0044,68386c,b55088,f6757a,e8b796,c28569".split(
","
),
},
"Resurrect 64": {
colors: "2e222f,3e3546,625565,966c6c,ab947a,694f62,7f708a,9babb2,c7dcd0,ffffff,6e2727,b33831,ea4f36,f57d4a,ae2334,e83b3b,fb6b1d,f79617,f9c22b,7a3045,9e4539,cd683d,e6904e,fbb954,4c3e24,676633,a2a947,d5e04b,fbff86,165a4c,239063,1ebc73,91db69,cddf6c,313638,374e4a,547e64,92a984,b2ba90,0b5e65,0b8a8f,0eaf9b,30e1b9,8ff8e2,323353,484a77,4d65b4,4d9be6,8fd3ff,45293f,6b3e75,905ea9,a884f3,eaaded,753c54,a24b6f,cf657f,ed8099,831c5d,c32454,f04f78,f68181,fca790,fdcbb0".split(
","
),
},
"AAP-64": {
colors: "060608,141013,3b1725,73172d,b4202a,df3e23,fa6a0a,f9a31b,ffd541,fffc40,d6f264,9cdb43,59c135,14a02e,1a7a3e,24523b,122020,143464,285cc4,249fde,20d6c7,a6fcdb,ffffff,fef3c0,fad6b8,f5a097,e86a73,bc4a9b,793a80,403353,242234,221c1a,322b28,71413b,bb7547,dba463,f4d29c,dae0ea,b3b9d1,8b93af,6d758d,4a5462,333941,422433,5b3138,8e5252,ba756a,e9b5a3,e3e6ff,b9bffb,849be4,588dbe,477d85,23674e,328464,5daf8d,92dcba,cdf7e2,e4d2aa,c7b08b,a08662,796755,5a4e44,423934".split(
","
),
},
"Zughy 32": {
colors: "472d3c,5e3643,7a444a,a05b53,bf7958,eea160,f4cca1,b6d53c,71aa34,397b44,3c5956,302c2e,5a5353,7d7071,a0938e,cfc6b8,dff6f5,8aebf1,28ccdf,3978a8,394778,39314b,564064,8e478c,cd6093,ffaeb6,f4b41b,f47e1b,e6482e,a93b3b,827094,4f546b".split(
","
),
},
Journey: {
colors: "050914,110524,3b063a,691749,9c3247,d46453,f5a15d,ffcf8e,ff7a7d,ff417d,d61a88,94007a,42004e,220029,100726,25082c,3d1132,73263d,bd4035,ed7b39,ffb84a,fff540,c6d831,77b02a,429058,2c645e,153c4a,052137,0e0421,0c0b42,032769,144491,488bd4,78d7ff,b0fff1,faffff,c7d4e1,928fb8,5b537d,392946,24142c,0e0f2c,132243,1a466b,10908e,28c074,3dff6e,f8ffb8,f0c297,cf968c,8f5765,52294b,0f022e,35003b,64004c,9b0e3e,d41e3c,ed4c40,ff9757,d4662f,9c341a,691b22,450c28,2d002e".split(
","
),
},
Vinik24: {
colors: "000000,6f6776,9a9a97,c5ccb8,8b5580,c38890,a593a5,666092,9a4f50,c28d75,7ca1c0,416aa3,8d6268,be955c,68aca9,387080,6e6962,93a167,6eaa78,557064,9d9f7f,7e9e99,5d6872,433455".split(
","
),
},
"Sweetie 16": {
colors: "1a1c2c,5d275d,b13e53,ef7d57,ffcd75,a7f070,38b764,257179,29366f,3b5dc9,41a6f6,73eff7,f4f4f4,94b0c2,566c86,333c57".split(
","
),
},
Lospec500: {
colors: "10121c,2c1e31,6b2643,ac2847,ec273f,94493a,de5d3a,e98537,f3a833,4d3533,6e4c30,a26d3f,ce9248,dab163,e8d282,f7f3b7,1e4044,006554,26854c,5ab552,9de64e,008b8b,62a477,a6cb96,d3eed3,3e3b65,3859b3,3388de,36c5f4,6dead6,5e5b8c,8c78a5,b0a7b8,deceed,9a4d76,c878af,cc99ff,fa6e79,ffa2ac,ffd1d5,f6e8e0,ffffff".split(
","
),
},
};
palettes["Commodore 64"] = {"name":"Commodore 64","author":"","colors":["000000","626262","898989","adadad","ffffff","9f4e44","cb7e75","6d5412","a1683c","c9d487","9ae29b","5cab5e","6abfc6","887ecb","50459b","a057a3"]};
palettes["PICO-8"] = {"name":"PICO-8","author":"","colors":["000000","1D2B53","7E2553","008751","AB5236","5F574F","C2C3C7","FFF1E8","FF004D","FFA300","FFEC27","00E436","29ADFF","83769C","FF77A8","FFCCAA"]};
palettes["Gameboy Color"] = {"name":"Nintendo Gameboy (Black Zero)","author":"","colors":["2e463d","385d49","577b46","7e8416"]};
//populate palettes list in new pixel menu
(() => {
const palettesMenu = document.getElementById('palette-menu');
@ -9,43 +65,50 @@
const loadPaletteButton = document.getElementById('load-palette-button');
const loadPaletteButtonSplash = document.getElementById('load-palette-button-splash');
Object.keys(palettes).forEach((paletteName,) => {
splashPalettes.refresh = function () {
splashPalettes.innerHTML = '';
palettesMenu.innerHTML = '';
const button = document.createElement('button');
button.appendChild(document.createTextNode(paletteName));
Object.keys(palettes).forEach((paletteName,) => {
//if the palette was specified by the user, change the dropdown to it
if (palettes[paletteName].specified) {
Util.setText('palette-button', paletteName);
Util.setText('palette-button-splash', paletteName)
//Show empty palette option
noPaletteButton.style.display = 'block';
}
const button = document.createElement('button');
button.appendChild(document.createTextNode(paletteName));
const buttonEvent = () => {
//hide the dropdown menu
Util.deselect('palette-menu');
Util.deselect('palette-button');
Util.deselect('palette-menu-splash');
Util.deselect('palette-button-splash');
//if the palette was specified by the user, change the dropdown to it
if (palettes[paletteName].specified) {
Util.setText('palette-button', paletteName);
Util.setText('palette-button-splash', paletteName)
//Show empty palette option
noPaletteButton.style.display = 'block';
}
//show empty palette option
noPaletteButton.style.display = 'block';
const buttonEvent = () => {
//hide the dropdown menu
Util.deselect('palette-menu');
Util.deselect('palette-button');
Util.deselect('palette-menu-splash');
Util.deselect('palette-button-splash');
//set the text of the dropdown to the newly selected preset
Util.setText('palette-button', paletteName);
Util.setText('palette-button-splash', paletteName);
}
//show empty palette option
noPaletteButton.style.display = 'block';
// Making a copy for the splash page too
const copyButton = button.cloneNode(true);
copyButton.addEventListener('click', buttonEvent);
button.addEventListener('click', buttonEvent);
//set the text of the dropdown to the newly selected preset
Util.setText('palette-button', paletteName);
Util.setText('palette-button-splash', paletteName);
}
// Appending it to the splash palette menu
splashPalettes.appendChild(copyButton);
palettesMenu.appendChild(button);
});
// Making a copy for the splash page too
const copyButton = button.cloneNode(true);
copyButton.addEventListener('click', buttonEvent);
button.addEventListener('click', buttonEvent);
// Appending it to the splash palette menu
splashPalettes.appendChild(copyButton);
palettesMenu.appendChild(button);
});
}
splashPalettes.refresh();
const loadPaletteButtonEvent = () => {
@ -78,7 +141,6 @@
})
newPixelElement.addEventListener('click', () => {
Util.deselect('editor-mode-menu');
Util.deselect('preset-button');
Util.deselect('preset-menu');
Util.deselect('palette-button');

View File

@ -1,9 +1,9 @@
// Start colour of the pixel grid (can be changed in the preferences)
let pixelGridColor = "#0000FF";
let pixelGridColor = "#000000";
// Distance between one line and another in HTML pixels
let lineDistance = 12;
// The grid is not visible at the beginning
let pixelGridVisible = false;
// The grid is visible by default
let pixelGridVisible = true;
// Saving the canvas containing the pixel grid
pixelGridCanvas = document.getElementById("pixel-grid");
@ -11,12 +11,15 @@ pixelGridCanvas = document.getElementById("pixel-grid");
* (triggered by the show pixel grid button in the top menu)
*
*/
function togglePixelGrid(event) {
function togglePixelGrid(newState) {
console.log('toggling pixel grid', newState)
// Getting the button because I have to change its text
let button = document.getElementById("toggle-pixelgrid-button");
// Toggling the state
pixelGridVisible = !pixelGridVisible;
//Set the state based on the passed newState variable, otherwise just toggle it
if (newState == 'on') pixelGridVisible = true;
else if (newState == 'off') pixelGridVisible = false;
else pixelGridVisible = !pixelGridVisible;
// If it was visible, I hide it
if (pixelGridVisible) {

View File

@ -15,7 +15,7 @@ if(!settingsFromCookie) {
enableEyedropperPreview: true, //unused - performance
numberOfHistoryStates: 20,
maxColorsOnImportedImage: 128,
pixelGridColour: '#0000FF'
pixelGridColour: '#000000'
};
}
else{

View File

@ -18,6 +18,6 @@ let coverImage = document.getElementById('editor-logo');
let authorLink = coverImage.getElementsByTagName('a')[0];
let chosenImage = images[Math.round(Math.random() * (images.length - 1))];
coverImage.style.backgroundImage = 'url("/pixel-editor/' + chosenImage.path + '.png")';
coverImage.style.backgroundImage = 'url("' + chosenImage.path + '.png")';
authorLink.setAttribute('href', chosenImage.link);
authorLink.innerHTML = 'Art by ' + chosenImage.author;

View File

@ -3,9 +3,9 @@ var canvasSize;
var zoom = 7;
var dragging = false;
var lastMouseClickPos = [0,0];
var dialogueOpen = false;
var dialogueOpen = true;
var documentCreated = false;
var pixelEditorMode = "Advanced";
var pixelEditorMode = "Basic";
//common elements
var brushPreview = document.getElementById("brush-preview");

View File

@ -0,0 +1,15 @@
function closeCompatibilityWarning() {
document.getElementById("compatibility-warning").style.visibility = "hidden";
}
//check browser/version
if (
(bowser.firefox && bowser.version >= 28) ||
(bowser.chrome && bowser.version >= 29) ||
(!bowser.mobile && !bowser.tablet)
)
console.log("compatibility check passed");
//show warning
else document.getElementById("compatibility-warning").style.visibility = "visible";

View File

@ -1,18 +1,18 @@
/**utilities**/
//=include utilities/on.js
//=include utilities/onChildren.js
//=include utilities/onClick.js
//=include utilities/onClickChildren.js
//=include utilities/select.js
//=include utilities/getSetText.js
//=include utilities/getSetValue.js
//=include utilities/hexToRgb.js
//=include utilities/rgbToHex.js
//=include utilities/rgbToHsl.js
//=include utilities/hslToRgb.js
//=include libraries/cookies.js
//=include util/on.js
//=include util/onChildren.js
//=include util/onClick.js
//=include util/onClickChildren.js
//=include util/select.js
//=include util/getSetText.js
//=include util/getSetValue.js
//=include util/hexToRgb.js
//=include util/rgbToHex.js
//=include util/rgbToHsl.js
//=include util/hslToRgb.js
//=include lib/cookies.js
//=include _pixelEditorUtility.js
//=include sortable.js
//=include lib/sortable.js
//=include _algorithms.js
//=include Util.js
@ -34,7 +34,7 @@
//=include _changeZoom.js
//=include ColorModule.js
//=include _dialogue.js
//=include _featuresLog.js
//!=include _featuresLog.js
//=include _drawLine.js
//=include _getCursorPosition.js
//=include _fill.js
@ -51,7 +51,6 @@
//=include _colorPicker.js
//=include _paletteBlock.js
//=include _splashPage.js
//=include _logs.js
/**load file**/
//=include _loadImage.js

79
js/util/ajax.js Normal file
View File

@ -0,0 +1,79 @@
//GET: ajax(String url, Function success [,timeout])
//POST: ajax(String url, Object postData, Function success [,timeout])
Util.ajax = function (url, arg2, arg3, arg4) {
if (typeof arg2 == 'function') {
var success = arg2;
var timeout = arg3 || 10000;
}
else {
var postData = arg2;
var success = arg3;
var timeout = arg4 || 10000;
}
var start = new Date();
console.log('AJAX - STARTING REQUEST', url, '(' + timeout + ')');
//start new request
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var result;
//try to parse as json
try {
result = JSON.parse(this.response);
console.log('AJAX - COMPLETE ('+(new Date()-start)+'ms) - json:', result);
}
catch (e) {
result = this.response;
console.log('AJAX - COMPLETE ('+(new Date()-start)+'ms) - string:', this.response, e);
}
//return result
success(result);
xhr = null;
}
else if (this.readyState == 4) {
console.log('ajax failed', this.readyState, this.status);
success({ error: 'failure' });
}
};
xhr.ontimeout = function(e) {
console.log('ajax request timed out')
success({ error: 'timeout' });
};
if (postData) {
//post request
console.log('post data: ', postData instanceof FormData, postData);
//the the input isn't already formdata, convert it to form data
if (!(postData instanceof FormData)) {
console.log('converting to form data');
var formData = new FormData();
for (var key in postData) {
formData.append(key, postData[key]);
}
postData = formData;
}
//send to server
xhr.open("POST", url, true);
xhr.timeout = timeout;
xhr.send(postData);
}
else {
//get request
xhr.open("GET", url, true);
xhr.timeout = timeout;
xhr.send();
}
return xhr;
}

11
package-lock.json generated
View File

@ -3135,8 +3135,9 @@
}
},
"handlebars-helper-svg": {
"version": "git+ssh://git@bitbucket.org/skeddles/npm-handlebars-helper-svg-lospec-open-source.git#2feeec5000aecce96ba2f714ec540880537ae208",
"from": "handlebars-helper-svg@git+https://bitbucket.org/skeddles/npm-handlebars-helper-svg-lospec-open-source.git",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/handlebars-helper-svg/-/handlebars-helper-svg-2.0.2.tgz",
"integrity": "sha512-uCLLeD3F+6pcTczOz2DH6OtFkJ2lKixWUT0nrZimME36BdCwHheAwL5tfyYpsUUUB/yle/ZRK0/Cv7Def/d5XA==",
"requires": {
"ltx": "^2.3.0",
"resolve": "^1.1.7"
@ -3855,9 +3856,9 @@
}
},
"ltx": {
"version": "2.9.2",
"resolved": "https://registry.npmjs.org/ltx/-/ltx-2.9.2.tgz",
"integrity": "sha512-llB7HflFhlfsYYT1SAe80elCBO5C20ryLdwPB/A/BZk38hhVeZztDlWQ9uTyvKNPX4aK6sA+JfS1f/mfzp5cxA==",
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/ltx/-/ltx-2.10.0.tgz",
"integrity": "sha512-RB4zR6Mrp/0wTNS9WxMvpgfht/7u/8QAC9DpPD19opL/4OASPa28uoliFqeDkLUU8pQ4aeAfATBZmz1aSAHkMw==",
"requires": {
"inherits": "^2.0.4"
}

View File

@ -25,7 +25,7 @@
"gulp-include": "^2.3.1",
"gulp-rename": "^2.0.0",
"gulp-sass": "^4.0.2",
"handlebars-helper-svg": "git+https://bitbucket.org/skeddles/npm-handlebars-helper-svg-lospec-open-source.git",
"handlebars-helper-svg": "^2.0.2",
"nodemon": "^2.0.7",
"open": "^8.0.6",
"open-cli": "^6.0.1",

View File

@ -6,30 +6,10 @@ const app = express();
const BUILDDIR = process.argv[2] || './build';
const PORT = process.argv[3] || 3000;
//ROUTE - index.htm
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, BUILDDIR, 'index.htm'), {}, function (err) {
if (err) {
console.log('error sending file', err);
} else {
console.log("Server: Successfully served index.html");
/*setTimeout(()=>{
console.log('closing server');
res.app.server.close();
process.exit();
},1000*10); */
}
});
});
// Better to show landing page rather than 404 on editor page reload
app.get('/pixel-editor/app', (req, res) => {
res.redirect('/');
})
//ROUTE - other files
app.use(express.static(path.join(__dirname, BUILDDIR)));
app.use('/pixel-editor', express.static(path.join(__dirname, BUILDDIR)));
// "reload" module allows us to trigger webpage reload automatically on file changes, but inside pixel editor it also
// makes browser steal focus from any other window in order to ask user about unsaved changes. It might be quite
@ -46,3 +26,26 @@ if (process.env.RELOAD === "yes") {
console.log(`Web server listening on port ${PORT}`);
})
}
// Better to show landing page rather than 404 on editor page reload
app.get('/', (req, res) => {
res.redirect('/pixel-editor');
})
//ROUTE - match / or any route with just numbers letters and dashes, and return index.htm (all other routes should have been handled already)
app.get(['/pixel-editor', /^\/pixel-editor\/[\/a-z0-9-]+$/gi ], (req, res) => {
res.sendFile(path.join(__dirname, BUILDDIR, 'index.htm'), {}, function (err) {
if (err) {
console.log('error sending file', err);
} else {
console.log("Server: Successfully served index.html", req.originalUrl);
}
});
});
// Better to show landing page rather than 404 on editor page reload
app.get('/pixel-editor/app', (req, res) => {
res.redirect('/');
})

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 793 B

After

Width:  |  Height:  |  Size: 793 B

View File

Before

Width:  |  Height:  |  Size: 782 B

After

Width:  |  Height:  |  Size: 782 B

View File

Before

Width:  |  Height:  |  Size: 771 B

After

Width:  |  Height:  |  Size: 771 B

View File

Before

Width:  |  Height:  |  Size: 831 B

After

Width:  |  Height:  |  Size: 831 B

View File

Before

Width:  |  Height:  |  Size: 346 B

After

Width:  |  Height:  |  Size: 346 B

View File

Before

Width:  |  Height:  |  Size: 837 B

After

Width:  |  Height:  |  Size: 837 B

View File

Before

Width:  |  Height:  |  Size: 796 B

After

Width:  |  Height:  |  Size: 796 B

View File

Before

Width:  |  Height:  |  Size: 809 B

After

Width:  |  Height:  |  Size: 809 B

View File

Before

Width:  |  Height:  |  Size: 798 B

After

Width:  |  Height:  |  Size: 798 B

View File

Before

Width:  |  Height:  |  Size: 221 B

After

Width:  |  Height:  |  Size: 221 B

View File

Before

Width:  |  Height:  |  Size: 325 B

After

Width:  |  Height:  |  Size: 325 B

View File

Before

Width:  |  Height:  |  Size: 439 B

After

Width:  |  Height:  |  Size: 439 B

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 528 B

After

Width:  |  Height:  |  Size: 528 B

View File

@ -1,41 +1,41 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M497,51H15C6.716,51,0,57.716,0,66v380c0,8.284,6.716,15,15,15h482c8.284,0,15-6.716,15-15V66
C512,57.716,505.284,51,497,51z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M497,51H15C6.716,51,0,57.716,0,66v380c0,8.284,6.716,15,15,15h482c8.284,0,15-6.716,15-15V66
C512,57.716,505.284,51,497,51z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 695 B

After

Width:  |  Height:  |  Size: 654 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,41 +1,41 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512.001 512.001" style="enable-background:new 0 0 512.001 512.001;" xml:space="preserve">
<g>
<g>
<path d="M506.143,5.859c-7.811-7.811-20.475-7.811-28.285,0l-472,472c-7.811,7.811-7.811,20.474,0,28.284
c3.905,3.906,9.024,5.858,14.142,5.858s10.237-1.953,14.143-5.858l472-472C513.954,26.333,513.954,13.67,506.143,5.859z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512.001 512.001" style="enable-background:new 0 0 512.001 512.001;" xml:space="preserve">
<g>
<g>
<path d="M506.143,5.859c-7.811-7.811-20.475-7.811-28.285,0l-472,472c-7.811,7.811-7.811,20.474,0,28.284
c3.905,3.906,9.024,5.858,14.142,5.858s10.237-1.953,14.143-5.858l472-472C513.954,26.333,513.954,13.67,506.143,5.859z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 799 B

After

Width:  |  Height:  |  Size: 758 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 317 B

After

Width:  |  Height:  |  Size: 317 B

View File

Before

Width:  |  Height:  |  Size: 222 B

After

Width:  |  Height:  |  Size: 222 B

View File

Before

Width:  |  Height:  |  Size: 815 B

After

Width:  |  Height:  |  Size: 815 B

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 726 B

After

Width:  |  Height:  |  Size: 726 B

View File

Before

Width:  |  Height:  |  Size: 376 B

After

Width:  |  Height:  |  Size: 376 B

View File

Before

Width:  |  Height:  |  Size: 327 B

After

Width:  |  Height:  |  Size: 327 B

View File

@ -1,41 +1,41 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M497,51H15C6.716,51,0,57.716,0,66v380c0,8.284,6.716,15,15,15h482c8.284,0,15-6.716,15-15V66
C512,57.716,505.284,51,497,51z M482,431H30V81h452V431z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M497,51H15C6.716,51,0,57.716,0,66v380c0,8.284,6.716,15,15,15h482c8.284,0,15-6.716,15-15V66
C512,57.716,505.284,51,497,51z M482,431H30V81h452V431z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 719 B

After

Width:  |  Height:  |  Size: 678 B

View File

@ -1,108 +1,108 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M160.003,21.333h-42.667c-5.888,0-10.667,4.779-10.667,10.667s4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667S165.913,21.333,160.003,21.333z"/>
</g>
</g>
<g>
<g>
<path d="M288.003,21.333h-42.667c-5.888,0-10.667,4.779-10.667,10.667s4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667S293.913,21.333,288.003,21.333z"/>
</g>
</g>
<g>
<g>
<path d="M160.003,352h-42.667c-5.888,0-10.667,4.779-10.667,10.667s4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667S165.913,352,160.003,352z"/>
</g>
</g>
<g>
<g>
<path d="M288.003,352h-42.667c-5.888,0-10.667,4.779-10.667,10.667s4.779,10.667,10.667,10.667h42.667
c5.888,0,10.667-4.779,10.667-10.667S293.913,352,288.003,352z"/>
</g>
</g>
<g>
<g>
<path d="M32.003,234.667c-5.909,0-10.667,4.779-10.667,10.667V288c0,5.888,4.779,10.667,10.667,10.667S42.67,293.888,42.67,288
v-42.667C42.67,239.445,37.913,234.667,32.003,234.667z"/>
</g>
</g>
<g>
<g>
<path d="M32.003,106.667c-5.909,0-10.667,4.779-10.667,10.667V160c0,5.888,4.779,10.667,10.667,10.667
c5.909,0,10.667-4.779,10.667-10.667v-42.667C42.67,111.445,37.913,106.667,32.003,106.667z"/>
</g>
</g>
<g>
<g>
<path d="M373.337,234.667c-5.888,0-10.667,4.779-10.667,10.667V288c0,5.888,4.779,10.667,10.667,10.667
c5.888,0,10.667-4.779,10.667-10.667v-42.667C384.003,239.445,379.246,234.667,373.337,234.667z"/>
</g>
</g>
<g>
<g>
<path d="M373.337,106.667c-5.909,0-10.667,4.779-10.667,10.667V160c0,5.888,4.779,10.667,10.667,10.667
c5.888,0,10.667-4.779,10.667-10.667v-42.667C384.003,111.445,379.246,106.667,373.337,106.667z"/>
</g>
</g>
<g>
<g>
<path d="M394.67,0h-42.667c-5.888,0-10.667,4.779-10.667,10.667v42.667c0,5.888,4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667V10.667C405.337,4.779,400.579,0,394.67,0z"/>
</g>
</g>
<g>
<g>
<path d="M53.337,0H10.67C4.782,0,0.003,4.779,0.003,10.667v42.667C0.003,59.221,4.782,64,10.67,64h42.667
c5.909,0,10.667-4.779,10.667-10.667V10.667C64.003,4.779,59.246,0,53.337,0z"/>
</g>
</g>
<g>
<g>
<path d="M53.337,330.667H10.67c-5.888,0-10.667,4.779-10.667,10.667V384c0,5.888,4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667v-42.667C64.003,335.445,59.246,330.667,53.337,330.667z"/>
</g>
</g>
<g>
<g>
<path d="M506.521,385.344l-192-106.667c-3.968-2.197-8.875-1.664-12.224,1.323c-3.392,2.987-4.544,7.765-2.859,11.968
l85.333,213.333c1.6,4.011,5.461,6.656,9.771,6.699c0.043,0,0.085,0,0.128,0c4.267,0,8.128-2.539,9.813-6.464l30.315-70.741
l70.741-30.315c3.733-1.6,6.229-5.205,6.443-9.259C512.195,391.168,510.062,387.328,506.521,385.344z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M160.003,21.333h-42.667c-5.888,0-10.667,4.779-10.667,10.667s4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667S165.913,21.333,160.003,21.333z"/>
</g>
</g>
<g>
<g>
<path d="M288.003,21.333h-42.667c-5.888,0-10.667,4.779-10.667,10.667s4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667S293.913,21.333,288.003,21.333z"/>
</g>
</g>
<g>
<g>
<path d="M160.003,352h-42.667c-5.888,0-10.667,4.779-10.667,10.667s4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667S165.913,352,160.003,352z"/>
</g>
</g>
<g>
<g>
<path d="M288.003,352h-42.667c-5.888,0-10.667,4.779-10.667,10.667s4.779,10.667,10.667,10.667h42.667
c5.888,0,10.667-4.779,10.667-10.667S293.913,352,288.003,352z"/>
</g>
</g>
<g>
<g>
<path d="M32.003,234.667c-5.909,0-10.667,4.779-10.667,10.667V288c0,5.888,4.779,10.667,10.667,10.667S42.67,293.888,42.67,288
v-42.667C42.67,239.445,37.913,234.667,32.003,234.667z"/>
</g>
</g>
<g>
<g>
<path d="M32.003,106.667c-5.909,0-10.667,4.779-10.667,10.667V160c0,5.888,4.779,10.667,10.667,10.667
c5.909,0,10.667-4.779,10.667-10.667v-42.667C42.67,111.445,37.913,106.667,32.003,106.667z"/>
</g>
</g>
<g>
<g>
<path d="M373.337,234.667c-5.888,0-10.667,4.779-10.667,10.667V288c0,5.888,4.779,10.667,10.667,10.667
c5.888,0,10.667-4.779,10.667-10.667v-42.667C384.003,239.445,379.246,234.667,373.337,234.667z"/>
</g>
</g>
<g>
<g>
<path d="M373.337,106.667c-5.909,0-10.667,4.779-10.667,10.667V160c0,5.888,4.779,10.667,10.667,10.667
c5.888,0,10.667-4.779,10.667-10.667v-42.667C384.003,111.445,379.246,106.667,373.337,106.667z"/>
</g>
</g>
<g>
<g>
<path d="M394.67,0h-42.667c-5.888,0-10.667,4.779-10.667,10.667v42.667c0,5.888,4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667V10.667C405.337,4.779,400.579,0,394.67,0z"/>
</g>
</g>
<g>
<g>
<path d="M53.337,0H10.67C4.782,0,0.003,4.779,0.003,10.667v42.667C0.003,59.221,4.782,64,10.67,64h42.667
c5.909,0,10.667-4.779,10.667-10.667V10.667C64.003,4.779,59.246,0,53.337,0z"/>
</g>
</g>
<g>
<g>
<path d="M53.337,330.667H10.67c-5.888,0-10.667,4.779-10.667,10.667V384c0,5.888,4.779,10.667,10.667,10.667h42.667
c5.909,0,10.667-4.779,10.667-10.667v-42.667C64.003,335.445,59.246,330.667,53.337,330.667z"/>
</g>
</g>
<g>
<g>
<path d="M506.521,385.344l-192-106.667c-3.968-2.197-8.875-1.664-12.224,1.323c-3.392,2.987-4.544,7.765-2.859,11.968
l85.333,213.333c1.6,4.011,5.461,6.656,9.771,6.699c0.043,0,0.085,0,0.128,0c4.267,0,8.128-2.539,9.813-6.464l30.315-70.741
l70.741-30.315c3.733-1.6,6.229-5.205,6.443-9.259C512.195,391.168,510.062,387.328,506.521,385.344z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 648 B

After

Width:  |  Height:  |  Size: 648 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 875 B

After

Width:  |  Height:  |  Size: 875 B

View File

@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="13.9" height="12.4" viewBox="0 0 13.9 12.4">
<path d="M13.9,10.8,8,1A1.4,1.4,0,0,0,6,1L.1,10.7c-.3.6,1.1,2.3,1.6,2.3H12.3C12.9,13,14.2,11.3,13.9,10.8ZM8,12H6V10H8ZM8,9H6V4H8Z" transform="translate(-0.1 -0.6)" style="fill-rule: evenodd"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="13.9" height="12.4" viewBox="0 0 13.9 12.4">
<path d="M13.9,10.8,8,1A1.4,1.4,0,0,0,6,1L.1,10.7c-.3.6,1.1,2.3,1.6,2.3H12.3C12.9,13,14.2,11.3,13.9,10.8ZM8,12H6V10H8ZM8,9H6V4H8Z" transform="translate(-0.1 -0.6)" style="fill-rule: evenodd"/>
</svg>

Before

Width:  |  Height:  |  Size: 298 B

After

Width:  |  Height:  |  Size: 295 B

View File

Before

Width:  |  Height:  |  Size: 389 B

After

Width:  |  Height:  |  Size: 389 B

View File

Before

Width:  |  Height:  |  Size: 710 B

After

Width:  |  Height:  |  Size: 710 B

10
views/about-popup.hbs Normal file
View File

@ -0,0 +1,10 @@
<div id="about">
<button class="close-button">{{svg "x.svg" width="20" height="20"}}</button>
<h1>About Lospec Pixel Editor</h1>
<div>version 1.1.0</div>
<p>This is a web-based tool for creating and editing pixel art.</p>
<p>The goal of this tool is to be an accessible and intuitive tool that's simple enough for a first time pixel artist while still being usable enough for a veteran. </p>
<p>In the future I hope to add enough features to become a full fledged pixel art editor, with everything an artist could need.</p>
<h1>About Lospec</h1>
<p>Lospec is a website created to host tools for pixel artists. To see more of our tools, visit our <a href="/">homepage</a>. To hear about any updates or new tools, follow us on <a href="http://twitter.com/lospecofficial">Twitter</a>.</p>
</div>

View File

@ -0,0 +1,59 @@
<!--CANVAS RESIZE-->
<div class="update" id = "resize-canvas">
<button class="close-button">{{svg "x.svg" width="20" height="20"}}</button>
<h1>Resize canvas</h1>
<!--PIVOTS-->
<span id = "pivot-menu">
<button class="pivot-button" value="topleft">{{svg "arrows/topleft.svg" width="20" height="20"}}</button>
<button class="pivot-button" value="top">{{svg "arrows/top.svg" width="20" height="20"}}</button>
<button class="pivot-button" value="topright">{{svg "arrows/topright.svg" width="20" height="20"}}</button>
<button class="pivot-button" value="left">{{svg "arrows/left.svg" width="20" height="20"}}</button>
<button class="pivot-button rc-selected-pivot" value="middle">{{svg "arrows/middle.svg" width="20" height="20"}}</button>
<button class="pivot-button" value="right">{{svg "arrows/right.svg" width="20" height="20"}}</button>
<button class="pivot-button" value="bottomleft">{{svg "arrows/bottomleft.svg" width="20" height="20"}}</button>
<button class="pivot-button" value="bottom">{{svg "arrows/bottom.svg" width="20" height="20"}}</button>
<button class="pivot-button" value="bottomright">{{svg "arrows/bottomright.svg" width="20" height="20"}}</button>
</span>
<!-- SIZE-->
<span id = "rc-size-menu">
<h2>Size</h2>
<div>
<span>
Width: <input id="rc-width" type="number" default="0" step="1"
value="{{#if border}}{{border}}{{else}}0{{/if}}" autocomplete="off"/>
</span>
<span>
Height: <input id="rc-height" default="0" step="1" type="number"
value="{{#if border}}{{border}}{{else}}0{{/if}}" autocomplete="off"/>
</span>
</div>
</span>
<!--BORDERS-->
<span id = "borders-menu">
<h2>Borders offsets</h2>
<div>
<span>
Left: <input id="rc-border-left" type="number" default="0" step="1"
value="{{#if border}}{{border}}{{else}}0{{/if}}" autocomplete="off"/>
</span>
<span>
Right: <input id="rc-border-right" type="number" default="0" step="1"
value="{{#if border}}{{border}}{{else}}0{{/if}}" autocomplete="off"/>
</span>
<span>
Top: <input id="rc-border-top" type="number" default="0" step="1"
value="{{#if border}}{{border}}{{else}}0{{/if}}" autocomplete="off"/>
</span>
<span>
Bottom: <input id="rc-border-bottom" default="0" step="1" type="number"
value="{{#if border}}{{border}}{{else}}0{{/if}}" autocomplete="off"/>
</span>
</div>
<button id = "resize-canvas-confirm">Resize canvas</button>
</span>
</div>

9
views/canvases.hbs Normal file
View File

@ -0,0 +1,9 @@
<!-- CANVASES -->
<div id="canvas-view">
<canvas id="vfx-canvas" class = "drawingCanvas"></canvas>
<canvas id = "tmp-canvas" class = "drawingCanvas"></canvas>
<canvas id="pixel-canvas" class = "drawingCanvas"></canvas>
<canvas id="checkerboard" class = "drawingCanvas"></canvas>
<canvas id="pixel-grid" class = "drawingCanvas"></canvas>
</div>
<div id="canvas-view-shadow"></div>

11
views/changelog-popup.hbs Normal file
View File

@ -0,0 +1,11 @@
<div id="changelog">
<button class="close-button">{{svg "x.svg" width="20" height="20"}}</button>
<h1>Changelog</h1>
{{#each changelog}}
<h2>Version {{@key}}</h2>
<ul>{{#each this}}
<li>{{change}} <span class="weak">- {{author}}</span></li>
{{/each}}</ul>
{{/each}}
</div>

14
views/colors-menu.hbs Normal file
View File

@ -0,0 +1,14 @@
<ul id="colors-menu">
<li class="noshrink"><button title="Add Current Color To Palette" id="add-color-button">{{svg "./plus.svg" width="30" height="30"}}</button></li>
</ul>
<div class="jscolor-picker-bottom">
<span>#</span><input type="text" id="jscolor-hex-input" />
<div id="duplicate-color-warning" title="Color is a duplicate of another in palette">{{svg "warning.svg" width="14"
height="12" }}</div>
<button class="delete-color-button">{{svg "trash.svg" width="20" height="20" }}</button>
</div>
<div class="color-edit-button">
{{svg "adjust.svg" width="20" height="20" }}
</div>

View File

@ -0,0 +1,15 @@
<div id="compatibility-warning">
<div>
<div>
<p><strong>Warning: a modern, desktop, web browser is required to use this tool.</strong></p>
<p>We detected that you may have an out of date or unsupported web browser. This tool, like many others on
this site and across the web uses features only available in new web browsers. We reccommend updating
your current browser or downloading <a href="https://www.mozilla.org/en-US/firefox/new/"
target="_blank">Firefox</a> or <a href="https://www.google.com/chrome/browser/desktop/index.html"
target="_blank">Chrome</a>. </p>
<button onclick="closeCompatibilityWarning()">Continue</button>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bowser@2.11.0/es5.min.js"></script>
<script src="/pixel-editor/checkCompatibilityPixelEditor.js"></script>

10
views/credits-popup.hbs Normal file
View File

@ -0,0 +1,10 @@
<div id="credits">
<button class="close-button">{{svg "x.svg" width="20" height="20"}}</button>
<h1>Credits</h1>
<h2>Icons</h2>
<ul>
<li><div>Icons made by <a href="http://www.freepik.com" title="Freepik">Freepik</a> from <a href="http://www.flaticon.com" title="Flaticon">www.flaticon.com</a> is licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></div></li>
<li><div>Font Awesome by Dave Gandy - <a href="http://fontawesome.io">http://fontawesome.io</a></div></li>
<li><div>Icons made by <a href="http://www.flaticon.com/authors/those-icons" title="Those Icons">Those Icons</a> from <a href="http://www.flaticon.com" title="Flaticon">www.flaticon.com</a> is licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></div></li>
</ul>
</div>

0
views/data-asdfgasd.hbs Normal file
View File

44
views/help-popup.hbs Normal file
View File

@ -0,0 +1,44 @@
<div id="help">
<button class="close-button">{{svg "x.svg" width="20" height="20"}}</button>
<h1>Help</h1>
<h2>Palette</h2>
<ul>
<li>Left Click - Choose Color</li>
<li>Right Click - Edit Color</li>
</ul>
<h2>Hotkeys</h2>
<ul>
<li><strong>Pencil:</strong> <span class="keyboard-key">B</span> or <span class="keyboard-key">1</span></li>
<li><strong>Eraser:</strong> <span class="keyboard-key">R</span></li>
<li><strong>Rectangle:</strong> <span class="keyboard-key">U</span></li>
<li><strong>Line:</strong> <span class="keyboard-key">L</span></li>
<li><strong>Fill:</strong> <span class="keyboard-key">F</span> or <span class="keyboard-key">2</span></li>
<li><strong>Eyedropper:</strong> <span class="keyboard-key">E</span> or <span class="keyboard-key">3</span></li>
<li><strong>Pan:</strong> <span class="keyboard-key">P</span> or <span class="keyboard-key">M</span> or <span class="keyboard-key">4</span></li>
<li><strong>Zoom:</strong> <span class="keyboard-key">Z</span> or <span class="keyboard-key">5</span></li>
<li><strong>Undo:</strong> Ctrl + <span class="keyboard-key">Z</span></li>
<li><strong>Redo:</strong> Ctrl + <span class="keyboard-key">Y</span> or Ctrl + Alt + <span class="keyboard-key">Z</span></li>
<li><strong>Rectangular selection:</strong> <span class="keyboard-key">M</span></li>
</ul>
<h2>Mouse Shortcuts</h2>
<ul>
<li><strong>Eyedropper: </strong>Alt + Click</li>
<li><strong>Pan: </strong>Space + Click</li>
<li><strong>Zoom: </strong>Alt + Scroll Wheel</li>
</ul>
<h2>Layers</h2>
<ul>
<li>{{svg "visible.svg" width="15" height="15" class = "default-icon"}}: show / hide layer</li>
<li>{{svg "lockedpadlock.svg" width="15" height="15" class = "default-icon"}}: lock / unlock layer, when a layer is locked it's not possible to draw on it</li>
<li>Right click on a layer to open the <strong>menu</strong>:
<ul>
<li><strong>Rename:</strong> change the name of the layer</li>
<li><strong>Duplicate:</strong> duplicate the layer</li>
<li><strong>Delete:</strong> delete the layer (doesn't work if there's only one layer)</li>
<li><strong>Merge below:</strong> merges the selected the layer with the one below it</li>
<li><strong>Flatten visible:</strong> merges all the visible layers</li>
<li></strong>Flatten all:</strong> merges all the layers</li>
</ul>
</li>
</ul>
</div>

7
views/holders.hbs Normal file
View File

@ -0,0 +1,7 @@
<div id="data-holders">
<a id="save-image-link-holder" href="#">dl</a>
<a id="save-project-link-holder" href="#">dl</a>
<input id="open-image-browse-holder" type="file" accept="image/png, image/gif, .lpe" />
<input id="load-palette-browse-holder" type="file" accept="image/png, image/gif" />
<canvas id="load-palette-canvas-holder"></canvas>
</div>

44
views/index.hbs Normal file
View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{title}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,400i,700,900" rel="stylesheet">
<link rel="stylesheet" href="/pixel-editor/pixel-editor.css" />
<meta name="ROBOTS" content="NOINDEX, NOFOLLOW">
{{{google-analytics}}}
{{{favicons}}}
</head>
<body oncontextmenu="return false;">
{{> compatibility-warning}}
{{> preload}}
{{> main-menu}}
{{> tools-menu}}
{{> colors-menu}}
{{> layers-menu}}
{{> tool-previews}}
{{> canvases}}
{{> holders}}
<div id="pop-up-container">
{{> start-pixel-popup}}
{{> splash-page-popup}}
{{> sprite-resize-popup}}
{{> canvas-resize-popup}}
{{> palette-popup}}
{{> help-popup}}
{{> about-popup}}
{{> changelog-popup}}
{{> credits-popup}}
{{> settings-popup}}
</div>
<script src="/pixel-editor/pixel-editor.js"></script>
<script src="/reload/reload.js"></script>
</body>
</html>

View File

@ -1,4 +1,3 @@
<h1>Latest update</h1>
Hello there, welcome to the latest version of the Lospec Pixel Editor. As you can see, we changed
quite a lot of things. Let's go through all them, starting from this page.

49
views/layers-menu.hbs Normal file
View File

@ -0,0 +1,49 @@
<!-- LAYER MENU -->
<ul id = "layers-menu">
<li class = "layers-menu-entry selected-layer">
<canvas class = "preview-canvas"></canvas>
<ul class="layer-buttons">
<li class = "layer-button">
<button title="Lock layer" class="lock-layer-button">
{{svg "unlockedpadlock.svg" width="15" height="15" class = "default-icon"}}
{{svg "lockedpadlock.svg" width="15" height="15" class = "edited-icon" display = "none"}}
</button>
</li>
<li class = "layer-button">
<button title="Show / hide layer" class="hide-layer-button">
{{svg "visible.svg" width="15" height="15" class = "default-icon"}}
{{svg "invisible.svg" width="15" height="15" class = "edited-icon" display = "none"}}
</button>
</li>
</ul>
<p>Layer 0<div class = "gradient"></div></p>
</li>
<li>
<button id = "add-layer-button">
{{svg "plus.svg" width="20" height="20"}} Add layer
</button>
</li>
</ul>
<ul id = "layer-properties-menu">
<li>
<button onclick = "renameLayer()">Rename</button>
</li>
<li>
<button onclick = "duplicateLayer()">Duplicate</button>
</li>
<li>
<button onclick = "deleteLayer()">Delete</button>
</li>
<li>
<button onclick = "merge()">Merge below</button>
</li>
<li>
<button onclick = "flatten(true)">Flatten visible</button>
</li>
<li>
<button onclick = "flatten(false)">Flatten all</button>
</li>
</ul>

Some files were not shown because too many files have changed in this diff Show More