├── out ├── .nojekyll ├── CNAME ├── _next │ └── static │ │ ├── webpack │ │ ├── 50f137e5b730c3808796.hot-update.json │ │ ├── 72097f8a1a3485eb75bc.hot-update.json │ │ ├── 90c0da8dede38a567598.hot-update.json │ │ ├── d151289e65a7b9db3e6c.hot-update.json │ │ ├── 0135a06cafde453d7782.hot-update.json │ │ ├── 020ef3ab3494a18d1d64.hot-update.json │ │ ├── 20f155801c7edeceb6ea.hot-update.json │ │ ├── 2311de639d0200380509.hot-update.json │ │ ├── 27303bf247feeaf3f6ef.hot-update.json │ │ ├── 2b8020f80659a997db42.hot-update.json │ │ ├── 3565a3948487df990917.hot-update.json │ │ ├── 372d23d2eb4c83d5308a.hot-update.json │ │ ├── 412f6968e28c05998376.hot-update.json │ │ ├── 4c62c85d8fab59c63b04.hot-update.json │ │ ├── 507ce56a3d0d1fee4683.hot-update.json │ │ ├── 51d5a5ca37b7aab07115.hot-update.json │ │ ├── 54de8703f42adb7ea049.hot-update.json │ │ ├── 570fcc3d59d78bb1009b.hot-update.json │ │ ├── 573c9699eea85a54a2d2.hot-update.json │ │ ├── 5d5310a8df5b0b854d23.hot-update.json │ │ ├── 613fc7b376c414b3771e.hot-update.json │ │ ├── 6718292124d7fd257f10.hot-update.json │ │ ├── 6bc8ce3e16432fdb9a6b.hot-update.json │ │ ├── 788f555dd50502f3b082.hot-update.json │ │ ├── 793da0fa240a79b4a76c.hot-update.json │ │ ├── 7e48d6d768cc8f1696b7.hot-update.json │ │ ├── 7ed215f3bf414812b5a3.hot-update.json │ │ ├── 8427bcf93fb7dad78d07.hot-update.json │ │ ├── 857eb59e87c991ed804c.hot-update.json │ │ ├── 85813ee1fc471524e895.hot-update.json │ │ ├── 86241e80fa583fe6a3fa.hot-update.json │ │ ├── 863c0a5b21096d8f9f24.hot-update.json │ │ ├── 8860c372590c758b6c36.hot-update.json │ │ ├── 89c981e68ddbc4be7e3e.hot-update.json │ │ ├── 90b7fc923a324bbb2283.hot-update.json │ │ ├── 9ae259aef7f3d7a89db1.hot-update.json │ │ ├── 9c7304e422de1036fe83.hot-update.json │ │ ├── 9ffc3b174e1d6049f8e7.hot-update.json │ │ ├── a05e5c928b3a440f8959.hot-update.json │ │ ├── aaf3388a35525454bd40.hot-update.json │ │ ├── ac7cf0870b293c2ad2a4.hot-update.json │ │ ├── af379a3cd729698d9719.hot-update.json │ │ ├── afe0afb53c1842a18ab1.hot-update.json │ │ ├── b8b382158c36b8569b31.hot-update.json │ │ ├── c73de4cde9b0bf8ec266.hot-update.json │ │ ├── d1c135f7c1b85b21c6dc.hot-update.json │ │ ├── ddcd30c6a4684f1f9da7.hot-update.json │ │ ├── eb7d53b695159e476e8f.hot-update.json │ │ ├── ef5999a3260596eaa01a.hot-update.json │ │ ├── f42afce3609948fb1f58.hot-update.json │ │ ├── fe70b607674f7346c241.hot-update.json │ │ ├── fffb9b9e521cff93b2a7.hot-update.json │ │ ├── 37319bc46f35f527f01f.hot-update.json │ │ ├── 3bb02521fb09f1ea0825.hot-update.json │ │ ├── f489aad1bada97b8449c.hot-update.json │ │ └── static │ │ │ └── development │ │ │ └── pages │ │ │ ├── index.js.7e48d6d768cc8f1696b7.hot-update.js.map │ │ │ ├── index.js.3565a3948487df990917.hot-update.js.map │ │ │ ├── index.js.9ffc3b174e1d6049f8e7.hot-update.js.map │ │ │ ├── index.js.8427bcf93fb7dad78d07.hot-update.js.map │ │ │ ├── index.js.5d5310a8df5b0b854d23.hot-update.js.map │ │ │ ├── index.js.d1c135f7c1b85b21c6dc.hot-update.js.map │ │ │ ├── index.js.788f555dd50502f3b082.hot-update.js.map │ │ │ ├── index.js.eb7d53b695159e476e8f.hot-update.js.map │ │ │ ├── index.js.4c62c85d8fab59c63b04.hot-update.js.map │ │ │ └── index.js.7ed215f3bf414812b5a3.hot-update.js.map │ │ ├── chunks │ │ ├── 0.js.map │ │ └── 0.js │ │ ├── runtime │ │ ├── webpack-035ac2b14bde147cb4a8.js │ │ └── main-e41dfaf02b5d8cdab94c.js │ │ ├── Uezz3L_O-5dJ9kwVCFH8K │ │ └── pages │ │ │ ├── _app.js │ │ │ └── _error.js │ │ └── pyt66n4UubC4sowL2krxT │ │ └── pages │ │ ├── _app.js │ │ └── _error.js ├── static │ ├── share.gif │ ├── share.png │ ├── favicon.png │ └── fonts │ │ ├── IBMPlexMono-Regular.woff │ │ └── IBMPlexMono-Regular.woff2 ├── 404.html └── index.html ├── static ├── share.gif ├── share.png ├── favicon.png └── fonts │ ├── IBMPlexMono-Regular.woff │ └── IBMPlexMono-Regular.woff2 ├── README.md ├── parts ├── theme.js └── utils.js ├── .gitignore ├── package.json ├── components └── nav.js └── pages ├── _document.js └── index.js /out/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /out/CNAME: -------------------------------------------------------------------------------- 1 | hex.constraint.systems 2 | -------------------------------------------------------------------------------- /static/share.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/constraint-systems/hex/master/static/share.gif -------------------------------------------------------------------------------- /static/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/constraint-systems/hex/master/static/share.png -------------------------------------------------------------------------------- /out/_next/static/webpack/50f137e5b730c3808796.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"4c62c85d8fab59c63b04","c":{}} -------------------------------------------------------------------------------- /out/_next/static/webpack/72097f8a1a3485eb75bc.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"570fcc3d59d78bb1009b","c":{}} -------------------------------------------------------------------------------- /out/_next/static/webpack/90c0da8dede38a567598.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"3bb02521fb09f1ea0825","c":{}} -------------------------------------------------------------------------------- /out/_next/static/webpack/d151289e65a7b9db3e6c.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"f489aad1bada97b8449c","c":{}} -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/constraint-systems/hex/master/static/favicon.png -------------------------------------------------------------------------------- /out/static/share.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/constraint-systems/hex/master/out/static/share.gif -------------------------------------------------------------------------------- /out/static/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/constraint-systems/hex/master/out/static/share.png -------------------------------------------------------------------------------- /out/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/constraint-systems/hex/master/out/static/favicon.png -------------------------------------------------------------------------------- /out/_next/static/chunks/0.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"static/chunks/0.js","sources":[],"mappings":";;;;;;;;;;;;;;A","sourceRoot":""} -------------------------------------------------------------------------------- /out/_next/static/webpack/0135a06cafde453d7782.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"c17d7a1c2e8708938d00","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/020ef3ab3494a18d1d64.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"7e48d6d768cc8f1696b7","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/20f155801c7edeceb6ea.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"ac7cf0870b293c2ad2a4","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/2311de639d0200380509.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"aaf3388a35525454bd40","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/27303bf247feeaf3f6ef.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"9ffc3b174e1d6049f8e7","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/2b8020f80659a997db42.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"9ae259aef7f3d7a89db1","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/3565a3948487df990917.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"27303bf247feeaf3f6ef","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/372d23d2eb4c83d5308a.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"fe70b607674f7346c241","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/412f6968e28c05998376.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"507ce56a3d0d1fee4683","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/4c62c85d8fab59c63b04.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"5d5310a8df5b0b854d23","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/507ce56a3d0d1fee4683.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"372d23d2eb4c83d5308a","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/51d5a5ca37b7aab07115.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"ddcd30c6a4684f1f9da7","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/54de8703f42adb7ea049.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"857eb59e87c991ed804c","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/570fcc3d59d78bb1009b.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"90b7fc923a324bbb2283","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/573c9699eea85a54a2d2.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"37319bc46f35f527f01f","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/5d5310a8df5b0b854d23.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"d1c135f7c1b85b21c6dc","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/613fc7b376c414b3771e.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"ef5999a3260596eaa01a","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/6718292124d7fd257f10.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"6bc8ce3e16432fdb9a6b","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/6bc8ce3e16432fdb9a6b.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"85813ee1fc471524e895","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/788f555dd50502f3b082.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"20f155801c7edeceb6ea","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/793da0fa240a79b4a76c.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"f42afce3609948fb1f58","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/7e48d6d768cc8f1696b7.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"613fc7b376c414b3771e","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/7ed215f3bf414812b5a3.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"793da0fa240a79b4a76c","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/8427bcf93fb7dad78d07.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"788f555dd50502f3b082","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/857eb59e87c991ed804c.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"51d5a5ca37b7aab07115","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/85813ee1fc471524e895.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"8427bcf93fb7dad78d07","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/86241e80fa583fe6a3fa.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"9c7304e422de1036fe83","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/863c0a5b21096d8f9f24.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"54de8703f42adb7ea049","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/8860c372590c758b6c36.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"6718292124d7fd257f10","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/89c981e68ddbc4be7e3e.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"a05e5c928b3a440f8959","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/90b7fc923a324bbb2283.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"573c9699eea85a54a2d2","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/9ae259aef7f3d7a89db1.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"2311de639d0200380509","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/9c7304e422de1036fe83.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"3565a3948487df990917","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/9ffc3b174e1d6049f8e7.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"7ed215f3bf414812b5a3","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/a05e5c928b3a440f8959.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"2b8020f80659a997db42","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/aaf3388a35525454bd40.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"c73de4cde9b0bf8ec266","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/ac7cf0870b293c2ad2a4.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"afe0afb53c1842a18ab1","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/af379a3cd729698d9719.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"0135a06cafde453d7782","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/afe0afb53c1842a18ab1.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"020ef3ab3494a18d1d64","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/b8b382158c36b8569b31.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"412f6968e28c05998376","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/c73de4cde9b0bf8ec266.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"72097f8a1a3485eb75bc","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/d1c135f7c1b85b21c6dc.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"eb7d53b695159e476e8f","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/ddcd30c6a4684f1f9da7.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"90c0da8dede38a567598","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/eb7d53b695159e476e8f.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"8860c372590c758b6c36","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/ef5999a3260596eaa01a.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"b8b382158c36b8569b31","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/f42afce3609948fb1f58.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"89c981e68ddbc4be7e3e","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/fe70b607674f7346c241.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"86241e80fa583fe6a3fa","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /out/_next/static/webpack/fffb9b9e521cff93b2a7.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"af379a3cd729698d9719","c":{"static/development/pages/index.js":true}} -------------------------------------------------------------------------------- /static/fonts/IBMPlexMono-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/constraint-systems/hex/master/static/fonts/IBMPlexMono-Regular.woff -------------------------------------------------------------------------------- /static/fonts/IBMPlexMono-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/constraint-systems/hex/master/static/fonts/IBMPlexMono-Regular.woff2 -------------------------------------------------------------------------------- /out/static/fonts/IBMPlexMono-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/constraint-systems/hex/master/out/static/fonts/IBMPlexMono-Regular.woff -------------------------------------------------------------------------------- /out/static/fonts/IBMPlexMono-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/constraint-systems/hex/master/out/static/fonts/IBMPlexMono-Regular.woff2 -------------------------------------------------------------------------------- /out/_next/static/webpack/37319bc46f35f527f01f.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"863c0a5b21096d8f9f24","c":{"static/development/pages/next/dist/pages/_error.js":false}} -------------------------------------------------------------------------------- /out/_next/static/webpack/3bb02521fb09f1ea0825.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"d151289e65a7b9db3e6c","c":{"static/development/pages/next/dist/pages/_error.js":false}} -------------------------------------------------------------------------------- /out/_next/static/webpack/f489aad1bada97b8449c.hot-update.json: -------------------------------------------------------------------------------- 1 | {"h":"fffb9b9e521cff93b2a7","c":{"static/development/pages/next/dist/pages/_error.js":false}} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hex 2 | 3 | A keyboard-driven, grid-based drawing tool. 4 | 5 | 6 | 7 | https://hex.constraint.systems/ 8 | 9 | Inspired by [Hundred Rabbits' Noodle](https://github.com/hundredrabbits/noodle). 10 | -------------------------------------------------------------------------------- /parts/theme.js: -------------------------------------------------------------------------------- 1 | let font_size = 14; 2 | let line_height = 1.5; 3 | let lx = font_size * line_height; 4 | 5 | export default { 6 | fonts: { 7 | body: 'IBM Plex Mono', 8 | }, 9 | fontSizes: [font_size], 10 | lineHeights: { 11 | body: line_height, 12 | }, 13 | colors: { 14 | background: '#efefef', 15 | }, 16 | space: [lx, lx / 2, lx / 4, lx / 8], 17 | }; 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | 14 | # production 15 | /build 16 | 17 | # misc 18 | .DS_Store 19 | .env* 20 | 21 | # debug 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /out/_next/static/chunks/0.js: -------------------------------------------------------------------------------- 1 | (window["webpackJsonp"] = window["webpackJsonp"] || []).push([[0],{ 2 | 3 | /***/ "./node_modules/next/dist/client/dev/noop.js": 4 | /*!***************************************************!*\ 5 | !*** ./node_modules/next/dist/client/dev/noop.js ***! 6 | \***************************************************/ 7 | /*! no static exports found */ 8 | /***/ (function(module, exports, __webpack_require__) { 9 | 10 | "use strict"; 11 | 12 | 13 | /***/ }) 14 | 15 | }]); 16 | //# sourceMappingURL=0.js.map -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "etch", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "deploy": "next build && next export && touch out/.nojekyll && touch out/CNAME && echo \"hex.constraint.systems\" >> out/CNAME && git add out/ && git commit -m \"Deploy to gh-pages\" && git subtree push --prefix out origin gh-pages", 9 | "start": "next start" 10 | }, 11 | "dependencies": { 12 | "@emotion/core": "^10.0.17", 13 | "@mdx-js/react": "^1.4.5", 14 | "gh-pages": "^2.1.1", 15 | "next": "9.0.6", 16 | "react": "16.9.0", 17 | "react-dom": "16.9.0", 18 | "theme-ui": "^0.2.43" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /parts/utils.js: -------------------------------------------------------------------------------- 1 | export let requestInterval = function(fn, delay) { 2 | var requestAnimFrame = (function() { 3 | return ( 4 | window.requestAnimationFrame || 5 | function(callback, element) { 6 | window.setTimeout(callback, 1000 / 60); 7 | } 8 | ); 9 | })(), 10 | start = new Date().getTime(), 11 | handle = {}; 12 | function loop() { 13 | handle.value = requestAnimFrame(loop); 14 | var current = new Date().getTime(), 15 | delta = current - start; 16 | if (delta >= delay) { 17 | fn.call(); 18 | start = new Date().getTime(); 19 | } 20 | } 21 | handle.value = requestAnimFrame(loop); 22 | return handle; 23 | }; 24 | -------------------------------------------------------------------------------- /components/nav.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Link from 'next/link' 3 | 4 | const links = [ 5 | { href: 'https://zeit.co/now', label: 'ZEIT' }, 6 | { href: 'https://github.com/zeit/next.js', label: 'GitHub' } 7 | ].map(link => { 8 | link.key = `nav-link-${link.href}-${link.label}` 9 | return link 10 | }) 11 | 12 | const Nav = () => ( 13 | 54 | ) 55 | 56 | export default Nav 57 | -------------------------------------------------------------------------------- /pages/_document.js: -------------------------------------------------------------------------------- 1 | import Document, { Html, Head, Main, NextScript } from 'next/document'; 2 | 3 | class MyDocument extends Document { 4 | static async getInitialProps(ctx) { 5 | const initialProps = await Document.getInitialProps(ctx); 6 | return { ...initialProps }; 7 | } 8 | 9 | render() { 10 | return ( 11 | 12 | 13 | 14 | 18 | 19 | 23 | 24 | 28 | 32 | 33 | 34 | 35 | 36 |
37 | 38 | 39 | 40 | ); 41 | } 42 | } 43 | 44 | export default MyDocument; 45 | -------------------------------------------------------------------------------- /out/_next/static/runtime/webpack-035ac2b14bde147cb4a8.js: -------------------------------------------------------------------------------- 1 | !function(e){function r(r){for(var n,l,f=r[0],i=r[1],a=r[2],c=0,s=[];c

404

This page could not be found.

-------------------------------------------------------------------------------- /out/index.html: -------------------------------------------------------------------------------- 1 | Hex
Hex is a keyboard-driven, grid-based drawing tool.
e toggle mode: drawerase
Draw & move:
asdfrg
hjkl
Special:
w save png  x clear  ? toggle help
-------------------------------------------------------------------------------- /out/_next/static/runtime/main-e41dfaf02b5d8cdab94c.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[5],{"/h46":function(e,t,r){r("cHUd")("Map")},"0IRE":function(e,t,r){"use strict";var n=r("LX0d"),a=r("/HRN"),o=r("WaGi");r("hfKm")(t,"__esModule",{value:!0});var u=function(){function e(t){a(this,e),this.data=new n(t)}return o(e,[{key:"getData",value:function(){return this.data}},{key:"get",value:function(e){return this.data.get(e)}},{key:"set",value:function(e,t){this.data.set(e,t)}},{key:"overwrite",value:function(e){this.data=new n(e)}}]),e}();t.DataManager=u},BMP1:function(e,t,r){"use strict";var n=r("5Uuq")(r("IKlv"));window.next=n,(0,n.default)().catch(function(e){console.error(e.message+"\n"+e.stack)})},DqTX:function(e,t,r){"use strict";var n=r("/HRN"),a=r("WaGi"),o=r("KI45");t.__esModule=!0,t.default=void 0;var u=o(r("eVuF")),i={acceptCharset:"accept-charset",className:"class",htmlFor:"for",httpEquiv:"http-equiv"},c=function(){function e(){var t=this;n(this,e),this.updateHead=function(e){var r=t.updatePromise=u.default.resolve().then(function(){r===t.updatePromise&&(t.updatePromise=null,t.doUpdateHead(e))})},this.updatePromise=null}return a(e,[{key:"doUpdateHead",value:function(e){var t=this,r={};e.forEach(function(e){var t=r[e.type]||[];t.push(e),r[e.type]=t}),this.updateTitle(r.title?r.title[0]:null);["meta","base","link","style","script"].forEach(function(e){t.updateElements(e,r[e]||[])})}},{key:"updateTitle",value:function(e){var t="";if(e){var r=e.props.children;t="string"===typeof r?r:r.join("")}t!==document.title&&(document.title=t)}},{key:"updateElements",value:function(e,t){var r=document.getElementsByTagName("head")[0],n=r.querySelector("meta[name=next-head-count]");for(var a=Number(n.content),o=[],u=0,i=n.previousElementSibling;u0?arguments[0]:void 0)}},{get:function(e){var t=n.getEntry(a(this,"Map"),e);return t&&t.v},set:function(e,t){return n.def(a(this,"Map"),0===e?0:e,t)}},n,!0)},qArv:function(e,t,r){"use strict";var n=r("hfKm"),a=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t.default=e,t};n(t,"__esModule",{value:!0});var o=a(r("q1tI"));t.DataManagerContext=o.createContext(null)},yLiY:function(e,t,r){"use strict";var n;r("hfKm")(t,"__esModule",{value:!0}),t.default=function(){return n},t.setConfig=function(e){n=e}},zmvN:function(e,t,r){"use strict";var n=r("ln6h"),a=r("/HRN"),o=r("WaGi"),u=r("KI45");t.__esModule=!0,t.default=void 0;var i=u(r("+oT+")),c=u(r("eVuF")),s=u(r("dZ6Y"));var p=function(e){try{return e.relList.supports("preload")}catch(t){return!1}}(document.createElement("link"));function f(e){var t=document.createElement("link");t.rel="preload",t.crossOrigin=void 0,t.href=encodeURI(e),t.as="script",document.head.appendChild(t)}var d=function(){function e(t,r){a(this,e),this.buildId=t,this.assetPrefix=r,this.pageCache={},this.pageRegisterEvents=(0,s.default)(),this.loadingRoutes={}}return o(e,[{key:"getDependencies",value:function(e){return this.promisedBuildManifest.then(function(t){return t[e]&&t[e].map(function(e){return"/_next/"+e})||[]})}},{key:"normalizeRoute",value:function(e){if("/"!==e[0])throw new Error('Route name should start with a "/", got "'+e+'"');return"/"===(e=e.replace(/\/index$/,"/"))?e:e.replace(/\/$/,"")}},{key:"loadPage",value:function(e){var t=this;return e=this.normalizeRoute(e),new c.default(function(r,n){var a=t.pageCache[e];if(a){var o=a.error,u=a.page;o?n(o):r(u)}else t.pageRegisterEvents.on(e,function a(o){var u=o.error,i=o.page;t.pageRegisterEvents.off(e,a),delete t.loadingRoutes[e],u?n(u):r(i)}),document.querySelector('script[data-next-page="'+e+'"]')||t.loadingRoutes[e]||(t.loadRoute(e),t.loadingRoutes[e]=!0)})}},{key:"loadRoute",value:function(e){var t=this;return(0,i.default)(n.mark(function r(){var a,o;return n.wrap(function(r){for(;;)switch(r.prev=r.next){case 0:e=t.normalizeRoute(e),a="/"===e?"/index.js":e+".js",o=t.assetPrefix+"/_next/static/"+encodeURIComponent(t.buildId)+"/pages"+a,t.loadScript(o,e,!0);case 4:case"end":return r.stop()}},r)}))()}},{key:"loadScript",value:function(e,t,r){var n=this,a=document.createElement("script");a.crossOrigin=void 0,a.src=encodeURI(e),a.onerror=function(){var r=new Error("Error loading script "+e);r.code="PAGE_LOAD_ERROR",n.pageRegisterEvents.emit(t,{error:r})},document.body.appendChild(a)}},{key:"registerPage",value:function(e,t){var r=this;!function(){try{var n=t(),a={page:n.default||n,mod:n};r.pageCache[e]=a,r.pageRegisterEvents.emit(e,a)}catch(o){r.pageCache[e]={error:o},r.pageRegisterEvents.emit(e,{error:o})}}()}},{key:"prefetch",value:function(e,t){var r=this;return(0,i.default)(n.mark(function a(){var o,u,i;return n.wrap(function(n){for(;;)switch(n.prev=n.next){case 0:if(e=r.normalizeRoute(e),o=("/"===e?"/index":e)+".js",u=t?e:r.assetPrefix+"/_next/static/"+encodeURIComponent(r.buildId)+"/pages"+o,!document.querySelector('link[rel="preload"][href^="'+u+'"], script[data-next-page="'+e+'"]')){n.next=6;break}return n.abrupt("return");case 6:if(!(i=navigator.connection)){n.next=9;break}if(-1===(i.effectiveType||"").indexOf("2g")&&!i.saveData){n.next=9;break}return n.abrupt("return");case 9:n.next=15;break;case 13:n.t0=function(e){r.prefetch(e,!0)},n.sent.forEach(n.t0);case 15:if(!p){n.next=18;break}return f(u),n.abrupt("return");case 18:if(!t){n.next=20;break}return n.abrupt("return");case 20:if("complete"!==document.readyState){n.next=24;break}return n.abrupt("return",r.loadPage(e).catch(function(){}));case 24:return n.abrupt("return",new c.default(function(t){window.addEventListener("load",function(){r.loadPage(e).then(function(){return t()},function(){return t()})})}));case 25:case"end":return n.stop()}},a)}))()}}]),e}();t.default=d}},[["BMP1",1,0]]]); -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | /* @jsx jsx */ 2 | import React, { useState, useEffect, useRef, useCallback } from 'react'; 3 | import Head from 'next/head'; 4 | import theme from '../parts/theme'; 5 | import { jsx } from 'theme-ui'; 6 | import { ThemeProvider } from 'theme-ui'; 7 | import { requestInterval } from '../parts/utils'; 8 | 9 | let fs = theme.fontSizes[0]; 10 | 11 | let once = false; 12 | let size = 14; 13 | 14 | let special_keys = 'x?ew'.split(''); 15 | 16 | Object.fromEntries = arr => 17 | Object.assign({}, ...Array.from(arr, ([k, v]) => ({ [k]: v }))); 18 | 19 | let xp = 4; 20 | let yp = 4; 21 | 22 | const Home = () => { 23 | let [dimensions, setDimensions] = useState([null, null]); 24 | let [mode, setMode] = useState('draw'); 25 | 26 | let canvasRef = useRef(); 27 | let overlayCanvasRef = useRef(); 28 | 29 | let requestRef = useRef(); 30 | let keymap = useRef({}); 31 | let coordinates = useRef([0, 0]); 32 | let vertical = useRef(null); 33 | let horizontal = useRef(null); 34 | let backslash = useRef(null); 35 | let slash = useRef(null); 36 | let [help, toggleHelp] = useState(true); 37 | 38 | function KeyTip(letter) { 39 | return ( 40 | { 43 | keymap.current[letter] = true; 44 | keyAction(letter, false); 45 | keymap.current[letter] = false; 46 | }} 47 | sx={{ 48 | outline: 'solid 1px black', 49 | width: '2ch', 50 | textAlign: 'center', 51 | display: 'inline-block', 52 | userSelect: 'none', 53 | cursor: 'default', 54 | }} 55 | > 56 | {letter} 57 | 58 | ); 59 | } 60 | 61 | function keyAction(key, repeat) { 62 | let canvas_width = Math.floor(canvasRef.current.offsetWidth); 63 | let canvas_height = Math.floor(canvasRef.current.offsetHeight); 64 | 65 | let grid_width = canvas_width - xp * 2 + size; 66 | let grid_height = canvas_height - yp * 2 + size; 67 | 68 | let ctx = canvasRef.current.getContext('2d'); 69 | ctx.fillStyle = 'black'; 70 | 71 | let _mode = mode; 72 | 73 | if (special_keys.includes(key)) { 74 | if (key === 'e' && !repeat) { 75 | if (_mode === 'draw') { 76 | _mode = 'erase'; 77 | setMode(_mode); 78 | } else if (_mode === 'erase') { 79 | _mode = 'draw'; 80 | setMode(_mode); 81 | } 82 | } else if (key === 'x' && !repeat) { 83 | clearGrid(); 84 | } else if (key === 'w' && !repeat) { 85 | let encoded = canvasRef.current.toDataURL('image/png'); 86 | let link = document.createElement('a'); 87 | link.setAttribute('href', encoded); 88 | link.setAttribute('download', 'hex.png'); 89 | link.dispatchEvent( 90 | new MouseEvent(`click`, { 91 | bubbles: true, 92 | cancelable: true, 93 | view: window, 94 | }) 95 | ); 96 | return; 97 | } else if (key === '?' && !repeat) { 98 | toggleHelp(!help); 99 | return; 100 | } 101 | } 102 | 103 | if (key === 'init') { 104 | ctx.fillStyle = 'white'; 105 | ctx.fillRect(0, 0, canvas_width, canvas_height); 106 | } 107 | 108 | let octx = overlayCanvasRef.current.getContext('2d'); 109 | octx.strokeStyle = _mode === 'draw' ? 'limegreen' : 'hotpink'; 110 | let ostroke = 4; 111 | octx.lineWidth = ostroke; 112 | 113 | let current = coordinates.current; 114 | 115 | let inc = size; 116 | let modify = [0, 0]; 117 | if (keymap.current['j']) modify[1] += inc; 118 | if (keymap.current['k']) modify[1] += -inc; 119 | if (keymap.current['h']) modify[0] += -inc; 120 | if (keymap.current['l']) modify[0] += inc; 121 | 122 | let next = [current[0] + modify[0], current[1] + modify[1]]; 123 | 124 | if (next[0] < 0) next[0] = grid_width - size * 2; 125 | if (next[0] >= grid_width - size) next[0] = 0; 126 | if (next[1] < 0) next[1] = grid_height - size * 2; 127 | if (next[1] >= grid_height - size) next[1] = 0; 128 | coordinates.current = next; 129 | 130 | // modify drawing 131 | let c = next[0] / size; 132 | let r = next[1] / size; 133 | 134 | let new_val = _mode === 'draw' ? true : false; 135 | if (keymap.current['a']) { 136 | let index = r * (grid_width / size + 1) + c; 137 | vertical.current[index] = new_val; 138 | } 139 | if (keymap.current['d']) { 140 | let index = (r + 1) * (grid_width / size + 1) + c; 141 | horizontal.current[index] = new_val; 142 | } 143 | if (keymap.current['s']) { 144 | let index = r * (grid_width / size + 1) + c; 145 | horizontal.current[index] = new_val; 146 | } 147 | if (keymap.current['f']) { 148 | let index = r * (grid_width / size + 1) + c + 1; 149 | vertical.current[index] = new_val; 150 | } 151 | if (keymap.current['g']) { 152 | let index = r * (grid_width / size + 1) + c; 153 | backslash.current[index] = new_val; 154 | } 155 | if (keymap.current['r']) { 156 | let index = r * (grid_width / size + 1) + c; 157 | slash.current[index] = new_val; 158 | } 159 | 160 | function moveTo(ctx, x, y) { 161 | ctx.moveTo(x + xp, y + yp); 162 | } 163 | 164 | function lineTo(ctx, x, y) { 165 | ctx.lineTo(x + xp, y + yp); 166 | } 167 | 168 | ctx.fillStyle = 'white'; 169 | ctx.fillRect(0, 0, canvas_width, canvas_height); 170 | 171 | if (vertical.current !== null) { 172 | let va = vertical.current; 173 | let ha = horizontal.current; 174 | let ba = backslash.current; 175 | let sa = slash.current; 176 | 177 | let dc = grid_width / size + 1; 178 | let dr = grid_height / size + 1; 179 | 180 | for (let i = 0; i < va.length; i++) { 181 | let v = va[i]; 182 | let h = ha[i]; 183 | let b = ba[i]; 184 | let s = sa[i]; 185 | 186 | let c = i % dc; 187 | let r = Math.floor(i / dc); 188 | 189 | ctx.beginPath(); 190 | if (v === true) { 191 | moveTo(ctx, c * size, r * size); 192 | lineTo(ctx, c * size, r * size + size); 193 | } 194 | if (h === true) { 195 | moveTo(ctx, c * size, r * size); 196 | lineTo(ctx, c * size + size, r * size); 197 | } 198 | if (b === true) { 199 | moveTo(ctx, c * size + size, r * size + size); 200 | lineTo(ctx, c * size, r * size); 201 | } 202 | if (s === true) { 203 | moveTo(ctx, c * size, r * size + size); 204 | lineTo(ctx, c * size + size, r * size); 205 | } 206 | ctx.stroke(); 207 | } 208 | } 209 | 210 | octx.clearRect(0, 0, window.innerWidth, window.innerHeight); 211 | octx.strokeRect( 212 | coordinates.current[0] - ostroke / 2 + xp, 213 | coordinates.current[1] - ostroke / 2 + yp, 214 | size + ostroke, 215 | size + ostroke 216 | ); 217 | } 218 | 219 | function downHandler(e) { 220 | keymap.current[e.key] = true; 221 | keyAction(e.key, e.repeat); 222 | } 223 | 224 | function upHandler(e) { 225 | keymap.current[e.key] = false; 226 | } 227 | 228 | function clearGrid() { 229 | let canvas_width = canvasRef.current.offsetWidth; 230 | let canvas_height = canvasRef.current.offsetHeight; 231 | 232 | let grid_width = canvas_width - xp * 2 + size; 233 | let grid_height = canvas_height - yp * 2 + size; 234 | 235 | let columns = grid_width / size; 236 | let rows = grid_height / size; 237 | 238 | vertical.current = Array(columns * rows).fill(false); 239 | horizontal.current = vertical.current.slice(); 240 | backslash.current = vertical.current.slice(); 241 | slash.current = vertical.current.slice(); 242 | } 243 | 244 | function setWindowSize() { 245 | let grid_width = Math.floor((window.innerWidth - xp * 2) / size) * size; 246 | let grid_height = Math.floor((window.innerHeight - yp * 2) / size) * size; 247 | 248 | let canvas_width = grid_width + xp * 2; 249 | let canvas_height = grid_height + yp * 2; 250 | 251 | let dpr = window.devicePixelRatio || 1; 252 | 253 | canvasRef.current.width = canvas_width * dpr; 254 | canvasRef.current.height = canvas_height * dpr; 255 | let ctx = canvasRef.current.getContext('2d'); 256 | ctx.scale(dpr, dpr); 257 | 258 | overlayCanvasRef.current.width = canvas_width * dpr; 259 | overlayCanvasRef.current.height = canvas_height * dpr; 260 | let octx = overlayCanvasRef.current.getContext('2d'); 261 | octx.scale(dpr, dpr); 262 | 263 | setDimensions([canvas_width, canvas_height]); 264 | } 265 | 266 | useEffect(() => { 267 | if (dimensions[0] !== null) { 268 | clearGrid(); 269 | } 270 | }, [dimensions]); 271 | 272 | useEffect(() => { 273 | if (!once) { 274 | setWindowSize(); 275 | document.documentElement.className = 'loaded'; 276 | setTimeout(() => { 277 | keyAction('init', false); 278 | }, 0); 279 | once = true; 280 | } 281 | 282 | window.addEventListener('keydown', downHandler); 283 | window.addEventListener('keyup', upHandler); 284 | // Remove event listeners on cleanup 285 | return () => { 286 | window.removeEventListener('keydown', downHandler); 287 | window.removeEventListener('keyup', upHandler); 288 | }; 289 | }, [mode, help]); 290 | 291 | return ( 292 | 293 |
294 | 295 | Hex 296 | 297 | 330 | 342 | 354 |
355 | 356 |
366 |
367 | Hex is a keyboard-driven, grid-based drawing tool. 368 |
369 |
370 |
371 | {KeyTip('e')} toggle mode:{' '} 372 | {['draw', 'erase'].map(m => ( 373 | 385 | {m} 386 | 387 | ))} 388 |
389 |
Draw & move:
390 |
391 |
392 | {[ 393 | [0, 0, 0, size], 394 | [0, 0, size, 0], 395 | [0, size, size, size], 396 | [size, 0, size, size], 397 | [size, 0, 0, size], 398 | [0, 0, size, size], 399 | ].map((c, i) => ( 400 |
408 | 409 | 3 ? 1 : 2} 416 | /> 417 | 418 |
419 | ))} 420 |
421 |
422 | {['←', '↓', '↑', '→'].map(a => ( 423 | 432 | {a} 433 | 434 | ))} 435 |
436 |
437 |
438 |
439 | {KeyTip('a')} 440 | {KeyTip('s')} 441 | {KeyTip('d')} 442 | {KeyTip('f')} 443 | {KeyTip('r')} 444 | {KeyTip('g')} 445 |
446 |
447 | {KeyTip('h')} 448 | {KeyTip('j')} 449 | {KeyTip('k')} 450 | {KeyTip('l')} 451 |
452 |
453 |
459 | Special: 460 |
461 |
462 | {KeyTip('w')} save png  {KeyTip('x')} clear  {KeyTip('?')}{' '} 463 | toggle help 464 |
465 | 470 |
471 |
472 | {help ? null : ( 473 |
480 | {KeyTip('?')} 481 |
482 | )} 483 |
484 | ); 485 | }; 486 | 487 | export default Home; 488 | -------------------------------------------------------------------------------- /out/_next/static/webpack/static/development/pages/index.js.7e48d6d768cc8f1696b7.hot-update.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"static/webpack/static/development/pages/index.js.7e48d6d768cc8f1696b7.hot-update.js","sources":["webpack:///./pages/index.js"],"sourcesContent":["/* @jsx jsx */\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport Head from 'next/head';\nimport theme from '../parts/theme';\nimport { jsx } from 'theme-ui';\nimport { ThemeProvider } from 'theme-ui';\nimport { requestInterval } from '../parts/utils';\n\nlet fs = theme.fontSizes[0];\n\nlet once = false;\nlet size = 14;\n\nlet special_keys = 'x?ew'.split('');\n\nObject.fromEntries = arr =>\n Object.assign({}, ...Array.from(arr, ([k, v]) => ({ [k]: v })));\n\nlet xp = 4;\nlet yp = 4;\n\nconst Home = () => {\n let [dimensions, setDimensions] = useState([null, null]);\n let [mode, setMode] = useState('draw');\n\n let canvasRef = useRef();\n let overlayCanvasRef = useRef();\n\n let requestRef = useRef();\n let keymap = useRef({});\n let coordinates = useRef([0, 0]);\n let vertical = useRef(null);\n let horizontal = useRef(null);\n let backslash = useRef(null);\n let slash = useRef(null);\n let [help, toggleHelp] = useState(true);\n\n function KeyTip(letter) {\n return (\n {\n keymap.current[letter] = true;\n keyAction(letter, false);\n keymap.current[letter] = false;\n }}\n sx={{\n outline: 'solid 1px black',\n width: '2ch',\n textAlign: 'center',\n display: 'inline-block',\n userSelect: 'none',\n cursor: 'default',\n }}\n >\n {letter}\n \n );\n }\n\n function keyAction(key, repeat) {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let ctx = canvasRef.current.getContext('2d');\n ctx.fillStyle = 'black';\n\n let _mode = mode;\n\n if (special_keys.includes(key)) {\n if (key === 'e' && !repeat) {\n if (_mode === 'draw') {\n _mode = 'erase';\n setMode(_mode);\n } else if (_mode === 'erase') {\n _mode = 'draw';\n setMode(_mode);\n }\n } else if (key === 'x' && !repeat) {\n clearGrid();\n } else if (key === 'w' && !repeat) {\n let encoded = canvasRef.current.toDataURL('image/png');\n let link = document.createElement('a');\n link.setAttribute('href', encoded);\n link.setAttribute('download', 'etch.png');\n link.dispatchEvent(\n new MouseEvent(`click`, {\n bubbles: true,\n cancelable: true,\n view: window,\n })\n );\n return;\n } else if (key === '?' && !repeat) {\n toggleHelp(!help);\n return;\n }\n }\n\n if (key === 'init') {\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas_width, canvas_height);\n }\n\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.strokeStyle = _mode === 'draw' ? 'limegreen' : 'hotpink';\n let ostroke = 4;\n octx.lineWidth = ostroke;\n\n let current = coordinates.current;\n\n let inc = size;\n let modify = [0, 0];\n if (keymap.current['j']) modify[1] += inc;\n if (keymap.current['k']) modify[1] += -inc;\n if (keymap.current['h']) modify[0] += -inc;\n if (keymap.current['l']) modify[0] += inc;\n\n let next = [current[0] + modify[0], current[1] + modify[1]];\n\n if (next[0] < 0) next[0] = grid_width - size * 2;\n if (next[0] >= grid_width - size) next[0] = 0;\n if (next[1] < 0) next[1] = grid_height - size * 2;\n if (next[1] >= grid_height - size) next[1] = 0;\n coordinates.current = next;\n\n // modify drawing\n let c = next[0] / size;\n let r = next[1] / size;\n\n let new_val = _mode === 'draw' ? true : false;\n if (keymap.current['a']) {\n let index = r * (grid_width / size + 1) + c;\n vertical.current[index] = new_val;\n }\n if (keymap.current['d']) {\n let index = (r + 1) * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['s']) {\n let index = r * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['f']) {\n let index = r * (grid_width / size + 1) + c + 1;\n vertical.current[index] = new_val;\n }\n if (keymap.current['g']) {\n let index = r * (grid_width / size + 1) + c;\n backslash.current[index] = new_val;\n }\n if (keymap.current['r']) {\n let index = r * (grid_width / size + 1) + c;\n slash.current[index] = new_val;\n }\n\n function moveTo(ctx, x, y) {\n ctx.moveTo(x + xp, y + yp);\n }\n\n function lineTo(ctx, x, y) {\n ctx.lineTo(x + xp, y + yp);\n }\n\n ctx.clearRect(0, 0, canvas_width, canvas_height);\n\n if (vertical.current !== null) {\n let va = vertical.current;\n let ha = horizontal.current;\n let ba = backslash.current;\n let sa = slash.current;\n\n let dc = grid_width / size + 1;\n let dr = grid_height / size + 1;\n\n for (let i = 0; i < va.length; i++) {\n let v = va[i];\n let h = ha[i];\n let b = ba[i];\n let s = sa[i];\n\n let c = i % dc;\n let r = Math.floor(i / dc);\n\n ctx.beginPath();\n if (v === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size, r * size + size);\n }\n if (h === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size + size, r * size);\n }\n if (b === true) {\n moveTo(ctx, c * size + size, r * size + size);\n lineTo(ctx, c * size, r * size);\n }\n if (s === true) {\n moveTo(ctx, c * size, r * size + size);\n lineTo(ctx, c * size + size, r * size);\n }\n ctx.stroke();\n }\n }\n\n octx.clearRect(0, 0, window.innerWidth, window.innerHeight);\n octx.strokeRect(\n coordinates.current[0] - ostroke / 2 + xp,\n coordinates.current[1] - ostroke / 2 + yp,\n size + ostroke,\n size + ostroke\n );\n }\n\n function downHandler(e) {\n keymap.current[e.key] = true;\n keyAction(e.key, e.repeat);\n }\n\n function upHandler(e) {\n keymap.current[e.key] = false;\n }\n\n function clearGrid() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let columns = grid_width / size + 1;\n let rows = grid_height / size + 1;\n\n vertical.current = Array(columns * rows).fill(false);\n horizontal.current = vertical.current.slice();\n backslash.current = vertical.current.slice();\n slash.current = vertical.current.slice();\n }\n\n function setWindowSize() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n clearGrid();\n\n let dpr = window.devicePixelRatio || 1;\n\n canvasRef.current.width = canvas_width * dpr;\n canvasRef.current.height = canvas_height * dpr;\n let ctx = canvasRef.current.getContext('2d');\n ctx.scale(dpr, dpr);\n\n overlayCanvasRef.current.width = canvas_width * dpr;\n overlayCanvasRef.current.height = canvas_height * dpr;\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.scale(dpr, dpr);\n\n setDimensions([canvas_width, canvas_height]);\n }\n\n useEffect(() => {\n if (!once) {\n setWindowSize();\n setTimeout(() => {\n keyAction('init', false);\n }, 0);\n once = true;\n }\n\n window.addEventListener('keydown', downHandler);\n window.addEventListener('keyup', upHandler);\n // Remove event listeners on cleanup\n return () => {\n window.removeEventListener('keydown', downHandler);\n window.removeEventListener('keyup', upHandler);\n };\n }, [mode, help]);\n\n return (\n \n
\n \n Hex\n \n \n \n \n
\n\n \n
\n Hex is a keyboard-driven, grid-based drawing tool.\n
\n
\n
\n {KeyTip('e')} toggle mode:{' '}\n {['draw', 'erase'].map(m => (\n \n {m}\n \n ))}\n
\n
Draw & move:
\n
\n
\n {[\n [0, 0, 0, size],\n [0, 0, size, 0],\n [0, size, size, size],\n [size, 0, size, size],\n [size, 0, 0, size],\n [0, 0, size, size],\n ].map((c, i) => (\n \n \n 3 ? 1 : 2}\n />\n \n
\n ))}\n
\n
\n {['←', '↓', '↑', '→'].map(a => (\n \n {a}\n \n ))}\n
\n
\n
\n
\n {KeyTip('a')}\n {KeyTip('s')}\n {KeyTip('d')}\n {KeyTip('f')}\n {KeyTip('r')}\n {KeyTip('g')}\n
\n
\n {KeyTip('h')}\n {KeyTip('j')}\n {KeyTip('k')}\n {KeyTip('l')}\n
\n
\n \n Special:\n \n
\n {KeyTip('w')} save png  {KeyTip('x')} clear  {KeyTip('?')}{' '}\n toggle help\n
\n \n \n {help ? null : (\n \n {KeyTip('?')}\n \n )}\n
\n );\n};\n\nexport default Home;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AADA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAdA;AAAA;AAAA;AACA;AAeA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAPA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAHA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAoCA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAPA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AARA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AADA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAiBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AACA;AACA;AACA;AACA;AAHA;AAFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AANA;AAAA;AAAA;AAAA;AAAA;AAAA;AAVA;AAsBA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAHA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAeA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AAFA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAHA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;;;;A","sourceRoot":""} -------------------------------------------------------------------------------- /out/_next/static/webpack/static/development/pages/index.js.3565a3948487df990917.hot-update.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"static/webpack/static/development/pages/index.js.3565a3948487df990917.hot-update.js","sources":["webpack:///./pages/index.js"],"sourcesContent":["/* @jsx jsx */\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport Head from 'next/head';\nimport theme from '../parts/theme';\nimport { jsx } from 'theme-ui';\nimport { ThemeProvider } from 'theme-ui';\nimport { requestInterval } from '../parts/utils';\n\nlet fs = theme.fontSizes[0];\n\nlet once = false;\nlet size = 14;\n\nlet special_keys = 'x?ew'.split('');\n\nObject.fromEntries = arr =>\n Object.assign({}, ...Array.from(arr, ([k, v]) => ({ [k]: v })));\n\nlet xp = 4;\nlet yp = 4;\n\nconst Home = () => {\n let [dimensions, setDimensions] = useState([null, null]);\n let [mode, setMode] = useState('draw');\n\n let canvasRef = useRef();\n let overlayCanvasRef = useRef();\n\n let requestRef = useRef();\n let keymap = useRef({});\n let coordinates = useRef([0, 0]);\n let vertical = useRef(null);\n let horizontal = useRef(null);\n let backslash = useRef(null);\n let slash = useRef(null);\n let [help, toggleHelp] = useState(true);\n\n function KeyTip(letter) {\n return (\n {\n keymap.current[letter] = true;\n keyAction(letter, false);\n keymap.current[letter] = false;\n }}\n sx={{\n outline: 'solid 1px black',\n width: '2ch',\n textAlign: 'center',\n display: 'inline-block',\n userSelect: 'none',\n cursor: 'default',\n }}\n >\n {letter}\n \n );\n }\n\n function keyAction(key, repeat) {\n let canvas_width = Math.floor(canvasRef.current.offsetWidth);\n let canvas_height = Math.floor(canvasRef.current.offsetHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let ctx = canvasRef.current.getContext('2d');\n ctx.fillStyle = 'black';\n\n let _mode = mode;\n\n if (special_keys.includes(key)) {\n if (key === 'e' && !repeat) {\n if (_mode === 'draw') {\n _mode = 'erase';\n setMode(_mode);\n } else if (_mode === 'erase') {\n _mode = 'draw';\n setMode(_mode);\n }\n } else if (key === 'x' && !repeat) {\n clearGrid();\n } else if (key === 'w' && !repeat) {\n let encoded = canvasRef.current.toDataURL('image/png');\n let link = document.createElement('a');\n link.setAttribute('href', encoded);\n link.setAttribute('download', 'etch.png');\n link.dispatchEvent(\n new MouseEvent(`click`, {\n bubbles: true,\n cancelable: true,\n view: window,\n })\n );\n return;\n } else if (key === '?' && !repeat) {\n toggleHelp(!help);\n return;\n }\n }\n\n if (key === 'init') {\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas_width, canvas_height);\n }\n\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.strokeStyle = _mode === 'draw' ? 'limegreen' : 'hotpink';\n let ostroke = 4;\n octx.lineWidth = ostroke;\n\n let current = coordinates.current;\n\n let inc = size;\n let modify = [0, 0];\n if (keymap.current['j']) modify[1] += inc;\n if (keymap.current['k']) modify[1] += -inc;\n if (keymap.current['h']) modify[0] += -inc;\n if (keymap.current['l']) modify[0] += inc;\n\n let next = [current[0] + modify[0], current[1] + modify[1]];\n\n if (next[0] < 0) next[0] = grid_width - size * 2;\n if (next[0] >= grid_width - size) next[0] = 0;\n if (next[1] < 0) next[1] = grid_height - size * 2;\n if (next[1] >= grid_height - size) next[1] = 0;\n coordinates.current = next;\n\n // modify drawing\n let c = next[0] / size;\n let r = next[1] / size;\n\n let new_val = _mode === 'draw' ? true : false;\n if (keymap.current['a']) {\n let index = r * (grid_width / size + 1) + c;\n vertical.current[index] = new_val;\n }\n if (keymap.current['d']) {\n let index = (r + 1) * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['s']) {\n let index = r * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['f']) {\n let index = r * (grid_width / size + 1) + c + 1;\n vertical.current[index] = new_val;\n }\n if (keymap.current['g']) {\n let index = r * (grid_width / size + 1) + c;\n backslash.current[index] = new_val;\n }\n if (keymap.current['r']) {\n let index = r * (grid_width / size + 1) + c;\n slash.current[index] = new_val;\n }\n\n function moveTo(ctx, x, y) {\n ctx.moveTo(x + xp, y + yp);\n }\n\n function lineTo(ctx, x, y) {\n ctx.lineTo(x + xp, y + yp);\n }\n\n ctx.clearRect(0, 0, canvas_width, canvas_height);\n\n if (vertical.current !== null) {\n let va = vertical.current;\n let ha = horizontal.current;\n let ba = backslash.current;\n let sa = slash.current;\n\n let dc = grid_width / size + 1;\n let dr = grid_height / size + 1;\n\n for (let i = 0; i < va.length; i++) {\n let v = va[i];\n let h = ha[i];\n let b = ba[i];\n let s = sa[i];\n\n let c = i % dc;\n let r = Math.floor(i / dc);\n\n ctx.beginPath();\n if (v === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size, r * size + size);\n }\n if (h === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size + size, r * size);\n }\n if (b === true) {\n moveTo(ctx, c * size + size, r * size + size);\n lineTo(ctx, c * size, r * size);\n }\n if (s === true) {\n moveTo(ctx, c * size, r * size + size);\n lineTo(ctx, c * size + size, r * size);\n }\n ctx.stroke();\n }\n }\n\n octx.clearRect(0, 0, window.innerWidth, window.innerHeight);\n octx.strokeRect(\n coordinates.current[0] - ostroke / 2 + xp,\n coordinates.current[1] - ostroke / 2 + yp,\n size + ostroke,\n size + ostroke\n );\n }\n\n function downHandler(e) {\n keymap.current[e.key] = true;\n keyAction(e.key, e.repeat);\n }\n\n function upHandler(e) {\n keymap.current[e.key] = false;\n }\n\n function clearGrid() {\n let canvas_width = Math.floor(canvasRef.current.offsetWidth);\n let canvas_height = Math.floor(canvasRef.current.offsetHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let columns = grid_width / size + 1;\n let rows = grid_height / size + 1;\n\n vertical.current = Array(columns * rows).fill(false);\n horizontal.current = vertical.current.slice();\n backslash.current = vertical.current.slice();\n slash.current = vertical.current.slice();\n }\n\n function setWindowSize() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let dpr = window.devicePixelRatio || 1;\n\n canvasRef.current.width = canvas_width * dpr;\n canvasRef.current.height = canvas_height * dpr;\n let ctx = canvasRef.current.getContext('2d');\n ctx.scale(dpr, dpr);\n\n overlayCanvasRef.current.width = canvas_width * dpr;\n overlayCanvasRef.current.height = canvas_height * dpr;\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.scale(dpr, dpr);\n\n clearGrid();\n\n setDimensions([canvas_width, canvas_height]);\n }\n\n useEffect(() => {\n if (!once) {\n setWindowSize();\n setTimeout(() => {\n keyAction('init', false);\n }, 0);\n once = true;\n }\n\n window.addEventListener('keydown', downHandler);\n window.addEventListener('keyup', upHandler);\n // Remove event listeners on cleanup\n return () => {\n window.removeEventListener('keydown', downHandler);\n window.removeEventListener('keyup', upHandler);\n };\n }, [mode, help]);\n\n return (\n \n
\n \n Hex\n \n \n \n \n
\n\n \n
\n Hex is a keyboard-driven, grid-based drawing tool.\n
\n
\n
\n {KeyTip('e')} toggle mode:{' '}\n {['draw', 'erase'].map(m => (\n \n {m}\n \n ))}\n
\n
Draw & move:
\n
\n
\n {[\n [0, 0, 0, size],\n [0, 0, size, 0],\n [0, size, size, size],\n [size, 0, size, size],\n [size, 0, 0, size],\n [0, 0, size, size],\n ].map((c, i) => (\n \n \n 3 ? 1 : 2}\n />\n \n
\n ))}\n
\n
\n {['←', '↓', '↑', '→'].map(a => (\n \n {a}\n \n ))}\n
\n
\n
\n
\n {KeyTip('a')}\n {KeyTip('s')}\n {KeyTip('d')}\n {KeyTip('f')}\n {KeyTip('r')}\n {KeyTip('g')}\n
\n
\n {KeyTip('h')}\n {KeyTip('j')}\n {KeyTip('k')}\n {KeyTip('l')}\n
\n
\n \n Special:\n \n
\n {KeyTip('w')} save png  {KeyTip('x')} clear  {KeyTip('?')}{' '}\n toggle help\n
\n \n \n {help ? null : (\n \n {KeyTip('?')}\n \n )}\n
\n );\n};\n\nexport default Home;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AADA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAdA;AAAA;AAAA;AACA;AAeA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAPA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAHA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAmCA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAPA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AARA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AADA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAiBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AACA;AACA;AACA;AACA;AAHA;AAFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AANA;AAAA;AAAA;AAAA;AAAA;AAAA;AAVA;AAsBA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAHA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAeA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AAFA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAHA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;;;;A","sourceRoot":""} -------------------------------------------------------------------------------- /out/_next/static/webpack/static/development/pages/index.js.9ffc3b174e1d6049f8e7.hot-update.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"static/webpack/static/development/pages/index.js.9ffc3b174e1d6049f8e7.hot-update.js","sources":["webpack:///./pages/index.js"],"sourcesContent":["/* @jsx jsx */\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport Head from 'next/head';\nimport theme from '../parts/theme';\nimport { jsx } from 'theme-ui';\nimport { ThemeProvider } from 'theme-ui';\nimport { requestInterval } from '../parts/utils';\n\nlet fs = theme.fontSizes[0];\n\nlet once = false;\nlet size = 14;\n\nlet special_keys = 'x?ew'.split('');\n\nObject.fromEntries = arr =>\n Object.assign({}, ...Array.from(arr, ([k, v]) => ({ [k]: v })));\n\nlet xp = 4;\nlet yp = 4;\n\nconst Home = () => {\n let [dimensions, setDimensions] = useState([null, null]);\n let [mode, setMode] = useState('draw');\n\n let canvasRef = useRef();\n let overlayCanvasRef = useRef();\n\n let requestRef = useRef();\n let keymap = useRef({});\n let coordinates = useRef([0, 0]);\n let vertical = useRef(null);\n let horizontal = useRef(null);\n let backslash = useRef(null);\n let slash = useRef(null);\n let [help, toggleHelp] = useState(true);\n\n function KeyTip(letter) {\n return (\n {\n keymap.current[letter] = true;\n keyAction(letter, false);\n keymap.current[letter] = false;\n }}\n sx={{\n outline: 'solid 1px black',\n width: '2ch',\n textAlign: 'center',\n display: 'inline-block',\n userSelect: 'none',\n cursor: 'default',\n }}\n >\n {letter}\n \n );\n }\n\n function keyAction(key, repeat) {\n let canvas_width = Math.floor(canvasRef.current.offsetWidth);\n let canvas_height = Math.floor(canvasRef.current.offsetHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let ctx = canvasRef.current.getContext('2d');\n ctx.fillStyle = 'black';\n\n let _mode = mode;\n\n if (special_keys.includes(key)) {\n if (key === 'e' && !repeat) {\n if (_mode === 'draw') {\n _mode = 'erase';\n setMode(_mode);\n } else if (_mode === 'erase') {\n _mode = 'draw';\n setMode(_mode);\n }\n } else if (key === 'x' && !repeat) {\n clearGrid();\n } else if (key === 'w' && !repeat) {\n let encoded = canvasRef.current.toDataURL('image/png');\n let link = document.createElement('a');\n link.setAttribute('href', encoded);\n link.setAttribute('download', 'etch.png');\n link.dispatchEvent(\n new MouseEvent(`click`, {\n bubbles: true,\n cancelable: true,\n view: window,\n })\n );\n return;\n } else if (key === '?' && !repeat) {\n toggleHelp(!help);\n return;\n }\n }\n\n if (key === 'init') {\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas_width, canvas_height);\n }\n\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.strokeStyle = _mode === 'draw' ? 'limegreen' : 'hotpink';\n let ostroke = 4;\n octx.lineWidth = ostroke;\n\n let current = coordinates.current;\n\n let inc = size;\n let modify = [0, 0];\n if (keymap.current['j']) modify[1] += inc;\n if (keymap.current['k']) modify[1] += -inc;\n if (keymap.current['h']) modify[0] += -inc;\n if (keymap.current['l']) modify[0] += inc;\n\n let next = [current[0] + modify[0], current[1] + modify[1]];\n\n if (next[0] < 0) next[0] = grid_width - size * 2;\n if (next[0] >= grid_width - size) next[0] = 0;\n if (next[1] < 0) next[1] = grid_height - size * 2;\n if (next[1] >= grid_height - size) next[1] = 0;\n coordinates.current = next;\n\n // modify drawing\n let c = next[0] / size;\n let r = next[1] / size;\n\n let new_val = _mode === 'draw' ? true : false;\n if (keymap.current['a']) {\n let index = r * (grid_width / size + 1) + c;\n vertical.current[index] = new_val;\n }\n if (keymap.current['d']) {\n let index = (r + 1) * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['s']) {\n let index = r * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['f']) {\n let index = r * (grid_width / size + 1) + c + 1;\n vertical.current[index] = new_val;\n }\n if (keymap.current['g']) {\n let index = r * (grid_width / size + 1) + c;\n backslash.current[index] = new_val;\n }\n if (keymap.current['r']) {\n let index = r * (grid_width / size + 1) + c;\n slash.current[index] = new_val;\n }\n\n function moveTo(ctx, x, y) {\n ctx.moveTo(x + xp, y + yp);\n }\n\n function lineTo(ctx, x, y) {\n ctx.lineTo(x + xp, y + yp);\n }\n\n ctx.clearRect(0, 0, canvas_width, canvas_height);\n\n if (vertical.current !== null) {\n let va = vertical.current;\n let ha = horizontal.current;\n let ba = backslash.current;\n let sa = slash.current;\n\n let dc = grid_width / size + 1;\n let dr = grid_height / size + 1;\n\n for (let i = 0; i < va.length; i++) {\n let v = va[i];\n let h = ha[i];\n let b = ba[i];\n let s = sa[i];\n\n let c = i % dc;\n let r = Math.floor(i / dc);\n\n ctx.beginPath();\n if (v === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size, r * size + size);\n }\n if (h === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size + size, r * size);\n }\n if (b === true) {\n moveTo(ctx, c * size + size, r * size + size);\n lineTo(ctx, c * size, r * size);\n }\n if (s === true) {\n moveTo(ctx, c * size, r * size + size);\n lineTo(ctx, c * size + size, r * size);\n }\n ctx.stroke();\n }\n }\n\n octx.clearRect(0, 0, window.innerWidth, window.innerHeight);\n octx.strokeRect(\n coordinates.current[0] - ostroke / 2 + xp,\n coordinates.current[1] - ostroke / 2 + yp,\n size + ostroke,\n size + ostroke\n );\n }\n\n function downHandler(e) {\n keymap.current[e.key] = true;\n keyAction(e.key, e.repeat);\n }\n\n function upHandler(e) {\n keymap.current[e.key] = false;\n }\n\n function clearGrid() {\n let canvas_width = Math.floor(canvasRef.current.offsetWidth);\n let canvas_height = Math.floor(canvasRef.current.offsetHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let columns = grid_width / size + 1;\n let rows = grid_height / size + 1;\n\n vertical.current = Array(columns * rows).fill(false);\n horizontal.current = vertical.current.slice();\n backslash.current = vertical.current.slice();\n slash.current = vertical.current.slice();\n }\n\n function setWindowSize() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let dpr = window.devicePixelRatio || 1;\n\n canvasRef.current.width = canvas_width * dpr;\n canvasRef.current.height = canvas_height * dpr;\n let ctx = canvasRef.current.getContext('2d');\n ctx.scale(dpr, dpr);\n\n overlayCanvasRef.current.width = canvas_width * dpr;\n overlayCanvasRef.current.height = canvas_height * dpr;\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.scale(dpr, dpr);\n\n clearGrid();\n\n setDimensions([canvas_width, canvas_height]);\n }\n\n useEffect(() => {\n if (!once) {\n setWindowSize();\n setTimeout(() => {\n keyAction('init', false);\n }, 0);\n once = true;\n }\n\n window.addEventListener('keydown', downHandler);\n window.addEventListener('keyup', upHandler);\n // Remove event listeners on cleanup\n return () => {\n window.removeEventListener('keydown', downHandler);\n window.removeEventListener('keyup', upHandler);\n };\n }, [mode, help]);\n\n return (\n \n
\n \n Hex\n \n \n \n \n
\n\n \n
\n Hex is a keyboard-driven, grid-based drawing tool.\n
\n
\n
\n {KeyTip('e')} toggle mode:{' '}\n {['draw', 'erase'].map(m => (\n \n {m}\n \n ))}\n
\n
Draw & move:
\n
\n
\n {[\n [0, 0, 0, size],\n [0, 0, size, 0],\n [0, size, size, size],\n [size, 0, size, size],\n [size, 0, 0, size],\n [0, 0, size, size],\n ].map((c, i) => (\n \n \n 3 ? 1 : 2}\n />\n \n
\n ))}\n
\n
\n {['←', '↓', '↑', '→'].map(a => (\n \n {a}\n \n ))}\n
\n
\n
\n
\n {KeyTip('a')}\n {KeyTip('s')}\n {KeyTip('d')}\n {KeyTip('f')}\n {KeyTip('r')}\n {KeyTip('g')}\n
\n
\n {KeyTip('h')}\n {KeyTip('j')}\n {KeyTip('k')}\n {KeyTip('l')}\n
\n
\n \n Special:\n \n
\n {KeyTip('w')} save png  {KeyTip('x')} clear  {KeyTip('?')}{' '}\n toggle help\n
\n \n \n {help ? null : (\n \n {KeyTip('?')}\n \n )}\n
\n );\n};\n\nexport default Home;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AADA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAdA;AAAA;AAAA;AACA;AAeA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAPA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAHA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAoCA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AARA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AADA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAiBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AACA;AACA;AACA;AACA;AAHA;AAFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AANA;AAAA;AAAA;AAAA;AAAA;AAAA;AAVA;AAsBA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAHA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAeA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AAFA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAHA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;;;;A","sourceRoot":""} -------------------------------------------------------------------------------- /out/_next/static/webpack/static/development/pages/index.js.8427bcf93fb7dad78d07.hot-update.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"static/webpack/static/development/pages/index.js.8427bcf93fb7dad78d07.hot-update.js","sources":["webpack:///./pages/index.js"],"sourcesContent":["/* @jsx jsx */\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport Head from 'next/head';\nimport theme from '../parts/theme';\nimport { jsx } from 'theme-ui';\nimport { ThemeProvider } from 'theme-ui';\nimport { requestInterval } from '../parts/utils';\n\nlet fs = theme.fontSizes[0];\n\nlet once = false;\nlet size = 14;\n\nlet special_keys = 'x?ew'.split('');\n\nObject.fromEntries = arr =>\n Object.assign({}, ...Array.from(arr, ([k, v]) => ({ [k]: v })));\n\nlet xp = 4;\nlet yp = 4;\n\nconst Home = () => {\n let [dimensions, setDimensions] = useState([null, null]);\n let [mode, setMode] = useState('draw');\n\n let canvasRef = useRef();\n let overlayCanvasRef = useRef();\n\n let requestRef = useRef();\n let keymap = useRef({});\n let coordinates = useRef([0, 0]);\n let vertical = useRef(null);\n let horizontal = useRef(null);\n let backslash = useRef(null);\n let slash = useRef(null);\n let [help, toggleHelp] = useState(true);\n\n function KeyTip(letter) {\n return (\n {\n keymap.current[letter] = true;\n keyAction(letter, false);\n keymap.current[letter] = false;\n }}\n sx={{\n outline: 'solid 1px black',\n width: '2ch',\n textAlign: 'center',\n display: 'inline-block',\n userSelect: 'none',\n cursor: 'default',\n }}\n >\n {letter}\n \n );\n }\n\n function keyAction(key, repeat) {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let ctx = canvasRef.current.getContext('2d');\n ctx.fillStyle = 'black';\n\n let _mode = mode;\n\n if (special_keys.includes(key)) {\n if (key === 'e' && !repeat) {\n if (_mode === 'draw') {\n _mode = 'erase';\n setMode(_mode);\n } else if (_mode === 'erase') {\n _mode = 'draw';\n setMode(_mode);\n }\n } else if (key === 'x' && !repeat) {\n clearGrid();\n } else if (key === 'w' && !repeat) {\n let encoded = canvasRef.current.toDataURL('image/png');\n let link = document.createElement('a');\n link.setAttribute('href', encoded);\n link.setAttribute('download', 'etch.png');\n link.dispatchEvent(\n new MouseEvent(`click`, {\n bubbles: true,\n cancelable: true,\n view: window,\n })\n );\n return;\n } else if (key === '?' && !repeat) {\n toggleHelp(!help);\n return;\n }\n }\n\n if (key === 'init') {\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas_width, canvas_height);\n }\n\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.strokeStyle = _mode === 'draw' ? 'limegreen' : 'hotpink';\n let ostroke = 4;\n octx.lineWidth = ostroke;\n\n let current = coordinates.current;\n\n let inc = size;\n let modify = [0, 0];\n if (keymap.current['j']) modify[1] += inc;\n if (keymap.current['k']) modify[1] += -inc;\n if (keymap.current['h']) modify[0] += -inc;\n if (keymap.current['l']) modify[0] += inc;\n\n let next = [current[0] + modify[0], current[1] + modify[1]];\n if (next[0] < 0) next[0] = grid_width - size;\n if (next[0] >= grid_width) next[0] = 0;\n if (next[1] < 0) next[1] = grid_height - size;\n if (next[1] >= grid_height) next[1] = 0;\n coordinates.current = next;\n\n console.log(coordinates.current);\n\n // modify drawing\n let c = next[0] / size;\n let r = next[1] / size;\n\n let new_val = _mode === 'draw' ? true : false;\n if (keymap.current['a']) {\n let index = r * (grid_width / size + 1) + c;\n vertical.current[index] = new_val;\n }\n if (keymap.current['d']) {\n let index = (r + 1) * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['s']) {\n let index = r * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['f']) {\n let index = r * (grid_width / size + 1) + c + 1;\n vertical.current[index] = new_val;\n }\n if (keymap.current['g']) {\n let index = r * (grid_width / size + 1) + c;\n backslash.current[index] = new_val;\n }\n if (keymap.current['r']) {\n let index = r * (grid_width / size + 1) + c;\n slash.current[index] = new_val;\n }\n\n function moveTo(ctx, x, y) {\n ctx.moveTo(x + xp, y + yp);\n }\n\n function lineTo(ctx, x, y) {\n ctx.lineTo(x + xp, y + yp);\n }\n\n ctx.clearRect(0, 0, canvas_width, canvas_height);\n\n if (vertical.current !== null) {\n let va = vertical.current;\n let ha = horizontal.current;\n let ba = backslash.current;\n let sa = slash.current;\n\n let dc = grid_width / size + 1;\n let dr = grid_height / size + 1;\n\n for (let i = 0; i < va.length; i++) {\n let v = va[i];\n let h = ha[i];\n let b = ba[i];\n let s = sa[i];\n\n let c = i % dc;\n let r = Math.floor(i / dc);\n\n ctx.beginPath();\n if (v === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size, r * size + size);\n }\n if (h === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size + size, r * size);\n }\n if (b === true) {\n moveTo(ctx, c * size + size, r * size + size);\n lineTo(ctx, c * size, r * size);\n }\n if (s === true) {\n moveTo(ctx, c * size, r * size + size);\n lineTo(ctx, c * size + size, r * size);\n }\n ctx.stroke();\n }\n }\n\n octx.clearRect(0, 0, window.innerWidth, window.innerHeight);\n octx.strokeRect(\n coordinates.current[0] - ostroke / 2 + xp,\n coordinates.current[1] - ostroke / 2 + yp,\n size + ostroke,\n size + ostroke\n );\n }\n\n function downHandler(e) {\n keymap.current[e.key] = true;\n keyAction(e.key, e.repeat);\n }\n\n function upHandler(e) {\n keymap.current[e.key] = false;\n }\n\n function clearGrid() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let columns = grid_width / size + 1;\n let rows = grid_height / size + 1;\n\n vertical.current = Array(columns * rows).fill(false);\n horizontal.current = vertical.current.slice();\n backslash.current = vertical.current.slice();\n slash.current = vertical.current.slice();\n }\n\n function setWindowSize() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n clearGrid();\n\n let dpr = window.devicePixelRatio || 1;\n\n canvasRef.current.width = canvas_width * dpr;\n canvasRef.current.height = canvas_height * dpr;\n let ctx = canvasRef.current.getContext('2d');\n ctx.scale(dpr, dpr);\n\n overlayCanvasRef.current.width = canvas_width * dpr;\n overlayCanvasRef.current.height = canvas_height * dpr;\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.scale(dpr, dpr);\n\n setDimensions([canvas_width, canvas_height]);\n }\n\n useEffect(() => {\n if (!once) {\n setWindowSize();\n setTimeout(() => {\n keyAction('init', false);\n }, 0);\n once = true;\n }\n\n window.addEventListener('keydown', downHandler);\n window.addEventListener('keyup', upHandler);\n // Remove event listeners on cleanup\n return () => {\n window.removeEventListener('keydown', downHandler);\n window.removeEventListener('keyup', upHandler);\n };\n }, [mode, help]);\n\n return (\n \n
\n \n Hex\n \n \n \n \n
\n\n \n
\n Hex is a keyboard-driven, grid-based drawing tool.\n
\n
\n
\n {KeyTip('e')} toggle mode:{' '}\n {['draw', 'erase'].map(m => (\n \n {m}\n \n ))}\n
\n
Draw & move:
\n
\n
\n {[\n [0, 0, 0, size],\n [0, 0, size, 0],\n [0, size, size, size],\n [size, 0, size, size],\n [size, 0, 0, size],\n [0, 0, size, size],\n ].map((c, i) => (\n \n \n 3 ? 1 : 2}\n />\n \n
\n ))}\n
\n
\n {['←', '↓', '↑', '→'].map(a => (\n \n {a}\n \n ))}\n
\n
\n
\n
\n {KeyTip('a')}\n {KeyTip('s')}\n {KeyTip('d')}\n {KeyTip('f')}\n {KeyTip('r')}\n {KeyTip('g')}\n
\n
\n {KeyTip('h')}\n {KeyTip('j')}\n {KeyTip('k')}\n {KeyTip('l')}\n
\n
\n \n Special:\n \n
\n {KeyTip('w')} save png  {KeyTip('x')} clear  {KeyTip('?')}{' '}\n toggle help\n
\n \n \n {help ? null : (\n \n {KeyTip('?')}\n \n )}\n
\n );\n};\n\nexport default Home;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AADA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAdA;AAAA;AAAA;AACA;AAeA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAPA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAHA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAoCA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAPA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AARA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AADA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAiBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AACA;AACA;AACA;AACA;AAHA;AAFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AANA;AAAA;AAAA;AAAA;AAAA;AAAA;AAVA;AAsBA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAHA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAeA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AAFA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAHA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;;;;A","sourceRoot":""} -------------------------------------------------------------------------------- /out/_next/static/webpack/static/development/pages/index.js.5d5310a8df5b0b854d23.hot-update.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"static/webpack/static/development/pages/index.js.5d5310a8df5b0b854d23.hot-update.js","sources":["webpack:///./pages/index.js"],"sourcesContent":["/* @jsx jsx */\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport Head from 'next/head';\nimport theme from '../parts/theme';\nimport { jsx } from 'theme-ui';\nimport { ThemeProvider } from 'theme-ui';\nimport { requestInterval } from '../parts/utils';\n\nlet fs = theme.fontSizes[0];\n\nlet once = false;\nlet size = 14;\n\nlet special_keys = 'x?ew'.split('');\n\nObject.fromEntries = arr =>\n Object.assign({}, ...Array.from(arr, ([k, v]) => ({ [k]: v })));\n\nlet xp = 4;\nlet yp = 4;\n\nconst Home = () => {\n let [dimensions, setDimensions] = useState([null, null]);\n let [mode, setMode] = useState('draw');\n\n let canvasRef = useRef();\n let overlayCanvasRef = useRef();\n\n let requestRef = useRef();\n let keymap = useRef({});\n let coordinates = useRef([0, 0]);\n let vertical = useRef(null);\n let horizontal = useRef(null);\n let backslash = useRef(null);\n let slash = useRef(null);\n let [help, toggleHelp] = useState(true);\n\n function KeyTip(letter) {\n return (\n {\n keymap.current[letter] = true;\n keyAction(letter, false);\n keymap.current[letter] = false;\n }}\n sx={{\n outline: 'solid 1px black',\n width: '2ch',\n textAlign: 'center',\n display: 'inline-block',\n userSelect: 'none',\n cursor: 'default',\n }}\n >\n {letter}\n \n );\n }\n\n function keyAction(key, repeat) {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let ctx = canvasRef.current.getContext('2d');\n ctx.fillStyle = 'black';\n\n let _mode = mode;\n\n if (special_keys.includes(key)) {\n if (key === 'e' && !repeat) {\n if (_mode === 'draw') {\n _mode = 'erase';\n setMode(_mode);\n } else if (_mode === 'erase') {\n _mode = 'draw';\n setMode(_mode);\n }\n } else if (key === 'x' && !repeat) {\n clearGrid();\n } else if (key === 'w' && !repeat) {\n let encoded = canvasRef.current.toDataURL('image/png');\n let link = document.createElement('a');\n link.setAttribute('href', encoded);\n link.setAttribute('download', 'etch.png');\n link.dispatchEvent(\n new MouseEvent(`click`, {\n bubbles: true,\n cancelable: true,\n view: window,\n })\n );\n return;\n } else if (key === '?' && !repeat) {\n toggleHelp(!help);\n return;\n }\n }\n\n if (key === 'init') {\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas_width, canvas_height);\n }\n\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.strokeStyle = _mode === 'draw' ? 'limegreen' : 'hotpink';\n let ostroke = 4;\n octx.lineWidth = ostroke;\n\n let current = coordinates.current;\n\n let inc = size;\n let modify = [0, 0];\n if (keymap.current['j']) modify[1] += inc;\n if (keymap.current['k']) modify[1] += -inc;\n if (keymap.current['h']) modify[0] += -inc;\n if (keymap.current['l']) modify[0] += inc;\n\n let next = [current[0] + modify[0], current[1] + modify[1]];\n if (next[0] < 0) next[0] = canvas_width - size;\n if (next[0] >= grid_width) next[0] = 0;\n if (next[1] < 0) next[1] = canvas_height - size;\n if (next[1] >= grid_height) next[1] = 0;\n coordinates.current = next;\n\n // modify drawing\n let c = next[0] / size;\n let r = next[1] / size;\n\n let new_val = _mode === 'draw' ? true : false;\n if (keymap.current['a']) {\n let index = r * (grid_width / size + 1) + c;\n vertical.current[index] = new_val;\n }\n if (keymap.current['d']) {\n let index = (r + 1) * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['s']) {\n let index = r * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['f']) {\n let index = r * (grid_width / size + 1) + c + 1;\n vertical.current[index] = new_val;\n }\n if (keymap.current['g']) {\n let index = r * (grid_width / size + 1) + c;\n backslash.current[index] = new_val;\n }\n if (keymap.current['r']) {\n let index = r * (grid_width / size + 1) + c;\n slash.current[index] = new_val;\n }\n\n function moveTo(ctx, x, y) {\n ctx.moveTo(x + xp, y + yp);\n }\n\n function lineTo(ctx, x, y) {\n ctx.lineTo(x + xp, y + yp);\n }\n\n ctx.clearRect(0, 0, canvas_width, canvas_height);\n\n if (vertical.current !== null) {\n let va = vertical.current;\n let ha = horizontal.current;\n let ba = backslash.current;\n let sa = slash.current;\n\n let dc = grid_width / size + 1;\n let dr = grid_height / size + 1;\n\n for (let i = 0; i < va.length; i++) {\n let v = va[i];\n let h = ha[i];\n let b = ba[i];\n let s = sa[i];\n\n let c = i % dc;\n let r = Math.floor(i / dc);\n\n ctx.beginPath();\n if (v === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size, r * size + size);\n }\n if (h === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size + size, r * size);\n }\n if (b === true) {\n moveTo(ctx, c * size + size, r * size + size);\n lineTo(ctx, c * size, r * size);\n }\n if (s === true) {\n moveTo(ctx, c * size, r * size + size);\n lineTo(ctx, c * size + size, r * size);\n }\n ctx.stroke();\n }\n }\n\n octx.clearRect(0, 0, window.innerWidth, window.innerHeight);\n octx.strokeRect(\n coordinates.current[0] - ostroke / 2 + xp,\n coordinates.current[1] - ostroke / 2 + yp,\n size + ostroke,\n size + ostroke\n );\n }\n\n function downHandler(e) {\n keymap.current[e.key] = true;\n keyAction(e.key, e.repeat);\n }\n\n function upHandler(e) {\n keymap.current[e.key] = false;\n }\n\n function clearGrid() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let columns = grid_width / size + 1;\n let rows = grid_height / size + 1;\n\n vertical.current = Array(columns * rows).fill(false);\n horizontal.current = vertical.current.slice();\n backslash.current = vertical.current.slice();\n slash.current = vertical.current.slice();\n }\n\n function setWindowSize() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n clearGrid();\n\n let dpr = window.devicePixelRatio || 1;\n\n canvasRef.current.width = canvas_width * dpr;\n canvasRef.current.height = canvas_height * dpr;\n let ctx = canvasRef.current.getContext('2d');\n ctx.scale(dpr, dpr);\n\n overlayCanvasRef.current.width = canvas_width * dpr;\n overlayCanvasRef.current.height = canvas_height * dpr;\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.scale(dpr, dpr);\n\n setDimensions([canvas_width, canvas_height]);\n }\n\n useEffect(() => {\n if (!once) {\n setWindowSize();\n setTimeout(() => {\n keyAction('init', false);\n }, 0);\n once = true;\n }\n\n window.addEventListener('keydown', downHandler);\n window.addEventListener('keyup', upHandler);\n // Remove event listeners on cleanup\n return () => {\n window.removeEventListener('keydown', downHandler);\n window.removeEventListener('keyup', upHandler);\n };\n }, [mode, help]);\n\n return (\n \n
\n \n Hex\n \n \n \n \n
\n\n \n
\n Hex is a keyboard-driven, grid-based drawing tool.\n
\n
\n
\n {KeyTip('e')} toggle mode:{' '}\n {['draw', 'erase'].map(m => (\n \n {m}\n \n ))}\n
\n
Draw & move:
\n
\n
\n {[\n [0, 0, 0, size],\n [0, 0, size, 0],\n [0, size, size, size],\n [size, 0, size, size],\n [size, 0, 0, size],\n [0, 0, size, size],\n ].map((c, i) => (\n \n \n 3 ? 1 : 2}\n />\n \n
\n ))}\n
\n
\n {['←', '↓', '↑', '→'].map(a => (\n \n {a}\n \n ))}\n
\n
\n
\n
\n {KeyTip('a')}\n {KeyTip('s')}\n {KeyTip('d')}\n {KeyTip('f')}\n {KeyTip('r')}\n {KeyTip('g')}\n
\n
\n {KeyTip('h')}\n {KeyTip('j')}\n {KeyTip('k')}\n {KeyTip('l')}\n
\n
\n \n Special:\n \n
\n {KeyTip('w')} save png  {KeyTip('x')} clear  {KeyTip('?')}{' '}\n toggle help\n
\n \n \n {help ? null : (\n \n {KeyTip('?')}\n \n )}\n
\n );\n};\n\nexport default Home;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AADA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAdA;AAAA;AAAA;AACA;AAeA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAPA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAHA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAoCA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAPA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AARA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AADA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAiBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AACA;AACA;AACA;AACA;AAHA;AAFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AANA;AAAA;AAAA;AAAA;AAAA;AAAA;AAVA;AAsBA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAHA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAeA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAHA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAHA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;;;;A","sourceRoot":""} -------------------------------------------------------------------------------- /out/_next/static/webpack/static/development/pages/index.js.d1c135f7c1b85b21c6dc.hot-update.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"static/webpack/static/development/pages/index.js.d1c135f7c1b85b21c6dc.hot-update.js","sources":["webpack:///./pages/index.js"],"sourcesContent":["/* @jsx jsx */\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport Head from 'next/head';\nimport theme from '../parts/theme';\nimport { jsx } from 'theme-ui';\nimport { ThemeProvider } from 'theme-ui';\nimport { requestInterval } from '../parts/utils';\n\nlet fs = theme.fontSizes[0];\n\nlet once = false;\nlet size = 14;\n\nlet special_keys = 'x?ew'.split('');\n\nObject.fromEntries = arr =>\n Object.assign({}, ...Array.from(arr, ([k, v]) => ({ [k]: v })));\n\nlet xp = 4;\nlet yp = 4;\n\nconst Home = () => {\n let [dimensions, setDimensions] = useState([null, null]);\n let [mode, setMode] = useState('draw');\n\n let canvasRef = useRef();\n let overlayCanvasRef = useRef();\n\n let requestRef = useRef();\n let keymap = useRef({});\n let coordinates = useRef([0, 0]);\n let vertical = useRef(null);\n let horizontal = useRef(null);\n let backslash = useRef(null);\n let slash = useRef(null);\n let [help, toggleHelp] = useState(true);\n\n function KeyTip(letter) {\n return (\n {\n keymap.current[letter] = true;\n keyAction(letter, false);\n keymap.current[letter] = false;\n }}\n sx={{\n outline: 'solid 1px black',\n width: '2ch',\n textAlign: 'center',\n display: 'inline-block',\n userSelect: 'none',\n cursor: 'default',\n }}\n >\n {letter}\n \n );\n }\n\n function keyAction(key, repeat) {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let ctx = canvasRef.current.getContext('2d');\n ctx.fillStyle = 'black';\n\n let _mode = mode;\n\n if (special_keys.includes(key)) {\n if (key === 'e' && !repeat) {\n if (_mode === 'draw') {\n _mode = 'erase';\n setMode(_mode);\n } else if (_mode === 'erase') {\n _mode = 'draw';\n setMode(_mode);\n }\n } else if (key === 'x' && !repeat) {\n clearGrid();\n } else if (key === 'w' && !repeat) {\n let encoded = canvasRef.current.toDataURL('image/png');\n let link = document.createElement('a');\n link.setAttribute('href', encoded);\n link.setAttribute('download', 'etch.png');\n link.dispatchEvent(\n new MouseEvent(`click`, {\n bubbles: true,\n cancelable: true,\n view: window,\n })\n );\n return;\n } else if (key === '?' && !repeat) {\n toggleHelp(!help);\n return;\n }\n }\n\n if (key === 'init') {\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas_width, canvas_height);\n }\n\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.strokeStyle = _mode === 'draw' ? 'limegreen' : 'hotpink';\n let ostroke = 4;\n octx.lineWidth = ostroke;\n\n let current = coordinates.current;\n\n let inc = size;\n let modify = [0, 0];\n if (keymap.current['j']) modify[1] += inc;\n if (keymap.current['k']) modify[1] += -inc;\n if (keymap.current['h']) modify[0] += -inc;\n if (keymap.current['l']) modify[0] += inc;\n\n let next = [current[0] + modify[0], current[1] + modify[1]];\n if (next[0] < 0) next[0] = canvas_width - size;\n if (next[0] >= grid_width) next[0] = 0;\n if (next[1] < 0) next[1] = canvas_height - size;\n if (next[1] >= grid_height) next[1] = 0;\n coordinates.current = next;\n\n // modify drawing\n let c = next[0] / size;\n let r = next[1] / size;\n\n let new_val = _mode === 'draw' ? true : false;\n if (keymap.current['a']) {\n let index = r * (grid_width / size + 1) + c;\n vertical.current[index] = new_val;\n }\n if (keymap.current['d']) {\n let index = (r + 1) * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['s']) {\n let index = r * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['f']) {\n let index = r * (grid_width / size + 1) + c + 1;\n vertical.current[index] = new_val;\n }\n if (keymap.current['g']) {\n let index = r * (grid_width / size + 1) + c;\n backslash.current[index] = new_val;\n }\n if (keymap.current['r']) {\n let index = r * (grid_width / size + 1) + c;\n slash.current[index] = new_val;\n }\n\n function moveTo(ctx, x, y) {\n ctx.moveTo(x + xp, y + yp);\n }\n\n function lineTo(ctx, x, y) {\n ctx.lineTo(x + xp, y + yp);\n }\n\n ctx.clearRect(0, 0, canvas_width, canvas_height);\n\n if (vertical.current !== null) {\n let va = vertical.current;\n let ha = horizontal.current;\n let ba = backslash.current;\n let sa = slash.current;\n\n let dc = grid_width / size + 1;\n let dr = grid_height / size + 1;\n\n for (let i = 0; i < va.length; i++) {\n let v = va[i];\n let h = ha[i];\n let b = ba[i];\n let s = sa[i];\n\n let c = i % dc;\n let r = Math.floor(i / dc);\n\n ctx.beginPath();\n if (v === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size, r * size + size);\n }\n if (h === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size + size, r * size);\n }\n if (b === true) {\n moveTo(ctx, c * size + size, r * size + size);\n lineTo(ctx, c * size, r * size);\n }\n if (s === true) {\n moveTo(ctx, c * size, r * size + size);\n lineTo(ctx, c * size + size, r * size);\n }\n ctx.stroke();\n }\n }\n\n octx.clearRect(0, 0, window.innerWidth, window.innerHeight);\n octx.strokeRect(\n coordinates.current[0] - ostroke / 2 + xp,\n coordinates.current[1] - ostroke / 2 + yp,\n size + ostroke,\n size + ostroke\n );\n }\n\n function downHandler(e) {\n keymap.current[e.key] = true;\n keyAction(e.key, e.repeat);\n }\n\n function upHandler(e) {\n keymap.current[e.key] = false;\n }\n\n function clearGrid() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let columns = grid_width / size + 1;\n let rows = grid_height / size + 1;\n\n vertical.current = Array(columns * rows).fill(false);\n horizontal.current = vertical.current.slice();\n backslash.current = vertical.current.slice();\n slash.current = vertical.current.slice();\n }\n\n function setWindowSize() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n clearGrid();\n\n let dpr = window.devicePixelRatio || 1;\n\n canvasRef.current.width = canvas_width * dpr;\n canvasRef.current.height = canvas_height * dpr;\n let ctx = canvasRef.current.getContext('2d');\n ctx.scale(dpr, dpr);\n\n overlayCanvasRef.current.width = canvas_width * dpr;\n overlayCanvasRef.current.height = canvas_height * dpr;\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.scale(dpr, dpr);\n\n setDimensions([canvas_width, canvas_height]);\n }\n\n useEffect(() => {\n if (!once) {\n setWindowSize();\n setTimeout(() => {\n keyAction('init', false);\n }, 0);\n once = true;\n }\n\n window.addEventListener('keydown', downHandler);\n window.addEventListener('keyup', upHandler);\n // Remove event listeners on cleanup\n return () => {\n window.removeEventListener('keydown', downHandler);\n window.removeEventListener('keyup', upHandler);\n };\n }, [mode, help]);\n\n return (\n \n
\n \n Hex\n \n \n \n \n
\n\n \n
\n Hex is a keyboard-driven, grid-based drawing tool.\n
\n
\n
\n {KeyTip('e')} toggle mode:{' '}\n {['draw', 'erase'].map(m => (\n \n {m}\n \n ))}\n
\n
Draw & move:
\n
\n
\n {[\n [0, 0, 0, size],\n [0, 0, size, 0],\n [0, size, size, size],\n [size, 0, size, size],\n [size, 0, 0, size],\n [0, 0, size, size],\n ].map((c, i) => (\n \n \n 3 ? 1 : 2}\n />\n \n
\n ))}\n
\n
\n {['←', '↓', '↑', '→'].map(a => (\n \n {a}\n \n ))}\n
\n
\n
\n
\n {KeyTip('a')}\n {KeyTip('s')}\n {KeyTip('d')}\n {KeyTip('f')}\n {KeyTip('r')}\n {KeyTip('g')}\n
\n
\n {KeyTip('h')}\n {KeyTip('j')}\n {KeyTip('k')}\n {KeyTip('l')}\n
\n
\n \n Special:\n \n
\n {KeyTip('w')} save png  {KeyTip('x')} clear  {KeyTip('?')}{' '}\n toggle help\n
\n \n \n {help ? null : (\n \n {KeyTip('?')}\n \n )}\n
\n );\n};\n\nexport default Home;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AADA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAdA;AAAA;AAAA;AACA;AAeA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAPA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAHA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAoCA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAPA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AARA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AADA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAiBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AACA;AACA;AACA;AACA;AAHA;AAFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AANA;AAAA;AAAA;AAAA;AAAA;AAAA;AAVA;AAsBA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAHA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAeA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAHA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAHA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;;;;A","sourceRoot":""} -------------------------------------------------------------------------------- /out/_next/static/webpack/static/development/pages/index.js.788f555dd50502f3b082.hot-update.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"static/webpack/static/development/pages/index.js.788f555dd50502f3b082.hot-update.js","sources":["webpack:///./pages/index.js"],"sourcesContent":["/* @jsx jsx */\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport Head from 'next/head';\nimport theme from '../parts/theme';\nimport { jsx } from 'theme-ui';\nimport { ThemeProvider } from 'theme-ui';\nimport { requestInterval } from '../parts/utils';\n\nlet fs = theme.fontSizes[0];\n\nlet once = false;\nlet size = 14;\n\nlet special_keys = 'x?ew'.split('');\n\nObject.fromEntries = arr =>\n Object.assign({}, ...Array.from(arr, ([k, v]) => ({ [k]: v })));\n\nlet xp = 4;\nlet yp = 4;\n\nconst Home = () => {\n let [dimensions, setDimensions] = useState([null, null]);\n let [mode, setMode] = useState('draw');\n\n let canvasRef = useRef();\n let overlayCanvasRef = useRef();\n\n let requestRef = useRef();\n let keymap = useRef({});\n let coordinates = useRef([0, 0]);\n let vertical = useRef(null);\n let horizontal = useRef(null);\n let backslash = useRef(null);\n let slash = useRef(null);\n let [help, toggleHelp] = useState(true);\n\n function KeyTip(letter) {\n return (\n {\n keymap.current[letter] = true;\n keyAction(letter, false);\n keymap.current[letter] = false;\n }}\n sx={{\n outline: 'solid 1px black',\n width: '2ch',\n textAlign: 'center',\n display: 'inline-block',\n userSelect: 'none',\n cursor: 'default',\n }}\n >\n {letter}\n \n );\n }\n\n function keyAction(key, repeat) {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let ctx = canvasRef.current.getContext('2d');\n ctx.fillStyle = 'black';\n\n let _mode = mode;\n\n if (special_keys.includes(key)) {\n if (key === 'e' && !repeat) {\n if (_mode === 'draw') {\n _mode = 'erase';\n setMode(_mode);\n } else if (_mode === 'erase') {\n _mode = 'draw';\n setMode(_mode);\n }\n } else if (key === 'x' && !repeat) {\n clearGrid();\n } else if (key === 'w' && !repeat) {\n let encoded = canvasRef.current.toDataURL('image/png');\n let link = document.createElement('a');\n link.setAttribute('href', encoded);\n link.setAttribute('download', 'etch.png');\n link.dispatchEvent(\n new MouseEvent(`click`, {\n bubbles: true,\n cancelable: true,\n view: window,\n })\n );\n return;\n } else if (key === '?' && !repeat) {\n toggleHelp(!help);\n return;\n }\n }\n\n if (key === 'init') {\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas_width, canvas_height);\n }\n\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.strokeStyle = _mode === 'draw' ? 'limegreen' : 'hotpink';\n let ostroke = 4;\n octx.lineWidth = ostroke;\n\n let current = coordinates.current;\n\n let inc = size;\n let modify = [0, 0];\n if (keymap.current['j']) modify[1] += inc;\n if (keymap.current['k']) modify[1] += -inc;\n if (keymap.current['h']) modify[0] += -inc;\n if (keymap.current['l']) modify[0] += inc;\n\n let next = [current[0] + modify[0], current[1] + modify[1]];\n if (next[0] < 0) next[0] = grid_width - size;\n if (next[0] >= grid_width - size) next[0] = 0;\n if (next[1] < 0) next[1] = grid_height - size;\n if (next[1] >= grid_height - size) next[1] = 0;\n coordinates.current = next;\n\n console.log(coordinates.current);\n\n // modify drawing\n let c = next[0] / size;\n let r = next[1] / size;\n\n let new_val = _mode === 'draw' ? true : false;\n if (keymap.current['a']) {\n let index = r * (grid_width / size + 1) + c;\n vertical.current[index] = new_val;\n }\n if (keymap.current['d']) {\n let index = (r + 1) * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['s']) {\n let index = r * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['f']) {\n let index = r * (grid_width / size + 1) + c + 1;\n vertical.current[index] = new_val;\n }\n if (keymap.current['g']) {\n let index = r * (grid_width / size + 1) + c;\n backslash.current[index] = new_val;\n }\n if (keymap.current['r']) {\n let index = r * (grid_width / size + 1) + c;\n slash.current[index] = new_val;\n }\n\n function moveTo(ctx, x, y) {\n ctx.moveTo(x + xp, y + yp);\n }\n\n function lineTo(ctx, x, y) {\n ctx.lineTo(x + xp, y + yp);\n }\n\n ctx.clearRect(0, 0, canvas_width, canvas_height);\n\n if (vertical.current !== null) {\n let va = vertical.current;\n let ha = horizontal.current;\n let ba = backslash.current;\n let sa = slash.current;\n\n let dc = grid_width / size + 1;\n let dr = grid_height / size + 1;\n\n for (let i = 0; i < va.length; i++) {\n let v = va[i];\n let h = ha[i];\n let b = ba[i];\n let s = sa[i];\n\n let c = i % dc;\n let r = Math.floor(i / dc);\n\n ctx.beginPath();\n if (v === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size, r * size + size);\n }\n if (h === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size + size, r * size);\n }\n if (b === true) {\n moveTo(ctx, c * size + size, r * size + size);\n lineTo(ctx, c * size, r * size);\n }\n if (s === true) {\n moveTo(ctx, c * size, r * size + size);\n lineTo(ctx, c * size + size, r * size);\n }\n ctx.stroke();\n }\n }\n\n octx.clearRect(0, 0, window.innerWidth, window.innerHeight);\n octx.strokeRect(\n coordinates.current[0] - ostroke / 2 + xp,\n coordinates.current[1] - ostroke / 2 + yp,\n size + ostroke,\n size + ostroke\n );\n }\n\n function downHandler(e) {\n keymap.current[e.key] = true;\n keyAction(e.key, e.repeat);\n }\n\n function upHandler(e) {\n keymap.current[e.key] = false;\n }\n\n function clearGrid() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let columns = grid_width / size + 1;\n let rows = grid_height / size + 1;\n\n vertical.current = Array(columns * rows).fill(false);\n horizontal.current = vertical.current.slice();\n backslash.current = vertical.current.slice();\n slash.current = vertical.current.slice();\n }\n\n function setWindowSize() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n clearGrid();\n\n let dpr = window.devicePixelRatio || 1;\n\n canvasRef.current.width = canvas_width * dpr;\n canvasRef.current.height = canvas_height * dpr;\n let ctx = canvasRef.current.getContext('2d');\n ctx.scale(dpr, dpr);\n\n overlayCanvasRef.current.width = canvas_width * dpr;\n overlayCanvasRef.current.height = canvas_height * dpr;\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.scale(dpr, dpr);\n\n setDimensions([canvas_width, canvas_height]);\n }\n\n useEffect(() => {\n if (!once) {\n setWindowSize();\n setTimeout(() => {\n keyAction('init', false);\n }, 0);\n once = true;\n }\n\n window.addEventListener('keydown', downHandler);\n window.addEventListener('keyup', upHandler);\n // Remove event listeners on cleanup\n return () => {\n window.removeEventListener('keydown', downHandler);\n window.removeEventListener('keyup', upHandler);\n };\n }, [mode, help]);\n\n return (\n \n
\n \n Hex\n \n \n \n \n
\n\n \n
\n Hex is a keyboard-driven, grid-based drawing tool.\n
\n
\n
\n {KeyTip('e')} toggle mode:{' '}\n {['draw', 'erase'].map(m => (\n \n {m}\n \n ))}\n
\n
Draw & move:
\n
\n
\n {[\n [0, 0, 0, size],\n [0, 0, size, 0],\n [0, size, size, size],\n [size, 0, size, size],\n [size, 0, 0, size],\n [0, 0, size, size],\n ].map((c, i) => (\n \n \n 3 ? 1 : 2}\n />\n \n
\n ))}\n
\n
\n {['←', '↓', '↑', '→'].map(a => (\n \n {a}\n \n ))}\n
\n
\n
\n
\n {KeyTip('a')}\n {KeyTip('s')}\n {KeyTip('d')}\n {KeyTip('f')}\n {KeyTip('r')}\n {KeyTip('g')}\n
\n
\n {KeyTip('h')}\n {KeyTip('j')}\n {KeyTip('k')}\n {KeyTip('l')}\n
\n
\n \n Special:\n \n
\n {KeyTip('w')} save png  {KeyTip('x')} clear  {KeyTip('?')}{' '}\n toggle help\n
\n \n \n {help ? null : (\n \n {KeyTip('?')}\n \n )}\n
\n );\n};\n\nexport default Home;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AADA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAdA;AAAA;AAAA;AACA;AAeA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAPA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAHA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAoCA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAPA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AARA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AADA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAiBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AACA;AACA;AACA;AACA;AAHA;AAFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AANA;AAAA;AAAA;AAAA;AAAA;AAAA;AAVA;AAsBA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAHA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAeA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AAFA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAHA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;;;;A","sourceRoot":""} -------------------------------------------------------------------------------- /out/_next/static/webpack/static/development/pages/index.js.eb7d53b695159e476e8f.hot-update.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"static/webpack/static/development/pages/index.js.eb7d53b695159e476e8f.hot-update.js","sources":["webpack:///./pages/index.js"],"sourcesContent":["/* @jsx jsx */\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport Head from 'next/head';\nimport theme from '../parts/theme';\nimport { jsx } from 'theme-ui';\nimport { ThemeProvider } from 'theme-ui';\nimport { requestInterval } from '../parts/utils';\n\nlet fs = theme.fontSizes[0];\n\nlet once = false;\nlet size = 14;\n\nlet special_keys = 'x?ew'.split('');\n\nObject.fromEntries = arr =>\n Object.assign({}, ...Array.from(arr, ([k, v]) => ({ [k]: v })));\n\nlet xp = 4;\nlet yp = 4;\n\nconst Home = () => {\n let [dimensions, setDimensions] = useState([null, null]);\n let [mode, setMode] = useState('draw');\n\n let canvasRef = useRef();\n let overlayCanvasRef = useRef();\n\n let requestRef = useRef();\n let keymap = useRef({});\n let coordinates = useRef([0, 0]);\n let vertical = useRef(null);\n let horizontal = useRef(null);\n let backslash = useRef(null);\n let slash = useRef(null);\n let [help, toggleHelp] = useState(true);\n\n function KeyTip(letter) {\n return (\n {\n keymap.current[letter] = true;\n keyAction(letter, false);\n keymap.current[letter] = false;\n }}\n sx={{\n outline: 'solid 1px black',\n width: '2ch',\n textAlign: 'center',\n display: 'inline-block',\n userSelect: 'none',\n cursor: 'default',\n }}\n >\n {letter}\n \n );\n }\n\n function keyAction(key, repeat) {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let ctx = canvasRef.current.getContext('2d');\n ctx.fillStyle = 'black';\n\n let _mode = mode;\n\n if (special_keys.includes(key)) {\n if (key === 'e' && !repeat) {\n if (_mode === 'draw') {\n _mode = 'erase';\n setMode(_mode);\n } else if (_mode === 'erase') {\n _mode = 'draw';\n setMode(_mode);\n }\n } else if (key === 'x' && !repeat) {\n clearGrid();\n } else if (key === 'w' && !repeat) {\n let encoded = canvasRef.current.toDataURL('image/png');\n let link = document.createElement('a');\n link.setAttribute('href', encoded);\n link.setAttribute('download', 'etch.png');\n link.dispatchEvent(\n new MouseEvent(`click`, {\n bubbles: true,\n cancelable: true,\n view: window,\n })\n );\n return;\n } else if (key === '?' && !repeat) {\n toggleHelp(!help);\n return;\n }\n }\n\n if (key === 'init') {\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas_width, canvas_height);\n }\n\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.strokeStyle = _mode === 'draw' ? 'limegreen' : 'hotpink';\n let ostroke = 4;\n octx.lineWidth = ostroke;\n\n let current = coordinates.current;\n\n let inc = size;\n let modify = [0, 0];\n if (keymap.current['j']) modify[1] += inc;\n if (keymap.current['k']) modify[1] += -inc;\n if (keymap.current['h']) modify[0] += -inc;\n if (keymap.current['l']) modify[0] += inc;\n\n let next = [current[0] + modify[0], current[1] + modify[1]];\n if (next[0] < 0) next[0] = canvas_width - size;\n if (next[0] >= grid_width) next[0] = 0;\n if (next[1] < 0) next[1] = canvas_height - size;\n if (next[1] >= grid_height) next[1] = 0;\n coordinates.current = next;\n\n // modify drawing\n let c = next[0] / size;\n let r = next[1] / size;\n\n let new_val = _mode === 'draw' ? true : false;\n if (keymap.current['a']) {\n let index = r * (grid_width / size + 1) + c;\n vertical.current[index] = new_val;\n }\n if (keymap.current['d']) {\n let index = (r + 1) * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['s']) {\n let index = r * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['f']) {\n let index = r * (grid_width / size + 1) + c + 1;\n vertical.current[index] = new_val;\n }\n if (keymap.current['g']) {\n let index = r * (grid_width / size + 1) + c;\n backslash.current[index] = new_val;\n }\n if (keymap.current['r']) {\n let index = r * (grid_width / size + 1) + c;\n slash.current[index] = new_val;\n }\n\n function moveTo(ctx, x, y) {\n ctx.moveTo(x + xp, y + yp);\n }\n\n function lineTo(ctx, x, y) {\n ctx.lineTo(x + xp, y + yp);\n }\n\n ctx.clearRect(0, 0, canvas_width, canvas_height);\n\n if (vertical.current !== null) {\n let va = vertical.current;\n let ha = horizontal.current;\n let ba = backslash.current;\n let sa = slash.current;\n\n let dc = grid_width / size + 1;\n let dr = grid_height / size + 1;\n\n for (let i = 0; i < va.length; i++) {\n let v = va[i];\n let h = ha[i];\n let b = ba[i];\n let s = sa[i];\n\n let c = i % dc;\n let r = Math.floor(i / dc);\n\n ctx.beginPath();\n if (v === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size, r * size + size);\n }\n if (h === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size + size, r * size);\n }\n if (b === true) {\n moveTo(ctx, c * size + size, r * size + size);\n lineTo(ctx, c * size, r * size);\n }\n if (s === true) {\n moveTo(ctx, c * size, r * size + size);\n lineTo(ctx, c * size + size, r * size);\n }\n ctx.stroke();\n }\n }\n\n octx.clearRect(0, 0, window.innerWidth, window.innerHeight);\n octx.strokeRect(\n coordinates.current[0] - ostroke / 2 + xp,\n coordinates.current[1] - ostroke / 2 + yp,\n size + ostroke,\n size + ostroke\n );\n }\n\n function downHandler(e) {\n keymap.current[e.key] = true;\n keyAction(e.key, e.repeat);\n }\n\n function upHandler(e) {\n keymap.current[e.key] = false;\n }\n\n function clearGrid() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let columns = grid_width / size + 1;\n let rows = grid_height / size + 1;\n\n vertical.current = Array(columns * rows).fill(false);\n horizontal.current = vertical.current.slice();\n backslash.current = vertical.current.slice();\n slash.current = vertical.current.slice();\n }\n\n function setWindowSize() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n clearGrid();\n\n let dpr = window.devicePixelRatio || 1;\n\n canvasRef.current.width = canvas_width * dpr;\n canvasRef.current.height = canvas_height * dpr;\n let ctx = canvasRef.current.getContext('2d');\n ctx.scale(dpr, dpr);\n\n overlayCanvasRef.current.width = canvas_width * dpr;\n overlayCanvasRef.current.height = canvas_height * dpr;\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.scale(dpr, dpr);\n\n setDimensions([canvas_width, canvas_height]);\n }\n\n useEffect(() => {\n if (!once) {\n setWindowSize();\n setTimeout(() => {\n keyAction('init', false);\n }, 0);\n once = true;\n }\n\n window.addEventListener('keydown', downHandler);\n window.addEventListener('keyup', upHandler);\n // Remove event listeners on cleanup\n return () => {\n window.removeEventListener('keydown', downHandler);\n window.removeEventListener('keyup', upHandler);\n };\n }, [mode, help]);\n\n return (\n \n
\n \n Hex\n \n \n \n \n
\n\n \n
\n Hex is a keyboard-driven, grid-based drawing tool.\n
\n
\n
\n {KeyTip('e')} toggle mode:{' '}\n {['draw', 'erase'].map(m => (\n \n {m}\n \n ))}\n
\n
Draw & move:
\n
\n
\n {[\n [0, 0, 0, size],\n [0, 0, size, 0],\n [0, size, size, size],\n [size, 0, size, size],\n [size, 0, 0, size],\n [0, 0, size, size],\n ].map((c, i) => (\n \n \n 3 ? 1 : 2}\n />\n \n
\n ))}\n
\n
\n {['←', '↓', '↑', '→'].map(a => (\n \n {a}\n \n ))}\n
\n
\n
\n
\n {KeyTip('a')}\n {KeyTip('s')}\n {KeyTip('d')}\n {KeyTip('f')}\n {KeyTip('r')}\n {KeyTip('g')}\n
\n
\n {KeyTip('h')}\n {KeyTip('j')}\n {KeyTip('k')}\n {KeyTip('l')}\n
\n
\n \n Special:\n \n
\n {KeyTip('w')} save png  {KeyTip('x')} clear  {KeyTip('?')}{' '}\n toggle help\n
\n \n \n {help ? null : (\n \n {KeyTip('?')}\n \n )}\n
\n );\n};\n\nexport default Home;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AADA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAdA;AAAA;AAAA;AACA;AAeA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAPA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAHA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAoCA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAPA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AARA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AADA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAiBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AACA;AACA;AACA;AACA;AAHA;AAFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AANA;AAAA;AAAA;AAAA;AAAA;AAAA;AAVA;AAsBA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAHA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAeA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAHA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAHA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;;;;A","sourceRoot":""} -------------------------------------------------------------------------------- /out/_next/static/webpack/static/development/pages/index.js.4c62c85d8fab59c63b04.hot-update.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"static/webpack/static/development/pages/index.js.4c62c85d8fab59c63b04.hot-update.js","sources":["webpack:///./pages/index.js"],"sourcesContent":["/* @jsx jsx */\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport Head from 'next/head';\nimport theme from '../parts/theme';\nimport { jsx } from 'theme-ui';\nimport { ThemeProvider } from 'theme-ui';\nimport { requestInterval } from '../parts/utils';\n\nlet fs = theme.fontSizes[0];\n\nlet once = false;\nlet size = 14;\n\nlet special_keys = 'x?ew'.split('');\n\nObject.fromEntries = arr =>\n Object.assign({}, ...Array.from(arr, ([k, v]) => ({ [k]: v })));\n\nlet xp = 4;\nlet yp = 4;\n\nconst Home = () => {\n let [dimensions, setDimensions] = useState([null, null]);\n let [mode, setMode] = useState('draw');\n\n let canvasRef = useRef();\n let overlayCanvasRef = useRef();\n\n let requestRef = useRef();\n let keymap = useRef({});\n let coordinates = useRef([0, 0]);\n let vertical = useRef(null);\n let horizontal = useRef(null);\n let backslash = useRef(null);\n let slash = useRef(null);\n let [help, toggleHelp] = useState(true);\n\n function KeyTip(letter) {\n return (\n {\n keymap.current[letter] = true;\n keyAction(letter, false);\n keymap.current[letter] = false;\n }}\n sx={{\n outline: 'solid 1px black',\n width: '2ch',\n textAlign: 'center',\n display: 'inline-block',\n userSelect: 'none',\n cursor: 'default',\n }}\n >\n {letter}\n \n );\n }\n\n function keyAction(key, repeat) {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let ctx = canvasRef.current.getContext('2d');\n ctx.fillStyle = 'black';\n\n let _mode = mode;\n\n if (special_keys.includes(key)) {\n if (key === 'e' && !repeat) {\n if (_mode === 'draw') {\n _mode = 'erase';\n setMode(_mode);\n } else if (_mode === 'erase') {\n _mode = 'draw';\n setMode(_mode);\n }\n } else if (key === 'x' && !repeat) {\n clearGrid();\n } else if (key === 'w' && !repeat) {\n let encoded = canvasRef.current.toDataURL('image/png');\n let link = document.createElement('a');\n link.setAttribute('href', encoded);\n link.setAttribute('download', 'etch.png');\n link.dispatchEvent(\n new MouseEvent(`click`, {\n bubbles: true,\n cancelable: true,\n view: window,\n })\n );\n return;\n } else if (key === '?' && !repeat) {\n toggleHelp(!help);\n return;\n }\n }\n\n if (key === 'init') {\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas_width, canvas_height);\n }\n\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.strokeStyle = _mode === 'draw' ? 'limegreen' : 'hotpink';\n let ostroke = 4;\n octx.lineWidth = ostroke;\n\n let current = coordinates.current;\n\n let inc = size;\n let modify = [0, 0];\n if (keymap.current['j']) modify[1] += inc;\n if (keymap.current['k']) modify[1] += -inc;\n if (keymap.current['h']) modify[0] += -inc;\n if (keymap.current['l']) modify[0] += inc;\n\n let next = [current[0] + modify[0], current[1] + modify[1]];\n if (next[0] < 0) next[0] = canvas_width - size;\n if (next[0] >= grid_width) next[0] = 0;\n if (next[1] < 0) next[1] = canvas_height - size;\n if (next[1] >= grid_height) next[1] = 0;\n coordinates.current = next;\n\n // modify drawing\n let c = next[0] / size;\n let r = next[1] / size;\n\n let new_val = _mode === 'draw' ? true : false;\n if (keymap.current['a']) {\n let index = r * (grid_width / size + 1) + c;\n vertical.current[index] = new_val;\n }\n if (keymap.current['d']) {\n let index = (r + 1) * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['s']) {\n let index = r * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['f']) {\n let index = r * (grid_width / size + 1) + c + 1;\n vertical.current[index] = new_val;\n }\n if (keymap.current['g']) {\n let index = r * (grid_width / size + 1) + c;\n backslash.current[index] = new_val;\n }\n if (keymap.current['r']) {\n let index = r * (grid_width / size + 1) + c;\n slash.current[index] = new_val;\n }\n\n function moveTo(ctx, x, y) {\n ctx.moveTo(x + xp, y + yp);\n }\n\n function lineTo(ctx, x, y) {\n ctx.lineTo(x + xp, y + yp);\n }\n\n ctx.clearRect(0, 0, canvas_width, canvas_height);\n\n if (vertical.current !== null) {\n let va = vertical.current;\n let ha = horizontal.current;\n let ba = backslash.current;\n let sa = slash.current;\n\n let dc = grid_width / size + 1;\n let dr = grid_height / size + 1;\n\n for (let i = 0; i < va.length; i++) {\n let v = va[i];\n let h = ha[i];\n let b = ba[i];\n let s = sa[i];\n\n let c = i % dc;\n let r = Math.floor(i / dc);\n\n ctx.beginPath();\n if (v === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size, r * size + size);\n }\n if (h === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size + size, r * size);\n }\n if (b === true) {\n moveTo(ctx, c * size + size, r * size + size);\n lineTo(ctx, c * size, r * size);\n }\n if (s === true) {\n moveTo(ctx, c * size, r * size + size);\n lineTo(ctx, c * size + size, r * size);\n }\n ctx.stroke();\n }\n }\n\n octx.clearRect(0, 0, window.innerWidth, window.innerHeight);\n octx.strokeRect(\n coordinates.current[0] - ostroke / 2 + xp,\n coordinates.current[1] - ostroke / 2 + yp,\n size + ostroke,\n size + ostroke\n );\n }\n\n function downHandler(e) {\n keymap.current[e.key] = true;\n keyAction(e.key, e.repeat);\n }\n\n function upHandler(e) {\n keymap.current[e.key] = false;\n }\n\n function clearGrid() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let columns = grid_width / size + 1;\n let rows = grid_height / size + 1;\n\n vertical.current = Array(columns * rows).fill(false);\n horizontal.current = vertical.current.slice();\n backslash.current = vertical.current.slice();\n slash.current = vertical.current.slice();\n }\n\n function setWindowSize() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n clearGrid();\n\n let dpr = window.devicePixelRatio || 1;\n\n canvasRef.current.width = canvas_width * dpr;\n canvasRef.current.height = canvas_height * dpr;\n let ctx = canvasRef.current.getContext('2d');\n ctx.scale(dpr, dpr);\n\n overlayCanvasRef.current.width = canvas_width * dpr;\n overlayCanvasRef.current.height = canvas_height * dpr;\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.scale(dpr, dpr);\n\n setDimensions([canvas_width, canvas_height]);\n }\n\n useEffect(() => {\n if (!once) {\n setWindowSize();\n setTimeout(() => {\n keyAction('init', false);\n }, 0);\n once = true;\n }\n\n window.addEventListener('keydown', downHandler);\n window.addEventListener('keyup', upHandler);\n // Remove event listeners on cleanup\n return () => {\n window.removeEventListener('keydown', downHandler);\n window.removeEventListener('keyup', upHandler);\n };\n }, [mode, help]);\n\n return (\n \n
\n \n Hex\n \n \n \n \n
\n\n \n
\n Hex is a keyboard-driven, grid-based drawing tool.\n
\n
\n
\n {KeyTip('e')} toggle mode:{' '}\n {['draw', 'erase'].map(m => (\n \n {m}\n \n ))}\n
\n
Draw & move:
\n
\n
\n {[\n [0, 0, 0, size],\n [0, 0, size, 0],\n [0, size, size, size],\n [size, 0, size, size],\n [size, 0, 0, size],\n [0, 0, size, size],\n ].map((c, i) => (\n \n \n 3 ? 1 : 2}\n />\n \n
\n ))}\n
\n
\n {['←', '↓', '↑', '→'].map(a => (\n \n {a}\n \n ))}\n
\n
\n
\n
\n {KeyTip('a')}\n {KeyTip('s')}\n {KeyTip('d')}\n {KeyTip('f')}\n {KeyTip('r')}\n {KeyTip('g')}\n
\n
\n {KeyTip('h')}\n {KeyTip('j')}\n {KeyTip('k')}\n {KeyTip('l')}\n
\n
\n \n Special:\n \n
\n {KeyTip('w')} save png  {KeyTip('x')} clear  {KeyTip('?')}{' '}\n toggle help\n
\n \n \n {help ? null : (\n \n {KeyTip('?')}\n \n )}\n
\n );\n};\n\nexport default Home;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AADA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAdA;AAAA;AAAA;AACA;AAeA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAPA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAHA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAoCA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAPA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AARA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AADA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAiBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AACA;AACA;AACA;AACA;AAHA;AAFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AANA;AAAA;AAAA;AAAA;AAAA;AAAA;AAVA;AAsBA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAHA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAeA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAHA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAHA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;;;;A","sourceRoot":""} -------------------------------------------------------------------------------- /out/_next/static/webpack/static/development/pages/index.js.7ed215f3bf414812b5a3.hot-update.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"static/webpack/static/development/pages/index.js.7ed215f3bf414812b5a3.hot-update.js","sources":["webpack:///./pages/index.js"],"sourcesContent":["/* @jsx jsx */\nimport React, { useState, useEffect, useRef, useCallback } from 'react';\nimport Head from 'next/head';\nimport theme from '../parts/theme';\nimport { jsx } from 'theme-ui';\nimport { ThemeProvider } from 'theme-ui';\nimport { requestInterval } from '../parts/utils';\n\nlet fs = theme.fontSizes[0];\n\nlet once = false;\nlet size = 14;\n\nlet special_keys = 'x?ew'.split('');\n\nObject.fromEntries = arr =>\n Object.assign({}, ...Array.from(arr, ([k, v]) => ({ [k]: v })));\n\nlet xp = 4;\nlet yp = 4;\n\nconst Home = () => {\n let [dimensions, setDimensions] = useState([null, null]);\n let [mode, setMode] = useState('draw');\n\n let canvasRef = useRef();\n let overlayCanvasRef = useRef();\n\n let requestRef = useRef();\n let keymap = useRef({});\n let coordinates = useRef([0, 0]);\n let vertical = useRef(null);\n let horizontal = useRef(null);\n let backslash = useRef(null);\n let slash = useRef(null);\n let [help, toggleHelp] = useState(true);\n\n function KeyTip(letter) {\n return (\n {\n keymap.current[letter] = true;\n keyAction(letter, false);\n keymap.current[letter] = false;\n }}\n sx={{\n outline: 'solid 1px black',\n width: '2ch',\n textAlign: 'center',\n display: 'inline-block',\n userSelect: 'none',\n cursor: 'default',\n }}\n >\n {letter}\n \n );\n }\n\n function keyAction(key, repeat) {\n let canvas_width = Math.floor(canvasRef.current.offsetWidth);\n let canvas_height = Math.floor(canvasRef.current.offsetHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let ctx = canvasRef.current.getContext('2d');\n ctx.fillStyle = 'black';\n\n let _mode = mode;\n\n if (special_keys.includes(key)) {\n if (key === 'e' && !repeat) {\n if (_mode === 'draw') {\n _mode = 'erase';\n setMode(_mode);\n } else if (_mode === 'erase') {\n _mode = 'draw';\n setMode(_mode);\n }\n } else if (key === 'x' && !repeat) {\n clearGrid();\n } else if (key === 'w' && !repeat) {\n let encoded = canvasRef.current.toDataURL('image/png');\n let link = document.createElement('a');\n link.setAttribute('href', encoded);\n link.setAttribute('download', 'etch.png');\n link.dispatchEvent(\n new MouseEvent(`click`, {\n bubbles: true,\n cancelable: true,\n view: window,\n })\n );\n return;\n } else if (key === '?' && !repeat) {\n toggleHelp(!help);\n return;\n }\n }\n\n if (key === 'init') {\n ctx.fillStyle = 'white';\n ctx.fillRect(0, 0, canvas_width, canvas_height);\n }\n\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.strokeStyle = _mode === 'draw' ? 'limegreen' : 'hotpink';\n let ostroke = 4;\n octx.lineWidth = ostroke;\n\n let current = coordinates.current;\n\n let inc = size;\n let modify = [0, 0];\n if (keymap.current['j']) modify[1] += inc;\n if (keymap.current['k']) modify[1] += -inc;\n if (keymap.current['h']) modify[0] += -inc;\n if (keymap.current['l']) modify[0] += inc;\n\n let next = [current[0] + modify[0], current[1] + modify[1]];\n\n if (next[0] < 0) next[0] = grid_width - size * 2;\n if (next[0] >= grid_width - size) next[0] = 0;\n if (next[1] < 0) next[1] = grid_height - size * 2;\n if (next[1] >= grid_height - size) next[1] = 0;\n coordinates.current = next;\n\n // modify drawing\n let c = next[0] / size;\n let r = next[1] / size;\n\n let new_val = _mode === 'draw' ? true : false;\n if (keymap.current['a']) {\n let index = r * (grid_width / size + 1) + c;\n vertical.current[index] = new_val;\n }\n if (keymap.current['d']) {\n let index = (r + 1) * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['s']) {\n let index = r * (grid_width / size + 1) + c;\n horizontal.current[index] = new_val;\n }\n if (keymap.current['f']) {\n let index = r * (grid_width / size + 1) + c + 1;\n vertical.current[index] = new_val;\n }\n if (keymap.current['g']) {\n let index = r * (grid_width / size + 1) + c;\n backslash.current[index] = new_val;\n }\n if (keymap.current['r']) {\n let index = r * (grid_width / size + 1) + c;\n slash.current[index] = new_val;\n }\n\n function moveTo(ctx, x, y) {\n ctx.moveTo(x + xp, y + yp);\n }\n\n function lineTo(ctx, x, y) {\n ctx.lineTo(x + xp, y + yp);\n }\n\n ctx.clearRect(0, 0, canvas_width, canvas_height);\n\n if (vertical.current !== null) {\n let va = vertical.current;\n let ha = horizontal.current;\n let ba = backslash.current;\n let sa = slash.current;\n\n let dc = grid_width / size + 1;\n let dr = grid_height / size + 1;\n\n for (let i = 0; i < va.length; i++) {\n let v = va[i];\n let h = ha[i];\n let b = ba[i];\n let s = sa[i];\n\n let c = i % dc;\n let r = Math.floor(i / dc);\n\n ctx.beginPath();\n if (v === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size, r * size + size);\n }\n if (h === true) {\n moveTo(ctx, c * size, r * size);\n lineTo(ctx, c * size + size, r * size);\n }\n if (b === true) {\n moveTo(ctx, c * size + size, r * size + size);\n lineTo(ctx, c * size, r * size);\n }\n if (s === true) {\n moveTo(ctx, c * size, r * size + size);\n lineTo(ctx, c * size + size, r * size);\n }\n ctx.stroke();\n }\n }\n\n octx.clearRect(0, 0, window.innerWidth, window.innerHeight);\n octx.strokeRect(\n coordinates.current[0] - ostroke / 2 + xp,\n coordinates.current[1] - ostroke / 2 + yp,\n size + ostroke,\n size + ostroke\n );\n }\n\n function downHandler(e) {\n keymap.current[e.key] = true;\n keyAction(e.key, e.repeat);\n }\n\n function upHandler(e) {\n keymap.current[e.key] = false;\n }\n\n function clearGrid() {\n let canvas_width = Math.floor(canvasRef.current.offsetWidth);\n let canvas_height = Math.floor(canvasRef.current.offsetHeight);\n\n let grid_width = Math.floor((canvas_width - xp * 2) / size) * size;\n let grid_height = Math.floor((canvas_height - yp * 2) / size) * size;\n\n let columns = grid_width / size + 1;\n let rows = grid_height / size + 1;\n\n vertical.current = Array(columns * rows).fill(false);\n horizontal.current = vertical.current.slice();\n backslash.current = vertical.current.slice();\n slash.current = vertical.current.slice();\n }\n\n function setWindowSize() {\n let canvas_width = Math.floor(window.innerWidth);\n let canvas_height = Math.floor(window.innerHeight);\n\n let dpr = window.devicePixelRatio || 1;\n\n canvasRef.current.width = canvas_width * dpr;\n canvasRef.current.height = canvas_height * dpr;\n let ctx = canvasRef.current.getContext('2d');\n ctx.scale(dpr, dpr);\n\n overlayCanvasRef.current.width = canvas_width * dpr;\n overlayCanvasRef.current.height = canvas_height * dpr;\n let octx = overlayCanvasRef.current.getContext('2d');\n octx.scale(dpr, dpr);\n\n clearGrid();\n\n setDimensions([canvas_width, canvas_height]);\n }\n\n useEffect(() => {\n if (!once) {\n setWindowSize();\n setTimeout(() => {\n keyAction('init', false);\n }, 0);\n once = true;\n }\n\n window.addEventListener('keydown', downHandler);\n window.addEventListener('keyup', upHandler);\n // Remove event listeners on cleanup\n return () => {\n window.removeEventListener('keydown', downHandler);\n window.removeEventListener('keyup', upHandler);\n };\n }, [mode, help]);\n\n return (\n \n
\n \n Hex\n \n \n \n \n
\n\n \n
\n Hex is a keyboard-driven, grid-based drawing tool.\n
\n
\n
\n {KeyTip('e')} toggle mode:{' '}\n {['draw', 'erase'].map(m => (\n \n {m}\n \n ))}\n
\n
Draw & move:
\n
\n
\n {[\n [0, 0, 0, size],\n [0, 0, size, 0],\n [0, size, size, size],\n [size, 0, size, size],\n [size, 0, 0, size],\n [0, 0, size, size],\n ].map((c, i) => (\n \n \n 3 ? 1 : 2}\n />\n \n
\n ))}\n
\n
\n {['←', '↓', '↑', '→'].map(a => (\n \n {a}\n \n ))}\n
\n
\n
\n
\n {KeyTip('a')}\n {KeyTip('s')}\n {KeyTip('d')}\n {KeyTip('f')}\n {KeyTip('r')}\n {KeyTip('g')}\n
\n
\n {KeyTip('h')}\n {KeyTip('j')}\n {KeyTip('k')}\n {KeyTip('l')}\n
\n
\n \n Special:\n \n
\n {KeyTip('w')} save png  {KeyTip('x')} clear  {KeyTip('?')}{' '}\n toggle help\n
\n \n \n {help ? null : (\n \n {KeyTip('?')}\n \n )}\n
\n );\n};\n\nexport default Home;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AADA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAdA;AAAA;AAAA;AACA;AAeA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAPA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAHA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAqCA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AARA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AADA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAiBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AACA;AACA;AACA;AACA;AAHA;AAFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AANA;AAAA;AAAA;AAAA;AAAA;AAAA;AAVA;AAsBA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAHA;AAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAeA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AAFA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAHA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA;AACA;AACA;;;;A","sourceRoot":""} --------------------------------------------------------------------------------