├── .gitignore ├── LICENSE ├── README.md ├── dist └── rough-painter.bundled.js ├── examples ├── basic.html └── boxes.html ├── package-lock.json ├── package.json ├── rollup.config.js └── src └── rough-painter.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Preet Shihn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rough-paint 2 | Using Houdini CSS [Paint API](https://developers.google.com/web/updates/2018/01/paintapi) with [Rough.js](https://roughjs.com/) 3 | 4 | Any element can be styled with rough.js using CSS only. 5 | 6 | For example: 7 | 8 | ![sample image](https://i.imgur.com/gzSzxab.png) 9 | 10 | ```html 11 | 25 |
26 |

Lorem ipsum dolor sit amet, consectetur adipiscing elit...

27 | 28 |
29 | ``` 30 | 31 | ## Examples 32 | 33 | ![sample image](https://i.imgur.com/9hQujNk.png) 34 | 35 | [Simple example - Live](https://pshihn.github.io/rough-paint/examples/basic.html) 36 | 37 | [Rough Boxes - Live](https://pshihn.github.io/rough-paint/examples/boxes.html) 38 | 39 | View the source code in the [examples folder](https://github.com/pshihn/rough-paint/tree/master/examples). 40 | 41 | ## CSS Properties 42 | 43 | Following properties corresponding to [rough.js options](https://github.com/pshihn/rough/wiki#options) can be set using CSS: 44 | 45 | `--rough-fill` - color to fill the element background with. 46 | 47 | `--rough-fill-style` - Fill style. Default is *hachure*. Other values can be *solid*, *zigzag*, *cross-hatch*, *dots*. See [rough.js fill style](https://github.com/pshihn/rough/wiki#fillstyle). 48 | 49 | `--rough-roughness` - Numeric value defining how rough the shape is. ([more](https://github.com/pshihn/rough/wiki#roughness)) 50 | 51 | `--rough-hachure-gap` - Numeric gap between hachure lines ([more](https://github.com/pshihn/rough/wiki#hachuregap)) 52 | 53 | `--rough-hachure-angle` - Numeric angle in degrees of hachure lines ([more](https://github.com/pshihn/rough/wiki#hachureangle)) 54 | 55 | `--rough-fill-weight` - Numeric value indicating the width of fill lines ([more](https://github.com/pshihn/rough/wiki#fillweight)) 56 | 57 | `--rough-border-width` - Draw a rough border with the specified numeric width. 58 | 59 | `--rough-border-color` - Color of the rough border. 60 | 61 | ## License 62 | [MIT License](https://github.com/pshihn/rough-paint/blob/master/LICENSE) (c) [Preet Shihn](https://twitter.com/preetster) 63 | -------------------------------------------------------------------------------- /dist/rough-painter.bundled.js: -------------------------------------------------------------------------------- 1 | (function(){'use strict';function a(a,b){return a.type===b}function b(a){const b=a[0],c=a[1];return n(l(b[0]-c[0],2)+l(b[1]-c[1],2))}function c(a,b){const c=[],d=new x([a[0],a[1]],[a[2],a[3]]);for(let e=0;em&&(m=4*b.strokeWidth),m=j(m,.1);const n=i%180*(s/180),o=p(n),r=q(n),t=h(n),u=new y(g-1,l+1,e-1,f+1,m,r,o,t);for(let b;null!=(b=u.nextLine());){const e=c(b,a);for(let a=0;a=m&&(m=4*f.strokeWidth);let o=f.fillWeight;0>o&&(o=f.strokeWidth/2);const p=h(l%180*(s/180)),q=k/j,t=n(q*p*q*p+1),u=q*p/t,v=1/t,w=m/(j*k/n(k*v*(k*v)+j*u*(j*u))/j);let x=n(j*j-(a-j+w)*(a-j+w));for(let h=a-j+w;hk){const a=n(1-k/(this._rx*this._rx*this._ry*this._ry));this._rx*=a,this._ry*=a,j=0}else j=(e===f?-1:1)*n(k/(this._rx*this._rx*i*i+this._ry*this._ry*h*h));const l=j*this._rx*i/this._ry,o=-j*this._ry*h/this._rx;this._C=[0,0],this._C[0]=this._cosPhi*l-this._sinPhi*o+(a[0]+b[0])/2,this._C[1]=this._sinPhi*l+this._cosPhi*o+(a[1]+b[1])/2,this._theta=this.calculateVectorAngle(1,0,(h-l)/this._rx,(i-o)/this._ry);let t=this.calculateVectorAngle((h-l)/this._rx,(i-o)/this._ry,(-h-l)/this._rx,(-i-o)/this._ry);!f&&0t&&(t+=2*s),this._numSegs=m(r(t/(s/2))),this._delta=t/this._numSegs,this._T=8/3*q(this._delta/4)*q(this._delta/4)/q(this._delta/2)}getNextSegment(){if(this._segIndex===this._numSegs)return null;const a=p(this._theta),b=q(this._theta),c=this._theta+this._delta,d=p(c),e=q(c),f=[this._cosPhi*this._rx*d-this._sinPhi*this._ry*e+this._C[0],this._sinPhi*this._rx*d+this._cosPhi*this._ry*e+this._C[1]],g=[this._from[0]+this._T*(-this._cosPhi*this._rx*b-this._sinPhi*this._ry*a),this._from[1]+this._T*(-this._sinPhi*this._rx*b+this._cosPhi*this._ry*a)],h=[f[0]+this._T*(this._cosPhi*this._rx*e+this._sinPhi*this._ry*d),f[1]+this._T*(this._sinPhi*this._rx*e-this._cosPhi*this._ry*d)];return this._theta=c,this._from=[f[0],f[1]],this._segIndex++,{cp1:g,cp2:h,to:f}}calculateVectorAngle(a,b,c,d){var e=Math.atan2;const f=e(b,a),g=e(d,c);return g>=f?g-f:2*s-(f-g)}}class w{constructor(a,b){this.sets=a,this.closed=b}fit(a){const b=[];for(const c of this.sets){const d=c.length;let e=Math.floor(a*d);if(5>e){if(5>=d)continue;e=5}b.push(this.reduce(c,e))}let c='';for(const d of b){for(let a=0;ab;){let e=-1,f=-1;for(let g=1;ge||i=k(d.py1,d.py2)&&this.py1<=j(d.py1,d.py2)?(this.xi=this.px1,this.yi=this.py1,!0):!!(this.py2>=k(d.py1,d.py2)&&this.py2<=j(d.py1,d.py2))&&(this.xi=this.px2,this.yi=this.py2,!0)):(this.xi=this.px1,this.yi=f*this.xi+h,!(-1e-5>(this.py1-this.yi)*(this.yi-this.py2)||-1e-5>(d.py1-this.yi)*(this.yi-d.py2))&&(!(1e-5>r(d.a))||!(-1e-5>(d.px1-this.xi)*(this.xi-d.px2)))):f===i?(this.xi=d.px1,this.yi=e*this.xi+g,!(-1e-5>(d.py1-this.yi)*(this.yi-d.py2)||-1e-5>(this.py1-this.yi)*(this.yi-this.py2))&&(!(1e-5>r(l))||!(-1e-5>(this.px1-this.xi)*(this.xi-this.px2)))):e===f?g==h&&(this.px1>=k(d.px1,d.px2)&&this.px1<=j(d.py1,d.py2)?(this.xi=this.px1,this.yi=this.py1,!0):!!(this.px2>=k(d.px1,d.px2)&&this.px2<=j(d.px1,d.px2))&&(this.xi=this.px2,this.yi=this.py2,!0)):(this.xi=(h-g)/(e-f),this.yi=e*this.xi+g,!(-1e-5>(this.px1-this.xi)*(this.xi-this.px2)||-1e-5>(d.px1-this.xi)*(this.xi-d.px2)))}}class y{constructor(a,b,c,d,e,f,g,h){this.deltaX=0,this.hGap=0,this.top=a,this.bottom=b,this.left=c,this.right=d,this.gap=e,this.sinAngle=f,this.tanAngle=h,1e-4>r(f)?this.pos=c+e:.9999r(this.sinAngle)){if(this.posthis.right&&b>this.right;)if(this.pos+=this.hGap,a=this.pos-this.deltaX/2,b=this.pos+this.deltaX/2,this.pos>this.right+this.deltaX)return null;const e=new x([a,c],[b,d]);this.sLeft&&e.intersects(this.sLeft)&&(a=e.xi,c=e.yi),this.sRight&&e.intersects(this.sRight)&&(b=e.xi,d=e.yi),0f&&(f=4*d.strokeWidth),f=j(f,.1);let g=d.fillWeight;0>g&&(g=d.strokeWidth/2);for(const h of a){const a=b(h),c=a/f,j=m(c)-1,k=Math.atan((h[1][1]-h[0][1])/(h[1][0]-h[0][0]));for(let a=0;ao;)o+=2*s,t+=2*s;t-o>2*s&&(o=0,t=2*s);const u=2*s/i.curveStepCount,v=k(u/2,(t-o)/2),w=this._arc(v,j,l,m,n,o,t,1,i),x=this._arc(v,j,l,m,n,o,t,1.5,i);let y=w.concat(x);return g&&(h?(y=y.concat(this.doubleLine(j,l,j+m*p(o),l+n*q(o),i)),y=y.concat(this.doubleLine(j,l,j+m*p(t),l+n*q(t),i))):(y.push({op:'lineTo',data:[j,l]}),y.push({op:'lineTo',data:[j+m*p(o),l+n*q(o)]}))),{type:'path',ops:y}}svgPath(a,b){a=(a||'').replace(/\n/g,' ').replace(/(-\s)/g,'-').replace('/(ss)/g',' ');let c=new u(a);if(b.simplification){const a=new w(c.linearPoints,c.closed),e=a.fit(b.simplification);c=new u(e)}let d=[];const e=c.segments||[];for(let f=0;fl;)l+=2*s,m+=2*s;m-l>2*s&&(l=0,m=2*s);const n=(m-l)/g.curveStepCount,o=[];for(let r=l;r<=m;r+=n)o.push([h+j*p(r),i+k*q(r)]);return o.push([h+j*p(m),i+k*q(m)]),o.push([h,i]),this.patternFillPolygon(o,g)}getOffset(a,b,c){return c.roughness*(Math.random()*(b-a)+a)}doubleLine(a,b,c,d,e){const f=this._line(a,b,c,d,e,!0,!1),g=this._line(a,b,c,d,e,!0,!0);return f.concat(g)}_line(a,b,c,d,e,f,g){const h=l(a-c,2)+l(b-d,2);let i=e.maxRandomnessOffset||0;100*(i*i)>h&&(i=n(h)/10);const j=i/2,k=.2+.2*Math.random();let m=e.bowing*e.maxRandomnessOffset*(d-b)/200,o=e.bowing*e.maxRandomnessOffset*(a-c)/200;m=this.getOffset(-m,m,e),o=this.getOffset(-o,o,e);const p=[];return f&&(g?p.push({op:'move',data:[a+this.getOffset(-j,j,e),b+this.getOffset(-j,j,e)]}):p.push({op:'move',data:[a+this.getOffset(-i,i,e),b+this.getOffset(-i,i,e)]})),g?p.push({op:'bcurveTo',data:[m+a+(c-a)*k+this.getOffset(-j,j,e),o+b+(d-b)*k+this.getOffset(-j,j,e),m+a+2*(c-a)*k+this.getOffset(-j,j,e),o+b+2*(d-b)*k+this.getOffset(-j,j,e),c+this.getOffset(-j,j,e),d+this.getOffset(-j,j,e)]}):p.push({op:'bcurveTo',data:[m+a+(c-a)*k+this.getOffset(-i,i,e),o+b+(d-b)*k+this.getOffset(-i,i,e),m+a+2*(c-a)*k+this.getOffset(-i,i,e),o+b+2*(d-b)*k+this.getOffset(-i,i,e),c+this.getOffset(-i,i,e),d+this.getOffset(-i,i,e)]}),p}_curve(a,c,d){const e=a.length;let f=[];if(3f;f++)0===f?k.push({op:'move',data:[h.x,h.y]}):k.push({op:'move',data:[h.x+this.getOffset(-l[0],l[0],j),h.y+this.getOffset(-l[0],l[0],j)]}),m=[e+this.getOffset(-l[f],l[f],j),g+this.getOffset(-l[f],l[f],j)],k.push({op:'bcurveTo',data:[a+this.getOffset(-l[f],l[f],j),b+this.getOffset(-l[f],l[f],j),c+this.getOffset(-l[f],l[f],j),d+this.getOffset(-l[f],l[f],j),m[0],m[1]]});return h.setPosition(m[0],m[1]),k}_processSegment(a,b,c,d){let e=[];switch(b.key){case'M':case'm':{const c='m'===b.key;if(2<=b.data.length){let f=+b.data[0],g=+b.data[1];c&&(f+=a.x,g+=a.y);const h=1*(d.maxRandomnessOffset||0);f+=this.getOffset(-h,h,d),g+=this.getOffset(-h,h,d),a.setPosition(f,g),e.push({op:'move',data:[f,g]})}break}case'L':case'l':{const c='l'===b.key;if(2<=b.data.length){let f=+b.data[0],g=+b.data[1];c&&(f+=a.x,g+=a.y),e=e.concat(this.doubleLine(a.x,a.y,f,g,d)),a.setPosition(f,g)}break}case'H':case'h':{const c='h'===b.key;if(b.data.length){let f=+b.data[0];c&&(f+=a.x),e=e.concat(this.doubleLine(a.x,a.y,f,a.y,d)),a.setPosition(f,a.y)}break}case'V':case'v':{const c='v'===b.key;if(b.data.length){let f=+b.data[0];c&&(f+=a.y),e=e.concat(this.doubleLine(a.x,a.y,a.x,f,d)),a.setPosition(a.x,f)}break}case'Z':case'z':{a.first&&(e=e.concat(this.doubleLine(a.x,a.y,a.first[0],a.first[1],d)),a.setPosition(a.first[0],a.first[1]),a.first=null);break}case'C':case'c':{const c='c'===b.key;if(6<=b.data.length){let f=+b.data[0],g=+b.data[1],h=+b.data[2],i=+b.data[3],j=+b.data[4],k=+b.data[5];c&&(f+=a.x,h+=a.x,j+=a.x,g+=a.y,i+=a.y,k+=a.y);const l=this._bezierTo(f,g,h,i,j,k,a,d);e=e.concat(l),a.bezierReflectionPoint=[j+(j-h),k+(k-i)]}break}case'S':case's':{const f='s'===b.key;if(4<=b.data.length){let g=+b.data[0],h=+b.data[1],i=+b.data[2],j=+b.data[3];f&&(g+=a.x,i+=a.x,h+=a.y,j+=a.y);let k=g,l=h;const m=c?c.key:'';let n=null;('c'===m||'C'===m||'s'===m||'S'===m)&&(n=a.bezierReflectionPoint),n&&(k=n[0],l=n[1]);const o=this._bezierTo(k,l,g,h,i,j,a,d);e=e.concat(o),a.bezierReflectionPoint=[i+(i-g),j+(j-h)]}break}case'Q':case'q':{const c='q'===b.key;if(4<=b.data.length){let g=+b.data[0],h=+b.data[1],i=+b.data[2],j=+b.data[3];c&&(g+=a.x,i+=a.x,h+=a.y,j+=a.y);const k=1*(1+.2*d.roughness),l=1.5*(1+.22*d.roughness);e.push({op:'move',data:[a.x+this.getOffset(-k,k,d),a.y+this.getOffset(-k,k,d)]});let m=[i+this.getOffset(-k,k,d),j+this.getOffset(-k,k,d)];e.push({op:'qcurveTo',data:[g+this.getOffset(-k,k,d),h+this.getOffset(-k,k,d),m[0],m[1]]}),e.push({op:'move',data:[a.x+this.getOffset(-l,l,d),a.y+this.getOffset(-l,l,d)]}),m=[i+this.getOffset(-l,l,d),j+this.getOffset(-l,l,d)],e.push({op:'qcurveTo',data:[g+this.getOffset(-l,l,d),h+this.getOffset(-l,l,d),m[0],m[1]]}),a.setPosition(m[0],m[1]),a.quadReflectionPoint=[i+(i-g),j+(j-h)]}break}case'T':case't':{const g='t'===b.key;if(2<=b.data.length){let h=+b.data[0],i=+b.data[1];g&&(h+=a.x,i+=a.y);let j=h,k=i;const l=c?c.key:'';let m=null;('q'===l||'Q'===l||'t'===l||'T'===l)&&(m=a.quadReflectionPoint),m&&(j=m[0],k=m[1]);const n=1*(1+.2*d.roughness),o=1.5*(1+.22*d.roughness);e.push({op:'move',data:[a.x+this.getOffset(-n,n,d),a.y+this.getOffset(-n,n,d)]});let p=[h+this.getOffset(-n,n,d),i+this.getOffset(-n,n,d)];e.push({op:'qcurveTo',data:[j+this.getOffset(-n,n,d),k+this.getOffset(-n,n,d),p[0],p[1]]}),e.push({op:'move',data:[a.x+this.getOffset(-o,o,d),a.y+this.getOffset(-o,o,d)]}),p=[h+this.getOffset(-o,o,d),i+this.getOffset(-o,o,d)],e.push({op:'qcurveTo',data:[j+this.getOffset(-o,o,d),k+this.getOffset(-o,o,d),p[0],p[1]]}),a.setPosition(p[0],p[1]),a.quadReflectionPoint=[h+(h-j),i+(i-k)]}break}case'A':case'a':{const c='a'===b.key;if(7<=b.data.length){const f=+b.data[0],g=+b.data[1],h=+b.data[2],i=+b.data[3],j=+b.data[4];let k=+b.data[5],l=+b.data[6];if(c&&(k+=a.x,l+=a.y),k===a.x&&l===a.y)break;if(0==f||0==g)e=e.concat(this.doubleLine(a.x,a.y,k,l,d)),a.setPosition(k,l);else for(let b=0;1>b;b++){const b=new v([a.x,a.y],[k,l],[f,g],h,!!i,!!j);for(let c=b.getNextSegment();c;){const f=this._bezierTo(c.cp1[0],c.cp1[1],c.cp2[0],c.cp2[1],c.to[0],c.to[1],a,d);e=e.concat(f),c=b.getNextSegment()}}}break}default:}return e}}class F{static get inputProperties(){return['--rough-fill','--rough-fill-style','--rough-roughness','--rough-hachure-gap','--rough-hachure-angle','--rough-fill-weight','--rough-border-color','--rough-border-width']}constructor(){this.renderer=new E,this.defaultOptions={maxRandomnessOffset:2,roughness:1,bowing:1,stroke:'#000',strokeWidth:1,curveTightness:0,curveStepCount:9,fill:null,fillStyle:'hachure',fillWeight:-1,hachureAngle:-41,hachureGap:-1}}_setFloatOption(a,b,c,d){a.get(b).length&&(d[c]=parseFloat(a.get(b).toString().trim()))}_setStringOption(a,b,c,d){a.get(b).length&&(d[c]=a.get(b).toString().trim())}paint(a,b,c){const d={};this._setFloatOption(c,'--rough-roughness','roughness',d),this._setFloatOption(c,'--rough-hachure-gap','hachureGap',d),this._setFloatOption(c,'--rough-hachure-angle','hachureAngle',d),this._setFloatOption(c,'--rough-fill-weight','fillWeight',d),this._setFloatOption(c,'--rough-border-width','strokeWidth',d),this._setStringOption(c,'--rough-fill-style','fillStyle',d),this._setStringOption(c,'--rough-fill','fill',d),this._setStringOption(c,'--rough-border-color','stroke',d);const e=Object.assign({},this.defaultOptions,d),f=d.strokeWidth||0,g=[[0+f,0+f],[b.width-f,0+f],[b.width-f,b.height-f],[0+f,b.height-f]],h=[];d.fill&&('solid'===e.fillStyle?h.push(this.renderer.solidFillPolygon(g,e)):h.push(this.renderer.patternFillPolygon(g,e))),d.strokeWidth&&0d&&(d=c.strokeWidth/2),a.save(),a.strokeStyle=c.fill||'',a.lineWidth=d,this._drawToContext(a,b),a.restore()}_drawToContext(a,b){a.beginPath();for(const c of b.ops){const b=c.data;switch(c.op){case'move':a.moveTo(b[0],b[1]);break;case'bcurveTo':a.bezierCurveTo(b[0],b[1],b[2],b[3],b[4],b[5]);break;case'qcurveTo':a.quadraticCurveTo(b[0],b[1],b[2],b[3]);break;case'lineTo':a.lineTo(b[0],b[1]);}}'fillPath'===b.type?a.fill():a.stroke()}}registerPaint('rough-painter',F)})(); 2 | -------------------------------------------------------------------------------- /examples/basic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 40 | 41 | 42 | 43 |
44 |

45 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 46 | Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute 47 | irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. 48 |

49 |

50 | 51 |

52 |
53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /examples/boxes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 60 | 61 | 62 | 63 |
64 |
65 |
66 |
67 |
68 |
69 | 70 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rough-paint", 3 | "version": "0.1.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@comandeer/babel-plugin-banner": { 8 | "version": "2.0.2", 9 | "resolved": "https://registry.npmjs.org/@comandeer/babel-plugin-banner/-/babel-plugin-banner-2.0.2.tgz", 10 | "integrity": "sha512-5/GMOcgqBy/+cMYfOTFhqrioolOP+g7ADjl4jo1nYONwVGvMpzKPdweuVaJsC/Ol2PH+GmwlF2WrNP3xjWoSiw==", 11 | "dev": true 12 | }, 13 | "@types/estree": { 14 | "version": "0.0.39", 15 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", 16 | "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", 17 | "dev": true 18 | }, 19 | "@types/node": { 20 | "version": "10.5.2", 21 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.2.tgz", 22 | "integrity": "sha512-m9zXmifkZsMHZBOyxZWilMwmTlpC8x5Ty360JKTiXvlXZfBWYpsg9ZZvP/Ye+iZUh+Q+MxDLjItVTWIsfwz+8Q==", 23 | "dev": true 24 | }, 25 | "ansi-regex": { 26 | "version": "2.1.1", 27 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 28 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 29 | "dev": true 30 | }, 31 | "ansi-styles": { 32 | "version": "2.2.1", 33 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 34 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 35 | "dev": true 36 | }, 37 | "babel-code-frame": { 38 | "version": "6.26.0", 39 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", 40 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", 41 | "dev": true, 42 | "requires": { 43 | "chalk": "^1.1.3", 44 | "esutils": "^2.0.2", 45 | "js-tokens": "^3.0.2" 46 | } 47 | }, 48 | "babel-core": { 49 | "version": "6.26.3", 50 | "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", 51 | "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", 52 | "dev": true, 53 | "requires": { 54 | "babel-code-frame": "^6.26.0", 55 | "babel-generator": "^6.26.0", 56 | "babel-helpers": "^6.24.1", 57 | "babel-messages": "^6.23.0", 58 | "babel-register": "^6.26.0", 59 | "babel-runtime": "^6.26.0", 60 | "babel-template": "^6.26.0", 61 | "babel-traverse": "^6.26.0", 62 | "babel-types": "^6.26.0", 63 | "babylon": "^6.18.0", 64 | "convert-source-map": "^1.5.1", 65 | "debug": "^2.6.9", 66 | "json5": "^0.5.1", 67 | "lodash": "^4.17.4", 68 | "minimatch": "^3.0.4", 69 | "path-is-absolute": "^1.0.1", 70 | "private": "^0.1.8", 71 | "slash": "^1.0.0", 72 | "source-map": "^0.5.7" 73 | } 74 | }, 75 | "babel-generator": { 76 | "version": "6.26.1", 77 | "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", 78 | "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", 79 | "dev": true, 80 | "requires": { 81 | "babel-messages": "^6.23.0", 82 | "babel-runtime": "^6.26.0", 83 | "babel-types": "^6.26.0", 84 | "detect-indent": "^4.0.0", 85 | "jsesc": "^1.3.0", 86 | "lodash": "^4.17.4", 87 | "source-map": "^0.5.7", 88 | "trim-right": "^1.0.1" 89 | } 90 | }, 91 | "babel-helper-evaluate-path": { 92 | "version": "0.4.3", 93 | "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.4.3.tgz", 94 | "integrity": "sha1-ComvcCwGshcCf6NxkI3UmJ0+Yz8=", 95 | "dev": true 96 | }, 97 | "babel-helper-flip-expressions": { 98 | "version": "0.4.3", 99 | "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz", 100 | "integrity": "sha1-NpZzahKKwYvCUlS19AoizrPB0/0=", 101 | "dev": true 102 | }, 103 | "babel-helper-is-nodes-equiv": { 104 | "version": "0.0.1", 105 | "resolved": "https://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", 106 | "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=", 107 | "dev": true 108 | }, 109 | "babel-helper-is-void-0": { 110 | "version": "0.4.3", 111 | "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz", 112 | "integrity": "sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=", 113 | "dev": true 114 | }, 115 | "babel-helper-mark-eval-scopes": { 116 | "version": "0.4.3", 117 | "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz", 118 | "integrity": "sha1-0kSjvvmESHJgP/tG4izorN9VFWI=", 119 | "dev": true 120 | }, 121 | "babel-helper-remove-or-void": { 122 | "version": "0.4.3", 123 | "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz", 124 | "integrity": "sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=", 125 | "dev": true 126 | }, 127 | "babel-helper-to-multiple-sequence-expressions": { 128 | "version": "0.4.3", 129 | "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.4.3.tgz", 130 | "integrity": "sha1-W1GLESf0ezA4dzOGoVYaK0jmMrY=", 131 | "dev": true 132 | }, 133 | "babel-helpers": { 134 | "version": "6.24.1", 135 | "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", 136 | "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", 137 | "dev": true, 138 | "requires": { 139 | "babel-runtime": "^6.22.0", 140 | "babel-template": "^6.24.1" 141 | } 142 | }, 143 | "babel-messages": { 144 | "version": "6.23.0", 145 | "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", 146 | "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", 147 | "dev": true, 148 | "requires": { 149 | "babel-runtime": "^6.22.0" 150 | } 151 | }, 152 | "babel-plugin-minify-builtins": { 153 | "version": "0.4.3", 154 | "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.4.3.tgz", 155 | "integrity": "sha1-nqPVn0rEp7uVjXEtKVVqH4b3+B4=", 156 | "dev": true, 157 | "requires": { 158 | "babel-helper-evaluate-path": "^0.4.3" 159 | } 160 | }, 161 | "babel-plugin-minify-constant-folding": { 162 | "version": "0.4.3", 163 | "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.4.3.tgz", 164 | "integrity": "sha1-MA+d6N2ghEoXaxk2U5YOJK0z4ZE=", 165 | "dev": true, 166 | "requires": { 167 | "babel-helper-evaluate-path": "^0.4.3" 168 | } 169 | }, 170 | "babel-plugin-minify-dead-code-elimination": { 171 | "version": "0.4.3", 172 | "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.4.3.tgz", 173 | "integrity": "sha1-c2KCZYZPkAjQAnUG9Yq+s8HQLZg=", 174 | "dev": true, 175 | "requires": { 176 | "babel-helper-evaluate-path": "^0.4.3", 177 | "babel-helper-mark-eval-scopes": "^0.4.3", 178 | "babel-helper-remove-or-void": "^0.4.3", 179 | "lodash.some": "^4.6.0" 180 | } 181 | }, 182 | "babel-plugin-minify-flip-comparisons": { 183 | "version": "0.4.3", 184 | "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz", 185 | "integrity": "sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=", 186 | "dev": true, 187 | "requires": { 188 | "babel-helper-is-void-0": "^0.4.3" 189 | } 190 | }, 191 | "babel-plugin-minify-guarded-expressions": { 192 | "version": "0.4.3", 193 | "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.3.tgz", 194 | "integrity": "sha1-zHCbRFP9IbHzAod0RMifiEJ845c=", 195 | "dev": true, 196 | "requires": { 197 | "babel-helper-flip-expressions": "^0.4.3" 198 | } 199 | }, 200 | "babel-plugin-minify-infinity": { 201 | "version": "0.4.3", 202 | "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz", 203 | "integrity": "sha1-37h2obCKBldjhO8/kuZTumB7Oco=", 204 | "dev": true 205 | }, 206 | "babel-plugin-minify-mangle-names": { 207 | "version": "0.4.3", 208 | "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.4.3.tgz", 209 | "integrity": "sha1-FvG/90t6fJPfwkHngx3V+0sCPvc=", 210 | "dev": true, 211 | "requires": { 212 | "babel-helper-mark-eval-scopes": "^0.4.3" 213 | } 214 | }, 215 | "babel-plugin-minify-numeric-literals": { 216 | "version": "0.4.3", 217 | "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz", 218 | "integrity": "sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=", 219 | "dev": true 220 | }, 221 | "babel-plugin-minify-replace": { 222 | "version": "0.4.3", 223 | "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.4.3.tgz", 224 | "integrity": "sha1-nSifS6FdTmAR6HmfpfG6d+yBIZ0=", 225 | "dev": true 226 | }, 227 | "babel-plugin-minify-simplify": { 228 | "version": "0.4.3", 229 | "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.4.3.tgz", 230 | "integrity": "sha1-N3VthcYURktLCSfytOQXGR1Vc4o=", 231 | "dev": true, 232 | "requires": { 233 | "babel-helper-flip-expressions": "^0.4.3", 234 | "babel-helper-is-nodes-equiv": "^0.0.1", 235 | "babel-helper-to-multiple-sequence-expressions": "^0.4.3" 236 | } 237 | }, 238 | "babel-plugin-minify-type-constructors": { 239 | "version": "0.4.3", 240 | "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz", 241 | "integrity": "sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=", 242 | "dev": true, 243 | "requires": { 244 | "babel-helper-is-void-0": "^0.4.3" 245 | } 246 | }, 247 | "babel-plugin-transform-inline-consecutive-adds": { 248 | "version": "0.4.3", 249 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz", 250 | "integrity": "sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=", 251 | "dev": true 252 | }, 253 | "babel-plugin-transform-member-expression-literals": { 254 | "version": "6.9.4", 255 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz", 256 | "integrity": "sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=", 257 | "dev": true 258 | }, 259 | "babel-plugin-transform-merge-sibling-variables": { 260 | "version": "6.9.4", 261 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz", 262 | "integrity": "sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=", 263 | "dev": true 264 | }, 265 | "babel-plugin-transform-minify-booleans": { 266 | "version": "6.9.4", 267 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz", 268 | "integrity": "sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=", 269 | "dev": true 270 | }, 271 | "babel-plugin-transform-property-literals": { 272 | "version": "6.9.4", 273 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz", 274 | "integrity": "sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=", 275 | "dev": true, 276 | "requires": { 277 | "esutils": "^2.0.2" 278 | } 279 | }, 280 | "babel-plugin-transform-regexp-constructors": { 281 | "version": "0.4.3", 282 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz", 283 | "integrity": "sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=", 284 | "dev": true 285 | }, 286 | "babel-plugin-transform-remove-console": { 287 | "version": "6.9.4", 288 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", 289 | "integrity": "sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=", 290 | "dev": true 291 | }, 292 | "babel-plugin-transform-remove-debugger": { 293 | "version": "6.9.4", 294 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz", 295 | "integrity": "sha1-QrcnYxyXl44estGZp67IShgznvI=", 296 | "dev": true 297 | }, 298 | "babel-plugin-transform-remove-undefined": { 299 | "version": "0.4.3", 300 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.4.3.tgz", 301 | "integrity": "sha1-1AsNp/kcCMBsxyt2dHTAHEiU3gI=", 302 | "dev": true, 303 | "requires": { 304 | "babel-helper-evaluate-path": "^0.4.3" 305 | } 306 | }, 307 | "babel-plugin-transform-simplify-comparison-operators": { 308 | "version": "6.9.4", 309 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz", 310 | "integrity": "sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=", 311 | "dev": true 312 | }, 313 | "babel-plugin-transform-undefined-to-void": { 314 | "version": "6.9.4", 315 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz", 316 | "integrity": "sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=", 317 | "dev": true 318 | }, 319 | "babel-preset-minify": { 320 | "version": "0.4.3", 321 | "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.4.3.tgz", 322 | "integrity": "sha1-spw91pGJBThFmPCSuVUVLiah/g8=", 323 | "dev": true, 324 | "requires": { 325 | "babel-plugin-minify-builtins": "^0.4.3", 326 | "babel-plugin-minify-constant-folding": "^0.4.3", 327 | "babel-plugin-minify-dead-code-elimination": "^0.4.3", 328 | "babel-plugin-minify-flip-comparisons": "^0.4.3", 329 | "babel-plugin-minify-guarded-expressions": "^0.4.3", 330 | "babel-plugin-minify-infinity": "^0.4.3", 331 | "babel-plugin-minify-mangle-names": "^0.4.3", 332 | "babel-plugin-minify-numeric-literals": "^0.4.3", 333 | "babel-plugin-minify-replace": "^0.4.3", 334 | "babel-plugin-minify-simplify": "^0.4.3", 335 | "babel-plugin-minify-type-constructors": "^0.4.3", 336 | "babel-plugin-transform-inline-consecutive-adds": "^0.4.3", 337 | "babel-plugin-transform-member-expression-literals": "^6.9.4", 338 | "babel-plugin-transform-merge-sibling-variables": "^6.9.4", 339 | "babel-plugin-transform-minify-booleans": "^6.9.4", 340 | "babel-plugin-transform-property-literals": "^6.9.4", 341 | "babel-plugin-transform-regexp-constructors": "^0.4.3", 342 | "babel-plugin-transform-remove-console": "^6.9.4", 343 | "babel-plugin-transform-remove-debugger": "^6.9.4", 344 | "babel-plugin-transform-remove-undefined": "^0.4.3", 345 | "babel-plugin-transform-simplify-comparison-operators": "^6.9.4", 346 | "babel-plugin-transform-undefined-to-void": "^6.9.4", 347 | "lodash.isplainobject": "^4.0.6" 348 | } 349 | }, 350 | "babel-register": { 351 | "version": "6.26.0", 352 | "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", 353 | "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", 354 | "dev": true, 355 | "requires": { 356 | "babel-core": "^6.26.0", 357 | "babel-runtime": "^6.26.0", 358 | "core-js": "^2.5.0", 359 | "home-or-tmp": "^2.0.0", 360 | "lodash": "^4.17.4", 361 | "mkdirp": "^0.5.1", 362 | "source-map-support": "^0.4.15" 363 | } 364 | }, 365 | "babel-runtime": { 366 | "version": "6.26.0", 367 | "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", 368 | "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", 369 | "dev": true, 370 | "requires": { 371 | "core-js": "^2.4.0", 372 | "regenerator-runtime": "^0.11.0" 373 | } 374 | }, 375 | "babel-template": { 376 | "version": "6.26.0", 377 | "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", 378 | "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", 379 | "dev": true, 380 | "requires": { 381 | "babel-runtime": "^6.26.0", 382 | "babel-traverse": "^6.26.0", 383 | "babel-types": "^6.26.0", 384 | "babylon": "^6.18.0", 385 | "lodash": "^4.17.4" 386 | } 387 | }, 388 | "babel-traverse": { 389 | "version": "6.26.0", 390 | "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", 391 | "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", 392 | "dev": true, 393 | "requires": { 394 | "babel-code-frame": "^6.26.0", 395 | "babel-messages": "^6.23.0", 396 | "babel-runtime": "^6.26.0", 397 | "babel-types": "^6.26.0", 398 | "babylon": "^6.18.0", 399 | "debug": "^2.6.8", 400 | "globals": "^9.18.0", 401 | "invariant": "^2.2.2", 402 | "lodash": "^4.17.4" 403 | } 404 | }, 405 | "babel-types": { 406 | "version": "6.26.0", 407 | "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", 408 | "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", 409 | "dev": true, 410 | "requires": { 411 | "babel-runtime": "^6.26.0", 412 | "esutils": "^2.0.2", 413 | "lodash": "^4.17.4", 414 | "to-fast-properties": "^1.0.3" 415 | } 416 | }, 417 | "babylon": { 418 | "version": "6.18.0", 419 | "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", 420 | "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", 421 | "dev": true 422 | }, 423 | "balanced-match": { 424 | "version": "1.0.0", 425 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 426 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 427 | "dev": true 428 | }, 429 | "brace-expansion": { 430 | "version": "1.1.11", 431 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 432 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 433 | "dev": true, 434 | "requires": { 435 | "balanced-match": "^1.0.0", 436 | "concat-map": "0.0.1" 437 | } 438 | }, 439 | "chalk": { 440 | "version": "1.1.3", 441 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 442 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 443 | "dev": true, 444 | "requires": { 445 | "ansi-styles": "^2.2.1", 446 | "escape-string-regexp": "^1.0.2", 447 | "has-ansi": "^2.0.0", 448 | "strip-ansi": "^3.0.0", 449 | "supports-color": "^2.0.0" 450 | } 451 | }, 452 | "concat-map": { 453 | "version": "0.0.1", 454 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 455 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 456 | "dev": true 457 | }, 458 | "convert-source-map": { 459 | "version": "1.5.1", 460 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", 461 | "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", 462 | "dev": true 463 | }, 464 | "core-js": { 465 | "version": "2.5.7", 466 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", 467 | "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", 468 | "dev": true 469 | }, 470 | "debug": { 471 | "version": "2.6.9", 472 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 473 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 474 | "dev": true, 475 | "requires": { 476 | "ms": "2.0.0" 477 | } 478 | }, 479 | "detect-indent": { 480 | "version": "4.0.0", 481 | "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", 482 | "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", 483 | "dev": true, 484 | "requires": { 485 | "repeating": "^2.0.0" 486 | } 487 | }, 488 | "escape-string-regexp": { 489 | "version": "1.0.5", 490 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 491 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 492 | "dev": true 493 | }, 494 | "esutils": { 495 | "version": "2.0.2", 496 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 497 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 498 | "dev": true 499 | }, 500 | "globals": { 501 | "version": "9.18.0", 502 | "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", 503 | "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", 504 | "dev": true 505 | }, 506 | "has-ansi": { 507 | "version": "2.0.0", 508 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 509 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 510 | "dev": true, 511 | "requires": { 512 | "ansi-regex": "^2.0.0" 513 | } 514 | }, 515 | "home-or-tmp": { 516 | "version": "2.0.0", 517 | "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", 518 | "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", 519 | "dev": true, 520 | "requires": { 521 | "os-homedir": "^1.0.0", 522 | "os-tmpdir": "^1.0.1" 523 | } 524 | }, 525 | "invariant": { 526 | "version": "2.2.4", 527 | "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", 528 | "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", 529 | "dev": true, 530 | "requires": { 531 | "loose-envify": "^1.0.0" 532 | } 533 | }, 534 | "is-finite": { 535 | "version": "1.0.2", 536 | "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", 537 | "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", 538 | "dev": true, 539 | "requires": { 540 | "number-is-nan": "^1.0.0" 541 | } 542 | }, 543 | "js-tokens": { 544 | "version": "3.0.2", 545 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 546 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", 547 | "dev": true 548 | }, 549 | "jsesc": { 550 | "version": "1.3.0", 551 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", 552 | "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", 553 | "dev": true 554 | }, 555 | "json5": { 556 | "version": "0.5.1", 557 | "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", 558 | "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", 559 | "dev": true 560 | }, 561 | "lodash": { 562 | "version": "4.17.10", 563 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", 564 | "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", 565 | "dev": true 566 | }, 567 | "lodash.isplainobject": { 568 | "version": "4.0.6", 569 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 570 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", 571 | "dev": true 572 | }, 573 | "lodash.some": { 574 | "version": "4.6.0", 575 | "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", 576 | "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", 577 | "dev": true 578 | }, 579 | "loose-envify": { 580 | "version": "1.4.0", 581 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 582 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 583 | "dev": true, 584 | "requires": { 585 | "js-tokens": "^3.0.0 || ^4.0.0" 586 | } 587 | }, 588 | "magic-string": { 589 | "version": "0.24.1", 590 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.24.1.tgz", 591 | "integrity": "sha512-YBfNxbJiixMzxW40XqJEIldzHyh5f7CZKalo1uZffevyrPEX8Qgo9s0dmcORLHdV47UyvJg8/zD+6hQG3qvJrA==", 592 | "dev": true, 593 | "requires": { 594 | "sourcemap-codec": "^1.4.1" 595 | } 596 | }, 597 | "minimatch": { 598 | "version": "3.0.4", 599 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 600 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 601 | "dev": true, 602 | "requires": { 603 | "brace-expansion": "^1.1.7" 604 | } 605 | }, 606 | "minimist": { 607 | "version": "0.0.8", 608 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 609 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 610 | "dev": true 611 | }, 612 | "mkdirp": { 613 | "version": "0.5.1", 614 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 615 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 616 | "dev": true, 617 | "requires": { 618 | "minimist": "0.0.8" 619 | } 620 | }, 621 | "ms": { 622 | "version": "2.0.0", 623 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 624 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 625 | "dev": true 626 | }, 627 | "number-is-nan": { 628 | "version": "1.0.1", 629 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 630 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 631 | "dev": true 632 | }, 633 | "os-homedir": { 634 | "version": "1.0.2", 635 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 636 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", 637 | "dev": true 638 | }, 639 | "os-tmpdir": { 640 | "version": "1.0.2", 641 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 642 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 643 | "dev": true 644 | }, 645 | "path-is-absolute": { 646 | "version": "1.0.1", 647 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 648 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 649 | "dev": true 650 | }, 651 | "private": { 652 | "version": "0.1.8", 653 | "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", 654 | "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", 655 | "dev": true 656 | }, 657 | "regenerator-runtime": { 658 | "version": "0.11.1", 659 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", 660 | "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", 661 | "dev": true 662 | }, 663 | "repeating": { 664 | "version": "2.0.1", 665 | "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", 666 | "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", 667 | "dev": true, 668 | "requires": { 669 | "is-finite": "^1.0.0" 670 | } 671 | }, 672 | "rollup": { 673 | "version": "0.62.0", 674 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.62.0.tgz", 675 | "integrity": "sha512-mZS0aIGfYzuJySJD78znu9/hCJsNfBzg4lDuZGMj0hFVcYHt2evNRHv8aqiu9/w6z6Qn8AQoVl4iyEjDmisGeA==", 676 | "dev": true, 677 | "requires": { 678 | "@types/estree": "0.0.39", 679 | "@types/node": "*" 680 | } 681 | }, 682 | "rollup-plugin-babel-minify": { 683 | "version": "5.0.0", 684 | "resolved": "https://registry.npmjs.org/rollup-plugin-babel-minify/-/rollup-plugin-babel-minify-5.0.0.tgz", 685 | "integrity": "sha512-/XMozvFf1wm0O04FEybfEGl05jq9RQ408Xx/GjCfCau9ETzKYlEkfdi19pj2EvmpbSO/r0yspMKmwnUHNycdsw==", 686 | "dev": true, 687 | "requires": { 688 | "@comandeer/babel-plugin-banner": "^2.0.2", 689 | "babel-core": "^6.26.0", 690 | "babel-preset-minify": "^0.4.0", 691 | "magic-string": "^0.24.0" 692 | } 693 | }, 694 | "roughjs": { 695 | "version": "2.2.3", 696 | "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-2.2.3.tgz", 697 | "integrity": "sha512-ZnlptJSz5Ii+Tcx3T60rZ9x4jZUK52iURLziYZiE3hjpaDJ5pzmYEnZiRpzRue6AUUK5uiMoJ9z+/pIO3eSKrA==" 698 | }, 699 | "slash": { 700 | "version": "1.0.0", 701 | "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", 702 | "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", 703 | "dev": true 704 | }, 705 | "source-map": { 706 | "version": "0.5.7", 707 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 708 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", 709 | "dev": true 710 | }, 711 | "source-map-support": { 712 | "version": "0.4.18", 713 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", 714 | "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", 715 | "dev": true, 716 | "requires": { 717 | "source-map": "^0.5.6" 718 | } 719 | }, 720 | "sourcemap-codec": { 721 | "version": "1.4.1", 722 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.1.tgz", 723 | "integrity": "sha512-hX1eNBNuilj8yfFnECh0DzLgwKpBLMIvmhgEhixXNui8lMLBInTI8Kyxt++RwJnMNu7cAUo635L2+N1TxMJCzA==", 724 | "dev": true 725 | }, 726 | "strip-ansi": { 727 | "version": "3.0.1", 728 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 729 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 730 | "dev": true, 731 | "requires": { 732 | "ansi-regex": "^2.0.0" 733 | } 734 | }, 735 | "supports-color": { 736 | "version": "2.0.0", 737 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 738 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 739 | "dev": true 740 | }, 741 | "to-fast-properties": { 742 | "version": "1.0.3", 743 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", 744 | "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", 745 | "dev": true 746 | }, 747 | "trim-right": { 748 | "version": "1.0.1", 749 | "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", 750 | "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", 751 | "dev": true 752 | } 753 | } 754 | } 755 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rough-paint", 3 | "version": "0.1.0", 4 | "description": "Using Houdini CSS Paint API with Rough.js", 5 | "scripts": { 6 | "build": "rollup -c", 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/pshihn/rough-paint.git" 12 | }, 13 | "author": "", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/pshihn/rough-paint/issues" 17 | }, 18 | "homepage": "https://github.com/pshihn/rough-paint#readme", 19 | "dependencies": { 20 | "roughjs": "^2.2.3" 21 | }, 22 | "devDependencies": { 23 | "rollup": "^0.62.0", 24 | "rollup-plugin-babel-minify": "^5.0.0" 25 | } 26 | } -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import minify from 'rollup-plugin-babel-minify'; 2 | 3 | const outFolder = 'dist'; 4 | 5 | export default [ 6 | { 7 | input: 'src/rough-painter.js', 8 | output: { 9 | file: `${outFolder}/rough-painter.bundled.js`, 10 | format: 'iife' 11 | }, 12 | plugins: [minify({ comments: false })] 13 | } 14 | ]; -------------------------------------------------------------------------------- /src/rough-painter.js: -------------------------------------------------------------------------------- 1 | import { RoughRenderer } from '../node_modules/roughjs/bin/renderer.js'; 2 | 3 | class RoughPainter { 4 | static get inputProperties() { 5 | return [ 6 | '--rough-fill', 7 | '--rough-fill-style', 8 | '--rough-roughness', 9 | '--rough-hachure-gap', 10 | '--rough-hachure-angle', 11 | '--rough-fill-weight', 12 | '--rough-border-color', 13 | '--rough-border-width' 14 | ]; 15 | } 16 | 17 | constructor() { 18 | this.renderer = new RoughRenderer(); 19 | this.defaultOptions = { 20 | maxRandomnessOffset: 2, 21 | roughness: 1, 22 | bowing: 1, 23 | stroke: '#000', 24 | strokeWidth: 1, 25 | curveTightness: 0, 26 | curveStepCount: 9, 27 | fill: null, 28 | fillStyle: 'hachure', 29 | fillWeight: -1, 30 | hachureAngle: -41, 31 | hachureGap: -1 32 | }; 33 | } 34 | 35 | _setFloatOption(properties, prop, option, options) { 36 | if (properties.get(prop).length) { 37 | options[option] = parseFloat(properties.get(prop).toString().trim()); 38 | } 39 | } 40 | 41 | _setStringOption(properties, prop, option, options) { 42 | if (properties.get(prop).length) { 43 | options[option] = properties.get(prop).toString().trim(); 44 | } 45 | } 46 | 47 | paint(ctx, geometry, properties) { 48 | const options = {}; 49 | this._setFloatOption(properties, '--rough-roughness', 'roughness', options); 50 | this._setFloatOption(properties, '--rough-hachure-gap', 'hachureGap', options); 51 | this._setFloatOption(properties, '--rough-hachure-angle', 'hachureAngle', options); 52 | this._setFloatOption(properties, '--rough-fill-weight', 'fillWeight', options); 53 | this._setFloatOption(properties, '--rough-border-width', 'strokeWidth', options); 54 | this._setStringOption(properties, '--rough-fill-style', 'fillStyle', options); 55 | this._setStringOption(properties, '--rough-fill', 'fill', options); 56 | this._setStringOption(properties, '--rough-border-color', 'stroke', options); 57 | const resolvedOptions = Object.assign({}, this.defaultOptions, options); 58 | 59 | const offset = (options.strokeWidth || 0); 60 | const points = [[0 + offset, 0 + offset], [geometry.width - offset, 0 + offset], [geometry.width - offset, geometry.height - offset], [0 + offset, geometry.height - offset]]; 61 | const opSets = []; 62 | if (options.fill) { 63 | if (resolvedOptions.fillStyle === 'solid') { 64 | opSets.push(this.renderer.solidFillPolygon(points, resolvedOptions)); 65 | } else { 66 | opSets.push(this.renderer.patternFillPolygon(points, resolvedOptions)); 67 | } 68 | } 69 | if (options.strokeWidth && (options.strokeWidth > 0)) { 70 | opSets.push(this.renderer.polygon(points, resolvedOptions)); 71 | } 72 | this._drawOps(opSets, resolvedOptions, ctx); 73 | } 74 | 75 | _drawOps(sets, o, ctx) { 76 | for (const drawing of sets) { 77 | switch (drawing.type) { 78 | case 'path': 79 | ctx.save(); 80 | ctx.strokeStyle = o.stroke; 81 | ctx.lineWidth = o.strokeWidth; 82 | this._drawToContext(ctx, drawing); 83 | ctx.restore(); 84 | break; 85 | case 'fillPath': 86 | ctx.save(); 87 | ctx.fillStyle = o.fill || ''; 88 | this._drawToContext(ctx, drawing); 89 | ctx.restore(); 90 | break; 91 | case 'fillSketch': 92 | this._fillSketch(ctx, drawing, o); 93 | break; 94 | } 95 | } 96 | } 97 | 98 | _fillSketch(ctx, drawing, o) { 99 | let fweight = o.fillWeight; 100 | if (fweight < 0) { 101 | fweight = o.strokeWidth / 2; 102 | } 103 | ctx.save(); 104 | ctx.strokeStyle = o.fill || ''; 105 | ctx.lineWidth = fweight; 106 | this._drawToContext(ctx, drawing); 107 | ctx.restore(); 108 | } 109 | 110 | _drawToContext(ctx, drawing) { 111 | ctx.beginPath(); 112 | for (const item of drawing.ops) { 113 | const data = item.data; 114 | switch (item.op) { 115 | case 'move': 116 | ctx.moveTo(data[0], data[1]); 117 | break; 118 | case 'bcurveTo': 119 | ctx.bezierCurveTo(data[0], data[1], data[2], data[3], data[4], data[5]); 120 | break; 121 | case 'qcurveTo': 122 | ctx.quadraticCurveTo(data[0], data[1], data[2], data[3]); 123 | break; 124 | case 'lineTo': 125 | ctx.lineTo(data[0], data[1]); 126 | break; 127 | } 128 | } 129 | if (drawing.type === 'fillPath') { 130 | ctx.fill(); 131 | } 132 | else { 133 | ctx.stroke(); 134 | } 135 | } 136 | } 137 | registerPaint('rough-painter', RoughPainter); --------------------------------------------------------------------------------