├── .firebaserc ├── .github └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── LICENSE ├── NOTICE ├── README.md ├── build.sh ├── css └── kiddopaint.css ├── firebase.json ├── img ├── bl1.png ├── bl2.png ├── br10.png ├── br11.png ├── br12.png ├── br13.png ├── br14.png ├── br15.png ├── br16.png ├── br18.png ├── br19.png ├── br20.png ├── br21.png ├── br23.png ├── br6.png ├── br7.png ├── br8.png ├── br9.png ├── pinch.png ├── pw1.png ├── pw2.png ├── pw3.png ├── pw4.png ├── pw5.png ├── sprk1.png ├── sprk2.png ├── sprk3.png ├── sprk4.png ├── sprk5.png ├── sprk6.png ├── sprk7.png ├── sprk8.png └── sprk9.png ├── index.html ├── js ├── brushes │ ├── circles.js │ ├── concen.js │ ├── dumbbell.js │ ├── fsine.js │ ├── icy.js │ ├── meanstreak.js │ ├── pies.js │ ├── rainbowball.js │ ├── rainbowbar.js │ ├── rainbowdoughnut.js │ ├── rose.js │ ├── rpent.js │ ├── spray.js │ └── twirly.js ├── builders │ ├── arrow.js │ ├── prints.js │ ├── rail.js │ └── road.js ├── init │ ├── kiddopaint.js │ └── submenus.js ├── sounds │ └── sounds.js ├── stamps │ ├── alphabet.js │ └── stamps.js ├── submenus │ ├── brush.js │ ├── circle.js │ ├── jumble.js │ ├── line.js │ ├── pencil.js │ ├── sparkles.js │ ├── spray.js │ ├── square.js │ └── stub.txt ├── textures │ ├── gco.js │ └── textures.js ├── tools │ ├── astroid.js │ ├── bezfollow.js │ ├── brush.js │ ├── circle.js │ ├── composite.js │ ├── contours.js │ ├── cut.js │ ├── flood.js │ ├── guilloche.js │ ├── kaleidoscope.js │ ├── lanczosbrush.js │ ├── line.js │ ├── magnify.js │ ├── maze.js │ ├── partialfx.js │ ├── pixelpencil.js │ ├── placer.js │ ├── plainbrush.js │ ├── scribble.js │ ├── smoke.js │ ├── smoothpen.js │ ├── smudge.js │ ├── spiral.js │ ├── square.js │ ├── stamp.js │ ├── trees.js │ └── wholefx.js └── util │ ├── cache.js │ ├── colors.js │ ├── display.js │ ├── dither.js │ ├── douglas-peucker.js │ ├── filters.js │ ├── fit-curve.js │ ├── glfx.js │ ├── html.js │ ├── kdtree.js │ ├── smoke.js │ ├── smooth.js │ ├── trim-canvas.js │ └── utils.js ├── misc ├── QnA9eZ.gif ├── patScreen Shot 2020-10-16 at 11.51.44 PM.png └── ultpat.png ├── package-lock.json ├── package.json ├── snd ├── explosion0.wav ├── explosion1.wav ├── explosion2.wav ├── flood0.wav ├── flood1.wav ├── oops0.wav ├── oops1.wav ├── oops2.wav ├── pencil0.wav ├── stamp0.wav └── stamp1.wav └── static └── kiddopaint.jpg /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "firebase-kiddopaint" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '30 12 * * 1' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 37 | # Learn more: 38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 39 | 40 | steps: 41 | - name: Checkout repository 42 | uses: actions/checkout@v2 43 | 44 | # Initializes the CodeQL tools for scanning. 45 | - name: Initialize CodeQL 46 | uses: github/codeql-action/init@v1 47 | with: 48 | languages: ${{ matrix.language }} 49 | # If you wish to specify custom queries, you can do so here or in a config file. 50 | # By default, queries listed here will override any specified in a config file. 51 | # Prefix the list here with "+" to use these queries and those in the config file. 52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 53 | 54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 55 | # If this step fails, then you should remove it and run the build manually (see below) 56 | - name: Autobuild 57 | uses: github/codeql-action/autobuild@v1 58 | 59 | # ℹ️ Command-line programs to run using the OS shell. 60 | # 📚 https://git.io/JvXDl 61 | 62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 63 | # and modify them (or add more) to build your code if your project 64 | # uses a compiled language 65 | 66 | #- run: | 67 | # make bootstrap 68 | # make release 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v1 72 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | js/app.js 3 | .firebase 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vikrum Nijjar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kiddopaint ❖ https://5f5.org/mirror/kiddopaint/ 2 | 3 | Dr Halo, Kid Pix, MacPaint, & MS Paint were some of my earliest intros to computers—less so on the artistic parts, but more so on the "what does this button do?" and getting mastery around the keyboard and mouse. Inspired by those early drawing apps, I made this for my kids. If you have kids in your life, I'd love your feedback! 4 | 5 | Kiddopaint was meant to be used without having to consult a user guide, so, dig in! There are a handful of hidden features behind various modifier keys (⌘, ⌥, ⇧) for some of the tools. Enjoy! :) 6 | 7 | [Six part video guide](https://www.youtube.com/playlist?list=PLWLJNgreFIUZ_4o8LpKkJ6HY3-Qt0dILt). 8 | 9 | ## See also: https://github.com/vikrum/kidpix 10 | 11 | ![https://5f5.org/mirror/kiddopaint/static/kiddopaint.jpg](https://5f5.org/mirror/kiddopaint/static/kiddopaint.jpg) 12 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | echo [clean] Removing old app. 6 | rm -f js/app.js 7 | 8 | echo [format] Format JS and CSS. 9 | node_modules/js-beautify/js/bin/js-beautify.js -r js/**/* 10 | node_modules/js-beautify/js/bin/js-beautify.js -r css/* 11 | 12 | 13 | echo -n [build] Building Kiddo Paint app.js.. 14 | 15 | # node_modules/uglify-js/bin/uglifyjs -b -o js/app.js \ 16 | #node_modules/uglify-js/bin/uglifyjs -c -m -o js/app.js \ 17 | #node_modules/uglify-es/bin/uglifyjs -c -m -o js/app.js \ 18 | node_modules/uglify-es/bin/uglifyjs -o js/app.js \ 19 | js/init/* \ 20 | js/util/* \ 21 | js/tools/* \ 22 | js/textures/* \ 23 | js/submenus/* \ 24 | js/brushes/* \ 25 | js/builders/* \ 26 | js/stamps/* \ 27 | js/sounds/* \ 28 | 29 | echo "" >> js/app.js 30 | echo "// $(date)" >> js/app.js 31 | 32 | echo . done. 33 | -------------------------------------------------------------------------------- /css/kiddopaint.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | width: 100%; 4 | height: 100%; 5 | margin: 0px; 6 | background-color: #fff; 7 | -webkit-touch-callout: none; 8 | -webkit-user-select: none; 9 | -khtml-user-select: none; 10 | -moz-user-select: none; 11 | -ms-user-select: none; 12 | user-select: none; 13 | } 14 | 15 | #container { 16 | /* 17 | border: solid; 18 | border-color: yellow; 19 | */ 20 | width: 100%; 21 | height: 100%; 22 | } 23 | 24 | #hcontainer { 25 | /* 26 | border: solid; 27 | border-color: blue; 28 | */ 29 | overflow: hidden; 30 | white-space: nowrap; 31 | height: 100%; 32 | } 33 | 34 | #toolbar { 35 | /* 36 | border: solid; 37 | border-color: red; 38 | */ 39 | display: block; 40 | width: 50px; 41 | float: left; 42 | } 43 | 44 | #colorbar { 45 | /* 46 | border: solid; 47 | border-color: red; 48 | */ 49 | display: block; 50 | width: 50px; 51 | float: left; 52 | } 53 | 54 | #colorselector { 55 | /* 56 | border: solid; 57 | border-color: red; 58 | */ 59 | width: 55px; 60 | } 61 | 62 | #toolbar { 63 | /* 64 | border: solid; 65 | border-color: red; 66 | */ 67 | display: block; 68 | width: 50px; 69 | float: left; 70 | } 71 | 72 | .hidden { 73 | display: none; 74 | } 75 | 76 | .invisible { 77 | visibility: hidden; 78 | } 79 | 80 | .subtoolbar { 81 | height: 50px; 82 | } 83 | 84 | .tool { 85 | width: 50px; 86 | height: 50px; 87 | padding: 0px 0px 0px 0px; 88 | vertical-align: middle; 89 | display: inline-block; 90 | } 91 | 92 | .currentColor { 93 | width: 50px; 94 | height: 50px; 95 | } 96 | 97 | .color { 98 | width: 25px; 99 | height: 25px; 100 | margin: 0px; 101 | } 102 | 103 | .slider { 104 | width: 95%; 105 | } 106 | 107 | .github { 108 | width: 95%; 109 | } 110 | 111 | #paint { 112 | position: relative; 113 | } 114 | 115 | #kiddopaint { 116 | border: 1px solid #00f; 117 | width: 1920px; 118 | height: 1200px; 119 | } 120 | 121 | #tmpCanvas { 122 | position: absolute; 123 | top: 1px; 124 | left: 1px; 125 | cursor: crosshair; 126 | } 127 | 128 | #previewCanvas { 129 | position: absolute; 130 | top: 1px; 131 | left: 1px; 132 | } 133 | 134 | h1 { 135 | font-size: 3em; 136 | margin: 0.5ex; 137 | } 138 | 139 | emj { 140 | font-family: 'Apple Color Emoji'; 141 | font-size: 3em; 142 | height: 50px; 143 | } -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": ".", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "headers": [ 10 | { 11 | "source": "**/*", 12 | "headers": [ 13 | { 14 | "key": "Access-Control-Allow-Origin", 15 | "value": "*" 16 | } 17 | ] 18 | } 19 | ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /img/bl1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/bl1.png -------------------------------------------------------------------------------- /img/bl2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/bl2.png -------------------------------------------------------------------------------- /img/br10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br10.png -------------------------------------------------------------------------------- /img/br11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br11.png -------------------------------------------------------------------------------- /img/br12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br12.png -------------------------------------------------------------------------------- /img/br13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br13.png -------------------------------------------------------------------------------- /img/br14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br14.png -------------------------------------------------------------------------------- /img/br15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br15.png -------------------------------------------------------------------------------- /img/br16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br16.png -------------------------------------------------------------------------------- /img/br18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br18.png -------------------------------------------------------------------------------- /img/br19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br19.png -------------------------------------------------------------------------------- /img/br20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br20.png -------------------------------------------------------------------------------- /img/br21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br21.png -------------------------------------------------------------------------------- /img/br23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br23.png -------------------------------------------------------------------------------- /img/br6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br6.png -------------------------------------------------------------------------------- /img/br7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br7.png -------------------------------------------------------------------------------- /img/br8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br8.png -------------------------------------------------------------------------------- /img/br9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/br9.png -------------------------------------------------------------------------------- /img/pinch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/pinch.png -------------------------------------------------------------------------------- /img/pw1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/pw1.png -------------------------------------------------------------------------------- /img/pw2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/pw2.png -------------------------------------------------------------------------------- /img/pw3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/pw3.png -------------------------------------------------------------------------------- /img/pw4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/pw4.png -------------------------------------------------------------------------------- /img/pw5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/pw5.png -------------------------------------------------------------------------------- /img/sprk1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/sprk1.png -------------------------------------------------------------------------------- /img/sprk2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/sprk2.png -------------------------------------------------------------------------------- /img/sprk3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/sprk3.png -------------------------------------------------------------------------------- /img/sprk4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/sprk4.png -------------------------------------------------------------------------------- /img/sprk5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/sprk5.png -------------------------------------------------------------------------------- /img/sprk6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/sprk6.png -------------------------------------------------------------------------------- /img/sprk7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/sprk7.png -------------------------------------------------------------------------------- /img/sprk8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/sprk8.png -------------------------------------------------------------------------------- /img/sprk9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/img/sprk9.png -------------------------------------------------------------------------------- /js/brushes/circles.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Brushes.Circles = function() { 2 | var flip = 0; 3 | return function(color1, color2, alwaysFill) { 4 | color1 = color1 || 'black'; 5 | color2 = color2 || color1; 6 | alwaysFill = alwaysFill || false; 7 | var size = 20 * KiddoPaint.Current.scaling; 8 | 9 | var canvasBrush = document.createElement('canvas'); 10 | canvasBrush.width = size * 2; 11 | canvasBrush.height = size * 2; 12 | var contextBrush = canvasBrush.getContext('2d'); 13 | 14 | contextBrush.beginPath(); 15 | contextBrush.arc(size, size, 10, 0, 2 * Math.PI); 16 | if (alwaysFill || flip % 2 == 0) { 17 | contextBrush.fillStyle = color1; 18 | contextBrush.fill(); 19 | } 20 | contextBrush.lineWidth = 2; 21 | contextBrush.strokeStyle = color2; 22 | contextBrush.stroke(); 23 | contextBrush.closePath(); 24 | flip++; 25 | 26 | return { 27 | brush: canvasBrush, 28 | offset: size 29 | }; 30 | } 31 | }(); 32 | 33 | KiddoPaint.Brushes.RCircles = function() { 34 | var color1 = KiddoPaint.Colors.randomColor(); 35 | var color2 = KiddoPaint.Colors.randomColor(); 36 | return KiddoPaint.Brushes.Circles(color1, color2, true); 37 | } -------------------------------------------------------------------------------- /js/brushes/concen.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Brushes.Concentric = function(color1, step) { 2 | color1 = color1 || 'black'; 3 | 4 | var canvasBrush = document.createElement('canvas'); 5 | var size = ((step % 7 * 5) + 5) * KiddoPaint.Current.scaling; 6 | canvasBrush.width = size * 2; 7 | canvasBrush.height = size * 2; 8 | var contextBrush = canvasBrush.getContext('2d'); 9 | 10 | contextBrush.beginPath(); 11 | contextBrush.arc(size, size, size, 0, Math.PI * 2); 12 | contextBrush.strokeStyle = color1; 13 | contextBrush.lineWidth = 1; 14 | contextBrush.stroke(); 15 | contextBrush.closePath(); 16 | 17 | return { 18 | brush: canvasBrush, 19 | offset: size 20 | }; 21 | } -------------------------------------------------------------------------------- /js/brushes/dumbbell.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Brushes.Dumbbell = function(color1, color2) { 2 | color1 = color1 || 'black'; 3 | color2 = color2 || 'black'; 4 | 5 | var radius = 25 * KiddoPaint.Current.scaling * KiddoPaint.Current.multiplier; 6 | var density = 128 * KiddoPaint.Current.scaling * KiddoPaint.Current.multiplier; 7 | 8 | var canvasBrush = document.createElement('canvas'); 9 | canvasBrush.width = radius * 2; 10 | canvasBrush.height = radius * 2; 11 | var contextBrush = canvasBrush.getContext('2d'); 12 | contextBrush.fillStyle = color1; 13 | 14 | function bar() { 15 | var rr = ziggurat() * radius; 16 | var ra = Math.random() * 2 * Math.PI; 17 | var x = Math.cos(ra) * rr; 18 | var y = Math.sin(ra) * rr / 11; 19 | contextBrush.fillRect(radius + x, radius + y, 0.7, 0.7); 20 | } 21 | 22 | for (var i = 0; i < density; i++) { 23 | contextBrush.globalAlpha = Math.random() / 2; 24 | bar(); 25 | } 26 | return { 27 | brush: canvasBrush, 28 | offset: radius 29 | }; 30 | } -------------------------------------------------------------------------------- /js/brushes/fsine.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Brushes.FollowingSine = function(color1, step) { 2 | color1 = color1 || 'black'; 3 | var interval = 50; 4 | step = step % interval / interval; 5 | 6 | var canvasBrush = document.createElement('canvas'); 7 | var size = 33 * KiddoPaint.Current.scaling; 8 | canvasBrush.width = size * 2; 9 | canvasBrush.height = size * 2; 10 | var contextBrush = canvasBrush.getContext('2d'); 11 | contextBrush.fillStyle = color1; 12 | 13 | for (var i = 0, s = step; i < 6; i++, s += 10 / interval) { 14 | x = size + (size * Math.cos(2 * Math.PI * s)); 15 | y = size + (size * Math.sin(2 * Math.PI * s)); 16 | contextBrush.fillRect(Math.round(x), Math.round(y), 3, 3); 17 | } 18 | 19 | return { 20 | brush: canvasBrush, 21 | offset: size, 22 | inplace: true 23 | }; 24 | } -------------------------------------------------------------------------------- /js/brushes/icy.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Brushes.Icy = function(color1) { 2 | color1 = color1 || 'black'; 3 | 4 | var radius = 32 * KiddoPaint.Current.scaling * KiddoPaint.Current.multiplier; 5 | var density = clamp(0, 2000, 600 * KiddoPaint.Current.scaling * KiddoPaint.Current.multiplier); 6 | 7 | var canvasBrush = document.createElement('canvas'); 8 | canvasBrush.width = 32; 9 | canvasBrush.height = 400; 10 | var contextBrush = canvasBrush.getContext('2d'); 11 | contextBrush.fillStyle = color1; 12 | 13 | function delicatespray() { 14 | var px = 0.4 * ((KiddoPaint.Current.multiplier < 6) ? 1 : 2); 15 | var x = randn_bm(-5, 5, 1); 16 | var y = randn_bm(-radius, radius, 5); 17 | contextBrush.fillRect(x, radius + y, px, px) 18 | } 19 | 20 | for (var i = 0; i < density; i++) { 21 | contextBrush.globalAlpha = Math.random() / 2; 22 | delicatespray(); 23 | } 24 | 25 | return { 26 | brush: canvasBrush, 27 | offset: 0 28 | }; 29 | } -------------------------------------------------------------------------------- /js/brushes/meanstreak.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Brushes.MeanStreak = function(step) { 2 | var canvasBrush = document.createElement('canvas'); 3 | var size = 32 * KiddoPaint.Current.scaling; 4 | canvasBrush.width = size * 2; 5 | canvasBrush.height = size * 2; 6 | var contextBrush = canvasBrush.getContext('2d'); 7 | 8 | var transforms = [ 9 | 'source-in', 10 | 'source-out', 11 | 'destination-atop', 12 | 'screen', 13 | 'overlay', 14 | 'soft-light', 15 | 'lighter', 16 | 'exclusion', 17 | 'luminosity' 18 | ]; 19 | 20 | var c = makeComposite(transforms[KiddoPaint.Current.multiplier]); 21 | 22 | contextBrush.translate(size / 2, size / 2); 23 | contextBrush.rotate(((step % 360)) * (Math.PI / 180)); 24 | contextBrush.translate(-size / 2, -size / 2); 25 | contextBrush.drawImage(c, 0, 0, c.width, c.height, 0, 0, size, size); 26 | 27 | return { 28 | brush: canvasBrush, 29 | offset: size / 2.0 30 | }; 31 | } -------------------------------------------------------------------------------- /js/brushes/pies.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Brushes.Pies = function(color1) { 2 | color1 = color1 || 'black'; 3 | 4 | var canvasBrush = document.createElement('canvas'); 5 | var size = 20 * KiddoPaint.Current.scaling; 6 | canvasBrush.width = size * 2; 7 | canvasBrush.height = size * 2; 8 | var contextBrush = canvasBrush.getContext('2d'); 9 | 10 | contextBrush.beginPath(); 11 | contextBrush.arc(size, size, size, 0, Math.PI * 2); 12 | contextBrush.fillStyle = color1; 13 | contextBrush.fill(); 14 | contextBrush.closePath(); 15 | 16 | contextBrush.globalCompositeOperation = 'destination-out'; 17 | contextBrush.beginPath(); 18 | contextBrush.fillStyle = color1; 19 | offset = Math.random() * 2 * Math.PI; 20 | contextBrush.arc(size, size, size + 2, 0 + offset, ((0.5 + Math.random() - 0.5) * Math.PI) + offset); 21 | contextBrush.lineTo(size, size); 22 | contextBrush.fill(); 23 | return { 24 | brush: canvasBrush, 25 | offset: size 26 | }; 27 | } -------------------------------------------------------------------------------- /js/brushes/rainbowball.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Brushes.RainbowBall = function(step) { // https://stackoverflow.com/questions/22223950/angle-gradient-in-canvas 2 | var canvas = document.createElement('canvas'); 3 | var size = 100 * KiddoPaint.Current.scaling; 4 | canvas.width = size * 2; 5 | canvas.height = size * 2; 6 | var ctx = canvas.getContext('2d'); 7 | 8 | var g1 = ctx.createRadialGradient(45, 45, 10, 52, 50, 30); 9 | g1.addColorStop(0, '#A7D30C'); 10 | g1.addColorStop(0.9, '#019F62'); 11 | g1.addColorStop(1, 'rgba(1,159,98,0)'); 12 | var g2 = ctx.createRadialGradient(125, 45, 20, 132, 50, 30); 13 | g2.addColorStop(0, '#FF5F98'); 14 | g2.addColorStop(0.75, '#FF0188'); 15 | g2.addColorStop(1, 'rgba(255,1,136,0)'); 16 | // draw shapes 17 | ctx.fillStyle = g1; 18 | //ctx.fillStyle = g2; 19 | 20 | ctx.fillRect(0, 0, size, size); 21 | 22 | return { 23 | brush: canvas, 24 | offset: size / 2.0 25 | }; 26 | } -------------------------------------------------------------------------------- /js/brushes/rainbowbar.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Brushes.RainbowBar = function(step) { // https://stackoverflow.com/questions/22223950/angle-gradient-in-canvas 2 | var canvas = document.createElement('canvas'); 3 | var size = 50 * KiddoPaint.Current.scaling; 4 | canvas.width = size * 2; 5 | canvas.height = size * 2; 6 | var ctx = canvas.getContext('2d'); 7 | 8 | var gradient = ctx.createLinearGradient(10, 0, 100, 0); 9 | gradient.addColorStop(0, 'red'); 10 | gradient.addColorStop(1 / 6, 'orange'); 11 | gradient.addColorStop(2 / 6, 'yellow'); 12 | gradient.addColorStop(3 / 6, 'green'); 13 | gradient.addColorStop(4 / 6, 'blue'); 14 | gradient.addColorStop(5 / 6, 'indigo'); 15 | gradient.addColorStop(1, 'violet'); 16 | ctx.fillStyle = gradient; 17 | ctx.rotate(20 * Math.PI / 180); 18 | ctx.fillRect(0, 0, 100, 16); 19 | 20 | return { 21 | brush: canvas, 22 | offset: size / 2.0 23 | }; 24 | } -------------------------------------------------------------------------------- /js/brushes/rainbowdoughnut.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Brushes.RainbowDoughnut = function(step) { // https://stackoverflow.com/questions/22223950/angle-gradient-in-canvas 2 | var canvas = document.createElement('canvas'); 3 | var size = 32 * KiddoPaint.Current.scaling; 4 | canvas.width = size * 2; 5 | canvas.height = size * 2; 6 | var ctx = canvas.getContext('2d'); 7 | 8 | function drawMultiRadiantCircle(xc, yc, r, radientColors) { 9 | var partLength = (2 * Math.PI) / radientColors.length; 10 | var start = 0; 11 | var gradient = null; 12 | var startColor = null, 13 | endColor = null; 14 | 15 | for (var i = 0; i < radientColors.length; i++) { 16 | startColor = radientColors[i]; 17 | endColor = radientColors[(i + 1) % radientColors.length]; 18 | 19 | // x start / end of the next arc to draw 20 | var xStart = xc + Math.cos(start) * r; 21 | var xEnd = xc + Math.cos(start + partLength) * r; 22 | // y start / end of the next arc to draw 23 | var yStart = yc + Math.sin(start) * r; 24 | var yEnd = yc + Math.sin(start + partLength) * r; 25 | 26 | ctx.beginPath(); 27 | 28 | gradient = ctx.createLinearGradient(xStart, yStart, xEnd, yEnd); 29 | gradient.addColorStop(0, startColor); 30 | gradient.addColorStop(1.0, endColor); 31 | 32 | ctx.strokeStyle = gradient; 33 | ctx.arc(xc, yc, r, start, start + partLength); 34 | ctx.lineWidth = size / 4; 35 | ctx.stroke(); 36 | ctx.closePath(); 37 | 38 | start += partLength; 39 | } 40 | } 41 | 42 | var someColors = []; 43 | someColors.push('#0F0'); 44 | someColors.push('#0FF'); 45 | someColors.push('#F00'); 46 | someColors.push('#FF0'); 47 | someColors.push('#F0F'); 48 | 49 | drawMultiRadiantCircle(size / 2, size / 2, size / 3, someColors); 50 | 51 | return { 52 | brush: canvas, 53 | offset: size / 2.0 54 | }; 55 | } -------------------------------------------------------------------------------- /js/brushes/rose.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Brushes.Rose = function(color1, step) { 2 | color1 = color1 || 'black'; 3 | var interval = 257; 4 | var fraction = interval / 7; 5 | var k = 5; 6 | step = step % interval / interval; 7 | 8 | var canvasBrush = document.createElement('canvas'); 9 | var size = 50 * KiddoPaint.Current.scaling; 10 | canvasBrush.width = size * 2; 11 | canvasBrush.height = size * 2; 12 | var contextBrush = canvasBrush.getContext('2d'); 13 | contextBrush.fillStyle = color1; 14 | contextBrush.strokeStyle = color1; 15 | 16 | for (var i = 0, s = step; i < 6; i++, s += fraction / interval) { 17 | x = size + (size * Math.cos(k * 2 * Math.PI * s) * Math.cos(2 * Math.PI * s)); 18 | y = size + (size * Math.cos(k * 2 * Math.PI * s) * Math.sin(2 * Math.PI * s)); 19 | // contextBrush.fillRect(Math.round(x), Math.round(y), 3, 3); 20 | contextBrush.lineTo(x, y); 21 | } 22 | contextBrush.stroke(); 23 | 24 | return { 25 | brush: canvasBrush, 26 | offset: size, 27 | inplace: true 28 | }; 29 | } -------------------------------------------------------------------------------- /js/brushes/rpent.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Brushes.RotatingPentagon = function(color1, step) { 2 | color1 = color1 || 'black'; 3 | var interval = 50; 4 | step = step % interval / interval; 5 | 6 | var canvasBrush = document.createElement('canvas'); 7 | var size = 33 * KiddoPaint.Current.scaling; 8 | canvasBrush.width = size * 2; 9 | canvasBrush.height = size * 2; 10 | var contextBrush = canvasBrush.getContext('2d'); 11 | contextBrush.fillStyle = color1; 12 | contextBrush.strokeStyle = color1; 13 | contextBrush.lineWidth = 1; 14 | 15 | for (var i = 0, s = step; i < 6; i++, s += 10 / interval) { 16 | x = size + (size * Math.cos(2 * Math.PI * s)); 17 | y = size + (size * Math.sin(2 * Math.PI * s)); 18 | contextBrush.lineTo(x, y); 19 | } 20 | 21 | contextBrush.stroke(); 22 | return { 23 | brush: canvasBrush, 24 | offset: size, 25 | inplace: true 26 | }; 27 | } -------------------------------------------------------------------------------- /js/brushes/spray.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Brushes.Spray = function(color1, color2) { 2 | color1 = color1 || 'black'; 3 | color2 = color2 || 'black'; 4 | 5 | var radius = 10 * KiddoPaint.Current.scaling * KiddoPaint.Current.multiplier; 6 | var density = 128 * KiddoPaint.Current.scaling * KiddoPaint.Current.multiplier; 7 | 8 | var canvasBrush = document.createElement('canvas'); 9 | canvasBrush.width = radius * 2; 10 | canvasBrush.height = radius * 2; 11 | var contextBrush = canvasBrush.getContext('2d'); 12 | contextBrush.fillStyle = color1; 13 | 14 | function ring() { 15 | var theta = Math.random() * 2 * Math.PI; 16 | var r1 = radius; 17 | var r2 = radius * 0.75; 18 | var rp = Math.random() + 0.33; 19 | 20 | var dist = Math.sqrt(Math.abs(ziggurat()) * ((r1 * r1) - (r2 * r2)) + (r2 * r2)) 21 | var xr = dist * Math.cos(theta); 22 | var yr = dist * Math.sin(theta); 23 | contextBrush.fillRect(radius + xr, radius + yr, rp, rp); 24 | } 25 | 26 | function disc() { 27 | // disc 28 | var rr = ziggurat() * radius * 1.1; 29 | var ra = Math.random() * 2 * Math.PI; 30 | var rp = Math.random(); 31 | var x = Math.cos(ra) * rr; 32 | var y = Math.sin(ra) * rr; 33 | contextBrush.fillRect(radius + x, radius + y, rp, rp); 34 | } 35 | 36 | function experiment() { 37 | var pts = boxmuller(); 38 | contextBrush.fillRect(radius + pts[0] * radius, radius + pts[1] * radius, 0.7, 0.7); 39 | } 40 | 41 | for (var i = 0; i < density; i++) { 42 | if (KiddoPaint.Current.modifiedToggle) { 43 | contextBrush.fillStyle = color1; 44 | if (KiddoPaint.Current.modifiedMeta) { 45 | contextBrush.globalAlpha = Math.random() / 4; 46 | } else { 47 | contextBrush.globalAlpha = Math.random() / 2; 48 | } 49 | ring(); 50 | if (KiddoPaint.Current.modifiedMeta) { 51 | contextBrush.globalAlpha = Math.random() / 3; 52 | contextBrush.fillStyle = color2; 53 | disc(); 54 | } 55 | } else { 56 | contextBrush.globalAlpha = Math.random() / 2; 57 | disc(); 58 | } 59 | } 60 | return { 61 | brush: canvasBrush, 62 | offset: radius 63 | }; 64 | } -------------------------------------------------------------------------------- /js/brushes/twirly.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Brushes.Twirly = function(color1, step) { 2 | color1 = color1 || 'black'; 3 | step = step % 24 / 24; 4 | 5 | var canvasBrush = document.createElement('canvas'); 6 | var size = 25 * KiddoPaint.Current.scaling; 7 | canvasBrush.width = size * 2; 8 | canvasBrush.height = size * 2; 9 | var contextBrush = canvasBrush.getContext('2d'); 10 | 11 | contextBrush.beginPath(); 12 | contextBrush.moveTo(size, size); 13 | x = size + (size * Math.cos(2 * Math.PI * step)); 14 | y = size + (size * Math.sin(2 * Math.PI * step)); 15 | contextBrush.lineTo(x, y); 16 | contextBrush.strokeStyle = color1; 17 | contextBrush.lineWidth = 1; 18 | contextBrush.stroke(); 19 | contextBrush.closePath(); 20 | 21 | return { 22 | brush: canvasBrush, 23 | offset: size, 24 | inplace: true 25 | }; 26 | } -------------------------------------------------------------------------------- /js/builders/arrow.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Builders.Arrow = function(color1, angle) { 2 | color1 = color1 || 'black'; 3 | angle = angle || 0; 4 | 5 | var canvasBrush = document.createElement('canvas'); 6 | canvasBrush.width = 43; 7 | canvasBrush.height = 43; 8 | var contextBrush = canvasBrush.getContext('2d'); 9 | 10 | contextBrush.beginPath(); 11 | // contextBrush.rect(0, 0, 43, 43); 12 | 13 | contextBrush.translate(21, 21); 14 | contextBrush.rotate(angle); 15 | contextBrush.translate(-10.5, -15.5); 16 | 17 | contextBrush.strokeStyle = color1; 18 | 19 | contextBrush.moveTo(10, 0); 20 | contextBrush.lineTo(10, 30); 21 | contextBrush.moveTo(10, 0); 22 | contextBrush.lineTo(0, 7); 23 | contextBrush.moveTo(10, 0); 24 | contextBrush.lineTo(20, 7); 25 | 26 | contextBrush.stroke(); 27 | 28 | return canvasBrush; 29 | } -------------------------------------------------------------------------------- /js/builders/prints.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Builders.Prints = function(color1, print, angle) { 2 | color1 = color1 || 'black'; 3 | angle = angle || 0; 4 | 5 | var canvasBrush = document.createElement('canvas'); 6 | canvasBrush.width = 100; 7 | canvasBrush.height = 100; 8 | var contextBrush = canvasBrush.getContext('2d'); 9 | 10 | contextBrush.save(); 11 | contextBrush.translate(50, 50); 12 | contextBrush.rotate(angle); 13 | contextBrush.translate(-25, 0); 14 | contextBrush.font = '36px sans-serif'; 15 | contextBrush.fillText(print, 0, 0); 16 | contextBrush.restore(); 17 | 18 | contextBrush.globalCompositeOperation = 'source-atop'; 19 | contextBrush.fillStyle = color1; 20 | contextBrush.fillRect(0, 0, canvasBrush.width, canvasBrush.height); 21 | 22 | return trimCanvas(canvasBrush); 23 | } -------------------------------------------------------------------------------- /js/builders/rail.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Builders.Rail = function(color1, angle) { 2 | color1 = color1 || 'black'; 3 | angle = angle || 0; 4 | 5 | var canvasBrush = document.createElement('canvas'); 6 | canvasBrush.width = 43; 7 | canvasBrush.height = 43; 8 | var contextBrush = canvasBrush.getContext('2d'); 9 | 10 | contextBrush.beginPath(); 11 | 12 | contextBrush.translate(21, 21); 13 | contextBrush.rotate(angle); 14 | contextBrush.translate(-15.5, -15.5); 15 | 16 | // left rail 17 | contextBrush.fillStyle = 'rgb(190, 190, 190)'; 18 | contextBrush.fillRect(0.5, 0, 3, 40); 19 | contextBrush.fillRect(30.5, 0, 2.5, 40); 20 | 21 | // right rail 22 | contextBrush.fillStyle = 'rgb(128, 128, 128)'; 23 | contextBrush.fillRect(3.5, 0, 2.5, 40); 24 | contextBrush.fillRect(27.5, 0, 2.5, 40); 25 | 26 | // ties 27 | for (var i = 0; i < 4; i++) { 28 | var offset = 8 * i; 29 | contextBrush.fillStyle = 'rgb(136, 104, 67)'; 30 | contextBrush.fillRect(0, 5.5 + offset, 35, 2); 31 | contextBrush.fillStyle = 'rgb(73, 61, 38)'; 32 | contextBrush.fillRect(0, 7 + offset, 35, 1.5); 33 | } 34 | return canvasBrush; 35 | } -------------------------------------------------------------------------------- /js/builders/road.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Builders.Road = function(color1, color2, angle) { 2 | color1 = color1 || 'black'; 3 | color2 = (color2 === color1) ? 'yellow' : color2; 4 | angle = angle || 0; 5 | 6 | var canvasBrush = document.createElement('canvas'); 7 | canvasBrush.width = 43; 8 | canvasBrush.height = 43; 9 | var contextBrush = canvasBrush.getContext('2d'); 10 | 11 | contextBrush.beginPath(); 12 | 13 | contextBrush.translate(21, 21); 14 | contextBrush.rotate(angle); 15 | contextBrush.translate(-15.5, -15.5); 16 | 17 | contextBrush.fillStyle = color1; 18 | contextBrush.fillRect(0, 0, 30, 40); 19 | 20 | contextBrush.fillStyle = color2; 21 | contextBrush.fillRect(13.5, 7.5, 3, 23); 22 | 23 | return canvasBrush; 24 | } -------------------------------------------------------------------------------- /js/init/submenus.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Submenu = {}; 2 | 3 | function show_generic_submenu(subtoolbar) { 4 | if (!KiddoPaint.Submenu[subtoolbar]) { 5 | return; 6 | } 7 | 8 | reset_ranges(); 9 | 10 | var subtoolbars = document.getElementById('subtoolbars').children; 11 | var genericsubmenu = null; 12 | for (var i = 0, len = subtoolbars.length; i < len; i++) { 13 | var div = subtoolbars[i]; 14 | if (div.id === 'genericsubmenu') { 15 | div.className = 'subtoolbar' 16 | genericsubmenu = div; 17 | } else { 18 | div.className = 'hidden' 19 | } 20 | } 21 | 22 | // clear old ; todo cache constructed buttons instead 23 | genericsubmenu.removeAllChildren(); 24 | for (var i = 0, len = KiddoPaint.Submenu[subtoolbar].length; i < len; i++) { 25 | var buttonDetail = KiddoPaint.Submenu[subtoolbar][i]; 26 | var button = document.createElement('button'); 27 | button.className = 'tool'; 28 | 29 | // title on hover 30 | button.title = buttonDetail.name; 31 | 32 | // display 33 | if (buttonDetail.invisible) { 34 | button.className += " invisible"; 35 | } else if (buttonDetail.imgSrc) { 36 | var img = document.createElement('img'); 37 | img.src = buttonDetail.imgSrc; 38 | img.className = 'tool'; 39 | button.appendChild(img); 40 | } else if (buttonDetail.imgJs) { 41 | var img = document.createElement('img'); 42 | img.src = buttonDetail.imgJs(); 43 | button.appendChild(img); 44 | } else if (buttonDetail.text) { 45 | var t = document.createTextNode(buttonDetail.text); 46 | button.appendChild(t); 47 | } else if (buttonDetail.emoji) { 48 | var emoji = document.createElement('emj'); 49 | var text = document.createTextNode(buttonDetail.emoji); 50 | emoji.appendChild(text); 51 | button.appendChild(emoji); 52 | } 53 | 54 | // click handler 55 | button.onclick = buttonDetail.handler; 56 | 57 | genericsubmenu.appendChild(button); 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /js/sounds/sounds.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Sounds.Library = {} 2 | KiddoPaint.Sounds.Library.enabled = true; 3 | 4 | KiddoPaint.Sounds.Library.explosion = [new Audio('snd/explosion0.wav'), new Audio('snd/explosion1.wav'), new Audio('snd/explosion2.wav')]; 5 | KiddoPaint.Sounds.Library.oops = [new Audio('snd/oops0.wav'), new Audio('snd/oops1.wav'), new Audio('snd/oops2.wav')]; 6 | KiddoPaint.Sounds.Library.pencil = [new Audio('snd/pencil0.wav')]; 7 | KiddoPaint.Sounds.Library.stamp = [new Audio('snd/stamp0.wav'), new Audio('snd/stamp1.wav')]; 8 | KiddoPaint.Sounds.Library.flood = [new Audio('snd/flood0.wav'), new Audio('snd/flood1.wav')]; 9 | 10 | KiddoPaint.Sounds.Library.play = function(sound) { 11 | if (KiddoPaint.Sounds.Library.enabled && KiddoPaint.Sounds.Library[sound]) { 12 | var idx = Math.floor(Math.random() * KiddoPaint.Sounds.Library[sound].length); 13 | var s = KiddoPaint.Sounds.Library[sound][idx]; 14 | s.play(); 15 | } 16 | }; 17 | 18 | KiddoPaint.Sounds.explosion = function() { 19 | KiddoPaint.Sounds.Library.play('explosion'); 20 | } 21 | KiddoPaint.Sounds.oops = function() { 22 | KiddoPaint.Sounds.Library.play('oops'); 23 | } 24 | KiddoPaint.Sounds.pencil = function() { 25 | KiddoPaint.Sounds.Library.play('pencil'); 26 | } 27 | KiddoPaint.Sounds.stamp = function() { 28 | KiddoPaint.Sounds.Library.play('stamp'); 29 | } 30 | KiddoPaint.Sounds.flood = function() { 31 | KiddoPaint.Sounds.Library.play('flood'); 32 | } -------------------------------------------------------------------------------- /js/stamps/alphabet.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Alphabet.english = { 2 | face: 'sans-serif', 3 | pages: 2, 4 | character1: { 5 | letters: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] 6 | }, 7 | character2: { 8 | letters: ['!', '?', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '<', '>', '$', '%', '^', '&', '@', '*', '(', ')', '~', '|'] 9 | } 10 | } 11 | 12 | KiddoPaint.Alphabet.wingdings = { 13 | face: 'sans-serif', 14 | pages: 2, 15 | character1: { 16 | letters: ['☃', '☼', '☂', '☁', '♠', '♣', '♥', '♦', '♚', '♛', '♜', '♝', '♞', '♟', '✂', '✇', '✈', '♨', '♆', '✠', '☯', '⚇'] 17 | }, 18 | character2: { 19 | letters: ['❖', '◎', '◉', '⦿', '✢', '✣', '✤', '✥', '✦', '✧', '★', '☆', '✯', '✩', '✪', '✫', '✬', '✭', '✮', '✶', '✷', '✵', '✸', '✹', '✺', '❊', '✻', '✽', '✼', '❉', '✱', '✲', '✾', '❃', '❋', '✳', '✴', '❇', '❈', '※', '❅', '❆', '❄', '✿', '❀', '❁', '❂', '☙', '❧', '❦'] 20 | } 21 | } 22 | 23 | KiddoPaint.Alphabet.nextPage = function() { 24 | KiddoPaint.Alphabet.page += 1; 25 | if (KiddoPaint.Alphabet.page > KiddoPaint.Alphabet.english.pages) { 26 | KiddoPaint.Alphabet.page = 1; 27 | } 28 | } 29 | 30 | KiddoPaint.Alphabet.nextWingding = function(page) { 31 | var idx = 0; 32 | return function(page) { 33 | if (idx >= KiddoPaint.Alphabet.wingdings['character' + page].letters.length) { 34 | idx = 0; 35 | } 36 | var ret = KiddoPaint.Alphabet.wingdings['character' + page].letters[idx]; 37 | idx += 1; 38 | return ret; 39 | } 40 | }(); -------------------------------------------------------------------------------- /js/stamps/stamps.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Stamps.grouping = { 2 | face: 'Apple Color Emoji', 3 | pages: 16, 4 | stamp1: { 5 | stamps: ['🚂', '🚃', '🚋', '🚎', '🚌', '🚍', '🏎', '🚙', '🚘', '🚗', '🚕', '🚛', '🚚', '🚒', '🚑', '🚐', '🚜', '⛵', '🚤', '🚀', '✈️', '🚁', '🛣', '🛤', '🚥', '🚦'] 6 | }, 7 | stamp2: { 8 | stamps: ['🏘️', '🏡', '🏠', '🏛️', '🏰', '🎪', '🏫', '🏢', '🏣', '🏥', '🏦', '🏪', '🏨', '🏬', '🏤', '🏭', '🏗️', '🛋️', '🚰', '🛁', '🚽', '🚪', '🕯', '🚏', '📭', '📦'] 9 | }, 10 | stamp3: { 11 | stamps: ['🏃', '🚶', '💃', '🏇', '🏂', '🏊', '🏄', '🎃', '⛄', '🚧', '⛽', '📡', '🛰', '🪁', '⚽', '🏀', '🏈', '⚾️', '🥎', '🎾', '🏐', '🎱', '🥌', '🎈', '💎', '🌀'] 12 | }, 13 | stamp4: { 14 | stamps: ['🤴🏻', '👸🏻', '🧚🏼‍♀️', '🧜🏼‍♀️', '🕺', '😆', '😂', '🙃', '😍', '😘', '😜', '😎', '🤖', '👧🏻', '👦🏻', '🤔', '🤗', '😴', '💀', '👻', '🤧', '💩', '🤠', '😸', ' ', ' '] 15 | }, 16 | stamp5: { 17 | stamps: ['🙈', '🙉', '🙊', '🐵', '🐒', '🦍', '🦧', '🐶', '🐕', '🐩', '🐺', '🦊', '🦝', '🐱', '🐈', '🦁', '🐯', '🐅', '🐆', '🐴', '🐎', '🦄', '🦓', '🦌', '🐮', '🐂', '🐃', '🐄', '🐷', '🐖'] 18 | }, 19 | stamp6: { 20 | stamps: ['🐗', '🐏', '🐑', '🐐', '🐪', '🐫', '🦙', '🦒', '🐘', '🦏', '🦛', '🐭', '🐁', '🐀', '🐹', '🐰', '🐇', '🐿', '🦔', '🦇', '🐻', '🐨', '🐼', '🦥', '🦦', '🦨', '🦘', '🦡', '🐾', '🦃'] 21 | }, 22 | stamp7: { 23 | stamps: ['🐔', '🐓', '🐣', '🐤', '🐥', '🐦', '🐧', '🕊', '🦅', '🦆', '🦢', '🦉', '🦩', '🦚', '🦜', '🐸', '🐊', '🐢', '🦎', '🐍', '🐲', '🐉', '🦕', '🦖', '🐳', '🐋', '🐬', '🐟', '🐠', '🐡'] 24 | }, 25 | stamp8: { 26 | stamps: ['🦈', '🐙', '🦀', '🦞', '🦐', '🦑', '🐚', '🐌', '🦋', '🐛', '🐜', '🐝', '🐞', '🕸', '🦟', '🦠', '💐', '🌸', '🌺', '💮', '🏵', '🌹', '🥀', '🌻', '🌼', '🌷', '🌱', '🌲', '🎄', '🌳'] 27 | }, 28 | stamp9: { 29 | stamps: ['🌴', '🌵', '🌾', '🌿', '☘', '🍀', '🍁', '🍂', '🍃', '🎋', '🎍', '🍄', '🌰', '🌍', '🌎', '🌏', '🌑', '🌒', '🌓', '🌔', '🌕', '🌖', '🌗', '🌘', '🌙', '🌚', '🌛', '☀', '🌝', '🌞'] 30 | }, 31 | stamp10: { 32 | stamps: ['⭐', '🌟', '💫', '✨', '🌠', '☁', '⛅', '⛈', '🌤', '🌥', '🌦', '🌧', '🌨', '🌩', '🌪', '🌫', '🌬', '💨', '🌈', '☂', '☔', '⚡', '❄', '☃', '⛄', '💥', '🔥', '💦', '💧', '🌊'] 33 | }, 34 | stamp11: { 35 | stamps: ['🍇', '🍈', '🍉', '🍊', '🍋', '🍌', '🍍', '🥭', '🍎', '🍏', '🍐', '🍑', '🍒', '🍓', '🥝', '🍅', '🥥', '🥑', '🍆', '🥕', '🌽', '🌶', '🥒', '🥦', '🍄', '🥜', '🍞', '🥐', '🥖', '🥨'] 36 | }, 37 | stamp12: { 38 | stamps: ['🥯', '🥞', '🧇', '🧀', '🍖', '🍗', '🥩', '🥓', '🍔', '🍟', '🍕', '🌭', '🥪', '🌮', '🌯', '🥙', '🥚', '🍳', '🥘', '🍲', '🥣', '🥗', '🍿', '🥫', '🍱', '🍚', '🍛', '🍜', '🍝', '🍠'] 39 | }, 40 | stamp13: { 41 | stamps: ['🍢', '🍣', '🍤', '🍥', '🍡', '🥟', '🥠', '🥡', '🦪', '🍦', '🍧', '🍨', '🍩', '🍪', '🎂', '🍰', '🥧', '🍫', '🍬', '🍭', '🍮', '🍯', '🍼', '🥛', '☕', '🍵', '🥤', '🍽', '🍴', '🥄'] 42 | }, 43 | stamp14: { 44 | stamps: ['🏓', '⛷', '🏄‍♀️', '🚴🏼‍♀️', '🚴‍♂️', '🎬', '🎧', '🎮', '🛴', '🚲', '🛵', '🏍', '', '🛸', '🛶', '⚓️', '🎡', '🏜', ] 45 | }, 46 | stamp15: { 47 | stamps: ['⛰', '🏔', '🗻', '🌋', '🏕', '⛺️', '💿', '📸', '💸', '💵', '💴', '💶', '💷', '💰', '💳', '🔮', '🚫', '♻️', ] 48 | }, 49 | stamp16: { 50 | stamps: ['❤️', '🧡', '💛', '💚', '💙', '💜', '🖤', '❣️', '💕', '💞', '💓', '💗', '💖', '💘', '💝', '🎀', '💟', '🏳️', '🏴', '🏁', '🇻🇮', '🏳️‍🌈', '🇺🇸', '🇮🇳', '🇦🇶', '🇨🇦', '🇳🇵'] 51 | }, 52 | } 53 | 54 | KiddoPaint.Stamps.stamp = function(stamp, alt, ctrl, size, shiftAmount, color) { 55 | stamp = stamp || ''; 56 | var canvasBrush = document.createElement('canvas'); 57 | canvasBrush.width = Math.max(size + (size * 0.05), 24); 58 | canvasBrush.height = Math.max(size + (size * 0.05), 24); 59 | canvasBrush.height += 0.15 * canvasBrush.height; // prevent clipping on bottom 60 | 61 | var contextBrush = canvasBrush.getContext('2d'); 62 | contextBrush.font = size + 'px ' + KiddoPaint.Stamps.currentFace; 63 | if (color) { // chrome & safari compat hack 64 | contextBrush.fillStyle = color; 65 | } 66 | 67 | contextBrush.save(); 68 | if (ctrl && alt) { 69 | contextBrush.scale(-1, 1); 70 | contextBrush.scale(1, -1); 71 | contextBrush.translate(-size, -size); 72 | contextBrush.fillText(stamp, 0, size - (0.15 * canvasBrush.height)); 73 | } else if (ctrl) { 74 | contextBrush.scale(1, -1); 75 | contextBrush.fillText(stamp, 0, -0.15 * canvasBrush.height); 76 | } else if (alt) { 77 | contextBrush.translate(size, size); 78 | contextBrush.scale(-1, 1); 79 | contextBrush.fillText(stamp, 0, 0); 80 | } else { 81 | contextBrush.fillText(stamp, 0, size); 82 | } 83 | contextBrush.restore(); 84 | 85 | if (shiftAmount != 0) { 86 | hueShift(canvasBrush, contextBrush, shiftAmount); 87 | } 88 | 89 | return canvasBrush; 90 | } 91 | 92 | KiddoPaint.Stamps.nextPage = function() { 93 | KiddoPaint.Stamps.page += 1; 94 | if (KiddoPaint.Stamps.page > KiddoPaint.Stamps.grouping.pages) { 95 | KiddoPaint.Stamps.page = 1; 96 | } 97 | } 98 | 99 | KiddoPaint.Stamps.prevPage = function() { 100 | KiddoPaint.Stamps.page -= 1; 101 | if (KiddoPaint.Stamps.page < 1) { 102 | KiddoPaint.Stamps.page = KiddoPaint.Stamps.grouping.pages; 103 | } 104 | } -------------------------------------------------------------------------------- /js/submenus/brush.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/js/submenus/brush.js -------------------------------------------------------------------------------- /js/submenus/jumble.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Submenu.jumble = [{ 2 | name: 'Ink', 3 | emoji: '🕸️', 4 | handler: function() { 5 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.INK; 6 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 7 | } 8 | }, 9 | { 10 | name: 'Color Shift', 11 | emoji: '♻️', 12 | handler: function() { 13 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.HUE; 14 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 15 | } 16 | }, 17 | { 18 | name: 'Grey Shift', 19 | emoji: '🔄', 20 | handler: function() { 21 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.SAT; 22 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 23 | } 24 | }, 25 | { 26 | name: 'Pinch', 27 | imgSrc: 'img/pinch.png', 28 | handler: function() { 29 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.PINCH; 30 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 31 | } 32 | }, 33 | { 34 | name: 'Swirl', 35 | emoji: '🍭', 36 | handler: function() { 37 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.SWIRL; 38 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 39 | } 40 | }, 41 | { 42 | name: 'Lens Blur', 43 | emoji: '👓', 44 | handler: function() { 45 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.LENSBLUR; 46 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 47 | } 48 | }, 49 | { 50 | name: 'Blur', 51 | emoji: '🌫️', 52 | handler: function() { 53 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.TRIBLUR; 54 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 55 | } 56 | }, 57 | { 58 | name: 'Zoom', 59 | emoji: '💫', 60 | handler: function() { 61 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.ZOOM; 62 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 63 | } 64 | }, 65 | { 66 | name: 'Hexagon', 67 | emoji: '🛑', 68 | handler: function() { 69 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.HEXAGON; 70 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 71 | } 72 | }, 73 | { 74 | name: 'Pixelate', 75 | emoji: '🔲', 76 | handler: function() { 77 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.PIXELATE; 78 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 79 | } 80 | }, 81 | { 82 | name: 'Edge', 83 | emoji: '💈', 84 | handler: function() { 85 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.EDGE; 86 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 87 | } 88 | }, 89 | { 90 | name: 'Night Vision', 91 | emoji: '🌃', 92 | handler: function() { 93 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.NIGHTVISION; 94 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 95 | } 96 | }, 97 | { 98 | name: 'Invert', 99 | emoji: '🔋', 100 | handler: function() { 101 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.INVERT; 102 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 103 | } 104 | }, 105 | { 106 | name: 'Black and White Threshold', 107 | emoji: '🦓', 108 | handler: function() { 109 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.THRESHOLD; 110 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 111 | } 112 | }, 113 | 114 | { 115 | name: 'Dither', 116 | emoji: '🏁', 117 | handler: function() { 118 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.DITHER; 119 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 120 | } 121 | }, 122 | { 123 | name: 'Sunshine', 124 | emoji: '☀️', 125 | handler: function() { 126 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.SUNSHINE; 127 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 128 | } 129 | }, 130 | { 131 | name: 'Pancake Stack', 132 | emoji: '🥞', 133 | handler: function() { 134 | KiddoPaint.Tools.WholeCanvasEffect.effect = JumbleFx.PANCAKE; 135 | KiddoPaint.Current.tool = KiddoPaint.Tools.WholeCanvasEffect; 136 | } 137 | }, 138 | ]; -------------------------------------------------------------------------------- /js/submenus/pencil.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Submenu.pencil = [{ 2 | name: 'Size 1', 3 | imgSrc: 'img/pw1.png', 4 | handler: function() { 5 | KiddoPaint.Tools.Pencil.size = 1; 6 | } 7 | }, 8 | { 9 | name: 'Size 5', 10 | imgSrc: 'img/pw2.png', 11 | handler: function() { 12 | KiddoPaint.Tools.Pencil.size = 5; 13 | } 14 | }, 15 | { 16 | name: 'Size 10', 17 | imgSrc: 'img/pw3.png', 18 | handler: function() { 19 | KiddoPaint.Tools.Pencil.size = 10; 20 | } 21 | }, 22 | { 23 | name: 'Size 25', 24 | imgSrc: 'img/pw4.png', 25 | handler: function() { 26 | KiddoPaint.Tools.Pencil.size = 25; 27 | } 28 | }, 29 | { 30 | name: 'Size 100', 31 | imgSrc: 'img/pw5.png', 32 | handler: function() { 33 | KiddoPaint.Tools.Pencil.size = 100; 34 | } 35 | }, 36 | 37 | { 38 | name: 'spacer', 39 | invisible: true, 40 | handler: true 41 | }, 42 | 43 | { 44 | name: 'Texture 1', 45 | imgJs: function() { 46 | return makeIcon(KiddoPaint.Textures.Solid) 47 | }, 48 | handler: function() { 49 | KiddoPaint.Tools.Pencil.texture = function() { 50 | return KiddoPaint.Textures.Solid(KiddoPaint.Current.color); 51 | } 52 | } 53 | }, 54 | { 55 | name: 'Texture 2', 56 | imgJs: function() { 57 | return makeIcon(KiddoPaint.Textures.Partial1); 58 | }, 59 | handler: function() { 60 | KiddoPaint.Tools.Pencil.texture = function() { 61 | return KiddoPaint.Textures.Partial1(KiddoPaint.Current.color); 62 | } 63 | } 64 | }, 65 | { 66 | name: 'Texture 3', 67 | imgJs: function() { 68 | return makeIcon(KiddoPaint.Textures.Partial2); 69 | }, 70 | handler: function() { 71 | KiddoPaint.Tools.Pencil.texture = function() { 72 | return KiddoPaint.Textures.Partial2(KiddoPaint.Current.color); 73 | } 74 | } 75 | }, 76 | { 77 | name: 'Texture 4', 78 | imgJs: function() { 79 | return makeIcon(KiddoPaint.Textures.Partial3); 80 | }, 81 | handler: function() { 82 | KiddoPaint.Tools.Pencil.texture = function() { 83 | return KiddoPaint.Textures.Partial3(KiddoPaint.Current.color); 84 | } 85 | } 86 | }, 87 | { 88 | name: 'Texture 5', 89 | imgJs: function() { 90 | return makeIcon(KiddoPaint.Textures.Smiley); 91 | }, 92 | handler: function() { 93 | KiddoPaint.Tools.Pencil.texture = function() { 94 | return KiddoPaint.Current.modifiedAlt ? KiddoPaint.Textures.RSmiley() : KiddoPaint.Textures.Smiley(KiddoPaint.Current.color); 95 | } 96 | } 97 | }, 98 | { 99 | name: 'Texture 6', 100 | imgJs: function() { 101 | return makeIcon(KiddoPaint.Textures.PartialSquares); 102 | }, 103 | handler: function() { 104 | KiddoPaint.Tools.Pencil.texture = function() { 105 | return KiddoPaint.Textures.PartialSquares(KiddoPaint.Current.color); 106 | } 107 | } 108 | }, 109 | { 110 | name: 'Texture 7', 111 | imgJs: function() { 112 | return makeIcon(KiddoPaint.Textures.Speckles); 113 | }, 114 | handler: function() { 115 | KiddoPaint.Tools.Pencil.texture = function() { 116 | return KiddoPaint.Textures.Speckles(KiddoPaint.Current.color); 117 | } 118 | } 119 | }, 120 | { 121 | name: 'Texture 8', 122 | imgJs: function() { 123 | return makeIcon(KiddoPaint.Textures.Bubbles); 124 | }, 125 | handler: function() { 126 | KiddoPaint.Tools.Pencil.texture = function() { 127 | return KiddoPaint.Textures.Bubbles(KiddoPaint.Current.color); 128 | } 129 | } 130 | }, 131 | { 132 | name: 'Texture 9', 133 | imgJs: function() { 134 | return makeIcon(KiddoPaint.Textures.Diamond); 135 | }, 136 | handler: function() { 137 | KiddoPaint.Tools.Pencil.texture = function() { 138 | return KiddoPaint.Textures.Diamond(KiddoPaint.Current.color); 139 | } 140 | } 141 | }, 142 | { 143 | name: 'Texture 10', 144 | imgJs: function() { 145 | return makeIcon(KiddoPaint.Textures.Sand); 146 | }, 147 | handler: function() { 148 | KiddoPaint.Tools.Pencil.texture = function() { 149 | return KiddoPaint.Textures.Sand(KiddoPaint.Current.color); 150 | } 151 | } 152 | }, 153 | { 154 | name: 'Texture 11', 155 | imgJs: function() { 156 | return makeIcon(KiddoPaint.Textures.Brick); 157 | }, 158 | handler: function() { 159 | KiddoPaint.Tools.Pencil.texture = function() { 160 | return KiddoPaint.Textures.Brick(KiddoPaint.Current.color); 161 | } 162 | } 163 | }, 164 | { 165 | name: 'Texture 12', 166 | imgJs: function() { 167 | return makeIcon(KiddoPaint.Textures.CornerStair); 168 | }, 169 | handler: function() { 170 | KiddoPaint.Tools.Pencil.texture = function() { 171 | return KiddoPaint.Textures.CornerStair(KiddoPaint.Current.color); 172 | } 173 | } 174 | }, 175 | { 176 | name: 'Texture 13', 177 | imgJs: function() { 178 | return makeIcon(KiddoPaint.Textures.Houndstooth) 179 | }, 180 | handler: function() { 181 | KiddoPaint.Tools.Pencil.texture = function() { 182 | return KiddoPaint.Textures.Houndstooth(KiddoPaint.Current.color); 183 | } 184 | } 185 | }, 186 | { 187 | name: 'Rainbow', 188 | emoji: '🌈', 189 | handler: function() { 190 | KiddoPaint.Tools.Pencil.texture = function() { 191 | return KiddoPaint.Textures.RSolid(); 192 | } 193 | } 194 | } 195 | ]; -------------------------------------------------------------------------------- /js/submenus/sparkles.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Submenu.sparkles = [{ 2 | name: 'Sparkle 1', 3 | imgSrc: 'img/sprk1.png', 4 | handler: function(e) { 5 | var img = new Image(); 6 | img.src = 'img/sprk1.png'; 7 | img.crossOrigin = 'anonymous'; 8 | img.onload = function() { 9 | KiddoPaint.Tools.Placer.image = img; 10 | KiddoPaint.Tools.Placer.size = { 11 | width: img.width, 12 | height: img.height 13 | }; 14 | KiddoPaint.Tools.Placer.prevTool = KiddoPaint.Current.tool; 15 | KiddoPaint.Current.tool = KiddoPaint.Tools.Placer; 16 | }; 17 | } 18 | }, 19 | { 20 | name: 'Sparkle 2', 21 | imgSrc: 'img/sprk2.png', 22 | handler: function(e) { 23 | var img = new Image(); 24 | img.src = 'img/sprk2.png'; 25 | img.crossOrigin = 'anonymous'; 26 | img.onload = function() { 27 | KiddoPaint.Tools.Placer.image = img; 28 | KiddoPaint.Tools.Placer.size = { 29 | width: img.width, 30 | height: img.height 31 | }; 32 | KiddoPaint.Tools.Placer.prevTool = KiddoPaint.Current.tool; 33 | KiddoPaint.Current.tool = KiddoPaint.Tools.Placer; 34 | }; 35 | } 36 | }, 37 | { 38 | name: 'Sparkle 3', 39 | imgSrc: 'img/sprk3.png', 40 | handler: function(e) { 41 | var img = new Image(); 42 | img.src = 'img/sprk3.png'; 43 | img.crossOrigin = 'anonymous'; 44 | img.onload = function() { 45 | KiddoPaint.Tools.Placer.image = img; 46 | KiddoPaint.Tools.Placer.size = { 47 | width: img.width, 48 | height: img.height 49 | }; 50 | KiddoPaint.Tools.Placer.prevTool = KiddoPaint.Current.tool; 51 | KiddoPaint.Current.tool = KiddoPaint.Tools.Placer; 52 | }; 53 | } 54 | }, 55 | { 56 | name: 'Sparkle 4', 57 | imgSrc: 'img/sprk4.png', 58 | handler: function(e) { 59 | var img = new Image(); 60 | img.src = 'img/sprk4.png'; 61 | img.crossOrigin = 'anonymous'; 62 | img.onload = function() { 63 | KiddoPaint.Tools.Placer.image = img; 64 | KiddoPaint.Tools.Placer.size = { 65 | width: img.width, 66 | height: img.height 67 | }; 68 | KiddoPaint.Tools.Placer.prevTool = KiddoPaint.Current.tool; 69 | KiddoPaint.Current.tool = KiddoPaint.Tools.Placer; 70 | }; 71 | } 72 | }, 73 | { 74 | name: 'Sparkle 5', 75 | imgSrc: 'img/sprk5.png', 76 | handler: function(e) { 77 | var img = new Image(); 78 | img.src = 'img/sprk5.png'; 79 | img.crossOrigin = 'anonymous'; 80 | img.onload = function() { 81 | KiddoPaint.Tools.Placer.image = img; 82 | KiddoPaint.Tools.Placer.size = { 83 | width: img.width, 84 | height: img.height 85 | }; 86 | KiddoPaint.Tools.Placer.prevTool = KiddoPaint.Current.tool; 87 | KiddoPaint.Current.tool = KiddoPaint.Tools.Placer; 88 | }; 89 | } 90 | }, 91 | { 92 | name: 'Sparkle 6', 93 | imgSrc: 'img/sprk6.png', 94 | handler: function(e) { 95 | var img = new Image(); 96 | img.src = 'img/sprk6.png'; 97 | img.crossOrigin = 'anonymous'; 98 | img.onload = function() { 99 | KiddoPaint.Tools.Placer.image = img; 100 | KiddoPaint.Tools.Placer.size = { 101 | width: img.width, 102 | height: img.height 103 | }; 104 | KiddoPaint.Tools.Placer.prevTool = KiddoPaint.Current.tool; 105 | KiddoPaint.Current.tool = KiddoPaint.Tools.Placer; 106 | }; 107 | } 108 | }, 109 | { 110 | name: 'Sparkle 7', 111 | imgSrc: 'img/sprk7.png', 112 | handler: function(e) { 113 | var img = new Image(); 114 | img.src = 'img/sprk7.png'; 115 | img.crossOrigin = 'anonymous'; 116 | img.onload = function() { 117 | KiddoPaint.Tools.Placer.image = img; 118 | KiddoPaint.Tools.Placer.size = { 119 | width: img.width, 120 | height: img.height 121 | }; 122 | KiddoPaint.Tools.Placer.prevTool = KiddoPaint.Current.tool; 123 | KiddoPaint.Current.tool = KiddoPaint.Tools.Placer; 124 | }; 125 | } 126 | }, 127 | { 128 | name: 'Sparkle 8', 129 | imgSrc: 'img/sprk8.png', 130 | handler: function(e) { 131 | var img = new Image(); 132 | img.src = 'img/sprk8.png'; 133 | img.crossOrigin = 'anonymous'; 134 | img.onload = function() { 135 | KiddoPaint.Tools.Placer.image = img; 136 | KiddoPaint.Tools.Placer.size = { 137 | width: img.width, 138 | height: img.height 139 | }; 140 | KiddoPaint.Tools.Placer.prevTool = KiddoPaint.Current.tool; 141 | KiddoPaint.Current.tool = KiddoPaint.Tools.Placer; 142 | }; 143 | } 144 | }, 145 | { 146 | name: 'Sparkle 9', 147 | imgSrc: 'img/sprk9.png', 148 | handler: function(e) { 149 | var img = new Image(); 150 | img.src = 'img/sprk9.png'; 151 | img.crossOrigin = 'anonymous'; 152 | img.onload = function() { 153 | KiddoPaint.Tools.Placer.image = img; 154 | KiddoPaint.Tools.Placer.size = { 155 | width: img.width, 156 | height: img.height 157 | }; 158 | KiddoPaint.Tools.Placer.prevTool = KiddoPaint.Current.tool; 159 | KiddoPaint.Current.tool = KiddoPaint.Tools.Placer; 160 | }; 161 | } 162 | }, 163 | ]; -------------------------------------------------------------------------------- /js/submenus/spray.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Submenu.spray = [{ 2 | name: 'Bezier Mean Streak', 3 | imgSrc: 'img/pw1.png', 4 | handler: function() { 5 | KiddoPaint.Tools.PlainBrush.reset(); 6 | KiddoPaint.Tools.PlainBrush.spacing = 1; 7 | KiddoPaint.Tools.PlainBrush.texture = function(step) { 8 | return KiddoPaint.Brushes.MeanStreak(step) 9 | }; 10 | KiddoPaint.Tools.BezFollow.synthtool = KiddoPaint.Tools.PlainBrush; 11 | KiddoPaint.Current.tool = KiddoPaint.Tools.BezFollow; 12 | } 13 | }, 14 | { 15 | name: 'Bezier Spray Can', 16 | imgSrc: 'img/pw2.png', 17 | handler: function() { 18 | KiddoPaint.Tools.PlainBrush.reset(); 19 | KiddoPaint.Tools.PlainBrush.spacing = 0; 20 | KiddoPaint.Tools.PlainBrush.texture = function() { 21 | return KiddoPaint.Brushes.Spray(KiddoPaint.Current.color, KiddoPaint.Current.terColor) 22 | }; 23 | KiddoPaint.Tools.PlainBrush.preprocess = function() { 24 | KiddoPaint.Display.context.shadowBlur = 16; 25 | KiddoPaint.Display.context.shadowColor = KiddoPaint.Current.altColor; 26 | }; 27 | KiddoPaint.Tools.PlainBrush.postprocess = function() { 28 | KiddoPaint.Display.context.shadowBlur = 0; 29 | KiddoPaint.Display.context.shadowColor = null; 30 | }; 31 | KiddoPaint.Tools.BezFollow.synthtool = KiddoPaint.Tools.PlainBrush; 32 | KiddoPaint.Current.tool = KiddoPaint.Tools.BezFollow; 33 | } 34 | }, 35 | { 36 | name: 'spacer', 37 | invisible: true, 38 | handler: true 39 | }, 40 | { 41 | name: 'Bar Spray Can', 42 | text: 'bar', 43 | handler: function() { 44 | KiddoPaint.Current.tool = KiddoPaint.Tools.PlainBrush; 45 | KiddoPaint.Tools.PlainBrush.reset(); 46 | KiddoPaint.Tools.PlainBrush.spacing = 0; 47 | KiddoPaint.Tools.PlainBrush.texture = function() { 48 | return KiddoPaint.Brushes.Dumbbell(KiddoPaint.Current.color, KiddoPaint.Current.terColor) 49 | }; 50 | } 51 | }, 52 | { 53 | name: 'Icy Spray Can', 54 | text: 'icy', 55 | handler: function() { 56 | KiddoPaint.Current.tool = KiddoPaint.Tools.PlainBrush; 57 | KiddoPaint.Tools.PlainBrush.reset(); 58 | KiddoPaint.Tools.PlainBrush.spacing = 0; 59 | KiddoPaint.Tools.PlainBrush.texture = function() { 60 | return KiddoPaint.Brushes.Icy(KiddoPaint.Current.color, KiddoPaint.Current.terColor) 61 | }; 62 | } 63 | }, 64 | ]; -------------------------------------------------------------------------------- /js/submenus/square.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Submenu.square = [{ 2 | name: 'Texture 1', 3 | imgJs: function() { 4 | return makeIcon(KiddoPaint.Textures.None) 5 | }, 6 | handler: function() { 7 | KiddoPaint.Tools.Square.texture = function() { 8 | return KiddoPaint.Textures.None(KiddoPaint.Current.color); 9 | } 10 | } 11 | }, 12 | { 13 | name: 'Texture 1', 14 | imgJs: function() { 15 | return makeIcon(KiddoPaint.Textures.Solid) 16 | }, 17 | handler: function() { 18 | KiddoPaint.Tools.Square.texture = function() { 19 | return KiddoPaint.Textures.Solid(KiddoPaint.Current.color); 20 | } 21 | } 22 | }, 23 | { 24 | name: 'Texture 2', 25 | imgJs: function() { 26 | return makeIcon(KiddoPaint.Textures.Partial1); 27 | }, 28 | handler: function() { 29 | KiddoPaint.Tools.Square.texture = function() { 30 | return KiddoPaint.Textures.Partial1(KiddoPaint.Current.color); 31 | } 32 | } 33 | }, 34 | { 35 | name: 'Texture 3', 36 | imgJs: function() { 37 | return makeIcon(KiddoPaint.Textures.Partial2); 38 | }, 39 | handler: function() { 40 | KiddoPaint.Tools.Square.texture = function() { 41 | return KiddoPaint.Textures.Partial2(KiddoPaint.Current.color); 42 | } 43 | } 44 | }, 45 | { 46 | name: 'Texture 4', 47 | imgJs: function() { 48 | return makeIcon(KiddoPaint.Textures.Partial3); 49 | }, 50 | handler: function() { 51 | KiddoPaint.Tools.Square.texture = function() { 52 | return KiddoPaint.Textures.Partial3(KiddoPaint.Current.color); 53 | } 54 | } 55 | }, 56 | { 57 | name: 'Texture 5', 58 | imgJs: function() { 59 | return makeIcon(KiddoPaint.Textures.Smiley); 60 | }, 61 | handler: function() { 62 | KiddoPaint.Tools.Square.texture = function() { 63 | return KiddoPaint.Current.modifiedAlt ? KiddoPaint.Textures.RSmiley() : KiddoPaint.Textures.Smiley(KiddoPaint.Current.color); 64 | } 65 | } 66 | }, 67 | { 68 | name: 'Texture 6', 69 | imgJs: function() { 70 | return makeIcon(KiddoPaint.Textures.PartialSquares); 71 | }, 72 | handler: function() { 73 | KiddoPaint.Tools.Square.texture = function() { 74 | return KiddoPaint.Textures.PartialSquares(KiddoPaint.Current.color); 75 | } 76 | } 77 | }, 78 | { 79 | name: 'Texture 6', 80 | imgJs: function() { 81 | return makeIcon(KiddoPaint.Textures.PartialArtifactAlias); 82 | }, 83 | handler: function() { 84 | KiddoPaint.Tools.Square.texture = function() { 85 | return KiddoPaint.Textures.PartialArtifactAlias(KiddoPaint.Current.color); 86 | } 87 | } 88 | }, 89 | { 90 | name: 'Texture 7', 91 | imgJs: function() { 92 | return makeIcon(KiddoPaint.Textures.Speckles); 93 | }, 94 | handler: function() { 95 | KiddoPaint.Tools.Square.texture = function() { 96 | return KiddoPaint.Textures.Speckles(KiddoPaint.Current.color); 97 | } 98 | } 99 | }, 100 | { 101 | name: 'Texture 7', 102 | imgJs: function() { 103 | return makeIcon(KiddoPaint.Textures.Stripes); 104 | }, 105 | handler: function() { 106 | KiddoPaint.Tools.Square.texture = function() { 107 | return KiddoPaint.Textures.Stripes(KiddoPaint.Current.color); 108 | } 109 | } 110 | }, 111 | { 112 | name: 'Texture 7', 113 | imgJs: function() { 114 | return makeIcon(KiddoPaint.Textures.Thatch); 115 | }, 116 | handler: function() { 117 | KiddoPaint.Tools.Square.texture = function() { 118 | return KiddoPaint.Textures.Thatch(KiddoPaint.Current.color); 119 | } 120 | } 121 | }, 122 | { 123 | name: 'Texture 7', 124 | imgJs: function() { 125 | return makeIcon(KiddoPaint.Textures.Shingles); 126 | }, 127 | handler: function() { 128 | KiddoPaint.Tools.Square.texture = function() { 129 | return KiddoPaint.Textures.Shingles(KiddoPaint.Current.color); 130 | } 131 | } 132 | }, 133 | { 134 | name: 'Texture 8', 135 | imgJs: function() { 136 | return makeIcon(KiddoPaint.Textures.Bubbles); 137 | }, 138 | handler: function() { 139 | KiddoPaint.Tools.Square.texture = function() { 140 | return KiddoPaint.Textures.Bubbles(KiddoPaint.Current.color); 141 | } 142 | } 143 | }, 144 | { 145 | name: 'Texture 9', 146 | imgJs: function() { 147 | return makeIcon(KiddoPaint.Textures.Diamond); 148 | }, 149 | handler: function() { 150 | KiddoPaint.Tools.Square.texture = function() { 151 | return KiddoPaint.Textures.Diamond(KiddoPaint.Current.color); 152 | } 153 | } 154 | }, 155 | { 156 | name: 'Texture 9', 157 | imgJs: function() { 158 | return makeIcon(KiddoPaint.Textures.Ribbon); 159 | }, 160 | handler: function() { 161 | KiddoPaint.Tools.Square.texture = function() { 162 | return KiddoPaint.Textures.Ribbon(KiddoPaint.Current.color); 163 | } 164 | } 165 | }, 166 | { 167 | name: 'Texture 10', 168 | imgJs: function() { 169 | return makeIcon(KiddoPaint.Textures.Sand); 170 | }, 171 | handler: function() { 172 | KiddoPaint.Tools.Square.texture = function() { 173 | return KiddoPaint.Textures.Sand(KiddoPaint.Current.color); 174 | } 175 | } 176 | }, 177 | { 178 | name: 'Texture 11', 179 | imgJs: function() { 180 | return makeIcon(KiddoPaint.Textures.Brick); 181 | }, 182 | handler: function() { 183 | KiddoPaint.Tools.Square.texture = function() { 184 | return KiddoPaint.Textures.Brick(KiddoPaint.Current.color); 185 | } 186 | } 187 | }, 188 | { 189 | name: 'Texture 11', 190 | imgJs: function() { 191 | return makeIcon(KiddoPaint.Textures.Chevron); 192 | }, 193 | handler: function() { 194 | KiddoPaint.Tools.Square.texture = function() { 195 | return KiddoPaint.Textures.Chevron(KiddoPaint.Current.color); 196 | } 197 | } 198 | }, 199 | { 200 | name: 'Texture 11', 201 | imgJs: function() { 202 | return makeIcon(KiddoPaint.Textures.Stairs); 203 | }, 204 | handler: function() { 205 | KiddoPaint.Tools.Square.texture = function() { 206 | return KiddoPaint.Textures.Stairs(KiddoPaint.Current.color); 207 | } 208 | } 209 | }, 210 | { 211 | name: 'Texture 11', 212 | imgJs: function() { 213 | return makeIcon(KiddoPaint.Textures.Cross); 214 | }, 215 | handler: function() { 216 | KiddoPaint.Tools.Square.texture = function() { 217 | return KiddoPaint.Textures.Cross(KiddoPaint.Current.color); 218 | } 219 | } 220 | }, 221 | { 222 | name: 'Texture 11', 223 | imgJs: function() { 224 | return makeIcon(KiddoPaint.Textures.DiagBrick); 225 | }, 226 | handler: function() { 227 | KiddoPaint.Tools.Square.texture = function() { 228 | return KiddoPaint.Textures.DiagBrick(KiddoPaint.Current.color); 229 | } 230 | } 231 | }, 232 | { 233 | name: 'Texture 12', 234 | imgJs: function() { 235 | return makeIcon(KiddoPaint.Textures.CornerStair); 236 | }, 237 | handler: function() { 238 | KiddoPaint.Tools.Square.texture = function() { 239 | return KiddoPaint.Textures.CornerStair(KiddoPaint.Current.color); 240 | } 241 | } 242 | }, 243 | { 244 | name: 'Texture 13', 245 | imgJs: function() { 246 | return makeIcon(KiddoPaint.Textures.Houndstooth) 247 | }, 248 | handler: function() { 249 | KiddoPaint.Tools.Square.texture = function() { 250 | return KiddoPaint.Textures.Houndstooth(KiddoPaint.Current.color); 251 | } 252 | } 253 | }, 254 | ]; -------------------------------------------------------------------------------- /js/submenus/stub.txt: -------------------------------------------------------------------------------- 1 | KiddoPaint.Submenu.square = [{ 2 | name: 'Texture 1', 3 | imgJs: function() { 4 | return makeIcon(KiddoPaint.Textures.None) 5 | }, 6 | handler: function() { 7 | KiddoPaint.Tools.Square.texture = function() { 8 | return KiddoPaint.Textures.None(KiddoPaint.Current.color); 9 | } 10 | } 11 | }, 12 | { 13 | name: 'Texture 1', 14 | imgJs: function() { 15 | return makeIcon(KiddoPaint.Textures.Solid) 16 | }, 17 | handler: function() { 18 | KiddoPaint.Tools.Square.texture = function() { 19 | return KiddoPaint.Textures.Solid(KiddoPaint.Current.color); 20 | } 21 | } 22 | }, 23 | { 24 | name: 'Texture 2', 25 | imgJs: function() { 26 | return makeIcon(KiddoPaint.Textures.Partial1); 27 | }, 28 | handler: function() { 29 | KiddoPaint.Tools.Square.texture = function() { 30 | return KiddoPaint.Textures.Partial1(KiddoPaint.Current.color); 31 | } 32 | } 33 | }, 34 | { 35 | name: 'Texture 3', 36 | imgJs: function() { 37 | return makeIcon(KiddoPaint.Textures.Partial2); 38 | }, 39 | handler: function() { 40 | KiddoPaint.Tools.Square.texture = function() { 41 | return KiddoPaint.Textures.Partial2(KiddoPaint.Current.color); 42 | } 43 | } 44 | }, 45 | { 46 | name: 'Texture 4', 47 | imgJs: function() { 48 | return makeIcon(KiddoPaint.Textures.Partial3); 49 | }, 50 | handler: function() { 51 | KiddoPaint.Tools.Square.texture = function() { 52 | return KiddoPaint.Textures.Partial3(KiddoPaint.Current.color); 53 | } 54 | } 55 | }, 56 | { 57 | name: 'Texture 5', 58 | imgJs: function() { 59 | return makeIcon(KiddoPaint.Textures.Smiley); 60 | }, 61 | handler: function() { 62 | KiddoPaint.Tools.Square.texture = function() { 63 | return KiddoPaint.Current.modifiedAlt ? KiddoPaint.Textures.RSmiley() : KiddoPaint.Textures.Smiley(KiddoPaint.Current.color); 64 | } 65 | } 66 | }, 67 | { 68 | name: 'Texture 6', 69 | imgJs: function() { 70 | return makeIcon(KiddoPaint.Textures.PartialSquares); 71 | }, 72 | handler: function() { 73 | KiddoPaint.Tools.Square.texture = function() { 74 | return KiddoPaint.Textures.PartialSquares(KiddoPaint.Current.color); 75 | } 76 | } 77 | }, 78 | { 79 | name: 'Texture 6', 80 | imgJs: function() { 81 | return makeIcon(KiddoPaint.Textures.PartialArtifactAlias); 82 | }, 83 | handler: function() { 84 | KiddoPaint.Tools.Square.texture = function() { 85 | return KiddoPaint.Textures.PartialArtifactAlias(KiddoPaint.Current.color); 86 | } 87 | } 88 | }, 89 | { 90 | name: 'Texture 7', 91 | imgJs: function() { 92 | return makeIcon(KiddoPaint.Textures.Speckles); 93 | }, 94 | handler: function() { 95 | KiddoPaint.Tools.Square.texture = function() { 96 | return KiddoPaint.Textures.Speckles(KiddoPaint.Current.color); 97 | } 98 | } 99 | }, 100 | { 101 | name: 'Texture 7', 102 | imgJs: function() { 103 | return makeIcon(KiddoPaint.Textures.Stripes); 104 | }, 105 | handler: function() { 106 | KiddoPaint.Tools.Square.texture = function() { 107 | return KiddoPaint.Textures.Stripes(KiddoPaint.Current.color); 108 | } 109 | } 110 | }, 111 | { 112 | name: 'Texture 7', 113 | imgJs: function() { 114 | return makeIcon(KiddoPaint.Textures.Thatch); 115 | }, 116 | handler: function() { 117 | KiddoPaint.Tools.Square.texture = function() { 118 | return KiddoPaint.Textures.Thatch(KiddoPaint.Current.color); 119 | } 120 | } 121 | }, 122 | { 123 | name: 'Texture 7', 124 | imgJs: function() { 125 | return makeIcon(KiddoPaint.Textures.Shingles); 126 | }, 127 | handler: function() { 128 | KiddoPaint.Tools.Square.texture = function() { 129 | return KiddoPaint.Textures.Shingles(KiddoPaint.Current.color); 130 | } 131 | } 132 | }, 133 | { 134 | name: 'Texture 8', 135 | imgJs: function() { 136 | return makeIcon(KiddoPaint.Textures.Bubbles); 137 | }, 138 | handler: function() { 139 | KiddoPaint.Tools.Square.texture = function() { 140 | return KiddoPaint.Textures.Bubbles(KiddoPaint.Current.color); 141 | } 142 | } 143 | }, 144 | { 145 | name: 'Texture 9', 146 | imgJs: function() { 147 | return makeIcon(KiddoPaint.Textures.Diamond); 148 | }, 149 | handler: function() { 150 | KiddoPaint.Tools.Square.texture = function() { 151 | return KiddoPaint.Textures.Diamond(KiddoPaint.Current.color); 152 | } 153 | } 154 | }, 155 | { 156 | name: 'Texture 9', 157 | imgJs: function() { 158 | return makeIcon(KiddoPaint.Textures.Ribbon); 159 | }, 160 | handler: function() { 161 | KiddoPaint.Tools.Square.texture = function() { 162 | return KiddoPaint.Textures.Ribbon(KiddoPaint.Current.color); 163 | } 164 | } 165 | }, 166 | { 167 | name: 'Texture 10', 168 | imgJs: function() { 169 | return makeIcon(KiddoPaint.Textures.Sand); 170 | }, 171 | handler: function() { 172 | KiddoPaint.Tools.Square.texture = function() { 173 | return KiddoPaint.Textures.Sand(KiddoPaint.Current.color); 174 | } 175 | } 176 | }, 177 | { 178 | name: 'Texture 11', 179 | imgJs: function() { 180 | return makeIcon(KiddoPaint.Textures.Brick); 181 | }, 182 | handler: function() { 183 | KiddoPaint.Tools.Square.texture = function() { 184 | return KiddoPaint.Textures.Brick(KiddoPaint.Current.color); 185 | } 186 | } 187 | }, 188 | { 189 | name: 'Texture 11', 190 | imgJs: function() { 191 | return makeIcon(KiddoPaint.Textures.Chevron); 192 | }, 193 | handler: function() { 194 | KiddoPaint.Tools.Square.texture = function() { 195 | return KiddoPaint.Textures.Chevron(KiddoPaint.Current.color); 196 | } 197 | } 198 | }, 199 | { 200 | name: 'Texture 11', 201 | imgJs: function() { 202 | return makeIcon(KiddoPaint.Textures.Stairs); 203 | }, 204 | handler: function() { 205 | KiddoPaint.Tools.Square.texture = function() { 206 | return KiddoPaint.Textures.Stairs(KiddoPaint.Current.color); 207 | } 208 | } 209 | }, 210 | { 211 | name: 'Texture 11', 212 | imgJs: function() { 213 | return makeIcon(KiddoPaint.Textures.Cross); 214 | }, 215 | handler: function() { 216 | KiddoPaint.Tools.Square.texture = function() { 217 | return KiddoPaint.Textures.Cross(KiddoPaint.Current.color); 218 | } 219 | } 220 | }, 221 | { 222 | name: 'Texture 11', 223 | imgJs: function() { 224 | return makeIcon(KiddoPaint.Textures.DiagBrick); 225 | }, 226 | handler: function() { 227 | KiddoPaint.Tools.Square.texture = function() { 228 | return KiddoPaint.Textures.DiagBrick(KiddoPaint.Current.color); 229 | } 230 | } 231 | }, 232 | { 233 | name: 'Texture 12', 234 | imgJs: function() { 235 | return makeIcon(KiddoPaint.Textures.CornerStair); 236 | }, 237 | handler: function() { 238 | KiddoPaint.Tools.Square.texture = function() { 239 | return KiddoPaint.Textures.CornerStair(KiddoPaint.Current.color); 240 | } 241 | } 242 | }, 243 | { 244 | name: 'Texture 13', 245 | imgJs: function() { 246 | return makeIcon(KiddoPaint.Textures.Houndstooth) 247 | }, 248 | handler: function() { 249 | KiddoPaint.Tools.Square.texture = function() { 250 | return KiddoPaint.Textures.Houndstooth(KiddoPaint.Current.color); 251 | } 252 | } 253 | }, 254 | ]; -------------------------------------------------------------------------------- /js/textures/gco.js: -------------------------------------------------------------------------------- 1 | // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Compositing/Example#Compositing_example 2 | 3 | var lightMix = function() { 4 | var canvas2 = document.createElement("canvas"); 5 | canvas2.width = 360; 6 | canvas2.height = 360; 7 | var ctx = canvas2.getContext("2d"); 8 | ctx.save(); 9 | ctx.globalCompositeOperation = "lighter"; 10 | ctx.beginPath(); 11 | ctx.fillStyle = KiddoPaint.Current.color; 12 | ctx.arc(100, 200, 100, Math.PI * 2, 0, false); 13 | ctx.fill() 14 | ctx.beginPath(); 15 | ctx.fillStyle = KiddoPaint.Current.altColor; 16 | ctx.arc(220, 200, 100, Math.PI * 2, 0, false); 17 | ctx.fill() 18 | ctx.beginPath(); 19 | ctx.fillStyle = KiddoPaint.Current.terColor; 20 | ctx.arc(160, 100, 100, Math.PI * 2, 0, false); 21 | ctx.fill(); 22 | ctx.restore(); 23 | return ctx.canvas; 24 | }; 25 | 26 | var colorSphere = function() { 27 | var canvas1 = document.createElement("canvas"); 28 | canvas1.width = 360; 29 | canvas1.height = 360; 30 | var ctx = canvas1.getContext("2d"); 31 | var width = 360; 32 | var halfWidth = width / 2; 33 | var rotate = (1 / 360) * Math.PI * 2; // per degree 34 | var oleft = -20; 35 | var otop = -20; 36 | for (var n = 0; n <= 359; n++) { 37 | var gradient = ctx.createLinearGradient(oleft + halfWidth, otop, oleft + halfWidth, otop + halfWidth); 38 | var color = Color.HSV_RGB({ 39 | H: (n + 300) % 360, 40 | S: 100, 41 | V: 100 42 | }); 43 | gradient.addColorStop(0, KiddoPaint.Current.modifiedToggle ? "rgba(255, 255, 255, 0)" : "rgba(0, 0, 0, 0)"); 44 | //gradient.addColorStop(0, color2cssWithAlpha(KiddoPaint.Current.terColor, '0')); 45 | gradient.addColorStop(0.7, "rgba(" + color.R + "," + color.G + "," + color.B + ",1)"); 46 | gradient.addColorStop(1, "rgba(255,255,255,1)"); 47 | //gradient.addColorStop(0, color2cssWithAlpha(KiddoPaint.Current.altColor, '1')); 48 | ctx.beginPath(); 49 | ctx.moveTo(oleft + halfWidth, otop); 50 | ctx.lineTo(oleft + halfWidth, otop + halfWidth); 51 | ctx.lineTo(oleft + halfWidth + 6, otop); 52 | ctx.fillStyle = gradient; 53 | ctx.fill(); 54 | ctx.translate(oleft + halfWidth, otop + halfWidth); 55 | ctx.rotate(rotate); 56 | ctx.translate(-(oleft + halfWidth), -(otop + halfWidth)); 57 | } 58 | return ctx.canvas; 59 | }; 60 | 61 | 62 | // HSV (1978) = H: Hue / S: Saturation / V: Value 63 | Color = {}; 64 | Color.HSV_RGB = function(o) { 65 | var H = o.H / 360, 66 | S = o.S / 100, 67 | V = o.V / 100, 68 | R, G, B; 69 | var A, B, C, D; 70 | if (S == 0) { 71 | R = G = B = Math.round(V * 255); 72 | } else { 73 | if (H >= 1) H = 0; 74 | H = 6 * H; 75 | D = H - Math.floor(H); 76 | A = Math.round(255 * V * (1 - S)); 77 | B = Math.round(255 * V * (1 - (S * D))); 78 | C = Math.round(255 * V * (1 - (S * (1 - D)))); 79 | V = Math.round(255 * V); 80 | switch (Math.floor(H)) { 81 | case 0: 82 | R = V; 83 | G = C; 84 | B = A; 85 | break; 86 | case 1: 87 | R = B; 88 | G = V; 89 | B = A; 90 | break; 91 | case 2: 92 | R = A; 93 | G = V; 94 | B = C; 95 | break; 96 | case 3: 97 | R = A; 98 | G = B; 99 | B = V; 100 | break; 101 | case 4: 102 | R = C; 103 | G = A; 104 | B = V; 105 | break; 106 | case 5: 107 | R = V; 108 | G = A; 109 | B = B; 110 | break; 111 | } 112 | } 113 | return { 114 | R: R, 115 | G: G, 116 | B: B 117 | }; 118 | }; 119 | 120 | function makeComposite(gco) { 121 | var dest = document.createElement("canvas"); 122 | dest.width = 360; 123 | dest.height = 360; 124 | var ctx = dest.getContext('2d'); 125 | ctx.drawImage(colorSphere(), 0, 0); 126 | ctx.globalCompositeOperation = gco; 127 | ctx.drawImage(lightMix(), 0, 0); 128 | return dest; 129 | } -------------------------------------------------------------------------------- /js/tools/astroid.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Astroid = function() { 2 | var tool = this; 3 | this.size = 1; 4 | this.stroke = function() { 5 | return KiddoPaint.Current.color; 6 | }; 7 | this.points = []; 8 | 9 | // http://mathworld.wolfram.com/Astroid.html 10 | this.drawAstroid = function(pt1, pt2, pt3) { 11 | var interval = 31 * KiddoPaint.Current.scaling; 12 | 13 | seg1deltax = (pt2.x - pt1.x) / interval; 14 | seg1deltay = (pt2.y - pt1.y) / interval; 15 | 16 | seg2deltax = (pt3.x - pt2.x) / interval; 17 | seg2deltay = (pt3.y - pt2.y) / interval; 18 | 19 | for (var i = 0; i <= interval; i++) { 20 | var a1 = { 21 | x: pt1.x + (seg1deltax * i), 22 | y: pt1.y + (seg1deltay * i) 23 | }; 24 | var a2 = { 25 | x: pt2.x + (seg2deltax * i), 26 | y: pt2.y + (seg2deltay * i) 27 | }; 28 | KiddoPaint.Display.context.beginPath(); 29 | KiddoPaint.Display.context.moveTo(Math.round(a1.x), Math.round(a1.y)); 30 | KiddoPaint.Display.context.lineTo(Math.round(a2.x), Math.round(a2.y)); 31 | KiddoPaint.Display.context.strokeStyle = KiddoPaint.Current.modifiedMeta ? KiddoPaint.Colors.randomColor() : ((i % 2) ? KiddoPaint.Current.color : KiddoPaint.Current.altColor); 32 | KiddoPaint.Display.context.stroke(); 33 | KiddoPaint.Display.context.closePath(); 34 | } 35 | } 36 | 37 | this.mousedown = function(ev) { 38 | tool.points.push({ 39 | x: ev._x, 40 | y: ev._y 41 | }); 42 | }; 43 | 44 | this.mousemove = function(ev) { 45 | KiddoPaint.Display.clearTmp(); 46 | if (tool.points.length == 1) { 47 | KiddoPaint.Display.context.beginPath(); 48 | KiddoPaint.Display.context.moveTo(Math.round(tool.points[0].x), Math.round(tool.points[0].y)); 49 | KiddoPaint.Display.context.lineTo(ev._x, ev._y); 50 | KiddoPaint.Display.context.strokeStyle = tool.stroke(); 51 | KiddoPaint.Display.context.lineWidth = tool.size; 52 | KiddoPaint.Display.context.stroke(); 53 | KiddoPaint.Display.context.closePath(); 54 | } else if (tool.points.length == 2) { 55 | tool.drawAstroid(tool.points[0], tool.points[1], { 56 | x: ev._x, 57 | y: ev._y 58 | }); 59 | } 60 | }; 61 | 62 | this.mouseup = function(ev) { 63 | if (tool.points.length == 3) { 64 | KiddoPaint.Display.clearTmp(); 65 | tool.drawAstroid(tool.points[0], tool.points[1], { 66 | x: ev._x, 67 | y: ev._y 68 | }); 69 | tool.points = []; 70 | KiddoPaint.Display.saveMain(); 71 | } 72 | }; 73 | }; 74 | KiddoPaint.Tools.Astroid = new KiddoPaint.Tools.Toolbox.Astroid(); -------------------------------------------------------------------------------- /js/tools/bezfollow.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.BezFollow = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.previousEv = null; 5 | this.spacing = 25; 6 | this.synthtool = {}; 7 | this.ylimit = { 8 | min: 5000, 9 | max: -1 10 | }; 11 | this.points = []; 12 | 13 | this.size = function() { 14 | return KiddoPaint.Tools.Pencil.size; 15 | } 16 | 17 | this.texture = function() { 18 | return KiddoPaint.Tools.Pencil.texture(); 19 | }; 20 | 21 | this.mousedown = function(ev) { 22 | tool.isDown = true; 23 | tool.points = []; 24 | tool.mousemove(ev); 25 | tool.previousEv = ev; 26 | }; 27 | 28 | this.mousemove = function(ev) { 29 | if (tool.isDown) { 30 | if (ev._y < tool.ylimit.min) { 31 | tool.ylimit.min = ev._y; 32 | } 33 | if (ev._y > tool.ylimit.max) { 34 | tool.ylimit.max = ev._y; 35 | } 36 | 37 | if (tool.previousEv == null || distanceBetween(tool.previousEv, ev) > tool.spacing) { 38 | tool.points.push([ev._x, ev._y]); 39 | tool.previousEv = ev; 40 | } 41 | tool.points.forEach(pt => { 42 | KiddoPaint.Display.previewContext.fillStyle = '#0f0'; 43 | KiddoPaint.Display.previewContext.fillRect(pt[0], pt[1], 5, 5); 44 | }) 45 | } 46 | }; 47 | 48 | this.mouseup = function(ev) { 49 | if (tool.isDown) { 50 | tool.isDown = false; 51 | tool.points.push([ev._x, ev._y]); 52 | KiddoPaint.Display.clearPreview(); 53 | 54 | // calling synthetic tools have their own propagation to main, so pause undo state capture 55 | KiddoPaint.Display.pauseUndo(); 56 | bumpLimits(); // pad sizing and alpha a bit 57 | renderFitLine(KiddoPaint.Display.context); 58 | KiddoPaint.Display.resumeUndo(); 59 | 60 | KiddoPaint.Display.saveMain(); 61 | tool.ylimit = { 62 | min: 5000, 63 | max: -1 64 | }; 65 | } 66 | }; 67 | 68 | function bumpLimits() { 69 | tool.ylimit.min -= 15; 70 | tool.ylimit.max += 15; 71 | } 72 | 73 | function offsetPoints(bezPoints, offsetAmount) { 74 | var startPt = bezPoints[0]; 75 | var ctrl1 = bezPoints[1]; 76 | var ctrl2 = bezPoints[2]; 77 | var stopPt = bezPoints[3]; 78 | 79 | return [ 80 | [startPt[0] + offsetAmount, startPt[1] + offsetAmount], 81 | [ctrl1[0] + offsetAmount, ctrl1[1] + offsetAmount], 82 | [ctrl2[0] + offsetAmount, ctrl2[1] + offsetAmount], 83 | [stopPt[0] + offsetAmount, stopPt[1] + offsetAmount], 84 | ]; 85 | } 86 | 87 | function calculateInterval(startPt, ctrl1, ctrl2, stopPt) { 88 | var approxDistance = bezierLength(startPt, ctrl1, ctrl2, stopPt); 89 | return Math.round(approxDistance / 3.5); 90 | } 91 | 92 | function renderFitLine(ctx) { 93 | var fitted = fitCurve(tool.points, 25); 94 | if (fitted) { 95 | var oldMultiplier = KiddoPaint.Current.scaling; 96 | var oldAlpha = KiddoPaint.Display.context.globalAlpha; 97 | var lastSegmentEv = null; 98 | var startScaling = 5; // top heavy when start > end 99 | var endScaling = 1; 100 | var startAlpha = 0; 101 | var endAlpha = oldAlpha; 102 | 103 | fitted.forEach(element => { 104 | for (var i = 0; i < 1; i++) { 105 | var offsetElement = offsetPoints(element, 11 * i); 106 | 107 | var startPt = offsetElement[0]; 108 | var ctrl1 = offsetElement[1]; 109 | var ctrl2 = offsetElement[2]; 110 | var stopPt = offsetElement[3]; 111 | 112 | var fakeEv = getCubicBezierXYatPercent(startPt, ctrl1, ctrl2, stopPt, 0); 113 | KiddoPaint.Current.scaling = remap(tool.ylimit.min, tool.ylimit.max, startScaling, endScaling, fakeEv._y); 114 | KiddoPaint.Display.context.globalAlpha = remap(tool.ylimit.min, tool.ylimit.max, startAlpha, endAlpha, fakeEv._y); 115 | 116 | if (!lastSegmentEv) { 117 | tool.synthtool.mousedown(fakeEv); 118 | } else { 119 | tool.synthtool.mousemove(lastSegmentEv); 120 | } 121 | 122 | var interval = calculateInterval(startPt, ctrl1, ctrl2, stopPt); 123 | 124 | for (var n = 0; n <= interval; n++) { 125 | fakeEv = getCubicBezierXYatPercent(startPt, ctrl1, ctrl2, stopPt, n / (interval * 1.0)); 126 | KiddoPaint.Current.scaling = remap(tool.ylimit.min, tool.ylimit.max, startScaling, endScaling, fakeEv._y); 127 | KiddoPaint.Display.context.globalAlpha = remap(tool.ylimit.min, tool.ylimit.max, startAlpha, endAlpha, fakeEv._y); 128 | 129 | tool.synthtool.mousemove(fakeEv); 130 | //KiddoPaint.Current.scaling *= 1.002; 131 | } 132 | fakeEv = getCubicBezierXYatPercent(startPt, ctrl1, ctrl2, stopPt, 1); 133 | KiddoPaint.Current.scaling = remap(tool.ylimit.min, tool.ylimit.max, startScaling, endScaling, fakeEv._y); 134 | KiddoPaint.Display.context.globalAlpha = remap(tool.ylimit.min, tool.ylimit.max, startAlpha, endAlpha, fakeEv._y); 135 | tool.synthtool.mousemove(fakeEv); 136 | lastSegmentEv = fakeEv; 137 | } 138 | }); 139 | KiddoPaint.Current.scaling = remap(tool.ylimit.min, tool.ylimit.max, startScaling, endScaling, lastSegmentEv._y); 140 | tool.synthtool.mouseup(lastSegmentEv); 141 | 142 | // reset any changed values 143 | KiddoPaint.Current.scaling = oldMultiplier; 144 | KiddoPaint.Display.context.globalAlpha = oldAlpha; 145 | } 146 | } 147 | }; 148 | KiddoPaint.Tools.BezFollow = new KiddoPaint.Tools.Toolbox.BezFollow(); -------------------------------------------------------------------------------- /js/tools/brush.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Brush = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.didMove = false; 5 | this.previousEv = null; 6 | this.minDistance = 0; 7 | this.texture = function(angle) { 8 | return KiddoPaint.Current.modified ? KiddoPaint.Builders.Arrow(KiddoPaint.Colors.randomColor(), angle) : KiddoPaint.Builders.Arrow(KiddoPaint.Current.color, angle); 9 | }; 10 | 11 | this.mousedown = function(ev) { 12 | tool.isDown = true; 13 | 14 | tool.didMove = true; // put first click 15 | tool.mousemove(ev); 16 | tool.didMove = false; // clear first click if need be 17 | 18 | tool.previousEv = ev; 19 | }; 20 | 21 | this.mousemove = function(ev) { 22 | if (tool.isDown) { 23 | if (!tool.didMove) { 24 | // just kidding! we're moving, so clear the first builder mark and ... 25 | KiddoPaint.Display.clearTmp(); 26 | tool.didMove = true; 27 | tool.previousEv = ev; 28 | // ... start drawing the new builder as soon as possible. 29 | tool.minDistance = 0; 30 | } else if (tool.previousEv == null || distanceBetween(tool.previousEv, ev) > tool.minDistance) { 31 | var angle = tool.previousEv == null ? 0 : angleBetween(tool.previousEv, ev) + 0.5 * Math.PI; 32 | var brushFill = tool.texture(angle); 33 | KiddoPaint.Display.context.drawImage(brushFill, Math.round(ev._x), Math.round(ev._y)); 34 | tool.previousEv = ev; 35 | // next builder should be spaced out 36 | tool.minDistance = 25; 37 | } 38 | } else { 39 | var angle = tool.previousEv == null ? 0 : angleBetween(tool.previousEv, ev) + 0.5 * Math.PI; 40 | var brushFill = tool.texture(angle); 41 | KiddoPaint.Display.previewContext.drawImage(brushFill, Math.round(ev._x), Math.round(ev._y)); 42 | } 43 | }; 44 | 45 | this.mouseup = function(ev) { 46 | if (tool.isDown) { 47 | tool.isDown = false; 48 | tool.previousEv = null; 49 | tool.minDistance = 0; 50 | KiddoPaint.Display.saveMain(); 51 | } 52 | }; 53 | }; 54 | KiddoPaint.Tools.Brush = new KiddoPaint.Tools.Toolbox.Brush(); -------------------------------------------------------------------------------- /js/tools/circle.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Circle = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.size = 1; 5 | this.stomp = true; 6 | this.texture = function() { 7 | return KiddoPaint.Textures.None(); 8 | }; 9 | this.stroke = function() { 10 | return KiddoPaint.Textures.Solid(KiddoPaint.Current.color); 11 | }; 12 | 13 | this.mousedown = function(ev) { 14 | tool.isDown = true; 15 | tool.x = ev._x; 16 | tool.y = ev._y; 17 | }; 18 | 19 | this.mousemove = function(ev) { 20 | if (tool.isDown) { 21 | if (tool.stomp) { 22 | KiddoPaint.Display.clearTmp(); 23 | } 24 | KiddoPaint.Display.context.beginPath(); 25 | KiddoPaint.Display.context.fillStyle = tool.texture(); 26 | KiddoPaint.Display.context.strokeStyle = tool.stroke(); 27 | KiddoPaint.Display.context.lineWidth = 1.5; 28 | if (KiddoPaint.Current.modifiedMeta) { 29 | KiddoPaint.Display.context.arc((ev._x + tool.x) / 2.0, (ev._y + tool.y) / 2.0, 0.5 * distanceBetween(ev, { 30 | _x: tool.x, 31 | _y: tool.y 32 | }), 0, 2 * Math.PI); 33 | } else { 34 | KiddoPaint.Display.context.arc(tool.x, tool.y, distanceBetween(ev, { 35 | _x: tool.x, 36 | _y: tool.y 37 | }), 0, 2 * Math.PI); 38 | } 39 | KiddoPaint.Display.context.fill(); 40 | if (!KiddoPaint.Current.modifiedCtrl) { 41 | KiddoPaint.Display.context.stroke(); 42 | } 43 | KiddoPaint.Display.context.closePath(); 44 | } 45 | }; 46 | 47 | this.mouseup = function(ev) { 48 | if (tool.isDown) { 49 | tool.mousemove(ev); 50 | tool.isDown = false; 51 | KiddoPaint.Display.saveMain(); 52 | } 53 | }; 54 | }; 55 | KiddoPaint.Tools.Circle = new KiddoPaint.Tools.Toolbox.Circle(); -------------------------------------------------------------------------------- /js/tools/composite.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Composite = function() { 2 | var tool = this; 3 | this.composed = []; 4 | 5 | this.compose = function(t) { 6 | tool.composed.push(t); 7 | } 8 | 9 | this.clearComposed = function() { 10 | tool.composed.length = 0; 11 | } 12 | 13 | this.mousedown = function(ev) { 14 | // composites will be doing many saveMains, so pause state here 15 | KiddoPaint.Display.pauseUndo(); 16 | for (const ctool of tool.composed) { 17 | ctool.mousedown(ev); 18 | } 19 | }; 20 | 21 | this.mousemove = function(ev) { 22 | for (const ctool of tool.composed) { 23 | ctool.mousemove(ev); 24 | } 25 | }; 26 | 27 | this.mouseup = function(ev) { 28 | for (const ctool of tool.composed) { 29 | ctool.mouseup(ev); 30 | } 31 | // ... everything in between should have done saveMains, so all the composite's 32 | // intermediate preview, tmp contexts, etc are still pending turn it back on now and save main 33 | KiddoPaint.Display.resumeUndo(); 34 | KiddoPaint.Display.saveMain(); 35 | }; 36 | }; 37 | KiddoPaint.Tools.Composite = new KiddoPaint.Tools.Toolbox.Composite(); -------------------------------------------------------------------------------- /js/tools/contours.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Contours = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.size = 2; 5 | this.stroke = function() { 6 | return KiddoPaint.Textures.Solid(KiddoPaint.Current.modified ? KiddoPaint.Colors.randomColor() : KiddoPaint.Current.color); 7 | }; 8 | 9 | this.mousedown = function(ev) { 10 | tool.isDown = true; 11 | tool.x = ev._x; 12 | tool.y = ev._y; 13 | }; 14 | 15 | this.mousemove = function(ev) { 16 | if (tool.isDown) { 17 | KiddoPaint.Display.context.beginPath(); 18 | KiddoPaint.Display.context.strokeStyle = tool.stroke(); 19 | KiddoPaint.Display.context.lineWidth = tool.size; 20 | KiddoPaint.Current.modifiedAlt ? KiddoPaint.Display.context.moveTo(tool.x, ev._y) : KiddoPaint.Display.context.moveTo(ev._x, tool.y); 21 | KiddoPaint.Display.context.lineTo(ev._x, ev._y); 22 | KiddoPaint.Display.context.stroke(); 23 | KiddoPaint.Display.context.closePath(); 24 | } 25 | }; 26 | 27 | this.mouseup = function(ev) { 28 | if (tool.isDown) { 29 | tool.mousemove(ev); 30 | tool.isDown = false; 31 | KiddoPaint.Display.saveMain(); 32 | } 33 | }; 34 | }; 35 | KiddoPaint.Tools.Contours = new KiddoPaint.Tools.Toolbox.Contours(); -------------------------------------------------------------------------------- /js/tools/cut.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Cut = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.size = function() { 5 | return { 6 | x: 50 * KiddoPaint.Current.scaling * KiddoPaint.Current.multiplier * ((KiddoPaint.Current.modifiedCtrlRange + 100) / 100), 7 | y: 50 * KiddoPaint.Current.scaling * KiddoPaint.Current.multiplier * ((KiddoPaint.Current.modifiedAltRange + 100) / 100) 8 | } 9 | } 10 | this.stomp = true; 11 | this.selectedData; 12 | 13 | this.texture = function() { 14 | return KiddoPaint.Textures.None(); 15 | }; 16 | 17 | 18 | this.mousedown = function(ev) { 19 | tool.isDown = true; 20 | tool.x = ev._x; 21 | tool.y = ev._y; 22 | sizex = tool.size().x; 23 | sizey = tool.size().y; 24 | if (!KiddoPaint.Current.modifiedToggle) { 25 | // save previous capture to reuse; click and drag to reinstantiate 26 | tool.selectedData = KiddoPaint.Display.main_context.getImageData(ev._x - sizex, ev._y - sizey, 2 * sizex, 2 * sizey); 27 | } 28 | tool.mousemove(ev); 29 | }; 30 | 31 | this.mousemove = function(ev) { 32 | sizex = tool.size().x; 33 | sizey = tool.size().y; 34 | 35 | if (tool.stomp) { 36 | KiddoPaint.Display.clearTmp(); 37 | } 38 | 39 | if (tool.isDown || (KiddoPaint.Current.modifiedToggle && tool.selectedData)) { 40 | if (KiddoPaint.Current.modifiedMeta) { // preview what a cut will look like 41 | KiddoPaint.Display.previewContext.fillStyle = 'white'; 42 | KiddoPaint.Display.previewContext.fillRect(tool.x - sizex, tool.y - sizey, 2 * sizex, 2 * sizey); 43 | } 44 | KiddoPaint.Display.previewContext.putImageData(tool.selectedData, ev._x - sizex, ev._y - sizey); 45 | } else { 46 | KiddoPaint.Display.previewContext.strokeStyle = 'white'; 47 | KiddoPaint.Display.previewContext.lineWidth = 0.5; 48 | KiddoPaint.Display.previewContext.setLineDash((KiddoPaint.Display.step % 2) ? [4] : [2]); 49 | KiddoPaint.Display.previewContext.strokeRect(ev._x - sizex, ev._y - sizey, 2 * sizex, 2 * sizey); 50 | KiddoPaint.Display.previewContext.strokeStyle = 'black'; 51 | KiddoPaint.Display.previewContext.strokeRect(ev._x - sizex, ev._y - sizey, 2 * sizex + 1, 2 * sizey + 1); 52 | 53 | } 54 | }; 55 | 56 | this.mouseup = function(ev) { 57 | if (tool.isDown) { 58 | sizex = tool.size().x; 59 | sizey = tool.size().y; 60 | tool.isDown = false; 61 | KiddoPaint.Display.context.putImageData(tool.selectedData, ev._x - sizex, ev._y - sizey); 62 | 63 | // Since we're manipulating main_context and we need to do it between undo() and cleartmp(), we dupe 64 | // and peek into abstraction here 65 | // KiddoPaint.Display.saveMain(); 66 | KiddoPaint.Display.saveUndo(); 67 | if (KiddoPaint.Current.modifiedMeta) { // actually do the cut; and before placing the new pixels 68 | KiddoPaint.Display.main_context.clearRect(tool.x - sizex, tool.y - sizey, 2 * sizex, 2 * sizey); 69 | } 70 | KiddoPaint.Display.main_context.drawImage(KiddoPaint.Display.canvas, 0, 0); 71 | KiddoPaint.Display.clearTmp(); 72 | KiddoPaint.Display.saveToLocalStorage(); 73 | } 74 | }; 75 | }; 76 | KiddoPaint.Tools.Cut = new KiddoPaint.Tools.Toolbox.Cut(); -------------------------------------------------------------------------------- /js/tools/flood.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Flood = function() { 2 | 3 | var tool = this; 4 | 5 | this.mousedown = function(ev) { 6 | if (KiddoPaint.Current.modifiedAlt) { 7 | tool.canvasWideReplace(ev); 8 | } else { 9 | tool.boundedFill(ev); 10 | } 11 | } 12 | 13 | this.canvasWideReplace = function(ev) { 14 | KiddoPaint.Sounds.flood(); 15 | var x = ev._x; 16 | var y = ev._y; 17 | 18 | var pixels = KiddoPaint.Display.main_context.getImageData(0, 0, KiddoPaint.Display.canvas.width, KiddoPaint.Display.canvas.height); 19 | 20 | var linear_cords = (y * KiddoPaint.Display.canvas.width + x) * 4; 21 | var original_color = { 22 | r: pixels.data[linear_cords], 23 | g: pixels.data[linear_cords + 1], 24 | b: pixels.data[linear_cords + 2], 25 | a: pixels.data[linear_cords + 3] 26 | }; 27 | 28 | var color = color2json(KiddoPaint.Current.color); 29 | 30 | if (colorsEqual(color, original_color)) { 31 | return; 32 | } 33 | 34 | var d = pixels.data; 35 | for (var i = 0; i < d.length; i += 4) { 36 | if ((pixels.data[i] == original_color.r && 37 | pixels.data[i + 1] == original_color.g && 38 | pixels.data[i + 2] == original_color.b && 39 | pixels.data[i + 3] == original_color.a)) { 40 | pixels.data[i] = color.r; 41 | pixels.data[i + 1] = color.g; 42 | pixels.data[i + 2] = color.b; 43 | pixels.data[i + 3] = color.a; 44 | 45 | } 46 | 47 | } 48 | KiddoPaint.Display.context.putImageData(pixels, 0, 0); 49 | KiddoPaint.Display.clearBeforeSaveMain(); 50 | } 51 | 52 | this.boundedFill = function(ev) { 53 | KiddoPaint.Sounds.flood(); 54 | var x = ev._x; 55 | var y = ev._y; 56 | var pixel_stack = [{ 57 | x: x, 58 | y: y 59 | }]; 60 | // read from main_context for underlying pixels 61 | var pixels = KiddoPaint.Display.main_context.getImageData(0, 0, KiddoPaint.Display.canvas.width, KiddoPaint.Display.canvas.height); 62 | 63 | var linear_cords = (y * KiddoPaint.Display.canvas.width + x) * 4; 64 | var original_color = { 65 | r: pixels.data[linear_cords], 66 | g: pixels.data[linear_cords + 1], 67 | b: pixels.data[linear_cords + 2], 68 | a: pixels.data[linear_cords + 3] 69 | }; 70 | 71 | var color = color2json(KiddoPaint.Current.color); 72 | 73 | if (colorsEqual(color, original_color)) { 74 | return; 75 | } 76 | 77 | 78 | while (pixel_stack.length > 0) { 79 | var new_pixel = pixel_stack.shift(); 80 | x = new_pixel.x; 81 | y = new_pixel.y; 82 | 83 | var linear_cords = (y * KiddoPaint.Display.canvas.width + x) * 4; 84 | while (y-- >= 0 && 85 | (pixels.data[linear_cords] == original_color.r && 86 | pixels.data[linear_cords + 1] == original_color.g && 87 | pixels.data[linear_cords + 2] == original_color.b && 88 | pixels.data[linear_cords + 3] == original_color.a)) { 89 | linear_cords -= KiddoPaint.Display.canvas.width * 4; 90 | } 91 | linear_cords += KiddoPaint.Display.canvas.width * 4; 92 | y++; 93 | 94 | var reached_left = false; 95 | var reached_right = false; 96 | while (y++ < KiddoPaint.Display.canvas.height && 97 | (pixels.data[linear_cords] == original_color.r && 98 | pixels.data[linear_cords + 1] == original_color.g && 99 | pixels.data[linear_cords + 2] == original_color.b && 100 | pixels.data[linear_cords + 3] == original_color.a)) { 101 | 102 | pixels.data[linear_cords] = color.r; 103 | pixels.data[linear_cords + 1] = color.g; 104 | pixels.data[linear_cords + 2] = color.b; 105 | pixels.data[linear_cords + 3] = color.a; 106 | 107 | if (x > 0) { 108 | if (pixels.data[linear_cords - 4] == original_color.r && 109 | pixels.data[linear_cords - 4 + 1] == original_color.g && 110 | pixels.data[linear_cords - 4 + 2] == original_color.b && 111 | pixels.data[linear_cords - 4 + 3] == original_color.a) { 112 | if (!reached_left) { 113 | pixel_stack.push({ 114 | x: x - 1, 115 | y: y 116 | }); 117 | reached_left = true; 118 | } 119 | } else if (reached_left) { 120 | reached_left = false; 121 | } 122 | } 123 | 124 | if (x < KiddoPaint.Display.canvas.width - 1) { 125 | if (pixels.data[linear_cords + 4] == original_color.r && 126 | pixels.data[linear_cords + 4 + 1] == original_color.g && 127 | pixels.data[linear_cords + 4 + 2] == original_color.b && 128 | pixels.data[linear_cords + 4 + 3] == original_color.a) { 129 | if (!reached_right) { 130 | pixel_stack.push({ 131 | x: x + 1, 132 | y: y 133 | }); 134 | reached_right = true; 135 | } 136 | } else if (reached_right) { 137 | reached_right = false; 138 | } 139 | } 140 | 141 | linear_cords += KiddoPaint.Display.canvas.width * 4; 142 | } 143 | } 144 | // since we are possibly rewriting a non-rectangular shape back, we put back all the pixels. 145 | // however, due to alpha (& premultiplication w/ get -> put), it mutates unchanged pixels underneath 146 | // so, add a new helper that clears main before writing the preview context. this also preserves 147 | // undoing the fill properly. 148 | KiddoPaint.Display.context.putImageData(pixels, 0, 0); 149 | KiddoPaint.Display.clearBeforeSaveMain(); 150 | }; 151 | 152 | this.mousemove = function(ev) {}; 153 | this.mouseup = function(ev) {}; 154 | }; 155 | KiddoPaint.Tools.Flood = new KiddoPaint.Tools.Toolbox.Flood(); -------------------------------------------------------------------------------- /js/tools/guilloche.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Guilloche = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.connected = true; 5 | this.texture = function() { 6 | return KiddoPaint.Textures.Solid(KiddoPaint.Current.color); 7 | }; 8 | 9 | this.mousedown = function(ev) { 10 | var outradius = 41 + 64 * Math.random(); 11 | var inradius = 21 + 42 * Math.random(); 12 | var r = -5 * Math.random(), 13 | Q = 7 * Math.random(), 14 | m = 5 * Math.random(), 15 | n = 10 * Math.random(); 16 | 17 | tool.isDown = true; 18 | KiddoPaint.Display.context.beginPath(); 19 | 20 | KiddoPaint.Display.context.lineWidth = 0.5; 21 | KiddoPaint.Display.context.strokeStyle = tool.texture(); 22 | KiddoPaint.Display.context.fillStyle = tool.texture(); 23 | 24 | for (var i = 0; i < Math.PI * 4; i += 0.007) { 25 | var coord = guil(outradius, r, m, i, inradius, Q, m, n); 26 | if (tool.connected) { 27 | KiddoPaint.Display.context.lineTo(Math.round(ev._x + coord.x), Math.round(ev._y + coord.y)); 28 | } else { 29 | KiddoPaint.Display.context.fillRect(Math.round(ev._x + coord.x), Math.round(ev._y + coord.y), 1, 1); 30 | } 31 | } 32 | KiddoPaint.Display.context.stroke(); 33 | KiddoPaint.Display.context.closePath(); 34 | }; 35 | 36 | this.mousemove = function(ev) {}; 37 | this.mouseup = function(ev) { 38 | if (tool.isDown) { 39 | tool.isDown = false; 40 | KiddoPaint.Display.saveMain(); 41 | } 42 | }; 43 | }; 44 | KiddoPaint.Tools.Guilloche = new KiddoPaint.Tools.Toolbox.Guilloche(); -------------------------------------------------------------------------------- /js/tools/kaleidoscope.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Kaleidoscope = function() { 2 | // bug: undo does one quadrant 3 | var tool = this; 4 | this.isDown = false; 5 | this.size = 2; 6 | this.origin = {}; 7 | this.texture = function() { 8 | return KiddoPaint.Textures.Solid(KiddoPaint.Current.color); 9 | }; 10 | 11 | this.mousedown = function(ev) { 12 | tool.isDown = true; 13 | tool.previousEv = { 14 | x: 0, 15 | y: 0 16 | }; 17 | tool.origin = ev; 18 | KiddoPaint.Display.context.strokeStyle = tool.texture(); 19 | KiddoPaint.Display.context.lineWidth = tool.size; 20 | KiddoPaint.Display.context.beginPath(); 21 | KiddoPaint.Display.context.save(); 22 | KiddoPaint.Display.context.lineJoin = KiddoPaint.Display.context.lineCap = 'round'; 23 | KiddoPaint.Display.context.translate(ev._x + 0.1, ev._y + 0.1); 24 | KiddoPaint.Display.context.moveTo(0, 0); 25 | }; 26 | 27 | this.mousemove = function(ev) { 28 | if (tool.isDown) { 29 | var x = tool.origin._x - ev._x; 30 | var y = tool.origin._y - ev._y; 31 | 32 | if (KiddoPaint.Current.modifiedAlt) { 33 | KiddoPaint.Display.context.moveTo(tool.previousEv.x, tool.previousEv.y); 34 | KiddoPaint.Display.context.lineTo(x, y); 35 | 36 | KiddoPaint.Display.context.moveTo(tool.previousEv.y, tool.previousEv.x); 37 | KiddoPaint.Display.context.lineTo(y, x); 38 | 39 | KiddoPaint.Display.context.moveTo(-tool.previousEv.x, -tool.previousEv.y); 40 | KiddoPaint.Display.context.lineTo(-x, -y); 41 | 42 | KiddoPaint.Display.context.moveTo(-tool.previousEv.y, -tool.previousEv.x); 43 | KiddoPaint.Display.context.lineTo(-y, -x); 44 | } else { 45 | KiddoPaint.Display.context.moveTo(tool.previousEv.x, tool.previousEv.y); 46 | KiddoPaint.Display.context.lineTo(x, y); 47 | 48 | KiddoPaint.Display.context.moveTo(-tool.previousEv.x, tool.previousEv.y); 49 | KiddoPaint.Display.context.lineTo(-x, y); 50 | 51 | KiddoPaint.Display.context.moveTo(tool.previousEv.x, -tool.previousEv.y); 52 | KiddoPaint.Display.context.lineTo(x, -y); 53 | 54 | KiddoPaint.Display.context.moveTo(-tool.previousEv.x, -tool.previousEv.y); 55 | KiddoPaint.Display.context.lineTo(-x, -y); 56 | } 57 | 58 | KiddoPaint.Display.context.stroke(); 59 | tool.previousEv = { 60 | x: x, 61 | y: y 62 | }; 63 | } 64 | }; 65 | 66 | this.mouseup = function(ev) { 67 | if (tool.isDown) { 68 | KiddoPaint.Display.context.restore(); 69 | KiddoPaint.Display.context.closePath(); 70 | tool.previousEv = { 71 | x: 0, 72 | y: 0 73 | }; 74 | tool.isDown = false; 75 | KiddoPaint.Display.saveMain(); 76 | } 77 | }; 78 | }; 79 | KiddoPaint.Tools.Kaleidoscope = new KiddoPaint.Tools.Toolbox.Kaleidoscope(); -------------------------------------------------------------------------------- /js/tools/lanczosbrush.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.PlainBrush = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.previousEv = null; 5 | this.texture = function() {}; 6 | this.preprocess = function() {}; 7 | this.postprocess = function() {}; 8 | this.spacing = 5; 9 | this.step = 0; 10 | this.points = []; 11 | 12 | this.reset = function() { 13 | tool.isDown = false; 14 | tool.previousEv = null; 15 | tool.texture = function() {}; 16 | tool.preprocess = function() {}; 17 | tool.postprocess = function() {}; 18 | tool.step = 0; 19 | tool.points = []; 20 | } 21 | 22 | this.mousedown = function(ev) { 23 | tool.isDown = true; 24 | tool.mousemove(ev); 25 | tool.previousEv = ev; 26 | tool.preprocess(); 27 | }; 28 | 29 | this.mousemove = function(ev) { 30 | if (tool.isDown) { 31 | var point = [ev._x, ev.y]; 32 | tool.points.push(point); 33 | } 34 | tool.mousemoveDirect(ev); 35 | } 36 | 37 | this.mousemoveDirect = function(ev) { 38 | if (tool.isDown) { 39 | if (tool.previousEv == null || distanceBetween(tool.previousEv, ev) > tool.spacing) { 40 | if (KiddoPaint.Current.modifiedTilde) { 41 | // alpha decay 42 | KiddoPaint.Display.context.globalAlpha *= 0.95; 43 | KiddoPaint.Display.previewContext.globalAlpha *= 0.95; 44 | } 45 | // gap fill 46 | if (KiddoPaint.Current.modifiedAlt && tool.previousEv != null) { 47 | var dist = distanceBetween(tool.previousEv, ev); 48 | var angle = angleBetweenRad(tool.previousEv, ev); 49 | for (var i = 0; i < dist; i += 5) { 50 | var x = tool.previousEv._x + (Math.sin(angle) * i); 51 | var y = tool.previousEv._y + (Math.cos(angle) * i); 52 | var brushFill = tool.texture(tool.step); 53 | KiddoPaint.Display.context.drawImage(brushFill.brush, Math.round(x - brushFill.offset), Math.round(y - brushFill.offset)); 54 | tool.step += 1; 55 | if (KiddoPaint.Current.modifiedTilde) { 56 | // alpha decay 57 | KiddoPaint.Display.context.globalAlpha *= 0.99; 58 | KiddoPaint.Display.previewContext.globalAlpha *= 0.99; 59 | } 60 | } 61 | } 62 | var brushFill = tool.texture(tool.step); 63 | KiddoPaint.Display.context.drawImage(brushFill.brush, Math.round(ev._x - brushFill.offset), Math.round(ev._y - brushFill.offset)); 64 | tool.previousEv = ev; 65 | tool.step += 1; 66 | } 67 | } else { 68 | var brushFill = tool.texture(0); 69 | KiddoPaint.Display.previewContext.drawImage(brushFill.brush, Math.round(ev._x - brushFill.offset), Math.round(ev._y - brushFill.offset)); 70 | } 71 | }; 72 | 73 | this.mouseup = function(ev) { 74 | if (tool.isDown) { 75 | KiddoPaint.Display.clearTmp(); 76 | var s = Smooth(tool.points, { 77 | method: Smooth.METHOD_LANCZOS 78 | }); 79 | for (var i = 0; i < tool.points.length; i++) { 80 | for (var j = 0; j < 3; j++) { 81 | var pt = s(i + (j / 4.0)); 82 | var ptev = { 83 | _x: pt[0], 84 | _y: pt[1] 85 | }; 86 | tool.mousemoveDirect(ptev); 87 | } 88 | } 89 | tool.points = []; 90 | tool.mouseupDirect(ev); 91 | } 92 | } 93 | 94 | this.mouseupDirect = function(ev) { 95 | if (tool.isDown) { 96 | tool.mousemove(ev); 97 | tool.isDown = false; 98 | tool.previousEv = null; 99 | tool.step = 0; 100 | tool.postprocess(); 101 | KiddoPaint.Display.saveMain(); 102 | KiddoPaint.Display.context.globalAlpha = KiddoPaint.Current.globalAlpha; 103 | KiddoPaint.Display.previewContext.globalAlpha = KiddoPaint.Current.globalAlpha; 104 | } 105 | }; 106 | }; 107 | KiddoPaint.Tools.PlainBrush = new KiddoPaint.Tools.Toolbox.PlainBrush(); -------------------------------------------------------------------------------- /js/tools/line.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Line = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.size = 7; 5 | this.stomp = true; 6 | this.texture = function() { 7 | return KiddoPaint.Textures.Solid(KiddoPaint.Current.color); 8 | }; 9 | 10 | this.mousedown = function(ev) { 11 | tool.isDown = true; 12 | tool.x = ev._x; 13 | tool.y = ev._y; 14 | }; 15 | 16 | this.mousemove = function(ev) { 17 | if (tool.isDown) { 18 | if (tool.stomp) { 19 | KiddoPaint.Display.clearTmp(); 20 | } 21 | 22 | KiddoPaint.Display.context.beginPath(); 23 | KiddoPaint.Display.context.moveTo(Math.round(tool.x), Math.round(tool.y)); 24 | if (KiddoPaint.Current.modified) { 25 | deltax = Math.abs(ev._x - tool.x); 26 | deltay = Math.abs(ev._y - tool.y); 27 | if (deltax < deltay) { 28 | KiddoPaint.Display.context.lineTo(tool.x, ev._y); 29 | } else { 30 | KiddoPaint.Display.context.lineTo(ev._x, tool.y); 31 | } 32 | } else { 33 | KiddoPaint.Display.context.lineTo(ev._x, ev._y); 34 | } 35 | KiddoPaint.Display.context.strokeStyle = tool.texture(); 36 | KiddoPaint.Display.context.lineWidth = tool.size; 37 | KiddoPaint.Display.context.stroke(); 38 | KiddoPaint.Display.context.closePath(); 39 | } 40 | }; 41 | 42 | this.mouseup = function(ev) { 43 | if (tool.isDown) { 44 | tool.mousemove(ev); 45 | tool.isDown = false; 46 | KiddoPaint.Display.saveMain(); 47 | } 48 | }; 49 | }; 50 | KiddoPaint.Tools.Line = new KiddoPaint.Tools.Toolbox.Line(); -------------------------------------------------------------------------------- /js/tools/magnify.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Magnify = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.size = function() { 5 | return 36 * KiddoPaint.Current.scaling 6 | }; 7 | this.scale = 2; 8 | 9 | this.mousedown = function(ev) { 10 | tool.isDown = true; 11 | tool.mousemove(ev); 12 | }; 13 | 14 | this.mousemove = function(ev) { 15 | var target = KiddoPaint.Display.main_context.getImageData(ev._x - tool.size(), ev._y - tool.size(), 2 * tool.size(), 2 * tool.size()); 16 | var ctx = tool.isDown ? KiddoPaint.Display.context : KiddoPaint.Display.previewContext; 17 | if (KiddoPaint.Current.modifiedAlt) { 18 | var dithered = ditherImageData(target); 19 | ctx.putImageData(dithered, ev._x - tool.size(), ev._y - tool.size()); 20 | } else if (KiddoPaint.Current.modifiedCtrl) { 21 | var grey = greyscaleImageData(target); 22 | ctx.putImageData(grey, ev._x - tool.size(), ev._y - tool.size()); 23 | } else { 24 | var scaled = KiddoPaint.Current.modifiedAlt ? ditherImageData(target) : scaleImageData(target, tool.scale); 25 | ctx.putImageData(scaled, ev._x - (tool.scale * tool.size()), ev._y - (tool.scale * tool.size())); 26 | } 27 | }; 28 | 29 | this.mouseup = function(ev) { 30 | if (tool.isDown) { 31 | tool.isDown = false; 32 | KiddoPaint.Display.saveMain(); 33 | } 34 | }; 35 | }; 36 | KiddoPaint.Tools.Magnify = new KiddoPaint.Tools.Toolbox.Magnify(); -------------------------------------------------------------------------------- /js/tools/maze.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Maze = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | 5 | this.texture = function() { 6 | return KiddoPaint.Textures.Solid(KiddoPaint.Current.color); 7 | }; 8 | 9 | this.mousedown = function(ev) { 10 | tool.isDown = true; 11 | var maze = makeMaze(); 12 | KiddoPaint.Display.context.drawImage(maze, ev._x, ev._y); 13 | }; 14 | 15 | this.mousemove = function(ev) {}; 16 | this.mouseup = function(ev) { 17 | if (tool.isDown) { 18 | tool.isDown = false; 19 | KiddoPaint.Display.saveMain(); 20 | } 21 | }; 22 | }; 23 | KiddoPaint.Tools.Maze = new KiddoPaint.Tools.Toolbox.Maze(); 24 | 25 | function makeMaze() { 26 | // https://codepen.io/GabbeV/pen/viAec 27 | var canvasBrush = document.createElement('canvas'); 28 | var contextBrush = canvasBrush.getContext('2d'); 29 | 30 | pathWidth = 20 //Width of the Maze Path 31 | wall = 5 //Width of the Walls between Paths 32 | outerWall = 5 //Width of the Outer most wall 33 | width = 25 * KiddoPaint.Current.scaling //Number paths fitted horisontally 34 | height = 25 * KiddoPaint.Current.scaling //Number paths fitted vertically 35 | delay = 1 //Delay between algorithm cycles 36 | x = width / 2 | 0 //Horisontal starting position 37 | y = height / 2 | 0 //Vertical starting position 38 | seed = Math.random() * 100000 | 0 //Seed for random numbers 39 | wallColor = KiddoPaint.Current.color; 40 | pathColor = KiddoPaint.Current.altColor; 41 | 42 | randomGen = function(seed) { 43 | if (seed === undefined) var seed = performance.now() 44 | return function() { 45 | seed = (seed * 9301 + 49297) % 233280 46 | return seed / 233280 47 | } 48 | } 49 | 50 | init = function() { 51 | offset = pathWidth / 2 + outerWall 52 | map = [] 53 | mazeWidth = outerWall * 2 + width * (pathWidth + wall) - wall 54 | mazeHeight = outerWall * 2 + height * (pathWidth + wall) - wall 55 | canvasBrush.width = mazeWidth; 56 | canvasBrush.height = mazeHeight; 57 | contextBrush.globalCompositeOperation = 'source-over'; 58 | contextBrush.fillStyle = wallColor 59 | contextBrush.fillRect(0, 0, mazeWidth, mazeHeight) 60 | random = randomGen(seed) 61 | contextBrush.strokeStyle = pathColor 62 | contextBrush.globalCompositeOperation = 'destination-out'; 63 | contextBrush.lineCap = 'square' 64 | contextBrush.lineWidth = pathWidth 65 | contextBrush.beginPath() 66 | for (var i = 0; i < height * 2; i++) { 67 | map[i] = [] 68 | for (var j = 0; j < width * 2; j++) { 69 | map[i][j] = false 70 | } 71 | } 72 | map[y * 2][x * 2] = true 73 | route = [ 74 | [x, y] 75 | ] 76 | contextBrush.moveTo(x * (pathWidth + wall) + offset, 77 | y * (pathWidth + wall) + offset) 78 | } 79 | init(); 80 | 81 | loop = function() { 82 | x = route[route.length - 1][0] | 0 83 | y = route[route.length - 1][1] | 0 84 | 85 | var directions = [ 86 | [1, 0], 87 | [-1, 0], 88 | [0, 1], 89 | [0, -1] 90 | ], 91 | alternatives = [] 92 | 93 | for (var i = 0; i < directions.length; i++) { 94 | if (map[(directions[i][1] + y) * 2] != undefined && 95 | map[(directions[i][1] + y) * 2][(directions[i][0] + x) * 2] === false) { 96 | alternatives.push(directions[i]) 97 | } 98 | } 99 | 100 | if (alternatives.length === 0) { 101 | route.pop() 102 | if (route.length > 0) { 103 | contextBrush.moveTo(route[route.length - 1][0] * (pathWidth + wall) + offset, 104 | route[route.length - 1][1] * (pathWidth + wall) + offset) 105 | loop(); 106 | //timer = setTimeout(loop, delay) 107 | } 108 | return; 109 | } 110 | direction = alternatives[random() * alternatives.length | 0] 111 | route.push([direction[0] + x, direction[1] + y]) 112 | contextBrush.lineTo((direction[0] + x) * (pathWidth + wall) + offset, 113 | (direction[1] + y) * (pathWidth + wall) + offset) 114 | map[(direction[1] + y) * 2][(direction[0] + x) * 2] = true 115 | map[direction[1] + y * 2][direction[0] + x * 2] = true 116 | contextBrush.stroke(); 117 | //timer = setTimeout(loop, delay) 118 | loop(); 119 | } 120 | loop(); 121 | contextBrush.closePath(); 122 | return canvasBrush; 123 | } -------------------------------------------------------------------------------- /js/tools/partialfx.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Ink = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.size = 36; 5 | this.scale = 1; 6 | this.gfx = fx.canvas(); 7 | this.initialClick = {}; 8 | 9 | this.mousedown = function(ev) { 10 | tool.isDown = true; 11 | tool.initialClick = ev; 12 | tool.mousemove(ev); 13 | }; 14 | 15 | this.mousemove = function(ev) { 16 | var target = KiddoPaint.Display.main_context.getImageData(ev._x - tool.size, ev._y - tool.size, 2 * tool.size, 2 * tool.size); 17 | var ctx = tool.isDown ? KiddoPaint.Display.context : KiddoPaint.Display.previewContext; 18 | 19 | var t = tool.gfx.texture(target); 20 | // var moo = tool.gfx.draw(t).ink(0.25).update(); 21 | var moo = tool.gfx.draw(t).edgeWork(tool.size / 2).update(); 22 | ctx.drawImage(moo, ev._x - (tool.scale * tool.size), ev._y - (tool.scale * tool.size)); 23 | t.destroy(); 24 | }; 25 | 26 | this.mouseup = function(ev) { 27 | if (tool.isDown) { 28 | tool.isDown = false; 29 | KiddoPaint.Display.saveMain(); 30 | } 31 | }; 32 | }; 33 | KiddoPaint.Tools.Ink = new KiddoPaint.Tools.Toolbox.Ink(); -------------------------------------------------------------------------------- /js/tools/pixelpencil.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Pencil = function() { 2 | this.size = 7; 3 | this.spacing = 10; 4 | this.texture = function() { 5 | return KiddoPaint.Textures.Solid(KiddoPaint.Current.color); 6 | }; 7 | 8 | this.mousedown = function(ev) { 9 | KiddoPaint.Current.modifiedToggle ? KiddoPaint.Tools.LinePencil.mousedown(ev) : KiddoPaint.Tools.PixelPencil.mousedown(ev); 10 | }; 11 | 12 | this.mousemove = function(ev) { 13 | KiddoPaint.Current.modifiedToggle ? KiddoPaint.Tools.LinePencil.mousemove(ev) : KiddoPaint.Tools.PixelPencil.mousemove(ev); 14 | }; 15 | 16 | this.mouseup = function(ev) { 17 | KiddoPaint.Current.modifiedToggle ? KiddoPaint.Tools.LinePencil.mouseup(ev) : KiddoPaint.Tools.PixelPencil.mouseup(ev); 18 | }; 19 | }; 20 | KiddoPaint.Tools.Pencil = new KiddoPaint.Tools.Toolbox.Pencil(); 21 | 22 | KiddoPaint.Tools.Toolbox.PixelPencil = function() { 23 | var tool = this; 24 | this.isDown = false; 25 | this.size = function() { 26 | return KiddoPaint.Tools.Pencil.size * (1 + KiddoPaint.Current.modifiedRange / 100.0); 27 | } 28 | this.previousEv = null; 29 | this.spacing = 10; 30 | this.texture = function() { 31 | return KiddoPaint.Tools.Pencil.texture(); 32 | }; 33 | 34 | this.mousedown = function(ev) { 35 | tool.isDown = true; 36 | tool.mousemove(ev); 37 | tool.previousEv = ev; 38 | }; 39 | 40 | this.mousemove = function(ev) { 41 | var ctx = tool.isDown ? KiddoPaint.Display.context : KiddoPaint.Display.previewContext; 42 | ctx.fillStyle = tool.texture(); 43 | if (KiddoPaint.Current.modifiedAlt) { 44 | ev._x = ev._x - (ev._x % (tool.size())); 45 | ev._y = ev._y - (ev._y % (tool.size())); 46 | } 47 | if (tool.previousEv == null || distanceBetween(tool.previousEv, ev) < tool.spacing) { 48 | ctx.fillRect(Math.round(ev._x), Math.round(ev._y), tool.size(), tool.size()); 49 | } else { 50 | bresenham(tool.previousEv._x, tool.previousEv._y, ev._x, ev._y, function(x, y) { 51 | ctx.fillRect(Math.round(ev._x), Math.round(ev._y), tool.size(), tool.size()); 52 | }); 53 | } 54 | tool.previousEv = ev; 55 | }; 56 | 57 | this.mouseup = function(ev) { 58 | if (tool.isDown) { 59 | tool.mousemove(ev); 60 | tool.isDown = false; 61 | tool.previousEv = null; 62 | KiddoPaint.Display.saveMain(); 63 | } 64 | }; 65 | }; 66 | 67 | KiddoPaint.Tools.PixelPencil = new KiddoPaint.Tools.Toolbox.PixelPencil(); 68 | 69 | KiddoPaint.Tools.Toolbox.LinePencil = function() { 70 | var tool = this; 71 | this.isDown = false; 72 | this.size = function() { 73 | return KiddoPaint.Tools.Pencil.size * (1 + KiddoPaint.Current.modifiedRange / 100.0); 74 | } 75 | 76 | this.texture = function() { 77 | return KiddoPaint.Tools.Pencil.texture(); 78 | }; 79 | 80 | this.mousedown = function(ev) { 81 | tool.isDown = true; 82 | KiddoPaint.Display.context.beginPath(); 83 | KiddoPaint.Display.context.strokeStyle = tool.texture(); 84 | KiddoPaint.Display.context.lineWidth = tool.size(); 85 | KiddoPaint.Display.context.lineCap = 'round'; 86 | KiddoPaint.Display.context.lineJoin = 'round'; 87 | KiddoPaint.Display.context.moveTo(ev._x, ev._y); 88 | }; 89 | 90 | this.mousemove = function(ev) { 91 | if (tool.isDown) { 92 | KiddoPaint.Display.context.lineTo(ev._x, ev._y); 93 | KiddoPaint.Display.context.stroke(); 94 | } 95 | }; 96 | 97 | this.mouseup = function(ev) { 98 | if (tool.isDown) { 99 | tool.mousemove(ev); 100 | KiddoPaint.Display.context.closePath(); 101 | tool.isDown = false; 102 | KiddoPaint.Display.saveMain(); 103 | } 104 | }; 105 | }; 106 | KiddoPaint.Tools.LinePencil = new KiddoPaint.Tools.Toolbox.LinePencil(); -------------------------------------------------------------------------------- /js/tools/placer.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Placer = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.image = {}; 5 | this.prevTool = {}; 6 | this.size = {}; 7 | 8 | this.mousedown = function(ev) { 9 | tool.isDown = true; 10 | tool.mousemove(ev); 11 | }; 12 | 13 | this.mousemove = function(ev) { 14 | var ctx = tool.isDown ? KiddoPaint.Display.context : KiddoPaint.Display.previewContext; 15 | var alt = KiddoPaint.Current.modifiedAlt; 16 | var ctrl = KiddoPaint.Current.modifiedMeta; 17 | 18 | // https://stackoverflow.com/a/37388113 19 | function drawImageff(img, x, y, width, height, flip, flop, center) { 20 | ctx.save(); 21 | if (typeof width === "undefined") width = img.width; 22 | if (typeof height === "undefined") height = img.height; 23 | if (typeof center === "undefined") center = false; 24 | // Set rotation point to center of image, instead of top/left 25 | if (center) { 26 | x -= width / 2; 27 | y -= height / 2; 28 | } 29 | 30 | // Set the origin to the center of the image 31 | ctx.translate(x + width / 2, y + height / 2); 32 | 33 | // Rotate the canvas around the origin 34 | //var rad = 2 * Math.PI - deg * Math.PI / 180; 35 | //context.rotate(rad); 36 | 37 | // Flip/flop the canvas 38 | ctx.scale((flip) ? -1 : 1, (flop) ? -1 : 1); 39 | 40 | // Draw the image 41 | ctx.drawImage(img, -width / 2, -height / 2); 42 | ctx.restore(); 43 | } 44 | 45 | if (KiddoPaint.Current.modifiedRange != 0) { 46 | var scale = 1 + KiddoPaint.Current.modifiedRange / 100.0; 47 | var scaledImg = scaleImageDataCanvasAPI(tool.image, scale); 48 | drawImageff(scaledImg, ev._x, ev._y, tool.size.width * scale, tool.size.height * scale, KiddoPaint.Current.modifiedAlt, KiddoPaint.Current.modifiedMeta, true); 49 | } else { 50 | drawImageff(tool.image, ev._x, ev._y, tool.size.width, tool.size.height, KiddoPaint.Current.modifiedAlt, KiddoPaint.Current.modifiedMeta, true); 51 | } 52 | }; 53 | 54 | this.mouseup = function(ev) { 55 | if (tool.isDown) { 56 | tool.isDown = false; 57 | tool.image = {}; 58 | KiddoPaint.Display.saveMain(); 59 | KiddoPaint.Current.tool = tool.prevTool; 60 | reset_ranges(); 61 | tool.prevTool = {}; 62 | tool.size = {}; 63 | } 64 | }; 65 | }; 66 | KiddoPaint.Tools.Placer = new KiddoPaint.Tools.Toolbox.Placer(); -------------------------------------------------------------------------------- /js/tools/plainbrush.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.PlainBrush = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.previousEv = null; 5 | this.texture = function() {}; 6 | this.preprocess = function() {}; 7 | this.postprocess = function() {}; 8 | this.spacing = 5; 9 | this.step = 0; 10 | 11 | this.reset = function() { 12 | tool.isDown = false; 13 | tool.previousEv = null; 14 | tool.texture = function() {}; 15 | tool.preprocess = function() {}; 16 | tool.postprocess = function() {}; 17 | tool.step = 0; 18 | } 19 | 20 | this.mousedown = function(ev) { 21 | tool.isDown = true; 22 | tool.mousemove(ev); 23 | tool.previousEv = ev; 24 | tool.preprocess(); 25 | }; 26 | 27 | this.mousemove = function(ev) { 28 | if (tool.isDown) { 29 | if (tool.previousEv == null || distanceBetween(tool.previousEv, ev) > tool.spacing) { 30 | if (KiddoPaint.Current.modifiedTilde) { 31 | // alpha decay 32 | KiddoPaint.Display.context.globalAlpha *= 0.95; 33 | KiddoPaint.Display.previewContext.globalAlpha *= 0.95; 34 | } 35 | // gap fill 36 | if (KiddoPaint.Current.modifiedAlt && tool.previousEv != null) { 37 | var dist = distanceBetween(tool.previousEv, ev); 38 | var angle = angleBetweenRad(tool.previousEv, ev); 39 | for (var i = 0; i < dist; i += 5) { 40 | var x = tool.previousEv._x + (Math.sin(angle) * i); 41 | var y = tool.previousEv._y + (Math.cos(angle) * i); 42 | var brushFill = tool.texture(tool.step); 43 | KiddoPaint.Display.context.drawImage(brushFill.brush, Math.round(x - brushFill.offset), Math.round(y - brushFill.offset)); 44 | tool.step += 1; 45 | if (KiddoPaint.Current.modifiedTilde) { 46 | // alpha decay 47 | KiddoPaint.Display.context.globalAlpha *= 0.99; 48 | KiddoPaint.Display.previewContext.globalAlpha *= 0.99; 49 | } 50 | } 51 | } 52 | var brushFill = tool.texture(tool.step); 53 | KiddoPaint.Display.context.drawImage(brushFill.brush, Math.round(ev._x - brushFill.offset), Math.round(ev._y - brushFill.offset)); 54 | tool.previousEv = ev; 55 | tool.step += 1; 56 | } 57 | } else { 58 | var brushFill = tool.texture(0); 59 | KiddoPaint.Display.previewContext.drawImage(brushFill.brush, Math.round(ev._x - brushFill.offset), Math.round(ev._y - brushFill.offset)); 60 | } 61 | }; 62 | 63 | this.mouseup = function(ev) { 64 | if (tool.isDown) { 65 | tool.mousemove(ev); 66 | tool.isDown = false; 67 | tool.previousEv = null; 68 | tool.step = 0; 69 | tool.postprocess(); 70 | KiddoPaint.Display.saveMain(); 71 | KiddoPaint.Display.context.globalAlpha = KiddoPaint.Current.globalAlpha; 72 | KiddoPaint.Display.previewContext.globalAlpha = KiddoPaint.Current.globalAlpha; 73 | } 74 | }; 75 | }; 76 | KiddoPaint.Tools.PlainBrush = new KiddoPaint.Tools.Toolbox.PlainBrush(); -------------------------------------------------------------------------------- /js/tools/scribble.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Scribble = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.previousEv = null; 5 | this.texture = function() { 6 | return KiddoPaint.Textures.Solid(KiddoPaint.Current.color); 7 | }; 8 | this.spacing = 5; 9 | this.size = 1; 10 | this.jitter = function() { 11 | return 25 + (Math.random() * 25); 12 | }; 13 | 14 | this.mousedown = function(ev) { 15 | tool.isDown = true; 16 | KiddoPaint.Display.context.beginPath(); 17 | KiddoPaint.Display.context.moveTo(ev._x, ev._y); 18 | tool.previousEv = ev; 19 | }; 20 | 21 | this.mousemove = function(ev) { 22 | if (tool.isDown) { 23 | if (tool.previousEv == null || distanceBetween(tool.previousEv, ev) > tool.spacing) { 24 | jitterx = tool.jitter(); 25 | jittery = tool.jitter(); 26 | KiddoPaint.Display.context.lineTo(ev._x + (Math.random() * jitterx - jitterx / 2), ev._y + (Math.random() * jittery - jittery / 2)); 27 | KiddoPaint.Display.context.strokeStyle = tool.texture(); 28 | KiddoPaint.Display.context.lineWidth = tool.size; 29 | KiddoPaint.Display.context.stroke(); 30 | tool.previousEv = ev; 31 | } 32 | } 33 | }; 34 | 35 | this.mouseup = function(ev) { 36 | if (tool.isDown) { 37 | tool.mousemove(ev); 38 | tool.isDown = false; 39 | tool.previousEv = null; 40 | KiddoPaint.Display.context.closePath(); 41 | KiddoPaint.Display.saveMain(); 42 | } 43 | }; 44 | }; 45 | KiddoPaint.Tools.Scribble = new KiddoPaint.Tools.Toolbox.Scribble(); -------------------------------------------------------------------------------- /js/tools/smoke.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Smoke = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.party = {}; 5 | 6 | this.mousedown = function(ev) { 7 | tool.isDown = true; 8 | KiddoPaint.Display.context.save(); 9 | var smokeColor = color2json(KiddoPaint.Current.color); 10 | tool.party = SmokeMachine(KiddoPaint.Display.context, [smokeColor.r, smokeColor.g, smokeColor.b]); // ; 11 | tool.party.start(); 12 | setTimeout(function() { 13 | tool.party.addSmoke(ev._x, ev._y, 64); 14 | tool.party.step(10); 15 | }, 100); 16 | }; 17 | 18 | this.mousemove = function(ev) { 19 | if (tool.isDown) { 20 | tool.party.addSmoke(ev._x, ev._y, 4); 21 | } 22 | }; 23 | 24 | this.mouseup = function(ev) { 25 | if (tool.isDown) { 26 | tool.isDown = false; 27 | setTimeout(function() { 28 | tool.party.stop(); 29 | KiddoPaint.Display.saveMain(); 30 | tool.party = {}; 31 | KiddoPaint.Display.context.restore(); 32 | }, 100); 33 | } 34 | }; 35 | }; 36 | KiddoPaint.Tools.Smoke = new KiddoPaint.Tools.Toolbox.Smoke(); -------------------------------------------------------------------------------- /js/tools/smoothpen.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.SmoothPen = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.previousEv = null; 5 | this.spacing = 25; 6 | this.points = []; 7 | this.rainbowMode = false; 8 | 9 | this.size = function() { 10 | return KiddoPaint.Tools.Pencil.size; 11 | } 12 | 13 | this.texture = function() { 14 | tool.rainbowMode = KiddoPaint.Tools.Pencil.texture.toString().includes('RSolid'); 15 | return KiddoPaint.Tools.Pencil.texture(); 16 | }; 17 | 18 | this.mousedown = function(ev) { 19 | tool.isDown = true; 20 | tool.points = []; 21 | }; 22 | 23 | this.mousemove = function(ev) { 24 | if (tool.isDown) { 25 | if (tool.previousEv == null || distanceBetween(tool.previousEv, ev) > tool.spacing) { 26 | tool.points.push([ev._x, ev._y]); 27 | tool.previousEv = ev; 28 | } 29 | renderFitLine(KiddoPaint.Display.previewContext); 30 | } 31 | }; 32 | 33 | this.mouseup = function(ev) { 34 | if (tool.isDown) { 35 | tool.isDown = false; 36 | tool.points.push([ev._x, ev._y]); 37 | KiddoPaint.Display.clearPreview(); 38 | renderFitLine(KiddoPaint.Display.context); 39 | KiddoPaint.Display.saveMain(); 40 | } 41 | }; 42 | 43 | function offsetPoints(bezPoints, xoffsetAmount, yoffsetAmount, index) { 44 | var colors = KiddoPaint.Colors.rainbowPalette(); 45 | var startPt = bezPoints[0]; 46 | var ctrl1 = bezPoints[1]; 47 | var ctrl2 = bezPoints[2]; 48 | var stopPt = bezPoints[3]; 49 | 50 | return [ 51 | [startPt[0] + xoffsetAmount, startPt[1] + yoffsetAmount], 52 | [ctrl1[0] + xoffsetAmount, ctrl1[1] + yoffsetAmount], 53 | [ctrl2[0] + xoffsetAmount, ctrl2[1] + yoffsetAmount], 54 | [stopPt[0] + xoffsetAmount, stopPt[1] + yoffsetAmount], 55 | colors[index] 56 | ]; 57 | } 58 | 59 | function renderFitLine(ctx) { 60 | var fitted = fitCurve(tool.points, 75); 61 | if (fitted) { 62 | ctx.strokeStyle = tool.texture(); 63 | ctx.lineWidth = tool.size(); 64 | ctx.lineCap = 'round'; 65 | ctx.lineJoin = 'round'; 66 | 67 | var lines = tool.rainbowMode ? 7 : 1; 68 | 69 | fitted.forEach(element => { 70 | for (var i = 0; i < lines; i++) { 71 | var offsetElement = offsetPoints(element, 0, 11 * i, i); 72 | 73 | var startPt = offsetElement[0]; 74 | var ctrl1 = offsetElement[1]; 75 | var ctrl2 = offsetElement[2]; 76 | var stopPt = offsetElement[3]; 77 | var rainbowColor = tool.rainbowMode ? offsetElement[4] : null; 78 | 79 | ctx.beginPath(); 80 | if (rainbowColor) { 81 | ctx.strokeStyle = rainbowColor; 82 | } 83 | ctx.moveTo(startPt[0], startPt[1]); 84 | ctx.bezierCurveTo(ctrl1[0], ctrl1[1], ctrl2[0], ctrl2[1], stopPt[0], stopPt[1]); 85 | ctx.stroke(); 86 | ctx.closePath(); 87 | 88 | } 89 | 90 | }); 91 | } 92 | } 93 | }; 94 | KiddoPaint.Tools.SmoothPen = new KiddoPaint.Tools.Toolbox.SmoothPen(); -------------------------------------------------------------------------------- /js/tools/smudge.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Smudge = function() { 2 | // https://stackoverflow.com/a/61970857 3 | var tool = this; 4 | this.isDown = false; 5 | this.size = 36; 6 | this.previousEv = null; 7 | this.brushCtx = document.createElement('canvas').getContext("2d"); 8 | 9 | 10 | this.mousedown = function(ev) { 11 | tool.isDown = true; 12 | tool.previousEv = ev; 13 | updateBrush(ev._x, ev._y); 14 | }; 15 | 16 | this.mousemove = function(ev) { 17 | if (!tool.isDown) { 18 | return; 19 | } 20 | 21 | const line = setupLine(tool.previousEv._x, tool.previousEv._y, ev._x, ev._y); 22 | KiddoPaint.Display.context.globalAlpha = 0.5; 23 | 24 | for (let more = true; more;) { 25 | more = advanceLine(line); 26 | 27 | KiddoPaint.Display.context.drawImage( 28 | tool.brushCtx.canvas, 29 | line.position[0] - tool.brushCtx.canvas.width / 2, 30 | line.position[1] - tool.brushCtx.canvas.height / 2 31 | ); 32 | updateBrush(line.position[0], line.position[1]); 33 | } 34 | tool.previousEv = ev; 35 | }; 36 | 37 | this.mouseup = function(ev) { 38 | if (tool.isDown) { 39 | tool.isDown = false; 40 | KiddoPaint.Display.context.globalAlpha = 1; 41 | KiddoPaint.Display.saveMain(); 42 | } 43 | }; 44 | 45 | function feather(ctx) { 46 | ctx.save(); 47 | ctx.fillStyle = createFeatherGradient(tool.size, 0.1); 48 | ctx.globalCompositeOperation = 'destination-out'; 49 | const { 50 | width, 51 | height 52 | } = ctx.canvas; 53 | ctx.translate(width / 2, height / 2); 54 | ctx.fillRect(-width / 2, -height / 2, width, height); 55 | ctx.restore(); 56 | } 57 | 58 | function updateBrush(x, y) { 59 | let width = tool.brushCtx.canvas.width; 60 | let height = tool.brushCtx.canvas.height; 61 | let srcX = x - width / 2; 62 | let srcY = y - height / 2; 63 | // draw it in the middle of the brush 64 | let dstX = (tool.brushCtx.canvas.width - width) / 2; 65 | let dstY = (tool.brushCtx.canvas.height - height) / 2; 66 | 67 | // clear the brush canvas 68 | tool.brushCtx.clearRect(0, 0, tool.brushCtx.canvas.width, tool.brushCtx.canvas.height); 69 | 70 | // clip the rectangle to be 71 | // inside 72 | if (srcX < 0) { 73 | width += srcX; 74 | dstX -= srcX; 75 | srcX = 0; 76 | } 77 | const overX = srcX + width - KiddoPaint.Display.main_context.canvas.width; 78 | if (overX > 0) { 79 | width -= overX; 80 | } 81 | 82 | if (srcY < 0) { 83 | dstY -= srcY; 84 | height += srcY; 85 | srcY = 0; 86 | } 87 | const overY = srcY + height - KiddoPaint.Display.main_context.canvas.height; 88 | if (overY > 0) { 89 | height -= overY; 90 | } 91 | 92 | if (width <= 0 || height <= 0) { 93 | return; 94 | } 95 | 96 | // kiddopaint needs to update the brush initially with the main context... 97 | tool.brushCtx.drawImage( 98 | KiddoPaint.Display.main_context.canvas, 99 | srcX, srcY, width, height, 100 | dstX, dstY, width, height); 101 | 102 | // and also with the preview context. 103 | tool.brushCtx.drawImage( 104 | KiddoPaint.Display.context.canvas, 105 | srcX, srcY, width, height, 106 | dstX, dstY, width, height); 107 | 108 | feather(tool.brushCtx); 109 | } 110 | 111 | 112 | function setupLine(x, y, targetX, targetY) { 113 | const deltaX = targetX - x; 114 | const deltaY = targetY - y; 115 | const deltaRow = Math.abs(deltaX); 116 | const deltaCol = Math.abs(deltaY); 117 | const counter = Math.max(deltaCol, deltaRow); 118 | const axis = counter == deltaCol ? 1 : 0; 119 | 120 | // setup a line draw. 121 | return { 122 | position: [x, y], 123 | delta: [deltaX, deltaY], 124 | deltaPerp: [deltaRow, deltaCol], 125 | inc: [Math.sign(deltaX), Math.sign(deltaY)], 126 | accum: Math.floor(counter / 2), 127 | counter: counter, 128 | endPnt: counter, 129 | axis: axis, 130 | u: 0, 131 | }; 132 | }; 133 | 134 | function advanceLine(line) { 135 | --line.counter; 136 | line.u = 1 - line.counter / line.endPnt; 137 | if (line.counter <= 0) { 138 | return false; 139 | } 140 | const axis = line.axis; 141 | const perp = 1 - axis; 142 | line.accum += line.deltaPerp[perp]; 143 | if (line.accum >= line.endPnt) { 144 | line.accum -= line.endPnt; 145 | line.position[perp] += line.inc[perp]; 146 | } 147 | line.position[axis] += line.inc[axis]; 148 | return true; 149 | } 150 | 151 | }; 152 | KiddoPaint.Tools.Smudge = new KiddoPaint.Tools.Toolbox.Smudge(); -------------------------------------------------------------------------------- /js/tools/spiral.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Spiral = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | 5 | this.mousedown = function(ev) { 6 | tool.isDown = true; 7 | drawSpiral(ev._x, ev._y) 8 | processMainCanvas(); 9 | }; 10 | 11 | this.mousemove = function(ev) {}; 12 | 13 | this.mouseup = function(ev) { 14 | if (tool.isDown) { 15 | tool.isDown = false; 16 | KiddoPaint.Display.saveMain(); 17 | } 18 | }; 19 | }; 20 | KiddoPaint.Tools.Spiral = new KiddoPaint.Tools.Toolbox.Spiral(); 21 | 22 | KiddoPaint.Current.kdspiral = {}; 23 | 24 | function drawSpiral(cx, cy) { 25 | var width = 5000; 26 | var height = 5000; 27 | 28 | var phi = (Math.sqrt(5) + 1) / 2 - 1; 29 | var golden_angle = phi * 2 * Math.PI; 30 | 31 | var lg_area = width * height; 32 | 33 | var points = []; 34 | 35 | var sm_area = golden_angle * 3; 36 | var nbr_circles = lg_area / sm_area; 37 | 38 | for (var i = 1; i <= nbr_circles; ++i) { 39 | var angle = i * golden_angle; 40 | var cum_area = i * sm_area; 41 | var spiral_rad = Math.sqrt(cum_area / Math.PI); 42 | var x = cx + Math.cos(angle) * spiral_rad; 43 | var y = cy + Math.sin(angle) * spiral_rad; 44 | points.push({ 45 | x: x, 46 | y: y 47 | }); 48 | //KiddoPaint.Display.context.fillRect(Math.round(x), Math.round(y), 1, 1); 49 | } 50 | 51 | var distance = function(a, b) { 52 | return Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2); 53 | } 54 | KiddoPaint.Current.kdspiral = new kdTree(points, distance, ["x", "y"]); 55 | } 56 | 57 | function processMainCanvas() { 58 | var w = KiddoPaint.Display.main_canvas.width; 59 | var h = KiddoPaint.Display.main_canvas.height; 60 | 61 | var pixels = KiddoPaint.Display.main_context.getImageData(0, 0, w, h); 62 | 63 | function isBlack(n) { 64 | return pixels.data[n] == 0 && 65 | pixels.data[n + 1] == 0 && 66 | pixels.data[n + 2] == 0 && 67 | pixels.data[n + 3] == 255; 68 | } 69 | 70 | function isTransparent(n) { 71 | return pixels.data[n + 3] == 0; 72 | } 73 | 74 | function isWhite(n) { 75 | return pixels.data[n] == 255 && 76 | pixels.data[n + 1] == 255 && 77 | pixels.data[n + 2] == 255 && 78 | pixels.data[n + 3] == 255; 79 | } 80 | 81 | function isAlone(x, y) { 82 | var above = (((y - 1) * w + x) * 4); 83 | var abover = (((y - 1) * w + (x + 1)) * 4); 84 | var abovel = (((y - 1) * w + (x - 1)) * 4); 85 | 86 | var below = (((y + 1) * w + x) * 4); 87 | var belowr = (((y + 1) * w + (x + 1)) * 4); 88 | var belowl = (((y + 1) * w + (x - 1)) * 4); 89 | 90 | var left = ((y * w + (x - 1)) * 4); 91 | var right = ((y * w + (x + 1)) * 4); 92 | 93 | return isBlack(above) && 94 | isBlack(below) && 95 | isBlack(right) && 96 | isBlack(left) && 97 | isBlack(abover) && 98 | isBlack(abovel) && 99 | isBlack(belowr) && 100 | isBlack(belowl); 101 | } 102 | 103 | var snaptospiral = []; 104 | for (i = 1; i < w - 1; i++) { 105 | for (j = 1; j < h - 1; j++) { 106 | var linear_cords = 4 * (j * w + i); 107 | 108 | if (isWhite(linear_cords) && isAlone(i, j)) { 109 | // turn off 110 | pixels.data[linear_cords + 0] = 0; 111 | pixels.data[linear_cords + 1] = 0; 112 | pixels.data[linear_cords + 2] = 0; 113 | pixels.data[linear_cords + 3] = 255; 114 | 115 | // look for closes 116 | var nearest = KiddoPaint.Current.kdspiral.nearest({ 117 | x: i, 118 | y: j 119 | }, 1); 120 | snaptospiral.push(nearest[0][0]); 121 | } 122 | } 123 | } 124 | KiddoPaint.Display.clearMain(); 125 | KiddoPaint.Display.main_context.putImageData(pixels, 0, 0); 126 | KiddoPaint.Display.context.fillStyle = 'white'; 127 | console.log(snaptospiral.length); 128 | snaptospiral.forEach(element => KiddoPaint.Display.context.fillRect(Math.round(element.x), Math.round(element.y), 1, 1)); 129 | } -------------------------------------------------------------------------------- /js/tools/square.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Square = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.size = 1; 5 | this.startEv = null; 6 | this.texture = function() { 7 | return KiddoPaint.Textures.None(); 8 | }; 9 | this.stroke = function() { 10 | return KiddoPaint.Textures.Solid(KiddoPaint.Current.color); 11 | }; 12 | 13 | this.mousedown = function(ev) { 14 | tool.isDown = true; 15 | tool.startEv = ev; 16 | }; 17 | 18 | this.mousemove = function(ev) { 19 | if (tool.startEv) { 20 | var ctx = tool.isDown ? KiddoPaint.Display.previewContext : KiddoPaint.Display.context; 21 | if (!KiddoPaint.Current.modifiedCtrl) { 22 | ctx.strokeStyle = tool.stroke(); 23 | ctx.lineWidth = 1.5; 24 | ctx.strokeRect(tool.startEv._x, tool.startEv._y, ev._x - tool.startEv._x, ev._y - tool.startEv._y); 25 | } 26 | ctx.fillStyle = tool.texture(); 27 | ctx.fillRect(tool.startEv._x, tool.startEv._y, ev._x - tool.startEv._x, ev._y - tool.startEv._y); 28 | } 29 | }; 30 | 31 | this.mouseup = function(ev) { 32 | if (tool.isDown) { 33 | tool.isDown = false; 34 | tool.mousemove(ev); 35 | KiddoPaint.Display.saveMain(); 36 | tool.startEv = null; 37 | } 38 | }; 39 | }; 40 | KiddoPaint.Tools.Square = new KiddoPaint.Tools.Toolbox.Square(); -------------------------------------------------------------------------------- /js/tools/stamp.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Tools.Toolbox.Stamp = function() { 2 | var tool = this; 3 | this.isDown = false; 4 | this.stamp = '🚂'; 5 | this.size = 64; 6 | this.useColor = false; 7 | this.seed = 1; 8 | this.texture = function() { 9 | var altSize = KiddoPaint.Cache.getStampSettings(tool.stamp).altSize; 10 | if (KiddoPaint.Current.modifiedRange !== 0) { 11 | var modifiedSize = KiddoPaint.Current.modifiedRange + 112; 12 | KiddoPaint.Cache.setStampSetting(tool.stamp, 'altSize', modifiedSize); 13 | altSize = modifiedSize; 14 | } 15 | tool.size = KiddoPaint.Current.modified ? altSize : 64; 16 | 17 | var hueShift = KiddoPaint.Cache.getStampSettings(tool.stamp).hueShift; 18 | if (KiddoPaint.Current.modifiedCtrlRange !== 0) { 19 | var modifiedHue = KiddoPaint.Current.modifiedCtrlRange / 100; 20 | KiddoPaint.Cache.setStampSetting(tool.stamp, 'hueShift', modifiedHue); 21 | hueShift = modifiedHue; 22 | } 23 | 24 | return KiddoPaint.Stamps.stamp(tool.stamp, KiddoPaint.Current.modifiedAlt, KiddoPaint.Current.modifiedMeta, tool.size, hueShift, tool.useColor ? KiddoPaint.Current.color : null); 25 | }; 26 | 27 | this.mousedown = function(ev) { 28 | var rng = srng(tool.seed); 29 | tool.isDown = true; 30 | KiddoPaint.Sounds.stamp(); 31 | 32 | KiddoPaint.Display.context.fillStyle = tool.useColor ? KiddoPaint.Current.color : null; 33 | var brushFill = tool.texture(); 34 | KiddoPaint.Display.context.drawImage(brushFill, Math.round(ev._x), Math.round(ev._y - tool.size)); 35 | if (KiddoPaint.Current.multiplier > 1) { 36 | for (var i = 0; i < 2 * KiddoPaint.Current.multiplier; i++) { 37 | var x = Math.round(ev._x + (1000 * rng.next() - 500)); 38 | var y = Math.round(ev._y + (20 * rng.next() - 10) - tool.size); 39 | KiddoPaint.Display.context.drawImage(brushFill, x, y); 40 | } 41 | } 42 | }; 43 | 44 | this.mousemove = function(ev) { 45 | var rng = srng(tool.seed); 46 | if (!tool.isDown) { 47 | KiddoPaint.Display.previewContext.fillStyle = tool.useColor ? KiddoPaint.Current.color : null; 48 | var brushFill = tool.texture(); 49 | KiddoPaint.Display.previewContext.drawImage(brushFill, Math.round(ev._x), Math.round(ev._y - tool.size)); 50 | if (KiddoPaint.Current.multiplier > 1) { 51 | for (var i = 0; i < 2 * KiddoPaint.Current.multiplier; i++) { 52 | var x = Math.round(ev._x + (1000 * rng.next() - 500)); 53 | var y = Math.round(ev._y + (20 * rng.next() - 10) - tool.size); 54 | KiddoPaint.Display.previewContext.drawImage(brushFill, x, y); 55 | } 56 | } 57 | } 58 | }; 59 | 60 | this.mouseup = function(ev) { 61 | tool.isDown = false; 62 | tool.seed += 1; 63 | KiddoPaint.Display.saveMain(); 64 | }; 65 | }; 66 | KiddoPaint.Tools.Stamp = new KiddoPaint.Tools.Toolbox.Stamp(); -------------------------------------------------------------------------------- /js/tools/trees.js: -------------------------------------------------------------------------------- 1 | // this & maze can be refactored to a generic tool that takes a lambda 2 | KiddoPaint.Tools.Toolbox.Tree = function() { 3 | var tool = this; 4 | this.isDown = false; 5 | 6 | this.mousedown = function(ev) { 7 | tool.isDown = true; 8 | drawTree(ev._x, ev._y, 32 * KiddoPaint.Current.scaling, -Math.PI / 2, 12, 15) 9 | }; 10 | 11 | this.mousemove = function(ev) {}; 12 | 13 | this.mouseup = function(ev) { 14 | if (tool.isDown) { 15 | tool.isDown = false; 16 | KiddoPaint.Display.saveMain(); 17 | } 18 | }; 19 | }; 20 | KiddoPaint.Tools.Tree = new KiddoPaint.Tools.Toolbox.Tree(); 21 | 22 | /* 23 | drawTree(320, 600, 60, -Math.PI / 2, 12, 15); 24 | drawTree(500, 600, 60, -Math.PI / 2, 12, 7); 25 | drawTree(680, 600, 60, -Math.PI / 2, 12, 15); 26 | drawTree(750, 600, 60, -Math.PI / 2, 12, 15); 27 | */ 28 | 29 | // https://github.com/PavlyukVadim/amadev/tree/master/RecursiveTree 30 | function drawTree(startX, startY, length, angle, depth, branchWidth) { 31 | var rand = Math.random; 32 | var newLength, newAngle, newDepth, maxBranch = 3, 33 | endX, endY, maxAngle = 2 * Math.PI / 6, 34 | subBranches; 35 | 36 | KiddoPaint.Display.context.beginPath(); 37 | KiddoPaint.Display.context.moveTo(startX, startY); 38 | endX = startX + length * Math.cos(angle); 39 | endY = startY + length * Math.sin(angle); 40 | KiddoPaint.Display.context.lineCap = 'round'; 41 | KiddoPaint.Display.context.lineWidth = branchWidth; 42 | KiddoPaint.Display.context.lineTo(endX, endY); 43 | 44 | if (depth <= 2) { 45 | KiddoPaint.Display.context.strokeStyle = 'rgb(0,' + (((rand() * 64) + 128) >> 0) + ',0)'; 46 | } else { 47 | KiddoPaint.Display.context.strokeStyle = 'rgb(0,' + (((rand() * 64) + 64) >> 0) + ',20)'; 48 | } 49 | KiddoPaint.Display.context.stroke(); 50 | newDepth = depth - 1; 51 | 52 | if (!newDepth) { 53 | return; 54 | } 55 | subBranches = (rand() * (maxBranch - 1)) + 1; 56 | branchWidth *= 0.7; 57 | 58 | for (var i = 0; i < subBranches; i++) { 59 | newAngle = angle + rand() * maxAngle - maxAngle * 0.5; 60 | newLength = length * (0.7 + rand() * 0.3); 61 | drawTree(endX, endY, newLength, newAngle, newDepth, branchWidth); 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /js/tools/wholefx.js: -------------------------------------------------------------------------------- 1 | const JumbleFx = { 2 | PINCH: 'pinch', 3 | SWIRL: 'swirl', 4 | LENSBLUR: 'lensblur', 5 | TRIBLUR: 'triblur', 6 | ZOOM: 'zoom', 7 | HEXAGON: 'hexagon', 8 | INK: 'ink', 9 | EDGE: 'edge', 10 | PANCAKE: 'pancake', 11 | PIXELATE: 'pixelate', 12 | HUE: 'hue', 13 | SAT: 'sat', 14 | NIGHTVISION: 'nightvision', 15 | INVERT: 'invert', 16 | SUNSHINE: 'sunshine', 17 | DITHER: 'dither', 18 | THRESHOLD: 'threshold' 19 | } 20 | 21 | KiddoPaint.Tools.Toolbox.WholeCanvasEffect = function() { 22 | var tool = this; 23 | this.isDown = false; 24 | this.gfx = fx.canvas(); // expensive; create once 25 | this.textureGfx = {}; 26 | this.mainImageData = {}; 27 | this.initialClick = {}; 28 | this.effect = JumbleFx.PANCAKE; 29 | 30 | this.mousedown = function(ev) { 31 | tool.isDown = true; 32 | tool.initialClick = ev; 33 | tool.mainImageData = KiddoPaint.Display.main_context.getImageData(0, 0, KiddoPaint.Display.main_canvas.width, KiddoPaint.Display.main_canvas.height); 34 | tool.textureGfx = tool.gfx.texture(KiddoPaint.Display.main_canvas); 35 | KiddoPaint.Display.saveUndo(); 36 | KiddoPaint.Display.clearMain(); // this causes the bug where if the mouse move off screen, the mouseout even clears tmp context and everything is lost; but we need the main clear incase there's alpha it gets double rendered on preview... 37 | tool.mousemove(ev); 38 | }; 39 | 40 | this.mousemove = function(ev) { 41 | if (tool.isDown) { 42 | KiddoPaint.Display.clearTmp(); 43 | var drawDistance = distanceBetween(ev, tool.initialClick); 44 | switch (tool.effect) { 45 | case JumbleFx.PINCH: 46 | var strength = remap(0, 500, -1, 1, drawDistance); 47 | var renderedGfx = tool.gfx.draw(tool.textureGfx).bulgePinch(tool.initialClick._x, tool.initialClick._y, 200, strength).update(); 48 | break; 49 | case JumbleFx.SWIRL: 50 | var horizDist = Math.abs(ev._x - tool.initialClick._x); 51 | var vertDist = ev._y - tool.initialClick._y; 52 | var swirlAngle = remap(-300, 300, -Math.PI * 2, Math.PI * 2, vertDist); 53 | var renderedGfx = tool.gfx.draw(tool.textureGfx).swirl(tool.initialClick._x, tool.initialClick._y, horizDist, swirlAngle).update(); 54 | break; 55 | case JumbleFx.LENSBLUR: 56 | var strength = remap(0, 500, 0, 50, drawDistance); 57 | var renderedGfx = tool.gfx.draw(tool.textureGfx).lensBlur(strength, 0.88, 0.70841).update(); 58 | break; 59 | case JumbleFx.TRIBLUR: 60 | var renderedGfx = tool.gfx.draw(tool.textureGfx).triangleBlur(drawDistance / 5.0).update(); 61 | break; 62 | case JumbleFx.ZOOM: 63 | var strength = remap(0, 250, 0, 1, drawDistance); 64 | var renderedGfx = tool.gfx.draw(tool.textureGfx).zoomBlur(tool.initialClick._x, tool.initialClick._y, strength).update(); 65 | break; 66 | case JumbleFx.HEXAGON: 67 | var renderedGfx = tool.gfx.draw(tool.textureGfx).hexagonalPixelate(tool.initialClick._x, tool.initialClick._y, drawDistance / 10.0).update(); 68 | break; 69 | case JumbleFx.INK: 70 | var strength = remap(0, 250, -1, 1, drawDistance); 71 | var renderedGfx = tool.gfx.draw(tool.textureGfx).ink(strength).update(); 72 | break; 73 | case JumbleFx.HUE: 74 | var strength = remap(0, 1000, -1, 1, drawDistance); 75 | //KiddoPaint.Display.previewContext.fillText(strength, ev._x, ev._y); 76 | var renderedGfx = tool.gfx.draw(tool.textureGfx).hueSaturation(strength, 0).update(); 77 | break; 78 | case JumbleFx.SAT: 79 | var strength = remap(0, 500, -1, 1, drawDistance); 80 | var renderedGfx = tool.gfx.draw(tool.textureGfx).hueSaturation(0, strength).update(); 81 | break; 82 | case JumbleFx.EDGE: 83 | var renderedGfx = tool.gfx.draw(tool.textureGfx).edgeWork(drawDistance / 10.0).update(); 84 | break; 85 | case JumbleFx.PANCAKE: 86 | var renderedGfx = tool.gfx.draw(tool.textureGfx).brightnessContrast(0, 0).update(); 87 | var howManyPancakes = 2 + (drawDistance / 64); 88 | var increment = KiddoPaint.Current.modifiedAlt ? 4 : 16; 89 | var furthestAway = howManyPancakes * increment; 90 | 91 | var deltax = ev._x - tool.initialClick._x; 92 | var deltay = ev._y - tool.initialClick._y; 93 | 94 | for (var i = 1; i < howManyPancakes; i++) { 95 | KiddoPaint.Display.context.globalAlpha = i / (howManyPancakes * 1.0); 96 | KiddoPaint.Display.context.drawImage(renderedGfx, (furthestAway - (i * increment)) * Math.sign(deltax), (furthestAway - (i * increment)) * Math.sign(deltay)); 97 | } 98 | KiddoPaint.Display.context.globalAlpha = 1; 99 | break; 100 | case JumbleFx.PIXELATE: 101 | var renderedGfx = tool.gfx.draw(tool.textureGfx).brightnessContrast(0, 0).update(); 102 | var blocks = remap(0, 500, 50, 7, clamp(0, 500, drawDistance)); 103 | renderedGfx = pixelateCanvas(renderedGfx, blocks); 104 | break; 105 | case JumbleFx.NIGHTVISION: 106 | var s = Filters.sobel(tool.mainImageData); 107 | renderedGfx = KiddoPaint.Display.imageTypeToCanvas(s, false); 108 | break; 109 | case JumbleFx.INVERT: 110 | var alpha = remap(0, 500, 1, 0, clamp(0, 500, drawDistance)); 111 | var s = Filters.gcoInvert(tool.mainImageData, alpha); 112 | renderedGfx = s; 113 | break; 114 | case JumbleFx.SUNSHINE: 115 | var alpha = remap(0, 500, 1, 0, clamp(0, 500, drawDistance)); 116 | var s = Filters.gcoOverlay(tool.mainImageData, alpha); 117 | renderedGfx = s; 118 | break; 119 | case JumbleFx.DITHER: 120 | var s = {}; 121 | if (KiddoPaint.Current.modifiedCtrl) { 122 | var threshold = remap(0, 500, 192, 0, clamp(0, 500, drawDistance)); 123 | s = Dither.bayer(tool.mainImageData, threshold); 124 | } else if (KiddoPaint.Current.modifiedMeta) { 125 | s = Dither.atkinson(tool.mainImageData); 126 | } else { 127 | s = Dither.floydsteinberg(tool.mainImageData); 128 | } 129 | renderedGfx = KiddoPaint.Display.imageTypeToCanvas(s, false); 130 | break; 131 | case JumbleFx.THRESHOLD: 132 | // var threshold = remap(0, 500, 1, 255, clamp(0, 500, drawDistance)); 133 | var s = Dither.threshold(tool.mainImageData, 100); 134 | renderedGfx = KiddoPaint.Display.imageTypeToCanvas(s, false); 135 | break; 136 | } 137 | KiddoPaint.Display.context.drawImage(renderedGfx, 0, 0); 138 | } 139 | }; 140 | 141 | this.mouseup = function(ev) { 142 | if (tool.isDown) { 143 | tool.isDown = false; 144 | tool.textureGfx.destroy(); 145 | tool.textureGfx = {}; 146 | tool.mainImageData = {}; 147 | tool.initialClick = {}; 148 | KiddoPaint.Display.saveMainSkipUndo(); 149 | } 150 | }; 151 | }; 152 | KiddoPaint.Tools.WholeCanvasEffect = new KiddoPaint.Tools.Toolbox.WholeCanvasEffect(); -------------------------------------------------------------------------------- /js/util/cache.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Cache.StampSettings = {} 2 | KiddoPaint.Cache.Defaults = { 3 | hueShift: 0, 4 | altSize: 144 5 | } 6 | 7 | KiddoPaint.Cache.getStampSettings = function(stamp) { 8 | if (!KiddoPaint.Cache.StampSettings[stamp]) { 9 | KiddoPaint.Cache.StampSettings[stamp] = { 10 | hueShift: KiddoPaint.Cache.Defaults.hueShift, 11 | altSize: KiddoPaint.Cache.Defaults.altSize 12 | }; 13 | } 14 | return KiddoPaint.Cache.StampSettings[stamp]; 15 | } 16 | 17 | KiddoPaint.Cache.setStampSetting = function(stamp, setting, value) { 18 | if (!KiddoPaint.Cache.StampSettings[stamp]) { 19 | KiddoPaint.Cache.StampSettings[stamp] = { 20 | hueShift: KiddoPaint.Cache.Defaults.hueShift, 21 | altSize: KiddoPaint.Cache.Defaults.altSize 22 | }; 23 | } 24 | KiddoPaint.Cache.StampSettings[stamp][setting] = value; 25 | } -------------------------------------------------------------------------------- /js/util/colors.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Colors.Palette = {}; 2 | KiddoPaint.Colors.Current = {}; 3 | 4 | KiddoPaint.Colors.Palette.Blank = ['rgba(0, 0, 0, 0)']; 5 | KiddoPaint.Colors.Palette.Bright = ['rgb(255,0,0)', 'rgb(255,255,0)', 'rgb(0,255,0)', 'rgb(0,0,255)', 'rgb(0,255,255)', 'rgb(255,0,255)']; 6 | 7 | // these are len(pal)=32 8 | KiddoPaint.Colors.Palette.Basic = [ 9 | 'rgb(0, 0, 0)', 10 | 'rgb(255, 255, 255)', 11 | 'rgb(32, 32, 32)', 12 | 'rgb(64, 64, 64)', 13 | 'rgb(128, 128, 128)', 14 | 'rgb(192, 192, 192)', 15 | // red 16 | 'rgb(128, 0, 0)', 17 | 'rgb(255, 0, 0)', 18 | // yellow 19 | 'rgb(128, 128, 0)', 20 | 'rgb(255, 255, 1)', 21 | // green 22 | 'rgb(0, 64, 64)', 23 | 'rgb(0, 100, 0)', 24 | 'rgb(0, 128, 0)', 25 | 'rgb(0, 255, 0)', 26 | // cyan 27 | 'rgb(0, 128, 128)', 28 | //lcyan 29 | 'rgb(128, 255, 255)', 30 | //blue 31 | 'rgb(0, 0, 128)', 32 | 'rgb(0, 0, 255)', 33 | //dblue 34 | 'rgb(0, 64, 128)', 35 | //lblue 36 | 'rgb(0, 128, 255)', 37 | //dpurple 38 | 'rgb(128, 0, 255)', 39 | //lpurple 40 | 'rgb(128, 128, 255)', 41 | //magenta 42 | 'rgb(128, 0, 128)', 43 | 'rgb(255, 0, 255)', 44 | //redpink 45 | 'rgb(128, 0, 64)', 46 | 'rgb(255, 0, 128)', 47 | //brown 48 | 'rgb(73, 61, 38)', 49 | 'rgb(136, 104, 67)', 50 | //brown 51 | 'rgb(128, 64, 0)', 52 | //lorange 53 | 'rgb(255, 128, 64)', 54 | //orange 55 | 'rgb(225, 135, 0)', 56 | 'rgb(255, 195, 30)' 57 | ]; 58 | 59 | // https://lospec.com/palette-list/endesga-32 60 | KiddoPaint.Colors.Palette.Endesga = ['rgb(24,20,37)', 'rgb(255,255,255)', 'rgb(190,74,47)', 'rgb(215,118,67)', 'rgb(234,212,170)', 'rgb(228,166,114)', 'rgb(184,111,80)', 'rgb(115,62,57)', 'rgb(62,39,49)', 'rgb(162,38,51)', 'rgb(228,59,68)', 'rgb(247,118,34)', 'rgb(254,174,52)', 'rgb(254,231,97)', 'rgb(99,199,77)', 'rgb(62,137,72)', 'rgb(38,92,66)', 'rgb(25,60,62)', 'rgb(18,78,137)', 'rgb(0,153,219)', 'rgb(44,232,245)', 'rgb(192,203,220)', 'rgb(139,155,180)', 'rgb(90,105,136)', 'rgb(58,68,102)', 'rgb(38,43,68)', 'rgb(255,0,68)', 'rgb(104,56,108)', 'rgb(181,80,136)', 'rgb(246,117,122)', 'rgb(232,183,150)', 'rgb(194,133,105)']; 61 | // https://lospec.com/palette-list/dawnbringer-32 62 | KiddoPaint.Colors.Palette.DawnBringer = ['rgb(0, 0, 0)', 'rgb(255, 255, 255)', 'rgb( 34 , 32 ,52 )', 'rgb( 69 , 40 ,60 )', 'rgb( 102 , 57 ,49 )', 'rgb( 143 , 86 ,59 )', 'rgb( 223 , 113 ,38 )', 'rgb( 217 , 160 ,102 )', 'rgb( 238 , 195 ,154 )', 'rgb( 251 , 242 ,54 )', 'rgb( 153 , 229 ,80 )', 'rgb( 106 , 190 ,48 )', 'rgb( 55 , 148 ,110 )', 'rgb( 75 , 105 ,47 )', 'rgb( 82 , 75 ,36 )', 'rgb( 50 , 60 ,57 )', 'rgb( 63 , 63 ,116 )', 'rgb( 48 , 96 ,130 )', 'rgb( 91 , 110 ,225 )', 'rgb( 99 , 155 ,255 )', 'rgb( 95 , 205 ,228 )', 'rgb( 203 , 219 ,252 )', 'rgb( 155 , 173 ,183 )', 'rgb( 132 , 126 ,135 )', 'rgb( 105 , 106 ,106 )', 'rgb( 89 , 86 ,82 )', 'rgb( 118 , 66 ,138 )', 'rgb( 172 , 50 ,50 )', 'rgb( 217 , 87 ,99 )', 'rgb( 215 , 123 ,186 )', 'rgb( 143 , 151 ,74 )', 'rgb( 138 , 111 ,48 )']; 63 | // http://medialab.github.io/iwanthue/ 64 | KiddoPaint.Colors.Palette.Pastels = ["#84dcce", "#e8a2bd", "#9dd9b3", "#e5b8e7", "#d2f5c1", "#b8abe1", "#e0d59c", "#87afd9", "#f0b097", "#7cdfea", "#f7abb0", "#5cbbb7", "#cc9dc6", "#aed09e", "#f3daff", "#baab79", "#acd6ff", "#c5a780", "#5bb8cf", "#d1a189", "#acf9ff", "#c1a4b0", "#c8fff6", "#9eadbf", "#fffbe2", "#a6ada7", "#e5fff7", "#a7af93", "#dfe5ff", "#ffdfcb", "#fff5f8", "#ffe3ed"]; 65 | KiddoPaint.Colors.Palette.Pinks = ["#d170e6", "#984060", "#9d6fe8", "#e02f87", "#6d4bba", "#ea90b4", "#8a4bc8", "#e9a6db", "#9935b8", "#ba749c", "#b032a2", "#d6a5f2", "#b32c7c", "#a78ad1", "#af3b70", "#785bae", "#e969a2", "#72619d", "#db49af", "#864b6f", "#e97ad3", "#704889", "#c1589b", "#76409a", "#9a4876", "#9c52b5", "#8c588c", "#9c3d92", "#ba76b1", "#8c468c", "#b672c7", "#9166aa"]; 66 | KiddoPaint.Colors.Palette.Blues = ["#52e2ff", "#0065cd", "#83fae3", "#0e59ac", "#01ecf1", "#6d91fd", "#5cc4b1", "#596fbb", "#41ebff", "#0065a6", "#8df0fd", "#6b7abc", "#00988c", "#91a6ff", "#02c0c2", "#8cb0ff", "#46adb2", "#007cc5", "#02d8fd", "#476c9c", "#5ed5ff", "#006994", "#a3bdff", "#00a6c5", "#9ba6dd", "#69cae1", "#57b1ff", "#009dc4", "#6ec0ff", "#588cbb", "#00aeeb", "#0098dc"]; 67 | KiddoPaint.Colors.Palette.Greyscale = ['rgb(0, 0, 0)', 'rgb(8, 8, 8)', 'rgb(16, 16, 16)', 'rgb(24, 24, 24)', 'rgb(32, 32, 32)', 'rgb(40, 40, 40)', 'rgb(48, 48, 48)', 'rgb(56, 56, 56)', 'rgb(64, 64, 64)', 'rgb(72, 72, 72)', 'rgb(80, 80, 80)', 'rgb(88, 88, 88)', 'rgb(96, 96, 96)', 'rgb(104, 104, 104)', 'rgb(112, 112, 112)', 'rgb(120, 120, 120)', 'rgb(128, 128, 128)', 'rgb(136, 136, 136)', 'rgb(144, 144, 144)', 'rgb(152, 152, 152)', 'rgb(160, 160, 160)', 'rgb(168, 168, 168)', 'rgb(176, 176, 176)', 'rgb(184, 184, 184)', 'rgb(192, 192, 192)', 'rgb(200, 200, 200)', 'rgb(208, 208, 208)', 'rgb(216, 216, 216)', 'rgb(224, 224, 224)', 'rgb(232, 232, 232)', 'rgb(242, 242, 242)', 'rgb(255, 255, 255)']; 68 | // https://coolors.co/gradient-palette/88ffff-ff44ff?number=30 69 | KiddoPaint.Colors.Palette.CyanMagenta = ["#22FFFF", "#44FFFF", "#2AF7FF", "#31F0FF", "#39E8FF", "#40E1FF", "#48D9FF", "#50D1FF", "#57CAFF", "#5FC2FF", "#67BAFF", "#6EB3FF", "#76ABFF", "#7DA4FF", "#859CFF", "#8D94FF", "#948DFF", "#9C85FF", "#A47DFF", "#AB76FF", "#B36EFF", "#BA67FF", "#C25FFF", "#CA57FF", "#D150FF", "#D948FF", "#E140FF", "#E839FF", "#F031FF", "#F72AFF", "#FF88FF", "#FF22FF"]; 70 | 71 | 72 | KiddoPaint.Colors.All = [KiddoPaint.Colors.Palette.Basic, 73 | KiddoPaint.Colors.Palette.DawnBringer, 74 | KiddoPaint.Colors.Palette.Endesga, 75 | KiddoPaint.Colors.Palette.Pastels, 76 | KiddoPaint.Colors.Palette.Pinks, 77 | KiddoPaint.Colors.Palette.Blues, 78 | KiddoPaint.Colors.Palette.CyanMagenta, 79 | KiddoPaint.Colors.Palette.Greyscale 80 | ] 81 | 82 | KiddoPaint.Colors.Current.PaletteNumber = 0; 83 | KiddoPaint.Colors.Current.Palette = KiddoPaint.Colors.All[KiddoPaint.Colors.Current.PaletteNumber]; 84 | 85 | KiddoPaint.Colors.rainbowPalette = function() { 86 | var rpal = []; 87 | if (KiddoPaint.Colors.Current.PaletteNumber == 0) { 88 | rpal = ['red', 'orange', 'yellow', 'green', 'blue', 'purple', 'violet']; 89 | } else { 90 | const cpal = KiddoPaint.Colors.currentPalette(); 91 | const offset = KiddoPaint.Colors.Current.PaletteNumber % 2; 92 | rpal.push(cpal[0 + offset]); 93 | rpal.push(cpal[4 + offset]); 94 | rpal.push(cpal[8 + offset]); 95 | rpal.push(cpal[12 + offset]); 96 | rpal.push(cpal[16 + offset]); 97 | rpal.push(cpal[20 + offset]); 98 | rpal.push(cpal[30 + offset]); 99 | } 100 | return rpal; 101 | } 102 | 103 | KiddoPaint.Colors.currentPalette = function() { 104 | return KiddoPaint.Colors.All[KiddoPaint.Colors.Current.PaletteNumber]; 105 | } 106 | 107 | KiddoPaint.Colors.nextPalette = function() { 108 | KiddoPaint.Colors.Current.PaletteNumber += 1; 109 | if (KiddoPaint.Colors.Current.PaletteNumber >= KiddoPaint.Colors.All.length) { 110 | KiddoPaint.Colors.Current.PaletteNumber = 0; 111 | } 112 | KiddoPaint.Colors.Current.Palette = KiddoPaint.Colors.All[KiddoPaint.Colors.Current.PaletteNumber]; 113 | return KiddoPaint.Colors.Current.Palette; 114 | } 115 | 116 | KiddoPaint.Colors.nextColor = function() { 117 | return KiddoPaint.Colors.Palette.Bright[KiddoPaint.Display.step % KiddoPaint.Colors.Palette.Bright.length]; 118 | } 119 | 120 | KiddoPaint.Colors.randomColor = function() { 121 | return KiddoPaint.Colors.Palette.Bright[Math.floor(Math.random() * KiddoPaint.Colors.Palette.Bright.length)]; 122 | } 123 | 124 | KiddoPaint.Colors.Current.colorStep = 0; 125 | KiddoPaint.Colors.getAndIncColorStep = function() { 126 | KiddoPaint.Colors.Current.colorStep += 1; 127 | return KiddoPaint.Colors.Current.colorStep; 128 | } 129 | 130 | KiddoPaint.Colors.nextAllColor = function() { 131 | var pal = KiddoPaint.Colors.currentPalette(); 132 | return pal[KiddoPaint.Colors.getAndIncColorStep() % pal.length]; 133 | } 134 | 135 | KiddoPaint.Colors.randomAllColor = function() { 136 | var pal = KiddoPaint.Colors.currentPalette(); 137 | return pal[Math.floor(Math.random() * pal.length)]; 138 | } 139 | 140 | function getColorIndicesForCoord(x, y, width) { 141 | var red = y * (width * 4) + x * 4; 142 | return [red, red + 1, red + 2, red + 3]; 143 | } -------------------------------------------------------------------------------- /js/util/display.js: -------------------------------------------------------------------------------- 1 | KiddoPaint.Display.undoData = null; 2 | KiddoPaint.Display.undoOn = true; 3 | KiddoPaint.Display.allowClearTmp = true; 4 | 5 | KiddoPaint.Display.clearAll = function() { 6 | KiddoPaint.Display.saveUndo(); 7 | KiddoPaint.Display.clearPreview(); 8 | KiddoPaint.Display.clearTmp(); 9 | KiddoPaint.Display.clearMain(); 10 | KiddoPaint.Display.clearLocalStorage(); 11 | } 12 | 13 | KiddoPaint.Display.clearMain = function() { 14 | KiddoPaint.Display.main_context.clearRect(0, 0, KiddoPaint.Display.main_canvas.width, KiddoPaint.Display.main_canvas.height); 15 | } 16 | 17 | KiddoPaint.Display.clearTmp = function() { 18 | if (KiddoPaint.Display.allowClearTmp) { 19 | KiddoPaint.Display.context.clearRect(0, 0, KiddoPaint.Display.canvas.width, KiddoPaint.Display.canvas.height); 20 | } 21 | } 22 | 23 | KiddoPaint.Display.clearPreview = function() { 24 | KiddoPaint.Display.previewContext.clearRect(0, 0, KiddoPaint.Display.canvas.width, KiddoPaint.Display.canvas.height); 25 | } 26 | 27 | KiddoPaint.Display.clearBeforeSaveMain = function() { 28 | if (KiddoPaint.Display.saveUndo()) { 29 | KiddoPaint.Display.clearMain(); 30 | KiddoPaint.Display.main_context.drawImage(KiddoPaint.Display.canvas, 0, 0); 31 | KiddoPaint.Display.clearTmp(); 32 | KiddoPaint.Display.saveToLocalStorage(); 33 | } 34 | } 35 | 36 | KiddoPaint.Display.saveMain = function() { 37 | if (KiddoPaint.Display.saveUndo()) { 38 | KiddoPaint.Display.main_context.drawImage(KiddoPaint.Display.canvas, 0, 0); 39 | KiddoPaint.Display.clearTmp(); 40 | KiddoPaint.Display.saveToLocalStorage(); 41 | } 42 | } 43 | 44 | KiddoPaint.Display.saveMainSkipUndo = function() { 45 | KiddoPaint.Display.main_context.drawImage(KiddoPaint.Display.canvas, 0, 0); 46 | KiddoPaint.Display.clearTmp(); 47 | KiddoPaint.Display.saveToLocalStorage(); 48 | } 49 | 50 | 51 | KiddoPaint.Display.pauseUndo = function() { 52 | KiddoPaint.Display.undoOn = false; 53 | } 54 | 55 | KiddoPaint.Display.resumeUndo = function() { 56 | KiddoPaint.Display.undoOn = true; 57 | } 58 | 59 | KiddoPaint.Display.toggleUndo = function() { 60 | KiddoPaint.Display.undoOn = !KiddoPaint.Display.undoOn; 61 | } 62 | 63 | KiddoPaint.Display.saveUndo = function() { 64 | if (KiddoPaint.Display.undoOn) { 65 | KiddoPaint.Display.undoData = KiddoPaint.Display.main_canvas.toDataURL(); 66 | } 67 | return KiddoPaint.Display.undoOn; 68 | } 69 | 70 | KiddoPaint.Display.undo = function(doClearMain) { 71 | if (KiddoPaint.Display.undoData) { 72 | var nextUndoData = KiddoPaint.Display.main_canvas.toDataURL(); 73 | var img = new Image(); 74 | img.src = KiddoPaint.Display.undoData; 75 | img.onload = function() { 76 | if (doClearMain) { 77 | KiddoPaint.Display.clearMain(); 78 | } 79 | KiddoPaint.Display.main_context.drawImage(img, 0, 0); 80 | } 81 | KiddoPaint.Display.undoData = nextUndoData; 82 | } 83 | } 84 | 85 | KiddoPaint.Display.clearLocalStorage = function() { 86 | if (typeof(Storage) != "undefined") { 87 | localStorage.removeItem("kiddopaint"); 88 | } 89 | } 90 | 91 | KiddoPaint.Display.saveToLocalStorage = function() { 92 | if (typeof(Storage) != "undefined") { 93 | try { 94 | localStorage.setItem("kiddopaint", KiddoPaint.Display.main_canvas.toDataURL()); 95 | } catch (e) { 96 | try { 97 | localStorage.setItem("kiddopaint", KiddoPaint.Display.main_canvas.toDataURL('image/jpeg', 0.87)); 98 | } catch (e2) { 99 | console.log(e2); 100 | } 101 | } 102 | } 103 | } 104 | 105 | KiddoPaint.Display.loadFromLocalStorage = function() { 106 | var img = new Image(); 107 | img.crossOrigin = "Anonymous"; 108 | img.onload = function() { 109 | KiddoPaint.Display.clearMain(); 110 | KiddoPaint.Display.main_context.drawImage(img, 0, 0); 111 | } 112 | if (typeof(Storage) != "undefined" && localStorage.getItem("kiddopaint")) { 113 | img.src = localStorage.getItem("kiddopaint"); 114 | } else { 115 | img.src = "static/kiddopaint.jpg"; 116 | } 117 | } 118 | 119 | KiddoPaint.Display.canvasToImageData = function(canvas) { 120 | return canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height); 121 | } 122 | 123 | KiddoPaint.Display.imageTypeToCanvas = function(imageData, doDraw) { 124 | var canvas = document.createElement('canvas'); 125 | var ctx = canvas.getContext('2d'); 126 | canvas.width = imageData.width; 127 | canvas.height = imageData.height; 128 | if (doDraw) { 129 | ctx.drawImage(imageData, 0, 0); 130 | } else { 131 | ctx.putImageData(imageData, 0, 0); 132 | } 133 | return canvas; 134 | } -------------------------------------------------------------------------------- /js/util/dither.js: -------------------------------------------------------------------------------- 1 | // https://github.com/NielsLeenheer/CanvasDither 2 | /** 3 | * Use the ImageData from a Canvas and turn the image in a 1-bit black and white image using dithering 4 | */ 5 | class CanvasDither { 6 | /** 7 | * Change the image to grayscale 8 | * 9 | * @param {object} image The imageData of a Canvas 2d context 10 | * @return {object} The resulting imageData 11 | * 12 | */ 13 | grayscale(image) { 14 | for (let i = 0; i < image.data.length; i += 4) { 15 | const luminance = (image.data[i] * 0.299) + (image.data[i + 1] * 0.587) + (image.data[i + 2] * 0.114); 16 | image.data.fill(luminance, i, i + 3); 17 | } 18 | 19 | return image; 20 | } 21 | 22 | /** 23 | * Change the image to blank and white using a simple threshold 24 | * 25 | * @param {object} image The imageData of a Canvas 2d context 26 | * @param {number} threshold Threshold value (0-255) 27 | * @return {object} The resulting imageData 28 | * 29 | */ 30 | threshold(image, threshold) { 31 | for (let i = 0; i < image.data.length; i += 4) { 32 | const luminance = (image.data[i] * 0.299) + (image.data[i + 1] * 0.587) + (image.data[i + 2] * 0.114); 33 | 34 | const value = luminance < threshold ? 0 : 255; 35 | image.data.fill(value, i, i + 3); 36 | } 37 | 38 | return image; 39 | } 40 | 41 | /** 42 | * Change the image to blank and white using the Bayer algorithm 43 | * 44 | * @param {object} image The imageData of a Canvas 2d context 45 | * @param {number} threshold Threshold value (0-255) 46 | * @return {object} The resulting imageData 47 | * 48 | */ 49 | bayer(image, threshold) { 50 | const thresholdMapA = [ 51 | [15, 135, 45, 165], 52 | [195, 75, 225, 105], 53 | [60, 180, 30, 150], 54 | [240, 120, 210, 90], 55 | ]; 56 | 57 | const thresholdMapB = [ 58 | [0, 8, 2, 10], 59 | [12, 4, 14, 6], 60 | [3, 11, 1, 9], 61 | [15, 7, 13, 5], 62 | ]; 63 | 64 | const thresholdMapC = [ 65 | [0, 48, 12, 60, 3, 51, 15, 63], 66 | [32, 16, 44, 28, 35, 19, 47, 31], 67 | [8, 56, 4, 52, 11, 59, 7, 55], 68 | [40, 24, 36, 20, 43, 27, 39, 23], 69 | [2, 50, 14, 62, 1, 49, 13, 61], 70 | [34, 18, 46, 30, 33, 17, 45, 29], 71 | [10, 58, 6, 54, 9, 57, 5, 53], 72 | [42, 26, 38, 22, 41, 25, 37, 21] 73 | 74 | ]; 75 | 76 | const thresholdMap = thresholdMapA; 77 | 78 | 79 | var ret = KiddoPaint.Display.context.createImageData(image); 80 | 81 | for (let i = 0; i < image.data.length; i += 4) { 82 | const luminance = (image.data[i] * 0.299) + (image.data[i + 1] * 0.587) + (image.data[i + 2] * 0.114); 83 | const x = i / 4 % image.width; 84 | const y = Math.floor(i / 4 / image.width); 85 | const map = Math.floor((luminance + thresholdMap[x % 4][y % 4]) / 2); 86 | const value = map < threshold ? 0 : 255; 87 | ret.data.fill(value, i, i + 3); 88 | ret.data[i + 3] = image.data[i + 3]; 89 | } 90 | return ret; 91 | } 92 | 93 | /** 94 | * Change the image to blank and white using the Floyd-Steinberg algorithm 95 | * 96 | * @param {object} image The imageData of a Canvas 2d context 97 | * @return {object} The resulting imageData 98 | * 99 | */ 100 | floydsteinberg(image) { 101 | const width = image.width; 102 | const luminance = new Uint8ClampedArray(image.width * image.height); 103 | 104 | for (let l = 0, i = 0; i < image.data.length; l++, i += 4) { 105 | luminance[l] = (image.data[i] * 0.299) + (image.data[i + 1] * 0.587) + (image.data[i + 2] * 0.114); 106 | } 107 | 108 | for (let l = 0, i = 0; i < image.data.length; l++, i += 4) { 109 | const value = luminance[l] < 129 ? 0 : 255; 110 | const error = Math.floor((luminance[l] - value) / 16); 111 | image.data.fill(value, i, i + 3); 112 | 113 | luminance[l + 1] += error * 7; 114 | luminance[l + width - 1] += error * 3; 115 | luminance[l + width] += error * 5; 116 | luminance[l + width + 1] += error * 1; 117 | } 118 | 119 | return image; 120 | } 121 | 122 | /** 123 | * Change the image to blank and white using the Atkinson algorithm 124 | * 125 | * @param {object} image The imageData of a Canvas 2d context 126 | * @return {object} The resulting imageData 127 | * 128 | */ 129 | atkinson(image) { 130 | const width = image.width; 131 | const luminance = new Uint8ClampedArray(image.width * image.height); 132 | 133 | for (let l = 0, i = 0; i < image.data.length; l++, i += 4) { 134 | luminance[l] = (image.data[i] * 0.299) + (image.data[i + 1] * 0.587) + (image.data[i + 2] * 0.114); 135 | } 136 | 137 | for (let l = 0, i = 0; i < image.data.length; l++, i += 4) { 138 | const value = luminance[l] < 129 ? 0 : 255; 139 | const error = Math.floor((luminance[l] - value) / 8); 140 | image.data.fill(value, i, i + 3); 141 | 142 | luminance[l + 1] += error; 143 | luminance[l + 2] += error; 144 | luminance[l + width - 1] += error; 145 | luminance[l + width] += error; 146 | luminance[l + width + 1] += error; 147 | luminance[l + 2 * width] += error; 148 | } 149 | 150 | return image; 151 | } 152 | } 153 | 154 | var Dither = new CanvasDither(); -------------------------------------------------------------------------------- /js/util/douglas-peucker.js: -------------------------------------------------------------------------------- 1 | // https://github.com/mattdesl/simplify-path 2 | // square distance from a point to a segment 3 | function getSqSegDist(p, p1, p2) { 4 | var x = p1[0], 5 | y = p1[1], 6 | dx = p2[0] - x, 7 | dy = p2[1] - y; 8 | 9 | if (dx !== 0 || dy !== 0) { 10 | 11 | var t = ((p[0] - x) * dx + (p[1] - y) * dy) / (dx * dx + dy * dy); 12 | 13 | if (t > 1) { 14 | x = p2[0]; 15 | y = p2[1]; 16 | 17 | } else if (t > 0) { 18 | x += dx * t; 19 | y += dy * t; 20 | } 21 | } 22 | 23 | dx = p[0] - x; 24 | dy = p[1] - y; 25 | 26 | return dx * dx + dy * dy; 27 | } 28 | 29 | function simplifyDPStep(points, first, last, sqTolerance, simplified) { 30 | var maxSqDist = sqTolerance, 31 | index; 32 | 33 | for (var i = first + 1; i < last; i++) { 34 | var sqDist = getSqSegDist(points[i], points[first], points[last]); 35 | 36 | if (sqDist > maxSqDist) { 37 | index = i; 38 | maxSqDist = sqDist; 39 | } 40 | } 41 | 42 | if (maxSqDist > sqTolerance) { 43 | if (index - first > 1) simplifyDPStep(points, first, index, sqTolerance, simplified); 44 | simplified.push(points[index]); 45 | if (last - index > 1) simplifyDPStep(points, index, last, sqTolerance, simplified); 46 | } 47 | } 48 | 49 | // simplification using Ramer-Douglas-Peucker algorithm 50 | function simplifyDouglasPeucker(points, tolerance) { 51 | if (points.length <= 1) 52 | return points; 53 | tolerance = typeof tolerance === 'number' ? tolerance : 1; 54 | var sqTolerance = tolerance * tolerance; 55 | 56 | var last = points.length - 1; 57 | 58 | var simplified = [points[0]]; 59 | simplifyDPStep(points, 0, last, sqTolerance, simplified); 60 | simplified.push(points[last]); 61 | 62 | return simplified; 63 | } -------------------------------------------------------------------------------- /js/util/filters.js: -------------------------------------------------------------------------------- 1 | // https://www.html5rocks.com/en/tutorials/canvas/imagefilters/ 2 | Filters = {}; 3 | Filters.getPixels = function(img) { 4 | var c, ctx; 5 | if (img.getContext) { 6 | c = img; 7 | try { 8 | ctx = c.getContext('2d'); 9 | } catch (e) {} 10 | } 11 | if (!ctx) { 12 | c = this.getCanvas(img.width, img.height); 13 | ctx = c.getContext('2d'); 14 | ctx.drawImage(img, 0, 0); 15 | } 16 | return ctx.getImageData(0, 0, c.width, c.height); 17 | }; 18 | 19 | Filters.getCanvas = function(w, h) { 20 | var c = document.createElement('canvas'); 21 | c.width = w; 22 | c.height = h; 23 | return c; 24 | }; 25 | 26 | Filters.filterImage = function(filter, image, var_args) { 27 | var args = [this.getPixels(image)]; 28 | for (var i = 2; i < arguments.length; i++) { 29 | args.push(arguments[i]); 30 | } 31 | return filter.apply(null, args); 32 | }; 33 | 34 | Filters.grayscale = function(pixels, args) { 35 | var d = pixels.data; 36 | for (var i = 0; i < d.length; i += 4) { 37 | var r = d[i]; 38 | var g = d[i + 1]; 39 | var b = d[i + 2]; 40 | // CIE luminance for the RGB 41 | var v = 0.2126 * r + 0.7152 * g + 0.0722 * b; 42 | d[i] = d[i + 1] = d[i + 2] = v 43 | } 44 | return pixels; 45 | }; 46 | 47 | Filters.brightness = function(pixels, adjustment) { 48 | var d = pixels.data; 49 | for (var i = 0; i < d.length; i += 4) { 50 | d[i] += adjustment; 51 | d[i + 1] += adjustment; 52 | d[i + 2] += adjustment; 53 | } 54 | return pixels; 55 | }; 56 | 57 | Filters.invert = function(pixels) { 58 | var d = pixels.data; 59 | for (var i = 0; i < d.length; i += 4) { 60 | d[i] = 255 - d[i]; 61 | d[i + 1] = 255 - d[i + 1]; 62 | d[i + 2] = 255 - d[i + 2]; 63 | } 64 | return pixels; 65 | }; 66 | 67 | Filters.gcoOpWithWhite = function(imageData, alpha, op) { 68 | var canvas = KiddoPaint.Display.imageTypeToCanvas(imageData, false); 69 | var ctx = canvas.getContext('2d'); 70 | ctx.globalCompositeOperation = op; 71 | ctx.fillStyle = "white"; 72 | ctx.globalAlpha = alpha; 73 | ctx.fillRect(0, 0, canvas.width, canvas.height); 74 | return canvas; 75 | } 76 | 77 | Filters.gcoInvert = function(imageData, alpha) { 78 | return Filters.gcoOpWithWhite(imageData, alert, 'difference'); 79 | } 80 | 81 | Filters.gcoOverlay = function(imageData, alpha) { 82 | return Filters.gcoOpWithWhite(imageData, alert, 'overlay'); 83 | } 84 | 85 | 86 | Filters.threshold = function(pixels, threshold) { 87 | var d = pixels.data; 88 | for (var i = 0; i < d.length; i += 4) { 89 | var r = d[i]; 90 | var g = d[i + 1]; 91 | var b = d[i + 2]; 92 | var v = (0.2126 * r + 0.7152 * g + 0.0722 * b >= threshold) ? 255 : 0; 93 | d[i] = d[i + 1] = d[i + 2] = v 94 | } 95 | return pixels; 96 | }; 97 | 98 | Filters.tmpCanvas = document.createElement('canvas'); 99 | Filters.tmpCtx = Filters.tmpCanvas.getContext('2d'); 100 | 101 | Filters.createImageData = function(w, h) { 102 | return this.tmpCtx.createImageData(w, h); 103 | }; 104 | 105 | Filters.convolute = function(pixels, weights, opaque) { 106 | var side = Math.round(Math.sqrt(weights.length)); 107 | var halfSide = Math.floor(side / 2); 108 | 109 | var src = pixels.data; 110 | var sw = pixels.width; 111 | var sh = pixels.height; 112 | 113 | var w = sw; 114 | var h = sh; 115 | var output = Filters.createImageData(w, h); 116 | var dst = output.data; 117 | 118 | var alphaFac = opaque ? 1 : 0; 119 | 120 | for (var y = 0; y < h; y++) { 121 | for (var x = 0; x < w; x++) { 122 | var sy = y; 123 | var sx = x; 124 | var dstOff = (y * w + x) * 4; 125 | var r = 0, 126 | g = 0, 127 | b = 0, 128 | a = 0; 129 | for (var cy = 0; cy < side; cy++) { 130 | for (var cx = 0; cx < side; cx++) { 131 | var scy = Math.min(sh - 1, Math.max(0, sy + cy - halfSide)); 132 | var scx = Math.min(sw - 1, Math.max(0, sx + cx - halfSide)); 133 | var srcOff = (scy * sw + scx) * 4; 134 | var wt = weights[cy * side + cx]; 135 | r += src[srcOff] * wt; 136 | g += src[srcOff + 1] * wt; 137 | b += src[srcOff + 2] * wt; 138 | a += src[srcOff + 3] * wt; 139 | } 140 | } 141 | dst[dstOff] = r; 142 | dst[dstOff + 1] = g; 143 | dst[dstOff + 2] = b; 144 | dst[dstOff + 3] = a + alphaFac * (255 - a); 145 | } 146 | } 147 | return output; 148 | }; 149 | 150 | if (!window.Float32Array) 151 | Float32Array = Array; 152 | 153 | Filters.convoluteFloat32 = function(pixels, weights, opaque) { 154 | var side = Math.round(Math.sqrt(weights.length)); 155 | var halfSide = Math.floor(side / 2); 156 | 157 | var src = pixels.data; 158 | var sw = pixels.width; 159 | var sh = pixels.height; 160 | 161 | var w = sw; 162 | var h = sh; 163 | var output = { 164 | width: w, 165 | height: h, 166 | data: new Float32Array(w * h * 4) 167 | }; 168 | var dst = output.data; 169 | 170 | var alphaFac = opaque ? 1 : 0; 171 | 172 | for (var y = 0; y < h; y++) { 173 | for (var x = 0; x < w; x++) { 174 | var sy = y; 175 | var sx = x; 176 | var dstOff = (y * w + x) * 4; 177 | var r = 0, 178 | g = 0, 179 | b = 0, 180 | a = 0; 181 | for (var cy = 0; cy < side; cy++) { 182 | for (var cx = 0; cx < side; cx++) { 183 | var scy = Math.min(sh - 1, Math.max(0, sy + cy - halfSide)); 184 | var scx = Math.min(sw - 1, Math.max(0, sx + cx - halfSide)); 185 | var srcOff = (scy * sw + scx) * 4; 186 | var wt = weights[cy * side + cx]; 187 | r += src[srcOff] * wt; 188 | g += src[srcOff + 1] * wt; 189 | b += src[srcOff + 2] * wt; 190 | a += src[srcOff + 3] * wt; 191 | } 192 | } 193 | dst[dstOff] = r; 194 | dst[dstOff + 1] = g; 195 | dst[dstOff + 2] = b; 196 | dst[dstOff + 3] = a + alphaFac * (255 - a); 197 | } 198 | } 199 | return output; 200 | }; 201 | 202 | Filters.sobel = function(px) { 203 | px = Filters.grayscale(px); 204 | var vertical = Filters.convoluteFloat32(px, 205 | [-1, -2, -1, 206 | 0, 0, 0, 207 | 1, 2, 1 208 | ]); 209 | var horizontal = Filters.convoluteFloat32(px, 210 | [-1, 0, 1, 211 | -2, 0, 2, 212 | -1, 0, 1 213 | ]); 214 | var id = Filters.createImageData(vertical.width, vertical.height); 215 | for (var i = 0; i < id.data.length; i += 4) { 216 | var v = Math.abs(vertical.data[i]); 217 | id.data[i] = v; 218 | var h = Math.abs(horizontal.data[i]); 219 | id.data[i + 1] = h 220 | id.data[i + 2] = (v + h) / 4; 221 | id.data[i + 3] = 255; 222 | } 223 | return id; 224 | } -------------------------------------------------------------------------------- /js/util/html.js: -------------------------------------------------------------------------------- 1 | HTMLElement.prototype.removeAllChildren = function() { 2 | while (this.lastChild) { 3 | this.removeChild(this.lastChild); 4 | } 5 | } -------------------------------------------------------------------------------- /js/util/smoke.js: -------------------------------------------------------------------------------- 1 | // smoke.js - https://github.com/bijection/smoke.js/blob/master/LICENSE - MIT 2 | /* Magic UMD boilerplate Beginning */ 3 | /**/ 4 | (function(root, factory) { 5 | /**/ 6 | if (typeof define === 'function' && define.amd) { 7 | /**/ 8 | define([], factory); 9 | /**/ 10 | } else if (typeof module === 'object' && module.exports) { 11 | /**/ 12 | module.exports = factory(); 13 | /**/ 14 | module.exports.default = module.exports 15 | /**/ 16 | } else { 17 | /**/ 18 | root.smokemachine = root.SmokeMachine = factory(); 19 | /**/ 20 | } 21 | /**/ 22 | }(typeof self !== 'undefined' ? self : this, function() { 23 | 24 | 25 | 26 | var opacities = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 5, 7, 4, 4, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 17, 27, 41, 52, 56, 34, 23, 15, 11, 4, 9, 5, 1, 0, 0, 0, 0, 0, 0, 1, 45, 63, 57, 45, 78, 66, 52, 41, 34, 37, 23, 20, 0, 1, 0, 0, 0, 0, 1, 43, 62, 66, 64, 67, 115, 112, 114, 56, 58, 47, 33, 18, 12, 10, 0, 0, 0, 0, 39, 50, 63, 76, 87, 107, 105, 112, 128, 104, 69, 64, 29, 18, 21, 15, 0, 0, 0, 7, 42, 52, 85, 91, 103, 126, 153, 128, 124, 82, 57, 52, 52, 24, 1, 0, 0, 0, 2, 17, 41, 67, 84, 100, 122, 136, 159, 127, 78, 69, 60, 50, 47, 25, 7, 1, 0, 0, 0, 34, 33, 66, 82, 113, 138, 149, 168, 175, 82, 142, 133, 70, 62, 41, 25, 6, 0, 0, 0, 18, 39, 55, 113, 111, 137, 141, 139, 141, 128, 102, 130, 90, 96, 65, 37, 0, 0, 0, 2, 15, 27, 71, 104, 129, 129, 158, 140, 154, 146, 150, 131, 92, 100, 67, 26, 3, 0, 0, 0, 0, 46, 73, 104, 124, 145, 135, 122, 107, 120, 122, 101, 98, 96, 35, 38, 7, 2, 0, 0, 0, 50, 58, 91, 124, 127, 139, 118, 121, 177, 156, 88, 90, 88, 28, 43, 3, 0, 0, 0, 0, 30, 62, 68, 91, 83, 117, 89, 139, 139, 99, 105, 77, 32, 1, 1, 0, 0, 0, 0, 0, 16, 21, 8, 45, 101, 125, 118, 87, 110, 86, 64, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 28, 79, 79, 117, 122, 88, 84, 54, 46, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 6, 55, 61, 68, 71, 30, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 23, 25, 20, 12, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 12, 9, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0] 27 | var smokeSpriteSize = 20 28 | 29 | var polyfillAnimFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || 30 | window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; 31 | 32 | function floatInRange(start, end) { 33 | return start + Math.random() * (end - start) 34 | } 35 | 36 | function makeSmokeSprite(color) { 37 | color = color || [24, 46.8, 48.2] 38 | var smokeSprite = document.createElement('canvas'), 39 | ctx = smokeSprite.getContext('2d'), 40 | data = ctx.createImageData(smokeSpriteSize, smokeSpriteSize), 41 | d = data.data 42 | 43 | for (var i = 0; i < d.length; i += 4) { 44 | d[i] = color[0] 45 | d[i + 1] = color[1] 46 | d[i + 2] = color[2] 47 | d[i + 3] = opacities[i / 4] 48 | } 49 | 50 | smokeSprite.width = smokeSpriteSize 51 | smokeSprite.height = smokeSpriteSize 52 | 53 | ctx.putImageData(data, 0, 0) 54 | 55 | return smokeSprite 56 | } 57 | 58 | function createParticle(x, y, options) { 59 | options = options || {} 60 | var lifetime = options.lifetime || 4000 61 | var particle = { 62 | x: x, 63 | y: y, 64 | vx: floatInRange(options.minVx || -4 / 100, options.maxVx || 4 / 100), 65 | startvy: floatInRange(options.minVy || -4 / 10, options.maxVy || -1 / 10), 66 | scale: floatInRange(options.minScale || 0, options.maxScale || 0.5), 67 | lifetime: floatInRange(options.minLifetime || 2000, options.maxLifetime || 8000), 68 | age: 0, 69 | } 70 | particle.finalScale = floatInRange( 71 | options.minScale || 25 + particle.scale, 72 | options.maxScale || 30 + particle.scale 73 | ) 74 | particle.vy = particle.startvy 75 | return particle 76 | } 77 | 78 | function updateParticle(particle, deltatime) { 79 | particle.x += particle.vx * deltatime 80 | particle.y += particle.vy * deltatime 81 | var frac = Math.sqrt(particle.age / particle.lifetime) 82 | particle.vy = (1 - frac) * particle.startvy 83 | particle.age += deltatime 84 | particle.scale = frac * particle.finalScale 85 | } 86 | 87 | function drawParticle(particle, smokeParticleImage, context) { 88 | context.globalAlpha = (1 - Math.abs(1 - 2 * particle.age / particle.lifetime)) / 8 89 | var off = particle.scale * smokeSpriteSize / 2 90 | var xmin = particle.x - off 91 | var xmax = xmin + off * 2 92 | var ymin = particle.y - off 93 | var ymax = ymin + off * 2 94 | context.drawImage(smokeParticleImage, xmin, ymin, xmax - xmin, ymax - ymin) 95 | } 96 | 97 | 98 | return function SmokeMachine(context, color) { 99 | var smokeParticleImage = makeSmokeSprite(color), 100 | particles = [], 101 | preDrawCallback = function() {} 102 | 103 | function updateAndDrawParticles(deltatime) { 104 | context.clearRect(0, 0, context.canvas.width, context.canvas.height); 105 | 106 | particles.forEach(function(p) { 107 | updateParticle(p, deltatime) 108 | }) 109 | particles = particles.filter(function(p) { 110 | return p.age < p.lifetime 111 | }) 112 | 113 | preDrawCallback(deltatime, particles) 114 | particles.forEach(function(p) { 115 | drawParticle(p, smokeParticleImage, context) 116 | }) 117 | } 118 | 119 | var running = false, 120 | lastframe = performance.now() 121 | 122 | function frame(time) { 123 | if (!running) return 124 | var dt = time - lastframe 125 | lastframe = time; 126 | 127 | updateAndDrawParticles(dt) 128 | polyfillAnimFrame(frame) 129 | } 130 | 131 | function addParticles(x, y, numParticles, options) { 132 | numParticles = numParticles || 10 133 | if (numParticles < 1) return Math.random() <= numParticles && particles.push(createParticle(x, y, options)); 134 | for (var i = 0; i < numParticles; i++) particles.push(createParticle(x, y, options)) 135 | } 136 | 137 | return { 138 | step: function step(dt) { 139 | dt = dt || 16 140 | updateAndDrawParticles(dt) 141 | }, 142 | start: function start() { 143 | running = true 144 | lastframe = performance.now() 145 | polyfillAnimFrame(frame) 146 | }, 147 | setPreDrawCallback: function(f) { 148 | preDrawCallback = f 149 | }, 150 | stop: function stop() { 151 | running = false 152 | }, 153 | addsmoke: addParticles, 154 | addSmoke: addParticles, 155 | } 156 | } 157 | 158 | 159 | 160 | /* Magic UMD Boilerplate Ending */ 161 | /**/ 162 | })) -------------------------------------------------------------------------------- /js/util/trim-canvas.js: -------------------------------------------------------------------------------- 1 | // MIT http://rem.mit-license.org 2 | // https://ourcodeworld.com/articles/read/683/how-to-remove-the-transparent-pixels-that-surrounds-a-canvas-in-javascript 3 | function trimCanvas(c) { 4 | var ctx = c.getContext('2d'), 5 | copy = document.createElement('canvas').getContext('2d'), 6 | pixels = ctx.getImageData(0, 0, c.width, c.height), 7 | l = pixels.data.length, 8 | i, 9 | bound = { 10 | top: null, 11 | left: null, 12 | right: null, 13 | bottom: null 14 | }, 15 | x, y; 16 | 17 | // Iterate over every pixel to find the highest 18 | // and where it ends on every axis () 19 | for (i = 0; i < l; i += 4) { 20 | if (pixels.data[i + 3] !== 0) { 21 | x = (i / 4) % c.width; 22 | y = ~~((i / 4) / c.width); 23 | 24 | if (bound.top === null) { 25 | bound.top = y; 26 | } 27 | 28 | if (bound.left === null) { 29 | bound.left = x; 30 | } else if (x < bound.left) { 31 | bound.left = x; 32 | } 33 | 34 | if (bound.right === null) { 35 | bound.right = x; 36 | } else if (bound.right < x) { 37 | bound.right = x; 38 | } 39 | 40 | if (bound.bottom === null) { 41 | bound.bottom = y; 42 | } else if (bound.bottom < y) { 43 | bound.bottom = y; 44 | } 45 | } 46 | } 47 | 48 | // Calculate the height and width of the content 49 | var trimHeight = bound.bottom - bound.top, 50 | trimWidth = bound.right - bound.left, 51 | trimmed = ctx.getImageData(bound.left, bound.top, trimWidth, trimHeight); 52 | 53 | copy.canvas.width = trimWidth; 54 | copy.canvas.height = trimHeight; 55 | copy.putImageData(trimmed, 0, 0); 56 | 57 | // Return trimmed canvas 58 | return copy.canvas; 59 | } -------------------------------------------------------------------------------- /misc/QnA9eZ.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/misc/QnA9eZ.gif -------------------------------------------------------------------------------- /misc/patScreen Shot 2020-10-16 at 11.51.44 PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/misc/patScreen Shot 2020-10-16 at 11.51.44 PM.png -------------------------------------------------------------------------------- /misc/ultpat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/misc/ultpat.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kiddopaint", 3 | "version": "1.0.0", 4 | "description": "Kiddo Paint", 5 | "main": "js/kiddopaint.js", 6 | "devDependencies": { 7 | "uglify-js": "^2.8.29" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/vikrum/kiddopaint.git" 15 | }, 16 | "keywords": [ 17 | "kiddo paint", 18 | "kid pix", 19 | "dr halo", 20 | "macdraw", 21 | "ms paint" 22 | ], 23 | "author": "@vikrum5000", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/vikrum/kiddopaint/issues" 27 | }, 28 | "homepage": "https://github.com/vikrum/kiddopaint#readme", 29 | "dependencies": { 30 | "js-beautify": "^1.13.13", 31 | "uglify-es": "^3.3.10" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /snd/explosion0.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/snd/explosion0.wav -------------------------------------------------------------------------------- /snd/explosion1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/snd/explosion1.wav -------------------------------------------------------------------------------- /snd/explosion2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/snd/explosion2.wav -------------------------------------------------------------------------------- /snd/flood0.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/snd/flood0.wav -------------------------------------------------------------------------------- /snd/flood1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/snd/flood1.wav -------------------------------------------------------------------------------- /snd/oops0.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/snd/oops0.wav -------------------------------------------------------------------------------- /snd/oops1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/snd/oops1.wav -------------------------------------------------------------------------------- /snd/oops2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/snd/oops2.wav -------------------------------------------------------------------------------- /snd/pencil0.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/snd/pencil0.wav -------------------------------------------------------------------------------- /snd/stamp0.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/snd/stamp0.wav -------------------------------------------------------------------------------- /snd/stamp1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/snd/stamp1.wav -------------------------------------------------------------------------------- /static/kiddopaint.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vikrum/kiddopaint/140ca297683db82daedccae321b519f10f3fde0d/static/kiddopaint.jpg --------------------------------------------------------------------------------