diff --git a/README.md b/README.md index b49a328..0537fdb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ The tool can be viewed online here: https://lospec.com/pixel-editor ## How to contribute -Please do not submit pull requests with new features or core changes. Instead, please file an issue first for discussion. +Before starting to work, please open an issue for discussion so that we can organize the work without creating too many conflicts. If your contribution is going to fix a bug, please + make a fork and use the bug-fixes branch. If you want to work on a new feature, please use the new-feature branch instead. ## What to Contribute diff --git a/README.md.bak b/README.md.bak new file mode 100644 index 0000000..b49a328 --- /dev/null +++ b/README.md.bak @@ -0,0 +1,74 @@ +# Lospec Pixel Editor + +This is a browser based software for creating pixel art + +The tool can be viewed online here: https://lospec.com/pixel-editor + +## How to contribute + +Please do not submit pull requests with new features or core changes. Instead, please file an issue first for discussion. + +## What to Contribute + +Any changes that fix bugs or add features are welcome. Check out the issues if you don't know where to start: if +you're new to the editor, we suggest you check out the Wiki first. + +The next version is mostly focused on adding missing essential features and porting to mobile. + +Suggestions / Planned features: + +- Documentation +- Possibility to hide and resize menus (layers, palette) +- Tiled mode +- Load palette from LPE file +- Symmetry options (currently being worked on) +- Make a palette grid instead of having a huge stack on the right when colours are too many +- Possibly add collaborate function + +- Mobile + - Touch equivalent for mouse clicks + - Hide or scale ui + - Maybe rearrange UI on portrait + - Fix popups + +- Polish: + - CTRL+A to select everything / selection -> all, same for deselection + - Warning windows for wrong inputs + - Palette option remove unused colors + - Move selection with arrows + - Update borders by dragging the canvas' edges with the mouse when resizing canvas + - Move the canvases so they're centered after resizing the canvas (maybe a .center() method in layer class) + - Scale / rotate selection + +## How to Contribute + +### Requirements + +You must have node.js and git installed. + +You also need `npm` in version 7 (because of 2nd version of lockfile which was introduced there) which comes with Node.js 15 or newer. To simplify installation of proper versions you can make use of [nvm](https://github.com/nvm-sh/nvm#installing-and-updating) and run `nvm install` – it will activate proper Node.js version in your current command prompt session. + +### Contribution Workflow + +1. Click **Fork** above. It will automatically create a copy of this repository and add it to your account. +2. Clone the repository to your computer. +3. Open the folder in command prompt and run **`npm install`** +4. Make any changes you would like to suggest. +5. In command prompt run **`npm run hot`** which will compile app to the `/build` folder, serve under [http://localhost:3000](http://localhost:3000), then open in your browser. Moreover, it restarts server every time you save your changes in a codebase. You can go even further by running `npm run hot:reload`, which will also trigger webpage reloads. +6. Add, Commit and Push your changes to your fork. +7. On the github page for your fork, click **New Pull Request** above the file list. +8. Change the **head repository** dropdown to your fork. +9. Add a title and description explaining your changes. +10. Click create pull request. + +If you have any trouble, see this page: https://help.github.com/en/articles/creating-a-pull-request-from-a-fork + +### Feature Toggles + +Some feature might be hidden by default. Functions to enable/disable them are available inside global `featureToggles` and operate on a `window.localStorage`. + +For example use `featureToggles.enableEllipseTool()` to make ellipse tool button visible. Then `featureToggles.disableEllipseTool()` to hide it. + +## License + +This software may not be resold, redistributed, rehosted or otherwise conveyed to a third party. diff --git a/build.js b/build.js index 5b4b4d0..410972b 100644 --- a/build.js +++ b/build.js @@ -17,12 +17,16 @@ console.log('Building Pixel Editor'); function copy_images(){ // Icons gulp.src('./images/*.png').pipe(gulp.dest(BUILDDIR)); + //favicon + gulp.src('./images/*.ico').pipe(gulp.dest(BUILDDIR)); // Splash images gulp.src('./images/Splash images/*.png').pipe(gulp.dest(BUILDDIR)); - // Logs images + // Logs gifs gulp.src('./images/Logs/*.gif').pipe(gulp.dest(BUILDDIR)); - // Logs images + // Logs pngs gulp.src('./images/Logs/*.png').pipe(gulp.dest(BUILDDIR)); + // Tool tutorials + gulp.src('./images/ToolTutorials/*.gif').pipe(gulp.dest(BUILDDIR)); } function copy_logs() { @@ -52,7 +56,7 @@ function compile_page(){ .pipe(handlebars({encoding: 'utf8', debug: true, bustCache: true}) .partials('./views/[!index]*.hbs').partials('./views/popups/*.hbs') - //.helpers({ svg: hb_svg }) + .partials('./views/components/*.hbs') .helpers('./helpers/**/*.js') .data({ projectSlug: 'pixel-editor', diff --git a/css/_canvas.scss b/css/_canvas.scss index 9a79f5a..c770411 100644 --- a/css/_canvas.scss +++ b/css/_canvas.scss @@ -1,7 +1,7 @@ .drawingCanvas { - cursor: url('/pixel-editor/pencil-tool-cursor.png'); + cursor: url('pencil-tool-cursor.png'); border: solid 1px #fff; image-rendering: optimizeSpeed; @@ -95,7 +95,7 @@ #canvas-view { bottom: 0px; - left: 64px; + left: 48px; right: 48px; top: 48px; cursor: default; @@ -107,7 +107,7 @@ box-shadow: inset 0px 0px 4px 0px rgba(0, 0, 0, 0.4); position: fixed; bottom: 0px; - left: 64px; + left: 48px; right: 48px; top: 48px; display: block; diff --git a/css/_colors-menu.scss b/css/_colors-menu.scss index ec70b43..a19277d 100644 --- a/css/_colors-menu.scss +++ b/css/_colors-menu.scss @@ -112,7 +112,7 @@ button { border: none; width: 100%; - cursor: url('/pixel-editor/eyedropper.png'), auto; + cursor: url('eyedropper.png'), auto; } //white outline &.selected button::before { content: ""; diff --git a/css/_components.scss b/css/_components.scss new file mode 100644 index 0000000..32bd510 --- /dev/null +++ b/css/_components.scss @@ -0,0 +1,56 @@ +.checkbox-holder { + position:relative; + width:15px; + height:15px; + display:block; + + .checkbox { + display: inline-block; + cursor: pointer; + padding-right: 1em; + + .box { + color: $basetext; + background: darken($basecolor, 5%); + border: none; + padding: 0.5rem; + border-radius: 0.5rem; + box-sizing: border-box; + margin-right: 0.5rem; + display: inline-block; + vertical-align: middle; + border: solid 2px $basecolor; + pointer-events: none; + + svg { + visibility: hidden; + width: 1em; + height: 1em; + display: block; + path { + fill: $basetext; + } + } + + } + + //checked + &.checked .box svg { + visibility: visible; + } + + label { + display: inline-block; + pointer-events: none; + } //hover label or box + + &:hover:not(.disabled){ + border-color: $basecolor; + } + + &.disabled { + cursor: not-allowed; + .box svg path {fill: $basetext;} + } + } +} \ No newline at end of file diff --git a/css/_main-menu.scss b/css/_main-menu.scss index 06453d8..04697d0 100644 --- a/css/_main-menu.scss +++ b/css/_main-menu.scss @@ -69,7 +69,7 @@ -/*app title*/ +/* app title */ .logo { color: lighten($basecolor, 20%); @@ -83,3 +83,57 @@ #main-menu li.open, #main-menu li button:hover { background: $basehover; } + +/* Editor info */ +li#editor-info { + float:right; + height:100%; + display:flex; + align-items: center; + background-color: $basecolor; + color:$basetext; + + ul { + background-color: $basecolor; + display:block; + position:relative; + top:0px; + padding-top:0px; + box-shadow: none; + padding-bottom: 0px; + + li { + top:0px; + padding-top:0px; + display:inline; + padding-right:20px; + } + + .checkbox-holder { + display: inline; + } + + input { + margin-left:10px; + background-color:darken($basecolor, 6%); + box-shadow:none; + border:none; + vertical-align: middle; + border-radius:5px; + padding: 5px; + color:$basetext; + } + input[type=number] { + appearance:none; + -moz-appearance:textfield; + -webkit-appearance:text; + width:25px; + height:15px; + } + input::-webkit-outer-spin-button, + input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + } +} \ No newline at end of file diff --git a/css/_popup-container.scss b/css/_popup-container.scss index b81cf3e..5e05ad3 100644 --- a/css/_popup-container.scss +++ b/css/_popup-container.scss @@ -116,7 +116,7 @@ } .dropdown-button { - background: $basehover url('/pixel-editor/dropdown-arrow.png') right center no-repeat; + background: $basehover url('dropdown-arrow.png') right center no-repeat; border: none; border-radius: 4px; color: $basehovertext; @@ -126,7 +126,7 @@ width: 200px; text-align: left; &:hover { - background: $baseselected url('/pixel-editor/dropdown-arrow-hover.png') right center no-repeat; + background: $baseselected url('dropdown-arrow-hover.png') right center no-repeat; color: $baseselectedtext; } &.selected { diff --git a/css/_splash-page.scss b/css/_splash-page.scss index 46939e3..c5f398d 100644 --- a/css/_splash-page.scss +++ b/css/_splash-page.scss @@ -3,6 +3,8 @@ #splash { width:100% !important; height:100%!important; + position:fixed; + margin-top:-20px; background-color: #232125 !important; opacity: 1 !important; @@ -155,11 +157,9 @@ .sp-template { display: flex; align-items: center; - height: 5em; - min-width: 5em; - + text-transform: uppercase; - width:16%; + width:5.5em; border-radius:5%; margin-right:4%; margin-top:4%; @@ -188,12 +188,11 @@ } } - /* .sp-template:before { content:''; float:left; padding-top:100%; - }*/ + } #sp-newpixel { -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */ diff --git a/css/_tools-menu.scss b/css/_tools-menu.scss index de7dc48..88f1f21 100644 --- a/css/_tools-menu.scss +++ b/css/_tools-menu.scss @@ -1,7 +1,7 @@ #tools-menu { left: 0; - width: 64px; + width: 48px; list-style-type: none; top: 48px; bottom: 0; @@ -10,17 +10,13 @@ background-color: $basecolor; box-sizing: border-box; position: fixed; - z-index: 1120; + z-index: 1108; } - - #tools-menu li { position: relative; } - - #tools-menu li button:first-child { text-align: center; border: none; @@ -28,15 +24,18 @@ width: 100%; padding: 0; cursor: pointer; - height: 64px; + height: 48px; + z-index:0; } -#tools-menu li button path { +#tools-menu li button path, #tools-menu li button ellipse { fill: $baseicon; + stroke: $baseicon; } -#tools-menu li:hover button:first-child path { +#tools-menu li:hover button:first-child path, #tools-menu li:hover button:first-child ellipse { fill: $basehovericon; + stroke: $basehovericon; } @@ -44,27 +43,21 @@ background: $baseselected !important; } -#tools-menu li.selected button:first-child path { +#tools-menu li.selected button:first-child path, #tools-menu li.selected button:first-child ellipse { 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; + width: 22px !important; + height:24px !important; + display: inline-block; line-height: 0; overflow: hidden; - position: absolute; - bottom: 0; + position: relative; path { fill: $baseselectedicon !important; @@ -77,40 +70,96 @@ } } -#tools-menu li button#brush-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 .size-buttons { + position:absolute; + display: none; + height:48px; + left:8px; + z-index:-1; + background-color: $basecolor !important; } -#tools-menu li button#brush-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 .size-buttons button { + text-align: center; + border: none; + padding: 0; + position: relative; + height:24px; + background-color: $baseselected !important; + cursor: pointer; + display:inline-block; + line-height: 0; + overflow: hidden; + width:22px; } -#tools-menu li.selected button#brush-bigger-button, -#tools-menu li.selected button#brush-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 .size-buttons button:hover { + background:$baseselected !important; +} + +#tools-menu .size-buttons button:active { + background:$basehovericon !important; +} + +#tools-menu li.selected .size-buttons { + display:inline-block; } #tools-menu li:hover { background: $basehover; +} + +@keyframes fadeIn { + to { + opacity: 1; + } +} +@keyframes fadeOut { + to { + opacity: 0; + } +} + +.fade-in { + opacity: 0; + animation: fadeIn .1s forwards; +} + +.fade-out { + animation: fadeOut .1s forwards; +} + +.is-paused { + animation-play-state: paused; +} + +/* Tool tutorial */ +#tool-tutorial { + display:inline-block; + position:absolute; + margin-left:48px; + margin-top:48px; + background-color: $basehover; + color:$basetext; + font-size:14px; + width:22%; + border-radius:0 5px 5px 5px; + z-index:1000; + + img { + width:100%; + } + + h3 { + margin-left:20px; + margin-bottom:-5px; + } +} + +#tool-tutorial:after { + border-left: 11px solid #222; + border-top: 8px solid transparent; + border-bottom: 8px solid transparent; + position: relative; } \ No newline at end of file diff --git a/css/pixel-editor.scss b/css/pixel-editor.scss index eb94914..4f24dae 100644 --- a/css/pixel-editor.scss +++ b/css/pixel-editor.scss @@ -2,6 +2,7 @@ @import 'general'; @import 'zindex'; @import 'shake'; +@import 'components'; @import 'help'; @import 'layers'; @import 'canvas'; diff --git a/images/Logs/tool-tutorials.gif b/images/Logs/tool-tutorials.gif new file mode 100644 index 0000000..7410491 Binary files /dev/null and b/images/Logs/tool-tutorials.gif differ diff --git a/images/ToolTutorials/brush-tutorial.gif b/images/ToolTutorials/brush-tutorial.gif new file mode 100644 index 0000000..50dd9c6 Binary files /dev/null and b/images/ToolTutorials/brush-tutorial.gif differ diff --git a/images/ToolTutorials/ellipse-tutorial.gif b/images/ToolTutorials/ellipse-tutorial.gif new file mode 100644 index 0000000..a341919 Binary files /dev/null and b/images/ToolTutorials/ellipse-tutorial.gif differ diff --git a/images/ToolTutorials/eraser-tutorial.gif b/images/ToolTutorials/eraser-tutorial.gif new file mode 100644 index 0000000..c2fedc5 Binary files /dev/null and b/images/ToolTutorials/eraser-tutorial.gif differ diff --git a/images/ToolTutorials/eyedropper-tutorial.gif b/images/ToolTutorials/eyedropper-tutorial.gif new file mode 100644 index 0000000..3fed0db Binary files /dev/null and b/images/ToolTutorials/eyedropper-tutorial.gif differ diff --git a/images/ToolTutorials/fill-tutorial.gif b/images/ToolTutorials/fill-tutorial.gif new file mode 100644 index 0000000..d56286d Binary files /dev/null and b/images/ToolTutorials/fill-tutorial.gif differ diff --git a/images/ToolTutorials/lassoselect-tutorial.gif b/images/ToolTutorials/lassoselect-tutorial.gif new file mode 100644 index 0000000..b33243a Binary files /dev/null and b/images/ToolTutorials/lassoselect-tutorial.gif differ diff --git a/images/ToolTutorials/line-tutorial.gif b/images/ToolTutorials/line-tutorial.gif new file mode 100644 index 0000000..7275331 Binary files /dev/null and b/images/ToolTutorials/line-tutorial.gif differ diff --git a/images/ToolTutorials/magicwand-tutorial.gif b/images/ToolTutorials/magicwand-tutorial.gif new file mode 100644 index 0000000..4a00f48 Binary files /dev/null and b/images/ToolTutorials/magicwand-tutorial.gif differ diff --git a/images/ToolTutorials/pan-tutorial.gif b/images/ToolTutorials/pan-tutorial.gif new file mode 100644 index 0000000..080e6a0 Binary files /dev/null and b/images/ToolTutorials/pan-tutorial.gif differ diff --git a/images/ToolTutorials/rectangle-tutorial.gif b/images/ToolTutorials/rectangle-tutorial.gif new file mode 100644 index 0000000..bf22dd5 Binary files /dev/null and b/images/ToolTutorials/rectangle-tutorial.gif differ diff --git a/images/ToolTutorials/rectselect-tutorial.gif b/images/ToolTutorials/rectselect-tutorial.gif new file mode 100644 index 0000000..89eef92 Binary files /dev/null and b/images/ToolTutorials/rectselect-tutorial.gif differ diff --git a/images/favicon.ico b/images/favicon.ico new file mode 100644 index 0000000..0c0b66b Binary files /dev/null and b/images/favicon.ico differ diff --git a/js/FeatureToggles.js b/js/FeatureToggles.js index 5b77f57..e4e6fff 100644 --- a/js/FeatureToggles.js +++ b/js/FeatureToggles.js @@ -1,4 +1,4 @@ -const featureToggles = (function featureTogglesModule() { +/*const featureToggles = (function featureTogglesModule() { const ellipseToolLocalStorageKey = 'feature_ellipseTool'; @@ -30,4 +30,4 @@ const featureToggles = (function featureTogglesModule() { } })(); - +*/ diff --git a/js/File.js b/js/File.js index 5ee3e30..d2eaabb 100644 --- a/js/File.js +++ b/js/File.js @@ -3,6 +3,7 @@ class File { canvasSize = []; zoom = 7; canvasView = document.getElementById("canvas-view"); + inited = false; // Layers layers = []; @@ -36,11 +37,13 @@ class File { // Start resize data startData = {width: 0, height:0, widthPercentage: 100, heightPercentage: 100}; - // Sprite scaling attributes openResizeCanvasWindow() { + if (!this.inited) { + this.initResizeCanvasInputs(); + this.inited = true; + } // Initializes the inputs - this.initResizeCanvasInputs(); Dialogue.showDialogue('resize-canvas'); } @@ -153,6 +156,9 @@ class File { currFile.canvasSize[1] = parseInt(currFile.canvasSize[1]) + this.rcBorders.top + this.rcBorders.bottom; + console.trace(); + console.log(currFile.canvasSize); + // Resize the canvases for (let i=0; i { case 77: case 109: Events.emit("tool-shortcut", "rectselect"); break; - // TODO: [ELLIPSE] Decide on a shortcut to use. "s" was chosen without any in-team consultation. + // Lasso tool, q + case 81: case 113: + Events.emit("tool-shortcut", "lassoselect"); + break; // ellipse tool, s case 83: - //Events.emit("tool-shortcut", "ellipse"); + Events.emit("tool-shortcut", "ellipse"); break; // rectangle tool, u case 85: Events.emit("tool-shortcut", "rectangle"); break; + // magic wand tool + case 87: case 119: + Events.emit("tool-shortcut", "magicwand"); + break; // Paste tool case 86: case 118: if (keyboardEvent.ctrlKey) { diff --git a/js/InputComponents.js b/js/InputComponents.js new file mode 100644 index 0000000..add8e9b --- /dev/null +++ b/js/InputComponents.js @@ -0,0 +1,73 @@ +const InputComponents = (() => { + setInputEvents(); + + function setInputEvents() { + // Make the checkboxes toggleable + let checkboxes = document.getElementsByClassName("checkbox"); + for (let i=0; i window.innerHeight) { + this.toolTutorial.style.top = window.innerHeight - 48 - (tutorialRect.bottom - tutorialRect.top) + "px"; + } + else { + this.toolTutorial.style.top = this.mainButton.getBoundingClientRect().top - 48 + "px"; + } + this.toolTutorial.className = "fade-in"; + } + hideTutorial() { + this.toolTutorial.className = "fade-out"; + } + + resetTutorial() { + this.tutorialString = ""; + } + setTutorial() { + this.toolTutorial.innerHTML = this.tutorialString; + } + addTutorialKey(key, text) { + this.tutorialString += '
  • ' + key + ' ' + text + '
  • '; + } + addTutorialText(key, text) { + this.tutorialString += '
  • ' + key + ': ' + text + '
  • '; + } + addTutorialImg(imgPath) { + this.tutorialString += ''; + } + addTutorialTitle(text) { + this.tutorialString += "

    " + text + "

    \ No newline at end of file diff --git a/views/popups/splash-page.hbs b/views/popups/splash-page.hbs index c4d67d5..7b3b169 100644 --- a/views/popups/splash-page.hbs +++ b/views/popups/splash-page.hbs @@ -12,7 +12,7 @@