├── .github
└── FUNDING.yml
├── .gitignore
├── docs
├── example.png
├── example.pxd
├── images
│ ├── fork.png
│ ├── github.png
│ └── twitter.png
├── retina-images
│ ├── fork.png
│ ├── fork@2x.png
│ ├── github.png
│ ├── twitter.png
│ ├── github@2x.png
│ └── twitter@2x.png
├── examples
│ ├── engine
│ │ ├── sprite.png
│ │ └── sprite.styl
│ ├── retina
│ │ ├── sprite.png
│ │ ├── sprite@2x.png
│ │ └── sprite.styl
│ ├── padding
│ │ ├── sprite.png
│ │ └── sprite.styl
│ ├── algorithm
│ │ ├── sprite.png
│ │ └── sprite.styl
│ ├── template-function
│ │ ├── sprite.png
│ │ └── sprite.yml
│ ├── handlebars-template
│ │ ├── sprite.png
│ │ └── sprite.css
│ └── handlebars-inheritance
│ │ ├── sprite.png
│ │ └── sprite.scss
├── handlebarsStr.css.handlebars
├── handlebarsInheritance.scss.handlebars
└── gulpfile.js
├── test
├── test-files
│ ├── sprite1.png
│ ├── sprite2.png
│ ├── sprite3.png
│ ├── sprite1@2x.png
│ ├── sprite2@2x.png
│ ├── sprite3@2x.png
│ └── scss.template.handlebars
├── expected-files
│ ├── retina
│ │ ├── pixelsmith.png
│ │ ├── pixelsmith@2x.png
│ │ └── sprite.css
│ ├── default
│ │ ├── pixelsmith.png
│ │ └── sprite.css
│ ├── formats
│ │ ├── mint-pngsmith.png
│ │ └── sprite.styl
│ ├── options
│ │ ├── mint-pngsmith.png
│ │ └── sprite.css
│ ├── two-streams
│ │ ├── pixelsmith.png
│ │ └── sprite.css
│ ├── retina-two-streams
│ │ ├── pixelsmith.png
│ │ ├── pixelsmith@2x.png
│ │ └── sprite.css
│ ├── template
│ │ ├── mint-graphicsmagick.png
│ │ └── sprite.scss
│ ├── spritesheet-name
│ │ └── sprite.scss
│ └── retina-mapped
│ │ └── sprite.scss
├── utils
│ ├── child.js
│ └── image.js
├── gulpfile.js
└── gulp-spritesmith_test.js
├── .travis.yml
├── .eslintrc.js
├── UNLICENSE
├── package.json
├── CHANGELOG.md
├── lib
└── gulp-spritesmith.js
└── README.md
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | custom: https://twolfson.com/support-me
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | test/actual-files/
3 | docs/path/
4 |
--------------------------------------------------------------------------------
/docs/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/example.png
--------------------------------------------------------------------------------
/docs/example.pxd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/example.pxd
--------------------------------------------------------------------------------
/docs/images/fork.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/images/fork.png
--------------------------------------------------------------------------------
/docs/images/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/images/github.png
--------------------------------------------------------------------------------
/docs/images/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/images/twitter.png
--------------------------------------------------------------------------------
/docs/retina-images/fork.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/retina-images/fork.png
--------------------------------------------------------------------------------
/test/test-files/sprite1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/test-files/sprite1.png
--------------------------------------------------------------------------------
/test/test-files/sprite2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/test-files/sprite2.png
--------------------------------------------------------------------------------
/test/test-files/sprite3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/test-files/sprite3.png
--------------------------------------------------------------------------------
/docs/examples/engine/sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/examples/engine/sprite.png
--------------------------------------------------------------------------------
/docs/examples/retina/sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/examples/retina/sprite.png
--------------------------------------------------------------------------------
/docs/retina-images/fork@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/retina-images/fork@2x.png
--------------------------------------------------------------------------------
/docs/retina-images/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/retina-images/github.png
--------------------------------------------------------------------------------
/docs/retina-images/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/retina-images/twitter.png
--------------------------------------------------------------------------------
/test/test-files/sprite1@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/test-files/sprite1@2x.png
--------------------------------------------------------------------------------
/test/test-files/sprite2@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/test-files/sprite2@2x.png
--------------------------------------------------------------------------------
/test/test-files/sprite3@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/test-files/sprite3@2x.png
--------------------------------------------------------------------------------
/docs/examples/padding/sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/examples/padding/sprite.png
--------------------------------------------------------------------------------
/docs/retina-images/github@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/retina-images/github@2x.png
--------------------------------------------------------------------------------
/docs/retina-images/twitter@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/retina-images/twitter@2x.png
--------------------------------------------------------------------------------
/docs/examples/algorithm/sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/examples/algorithm/sprite.png
--------------------------------------------------------------------------------
/docs/examples/retina/sprite@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/examples/retina/sprite@2x.png
--------------------------------------------------------------------------------
/test/expected-files/retina/pixelsmith.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/expected-files/retina/pixelsmith.png
--------------------------------------------------------------------------------
/docs/examples/template-function/sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/examples/template-function/sprite.png
--------------------------------------------------------------------------------
/test/expected-files/default/pixelsmith.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/expected-files/default/pixelsmith.png
--------------------------------------------------------------------------------
/docs/examples/handlebars-template/sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/examples/handlebars-template/sprite.png
--------------------------------------------------------------------------------
/test/expected-files/formats/mint-pngsmith.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/expected-files/formats/mint-pngsmith.png
--------------------------------------------------------------------------------
/test/expected-files/options/mint-pngsmith.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/expected-files/options/mint-pngsmith.png
--------------------------------------------------------------------------------
/test/expected-files/retina/pixelsmith@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/expected-files/retina/pixelsmith@2x.png
--------------------------------------------------------------------------------
/test/expected-files/two-streams/pixelsmith.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/expected-files/two-streams/pixelsmith.png
--------------------------------------------------------------------------------
/docs/examples/handlebars-inheritance/sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/docs/examples/handlebars-inheritance/sprite.png
--------------------------------------------------------------------------------
/test/expected-files/retina-two-streams/pixelsmith.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/expected-files/retina-two-streams/pixelsmith.png
--------------------------------------------------------------------------------
/test/expected-files/template/mint-graphicsmagick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/expected-files/template/mint-graphicsmagick.png
--------------------------------------------------------------------------------
/test/expected-files/retina-two-streams/pixelsmith@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twolfson/gulp.spritesmith/HEAD/test/expected-files/retina-two-streams/pixelsmith@2x.png
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "16"
4 | - "14"
5 | - "12"
6 |
7 | notifications:
8 | email:
9 | recipients:
10 | - todd@twolfson.com
11 | on_success: change
12 | on_failure: change
13 |
--------------------------------------------------------------------------------
/docs/handlebarsStr.css.handlebars:
--------------------------------------------------------------------------------
1 | {{#sprites}}
2 | .icon-{{name}}:before {
3 | display: block;
4 | background-image: url({{{escaped_image}}});
5 | background-position: {{px.offset_x}} {{px.offset_y}};
6 | width: {{px.width}};
7 | height: {{px.height}};
8 | }
9 | {{/sprites}}
10 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // Inherit from our package
3 | extends: 'eslint-config-twolfson',
4 |
5 | // Configure our environment
6 | // http://eslint.org/docs/user-guide/configuring#specifying-environments
7 | env: {
8 | node: true,
9 | mocha: true
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/test/test-files/scss.template.handlebars:
--------------------------------------------------------------------------------
1 | @mixin sprite($filename) {
2 |
3 | &:before {
4 | content: "";
5 | display: inline-block;
6 |
7 | {{#sprites}}
8 | @if $filename == {{name}} {
9 | background-image: url({{{escaped_image}}});
10 | background-position: {{px.offset_x}} {{px.offset_y}};
11 | height: {{px.height}};
12 | width: {{px.width}};
13 | }
14 | {{/sprites}}
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/docs/examples/handlebars-template/sprite.css:
--------------------------------------------------------------------------------
1 | .icon-fork:before {
2 | display: block;
3 | background-image: url(sprite.png);
4 | background-position: 0px 0px;
5 | width: 32px;
6 | height: 32px;
7 | }
8 | .icon-github:before {
9 | display: block;
10 | background-image: url(sprite.png);
11 | background-position: -32px 0px;
12 | width: 32px;
13 | height: 32px;
14 | }
15 | .icon-twitter:before {
16 | display: block;
17 | background-image: url(sprite.png);
18 | background-position: 0px -32px;
19 | width: 32px;
20 | height: 32px;
21 | }
22 |
--------------------------------------------------------------------------------
/test/expected-files/template/sprite.scss:
--------------------------------------------------------------------------------
1 | @mixin sprite($filename) {
2 |
3 | &:before {
4 | content: "";
5 | display: inline-block;
6 |
7 | @if $filename == sprite1 {
8 | background-image: url(sprite.png);
9 | background-position: 0px 0px;
10 | height: 50px;
11 | width: 50px;
12 | }
13 | @if $filename == sprite2 {
14 | background-image: url(sprite.png);
15 | background-position: 0px -50px;
16 | height: 50px;
17 | width: 50px;
18 | }
19 | @if $filename == sprite3 {
20 | background-image: url(sprite.png);
21 | background-position: 0px -100px;
22 | height: 200px;
23 | width: 100px;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/test/utils/child.js:
--------------------------------------------------------------------------------
1 | // Load in dependencies
2 | var exec = require('child_process').exec;
3 |
4 | // Define our execution helper
5 | exports.run = function (cmd) {
6 | before(function runFn(done) {
7 | exec(cmd, function (err, stdout, stderr) {
8 | if (!err && stderr) {
9 | err = new Error(stderr);
10 | }
11 | done(err);
12 | });
13 | });
14 | };
15 | exports.runSaveError = function (cmd) {
16 | before(function runFn(done) {
17 | var that = this;
18 | exec(cmd, function (err, stdout, stderr) {
19 | if (!err && stderr) {
20 | err = new Error(stderr);
21 | }
22 | that.err = err;
23 | done();
24 | });
25 | });
26 | after(function cleanup() {
27 | delete this.err;
28 | });
29 | };
30 |
--------------------------------------------------------------------------------
/docs/handlebarsInheritance.scss.handlebars:
--------------------------------------------------------------------------------
1 | {
2 | // Default options
3 | 'functions': true,
4 | 'variableNameTransforms': ['dasherize']
5 | }
6 |
7 | {{#extend "scss"}}
8 | {{#content "sprites"}}
9 | {{#each sprites}}
10 | ${{strings.name}}: ({{px.x}}, {{px.y}}, {{px.offset_x}}, {{px.offset_y}}, {{px.width}}, {{px.height}}, {{px.total_width}}, {{px.total_height}}, '{{{escaped_image}}}', '{{name}}', );
11 | {{/each}}
12 | {{/content}}
13 | {{#content "spritesheet"}}
14 | ${{spritesheet_info.strings.name_sprites}}: ({{#each sprites}}${{strings.name}}, {{/each}});
15 | ${{spritesheet_info.strings.name}}: ({{spritesheet.px.width}}, {{spritesheet.px.height}}, '{{{spritesheet.escaped_image}}}', ${{spritesheet_info.strings.name_sprites}}, );
16 | {{/content}}
17 | {{/extend}}
18 |
--------------------------------------------------------------------------------
/test/expected-files/default/sprite.css:
--------------------------------------------------------------------------------
1 | /*
2 | Icon classes can be used entirely standalone. They are named after their original file names.
3 |
4 | Example usage in HTML:
5 |
6 | `display: block` sprite:
7 |
8 |
9 | To change `display` (e.g. `display: inline-block;`), we suggest using a common CSS class:
10 |
11 | // CSS
12 | .icon {
13 | display: inline-block;
14 | }
15 |
16 | // HTML
17 |
18 | */
19 | .icon-sprite1 {
20 | background-image: url(sprite.png);
21 | background-position: -100px 0px;
22 | width: 50px;
23 | height: 50px;
24 | }
25 | .icon-sprite2 {
26 | background-image: url(sprite.png);
27 | background-position: -100px -50px;
28 | width: 50px;
29 | height: 50px;
30 | }
31 | .icon-sprite3 {
32 | background-image: url(sprite.png);
33 | background-position: 0px 0px;
34 | width: 100px;
35 | height: 200px;
36 | }
37 |
--------------------------------------------------------------------------------
/test/expected-files/two-streams/sprite.css:
--------------------------------------------------------------------------------
1 | /*
2 | Icon classes can be used entirely standalone. They are named after their original file names.
3 |
4 | Example usage in HTML:
5 |
6 | `display: block` sprite:
7 |
8 |
9 | To change `display` (e.g. `display: inline-block;`), we suggest using a common CSS class:
10 |
11 | // CSS
12 | .icon {
13 | display: inline-block;
14 | }
15 |
16 | // HTML
17 |
18 | */
19 | .icon-sprite1 {
20 | background-image: url(sprite.png);
21 | background-position: -100px 0px;
22 | width: 50px;
23 | height: 50px;
24 | }
25 | .icon-sprite2 {
26 | background-image: url(sprite.png);
27 | background-position: -100px -50px;
28 | width: 50px;
29 | height: 50px;
30 | }
31 | .icon-sprite3 {
32 | background-image: url(sprite.png);
33 | background-position: 0px 0px;
34 | width: 100px;
35 | height: 200px;
36 | }
37 |
--------------------------------------------------------------------------------
/test/expected-files/options/sprite.css:
--------------------------------------------------------------------------------
1 | /*
2 | Icon classes can be used entirely standalone. They are named after their original file names.
3 |
4 | Example usage in HTML:
5 |
6 | `display: block` sprite:
7 |
8 |
9 | To change `display` (e.g. `display: inline-block;`), we suggest using a common CSS class:
10 |
11 | // CSS
12 | .icon {
13 | display: inline-block;
14 | }
15 |
16 | // HTML
17 |
18 | */
19 | .icon-sprite1 {
20 | background-image: url(../../everywhere.png);
21 | background-position: -150px 0px;
22 | width: 50px;
23 | height: 50px;
24 | }
25 | .icon-sprite2 {
26 | background-image: url(../../everywhere.png);
27 | background-position: -100px -50px;
28 | width: 50px;
29 | height: 50px;
30 | }
31 | .icon-sprite3 {
32 | background-image: url(../../everywhere.png);
33 | background-position: 0px -100px;
34 | width: 100px;
35 | height: 200px;
36 | }
37 |
--------------------------------------------------------------------------------
/test/utils/image.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var pngparse = require('pngparse');
3 |
4 | // Modified from https://github.com/mikolalysenko/get-pixels/blob/2ac98645119244d6e52afcef5fe52cc9300fb27b/node-pixels.js
5 | // due to lack of loading '.jpg' as a '.png'
6 | exports._loadImage = function (filepath, cb) {
7 | fs.readFile(filepath, function (err, buff) {
8 | if (err) {
9 | return cb(err);
10 | }
11 | pngparse.parse(buff, cb);
12 | });
13 | };
14 |
15 | exports.loadActual = function (filepath) {
16 | before(function (done) {
17 | var that = this;
18 | exports._loadImage(filepath, function (err, pixels) {
19 | that.actualPixels = pixels;
20 | done(err);
21 | });
22 | });
23 | };
24 |
25 | exports.loadExpected = function (filepath) {
26 | before(function (done) {
27 | var that = this;
28 | exports._loadImage(filepath, function (err, pixels) {
29 | that.expectedPixels = pixels;
30 | done(err);
31 | });
32 | });
33 | };
34 |
--------------------------------------------------------------------------------
/UNLICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
25 |
--------------------------------------------------------------------------------
/test/expected-files/retina/sprite.css:
--------------------------------------------------------------------------------
1 | /*
2 | Icon classes can be used entirely standalone. They are named after their original file names.
3 |
4 | Example usage in HTML:
5 |
6 | `display: block` sprite:
7 |
8 |
9 | To change `display` (e.g. `display: inline-block;`), we suggest using a common CSS class:
10 |
11 | // CSS
12 | .icon {
13 | display: inline-block;
14 | }
15 |
16 | // HTML
17 |
18 | */
19 | .icon-sprite1 {
20 | background-image: url(sprite.png);
21 | background-position: -100px 0px;
22 | width: 50px;
23 | height: 50px;
24 | }
25 | .icon-sprite2 {
26 | background-image: url(sprite.png);
27 | background-position: -100px -50px;
28 | width: 50px;
29 | height: 50px;
30 | }
31 | .icon-sprite3 {
32 | background-image: url(sprite.png);
33 | background-position: 0px 0px;
34 | width: 100px;
35 | height: 200px;
36 | }
37 |
38 | @media (-webkit-min-device-pixel-ratio: 2),
39 | (min-resolution: 192dpi) {
40 | .icon-sprite1 {
41 | background-image: url(sprite@2x.png);
42 | background-size: 150px 200px;
43 | }
44 | .icon-sprite2 {
45 | background-image: url(sprite@2x.png);
46 | background-size: 150px 200px;
47 | }
48 | .icon-sprite3 {
49 | background-image: url(sprite@2x.png);
50 | background-size: 150px 200px;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/test/expected-files/retina-two-streams/sprite.css:
--------------------------------------------------------------------------------
1 | /*
2 | Icon classes can be used entirely standalone. They are named after their original file names.
3 |
4 | Example usage in HTML:
5 |
6 | `display: block` sprite:
7 |
8 |
9 | To change `display` (e.g. `display: inline-block;`), we suggest using a common CSS class:
10 |
11 | // CSS
12 | .icon {
13 | display: inline-block;
14 | }
15 |
16 | // HTML
17 |
18 | */
19 | .icon-sprite1 {
20 | background-image: url(sprite.png);
21 | background-position: -100px 0px;
22 | width: 50px;
23 | height: 50px;
24 | }
25 | .icon-sprite2 {
26 | background-image: url(sprite.png);
27 | background-position: -100px -50px;
28 | width: 50px;
29 | height: 50px;
30 | }
31 | .icon-sprite3 {
32 | background-image: url(sprite.png);
33 | background-position: 0px 0px;
34 | width: 100px;
35 | height: 200px;
36 | }
37 |
38 | @media (-webkit-min-device-pixel-ratio: 2),
39 | (min-resolution: 192dpi) {
40 | .icon-sprite1 {
41 | background-image: url(sprite@2x.png);
42 | background-size: 150px 200px;
43 | }
44 | .icon-sprite2 {
45 | background-image: url(sprite@2x.png);
46 | background-size: 150px 200px;
47 | }
48 | .icon-sprite3 {
49 | background-image: url(sprite@2x.png);
50 | background-size: 150px 200px;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/docs/examples/template-function/sprite.yml:
--------------------------------------------------------------------------------
1 | fork:
2 | x: 0
3 | 'y': 0
4 | width: 32
5 | height: 32
6 | source_image: /home/todd/github/gulp.spritesmith/docs/images/fork.png
7 | image: sprite.png
8 | total_width: 64
9 | total_height: 64
10 | escaped_image: sprite.png
11 | offset_x: -0.0
12 | offset_y: -0.0
13 | px:
14 | x: 0px
15 | 'y': 0px
16 | offset_x: 0px
17 | offset_y: 0px
18 | height: 32px
19 | width: 32px
20 | total_height: 64px
21 | total_width: 64px
22 | github:
23 | x: 32
24 | 'y': 0
25 | width: 32
26 | height: 32
27 | source_image: /home/todd/github/gulp.spritesmith/docs/images/github.png
28 | image: sprite.png
29 | total_width: 64
30 | total_height: 64
31 | escaped_image: sprite.png
32 | offset_x: -32
33 | offset_y: -0.0
34 | px:
35 | x: 32px
36 | 'y': 0px
37 | offset_x: '-32px'
38 | offset_y: 0px
39 | height: 32px
40 | width: 32px
41 | total_height: 64px
42 | total_width: 64px
43 | twitter:
44 | x: 0
45 | 'y': 32
46 | width: 32
47 | height: 32
48 | source_image: /home/todd/github/gulp.spritesmith/docs/images/twitter.png
49 | image: sprite.png
50 | total_width: 64
51 | total_height: 64
52 | escaped_image: sprite.png
53 | offset_x: -0.0
54 | offset_y: -32
55 | px:
56 | x: 0px
57 | 'y': 32px
58 | offset_x: 0px
59 | offset_y: '-32px'
60 | height: 32px
61 | width: 32px
62 | total_height: 64px
63 | total_width: 64px
64 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gulp.spritesmith",
3 | "description": "Convert a set of images into a spritesheet and CSS variables via gulp",
4 | "version": "6.13.1",
5 | "homepage": "https://github.com/twolfson/gulp.spritesmith",
6 | "author": {
7 | "name": "Todd Wolfson",
8 | "email": "todd@twolfson.com",
9 | "url": "http://twolfson.com/"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git://github.com/twolfson/gulp.spritesmith.git"
14 | },
15 | "bugs": {
16 | "url": "https://github.com/twolfson/gulp.spritesmith/issues"
17 | },
18 | "license": "Unlicense",
19 | "main": "lib/gulp-spritesmith",
20 | "engines": {
21 | "node": ">= 4.0.0"
22 | },
23 | "scripts": {
24 | "precheck": "eslint docs/ lib/ test/",
25 | "lint": "eslint docs/ lib/ test/ --max-warnings 0",
26 | "test": "npm run precheck && npm run test-mocha && npm run lint",
27 | "test-mocha": "cd test && mocha . --timeout 60000"
28 | },
29 | "dependencies": {
30 | "async": "~3.2.3",
31 | "minimatch": "~3.0.3",
32 | "spritesheet-templates": "^10.3.0",
33 | "spritesmith": "^3.4.0",
34 | "through2": "~2.0.3",
35 | "underscore": "~1.13.1",
36 | "url2": "~1.0.4",
37 | "vinyl": "~2.1.0"
38 | },
39 | "devDependencies": {
40 | "eslint": "~4.10.0",
41 | "eslint-config-twolfson": "~1.0.0",
42 | "foundry": "~4.3.2",
43 | "foundry-release-git": "~2.0.2",
44 | "foundry-release-npm": "~2.0.2",
45 | "gulp": "~5.0.0",
46 | "gulp-csso": "~3.0.0",
47 | "gulp-imagemin": "~3.1.1",
48 | "merge-stream": "~1.0.1",
49 | "mocha": "~8.4.0",
50 | "phantomjssmith": "~1.0.0",
51 | "pngparse": "~2.0.1",
52 | "rimraf": "~2.6.1",
53 | "vinyl-buffer": "~1.0.0"
54 | },
55 | "keywords": [
56 | "gulpplugin",
57 | "spritesmith",
58 | "sprite",
59 | "spritesheet"
60 | ],
61 | "foundry": {
62 | "releaseCommands": [
63 | "foundry-release-git",
64 | "foundry-release-npm"
65 | ]
66 | }
67 | }
--------------------------------------------------------------------------------
/docs/examples/handlebars-inheritance/sprite.scss:
--------------------------------------------------------------------------------
1 | // SCSS variables are information about icon's compiled state, stored under its original file name
2 | //
3 | // .icon-home {
4 | // width: $icon-home-width;
5 | // }
6 | //
7 | // The large array-like variables contain all information about a single icon
8 | // $icon-home: x y offset_x offset_y width height total_width total_height image_path;
9 | //
10 | // At the bottom of this section, we provide information about the spritesheet itself
11 | // $spritesheet: width height image $spritesheet-sprites;
12 | $fork: (0px, 0px, 0px, 0px, 32px, 32px, 64px, 64px, 'sprite.png', 'fork', );
13 | $github: (32px, 0px, -32px, 0px, 32px, 32px, 64px, 64px, 'sprite.png', 'github', );
14 | $twitter: (0px, 32px, 0px, -32px, 32px, 32px, 64px, 64px, 'sprite.png', 'twitter', );
15 | $spritesheet-sprites: ($fork, $github, $twitter, );
16 | $spritesheet: (64px, 64px, 'sprite.png', $spritesheet-sprites, );
17 |
18 | // The provided mixins are intended to be used with the array-like variables
19 | //
20 | // .icon-home {
21 | // @include sprite-width($icon-home);
22 | // }
23 | //
24 | // .icon-email {
25 | // @include sprite($icon-email);
26 | // }
27 | //
28 | // Example usage in HTML:
29 | //
30 | // `display: block` sprite:
31 | //
32 | //
33 | // To change `display` (e.g. `display: inline-block;`), we suggest using a common CSS class:
34 | //
35 | // // CSS
36 | // .icon {
37 | // display: inline-block;
38 | // }
39 | //
40 | // // HTML
41 | //
42 | @mixin sprite-width($sprite) {
43 | width: nth($sprite, 5);
44 | }
45 |
46 | @mixin sprite-height($sprite) {
47 | height: nth($sprite, 6);
48 | }
49 |
50 | @mixin sprite-position($sprite) {
51 | $sprite-offset-x: nth($sprite, 3);
52 | $sprite-offset-y: nth($sprite, 4);
53 | background-position: $sprite-offset-x $sprite-offset-y;
54 | }
55 |
56 | @mixin sprite-image($sprite) {
57 | $sprite-image: nth($sprite, 9);
58 | background-image: url(#{$sprite-image});
59 | }
60 |
61 | @mixin sprite($sprite) {
62 | @include sprite-image($sprite);
63 | @include sprite-position($sprite);
64 | @include sprite-width($sprite);
65 | @include sprite-height($sprite);
66 | }
67 |
68 | // The `sprites` mixin generates identical output to the CSS template
69 | // but can be overridden inside of SCSS
70 | //
71 | // @include sprites($spritesheet-sprites);
72 | @mixin sprites($sprites) {
73 | @each $sprite in $sprites {
74 | $sprite-name: nth($sprite, 10);
75 | .#{$sprite-name} {
76 | @include sprite($sprite);
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/docs/examples/engine/sprite.styl:
--------------------------------------------------------------------------------
1 | /*
2 | Stylus variables are information about icon's compiled state, stored under its original file name
3 |
4 | .icon-home {
5 | width: $icon_home_width;
6 | }
7 |
8 | The large array-like variables contain all information about a single icon
9 | $icon_home = x y offset_x offset_y width height total_width total_height image_path;
10 |
11 | At the bottom of this section, we provide information about the spritesheet itself
12 | $spritesheet = width height image $spritesheet_sprites;
13 | */
14 | $fork_name = 'fork';
15 | $fork_x = 0px;
16 | $fork_y = 0px;
17 | $fork_offset_x = 0px;
18 | $fork_offset_y = 0px;
19 | $fork_width = 32px;
20 | $fork_height = 32px;
21 | $fork_total_width = 64px;
22 | $fork_total_height = 64px;
23 | $fork_image = 'sprite.png';
24 | $fork = 0px 0px 0px 0px 32px 32px 64px 64px 'sprite.png' 'fork';
25 | $github_name = 'github';
26 | $github_x = 32px;
27 | $github_y = 0px;
28 | $github_offset_x = -32px;
29 | $github_offset_y = 0px;
30 | $github_width = 32px;
31 | $github_height = 32px;
32 | $github_total_width = 64px;
33 | $github_total_height = 64px;
34 | $github_image = 'sprite.png';
35 | $github = 32px 0px -32px 0px 32px 32px 64px 64px 'sprite.png' 'github';
36 | $twitter_name = 'twitter';
37 | $twitter_x = 0px;
38 | $twitter_y = 32px;
39 | $twitter_offset_x = 0px;
40 | $twitter_offset_y = -32px;
41 | $twitter_width = 32px;
42 | $twitter_height = 32px;
43 | $twitter_total_width = 64px;
44 | $twitter_total_height = 64px;
45 | $twitter_image = 'sprite.png';
46 | $twitter = 0px 32px 0px -32px 32px 32px 64px 64px 'sprite.png' 'twitter';
47 | $spritesheet_width = 64px;
48 | $spritesheet_height = 64px;
49 | $spritesheet_image = 'sprite.png';
50 | $spritesheet_sprites = $fork $github $twitter;
51 | $spritesheet = 64px 64px 'sprite.png' $spritesheet_sprites;
52 |
53 | /*
54 | The provided mixins are intended to be used with the array-like variables
55 |
56 | .icon-home {
57 | spriteWidth($icon_home)
58 | }
59 |
60 | .icon-email {
61 | sprite($icon_email)
62 | }
63 |
64 | Example usage in HTML:
65 |
66 | `display: block` sprite:
67 |
68 |
69 | To change `display` (e.g. `display: inline-block;`), we suggest using a common CSS class:
70 |
71 | // CSS
72 | .icon {
73 | display: inline-block;
74 | }
75 |
76 | // HTML
77 |
78 | */
79 | spriteWidth($sprite) {
80 | width: $sprite[4];
81 | }
82 |
83 | spriteHeight($sprite) {
84 | height: $sprite[5];
85 | }
86 |
87 | spritePosition($sprite) {
88 | background-position: $sprite[2] $sprite[3];
89 | }
90 |
91 | spriteImage($sprite) {
92 | background-image: url($sprite[8]);
93 | }
94 |
95 | sprite($sprite) {
96 | spriteImage($sprite)
97 | spritePosition($sprite)
98 | spriteWidth($sprite)
99 | spriteHeight($sprite)
100 | }
101 |
102 | /*
103 | The `sprites` mixin generates identical output to the CSS template
104 | but can be overridden inside of Stylus
105 |
106 | This must be run when you have at least 2 sprites.
107 | If run with a single sprite, then there will be reference errors.
108 |
109 | sprites($spritesheet_sprites);
110 | */
111 | sprites($sprites) {
112 | for $sprite in $sprites {
113 | $sprite_name = $sprite[9];
114 | .{$sprite_name} {
115 | sprite($sprite);
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/docs/examples/padding/sprite.styl:
--------------------------------------------------------------------------------
1 | /*
2 | Stylus variables are information about icon's compiled state, stored under its original file name
3 |
4 | .icon-home {
5 | width: $icon_home_width;
6 | }
7 |
8 | The large array-like variables contain all information about a single icon
9 | $icon_home = x y offset_x offset_y width height total_width total_height image_path;
10 |
11 | At the bottom of this section, we provide information about the spritesheet itself
12 | $spritesheet = width height image $spritesheet_sprites;
13 | */
14 | $fork_name = 'fork';
15 | $fork_x = 0px;
16 | $fork_y = 0px;
17 | $fork_offset_x = 0px;
18 | $fork_offset_y = 0px;
19 | $fork_width = 32px;
20 | $fork_height = 32px;
21 | $fork_total_width = 84px;
22 | $fork_total_height = 84px;
23 | $fork_image = 'sprite.png';
24 | $fork = 0px 0px 0px 0px 32px 32px 84px 84px 'sprite.png' 'fork';
25 | $github_name = 'github';
26 | $github_x = 52px;
27 | $github_y = 0px;
28 | $github_offset_x = -52px;
29 | $github_offset_y = 0px;
30 | $github_width = 32px;
31 | $github_height = 32px;
32 | $github_total_width = 84px;
33 | $github_total_height = 84px;
34 | $github_image = 'sprite.png';
35 | $github = 52px 0px -52px 0px 32px 32px 84px 84px 'sprite.png' 'github';
36 | $twitter_name = 'twitter';
37 | $twitter_x = 0px;
38 | $twitter_y = 52px;
39 | $twitter_offset_x = 0px;
40 | $twitter_offset_y = -52px;
41 | $twitter_width = 32px;
42 | $twitter_height = 32px;
43 | $twitter_total_width = 84px;
44 | $twitter_total_height = 84px;
45 | $twitter_image = 'sprite.png';
46 | $twitter = 0px 52px 0px -52px 32px 32px 84px 84px 'sprite.png' 'twitter';
47 | $spritesheet_width = 84px;
48 | $spritesheet_height = 84px;
49 | $spritesheet_image = 'sprite.png';
50 | $spritesheet_sprites = $fork $github $twitter;
51 | $spritesheet = 84px 84px 'sprite.png' $spritesheet_sprites;
52 |
53 | /*
54 | The provided mixins are intended to be used with the array-like variables
55 |
56 | .icon-home {
57 | spriteWidth($icon_home)
58 | }
59 |
60 | .icon-email {
61 | sprite($icon_email)
62 | }
63 |
64 | Example usage in HTML:
65 |
66 | `display: block` sprite:
67 |
68 |
69 | To change `display` (e.g. `display: inline-block;`), we suggest using a common CSS class:
70 |
71 | // CSS
72 | .icon {
73 | display: inline-block;
74 | }
75 |
76 | // HTML
77 |
78 | */
79 | spriteWidth($sprite) {
80 | width: $sprite[4];
81 | }
82 |
83 | spriteHeight($sprite) {
84 | height: $sprite[5];
85 | }
86 |
87 | spritePosition($sprite) {
88 | background-position: $sprite[2] $sprite[3];
89 | }
90 |
91 | spriteImage($sprite) {
92 | background-image: url($sprite[8]);
93 | }
94 |
95 | sprite($sprite) {
96 | spriteImage($sprite)
97 | spritePosition($sprite)
98 | spriteWidth($sprite)
99 | spriteHeight($sprite)
100 | }
101 |
102 | /*
103 | The `sprites` mixin generates identical output to the CSS template
104 | but can be overridden inside of Stylus
105 |
106 | This must be run when you have at least 2 sprites.
107 | If run with a single sprite, then there will be reference errors.
108 |
109 | sprites($spritesheet_sprites);
110 | */
111 | sprites($sprites) {
112 | for $sprite in $sprites {
113 | $sprite_name = $sprite[9];
114 | .{$sprite_name} {
115 | sprite($sprite);
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/docs/examples/algorithm/sprite.styl:
--------------------------------------------------------------------------------
1 | /*
2 | Stylus variables are information about icon's compiled state, stored under its original file name
3 |
4 | .icon-home {
5 | width: $icon_home_width;
6 | }
7 |
8 | The large array-like variables contain all information about a single icon
9 | $icon_home = x y offset_x offset_y width height total_width total_height image_path;
10 |
11 | At the bottom of this section, we provide information about the spritesheet itself
12 | $spritesheet = width height image $spritesheet_sprites;
13 | */
14 | $fork_name = 'fork';
15 | $fork_x = 64px;
16 | $fork_y = 0px;
17 | $fork_offset_x = -64px;
18 | $fork_offset_y = 0px;
19 | $fork_width = 32px;
20 | $fork_height = 32px;
21 | $fork_total_width = 96px;
22 | $fork_total_height = 96px;
23 | $fork_image = 'sprite.png';
24 | $fork = 64px 0px -64px 0px 32px 32px 96px 96px 'sprite.png' 'fork';
25 | $github_name = 'github';
26 | $github_x = 32px;
27 | $github_y = 32px;
28 | $github_offset_x = -32px;
29 | $github_offset_y = -32px;
30 | $github_width = 32px;
31 | $github_height = 32px;
32 | $github_total_width = 96px;
33 | $github_total_height = 96px;
34 | $github_image = 'sprite.png';
35 | $github = 32px 32px -32px -32px 32px 32px 96px 96px 'sprite.png' 'github';
36 | $twitter_name = 'twitter';
37 | $twitter_x = 0px;
38 | $twitter_y = 64px;
39 | $twitter_offset_x = 0px;
40 | $twitter_offset_y = -64px;
41 | $twitter_width = 32px;
42 | $twitter_height = 32px;
43 | $twitter_total_width = 96px;
44 | $twitter_total_height = 96px;
45 | $twitter_image = 'sprite.png';
46 | $twitter = 0px 64px 0px -64px 32px 32px 96px 96px 'sprite.png' 'twitter';
47 | $spritesheet_width = 96px;
48 | $spritesheet_height = 96px;
49 | $spritesheet_image = 'sprite.png';
50 | $spritesheet_sprites = $fork $github $twitter;
51 | $spritesheet = 96px 96px 'sprite.png' $spritesheet_sprites;
52 |
53 | /*
54 | The provided mixins are intended to be used with the array-like variables
55 |
56 | .icon-home {
57 | spriteWidth($icon_home)
58 | }
59 |
60 | .icon-email {
61 | sprite($icon_email)
62 | }
63 |
64 | Example usage in HTML:
65 |
66 | `display: block` sprite:
67 |
68 |
69 | To change `display` (e.g. `display: inline-block;`), we suggest using a common CSS class:
70 |
71 | // CSS
72 | .icon {
73 | display: inline-block;
74 | }
75 |
76 | // HTML
77 |
78 | */
79 | spriteWidth($sprite) {
80 | width: $sprite[4];
81 | }
82 |
83 | spriteHeight($sprite) {
84 | height: $sprite[5];
85 | }
86 |
87 | spritePosition($sprite) {
88 | background-position: $sprite[2] $sprite[3];
89 | }
90 |
91 | spriteImage($sprite) {
92 | background-image: url($sprite[8]);
93 | }
94 |
95 | sprite($sprite) {
96 | spriteImage($sprite)
97 | spritePosition($sprite)
98 | spriteWidth($sprite)
99 | spriteHeight($sprite)
100 | }
101 |
102 | /*
103 | The `sprites` mixin generates identical output to the CSS template
104 | but can be overridden inside of Stylus
105 |
106 | This must be run when you have at least 2 sprites.
107 | If run with a single sprite, then there will be reference errors.
108 |
109 | sprites($spritesheet_sprites);
110 | */
111 | sprites($sprites) {
112 | for $sprite in $sprites {
113 | $sprite_name = $sprite[9];
114 | .{$sprite_name} {
115 | sprite($sprite);
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/test/expected-files/formats/sprite.styl:
--------------------------------------------------------------------------------
1 | /*
2 | Stylus variables are information about icon's compiled state, stored under its original file name
3 |
4 | .icon-home {
5 | width: $icon_home_width;
6 | }
7 |
8 | The large array-like variables contain all information about a single icon
9 | $icon_home = x y offset_x offset_y width height total_width total_height image_path;
10 |
11 | At the bottom of this section, we provide information about the spritesheet itself
12 | $spritesheet = width height image $spritesheet_sprites;
13 | */
14 | $sprite1_name = 'sprite1';
15 | $sprite1_x = 0px;
16 | $sprite1_y = 0px;
17 | $sprite1_offset_x = 0px;
18 | $sprite1_offset_y = 0px;
19 | $sprite1_width = 50px;
20 | $sprite1_height = 50px;
21 | $sprite1_total_width = 100px;
22 | $sprite1_total_height = 300px;
23 | $sprite1_image = 'sprite.jpg';
24 | $sprite1 = 0px 0px 0px 0px 50px 50px 100px 300px 'sprite.jpg' 'sprite1';
25 | $sprite2_name = 'sprite2';
26 | $sprite2_x = 0px;
27 | $sprite2_y = 50px;
28 | $sprite2_offset_x = 0px;
29 | $sprite2_offset_y = -50px;
30 | $sprite2_width = 50px;
31 | $sprite2_height = 50px;
32 | $sprite2_total_width = 100px;
33 | $sprite2_total_height = 300px;
34 | $sprite2_image = 'sprite.jpg';
35 | $sprite2 = 0px 50px 0px -50px 50px 50px 100px 300px 'sprite.jpg' 'sprite2';
36 | $sprite3_name = 'sprite3';
37 | $sprite3_x = 0px;
38 | $sprite3_y = 100px;
39 | $sprite3_offset_x = 0px;
40 | $sprite3_offset_y = -100px;
41 | $sprite3_width = 100px;
42 | $sprite3_height = 200px;
43 | $sprite3_total_width = 100px;
44 | $sprite3_total_height = 300px;
45 | $sprite3_image = 'sprite.jpg';
46 | $sprite3 = 0px 100px 0px -100px 100px 200px 100px 300px 'sprite.jpg' 'sprite3';
47 | $spritesheet_width = 100px;
48 | $spritesheet_height = 300px;
49 | $spritesheet_image = 'sprite.jpg';
50 | $spritesheet_sprites = $sprite1 $sprite2 $sprite3;
51 | $spritesheet = 100px 300px 'sprite.jpg' $spritesheet_sprites;
52 |
53 | /*
54 | The provided mixins are intended to be used with the array-like variables
55 |
56 | .icon-home {
57 | spriteWidth($icon_home)
58 | }
59 |
60 | .icon-email {
61 | sprite($icon_email)
62 | }
63 |
64 | Example usage in HTML:
65 |
66 | `display: block` sprite:
67 |
68 |
69 | To change `display` (e.g. `display: inline-block;`), we suggest using a common CSS class:
70 |
71 | // CSS
72 | .icon {
73 | display: inline-block;
74 | }
75 |
76 | // HTML
77 |
78 | */
79 | spriteWidth($sprite) {
80 | width: $sprite[4];
81 | }
82 |
83 | spriteHeight($sprite) {
84 | height: $sprite[5];
85 | }
86 |
87 | spritePosition($sprite) {
88 | background-position: $sprite[2] $sprite[3];
89 | }
90 |
91 | spriteImage($sprite) {
92 | background-image: url($sprite[8]);
93 | }
94 |
95 | sprite($sprite) {
96 | spriteImage($sprite)
97 | spritePosition($sprite)
98 | spriteWidth($sprite)
99 | spriteHeight($sprite)
100 | }
101 |
102 | /*
103 | The `sprites` mixin generates identical output to the CSS template
104 | but can be overridden inside of Stylus
105 |
106 | This must be run when you have at least 2 sprites.
107 | If run with a single sprite, then there will be reference errors.
108 |
109 | sprites($spritesheet_sprites);
110 | */
111 | sprites($sprites) {
112 | for $sprite in $sprites {
113 | $sprite_name = $sprite[9];
114 | .{$sprite_name} {
115 | sprite($sprite);
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/test/expected-files/spritesheet-name/sprite.scss:
--------------------------------------------------------------------------------
1 | // SCSS variables are information about icon's compiled state, stored under its original file name
2 | //
3 | // .icon-home {
4 | // width: $icon-home-width;
5 | // }
6 | //
7 | // The large array-like variables contain all information about a single icon
8 | // $icon-home: x y offset_x offset_y width height total_width total_height image_path;
9 | //
10 | // At the bottom of this section, we provide information about the spritesheet itself
11 | // $spritesheet: width height image $spritesheet-sprites;
12 | $sprite1-name: 'sprite1';
13 | $sprite1-x: 0px;
14 | $sprite1-y: 0px;
15 | $sprite1-offset-x: 0px;
16 | $sprite1-offset-y: 0px;
17 | $sprite1-width: 50px;
18 | $sprite1-height: 50px;
19 | $sprite1-total-width: 100px;
20 | $sprite1-total-height: 300px;
21 | $sprite1-image: 'sprite.png';
22 | $sprite1: (0px, 0px, 0px, 0px, 50px, 50px, 100px, 300px, 'sprite.png', 'sprite1', );
23 | $sprite2-name: 'sprite2';
24 | $sprite2-x: 0px;
25 | $sprite2-y: 50px;
26 | $sprite2-offset-x: 0px;
27 | $sprite2-offset-y: -50px;
28 | $sprite2-width: 50px;
29 | $sprite2-height: 50px;
30 | $sprite2-total-width: 100px;
31 | $sprite2-total-height: 300px;
32 | $sprite2-image: 'sprite.png';
33 | $sprite2: (0px, 50px, 0px, -50px, 50px, 50px, 100px, 300px, 'sprite.png', 'sprite2', );
34 | $sprite3-name: 'sprite3';
35 | $sprite3-x: 0px;
36 | $sprite3-y: 100px;
37 | $sprite3-offset-x: 0px;
38 | $sprite3-offset-y: -100px;
39 | $sprite3-width: 100px;
40 | $sprite3-height: 200px;
41 | $sprite3-total-width: 100px;
42 | $sprite3-total-height: 300px;
43 | $sprite3-image: 'sprite.png';
44 | $sprite3: (0px, 100px, 0px, -100px, 100px, 200px, 100px, 300px, 'sprite.png', 'sprite3', );
45 | $icons-width: 100px;
46 | $icons-height: 300px;
47 | $icons-image: 'sprite.png';
48 | $icons-sprites: ($sprite1, $sprite2, $sprite3, );
49 | $icons: (100px, 300px, 'sprite.png', $icons-sprites, );
50 |
51 | // The provided mixins are intended to be used with the array-like variables
52 | //
53 | // .icon-home {
54 | // @include sprite-width($icon-home);
55 | // }
56 | //
57 | // .icon-email {
58 | // @include sprite($icon-email);
59 | // }
60 | //
61 | // Example usage in HTML:
62 | //
63 | // `display: block` sprite:
64 | //
65 | //
66 | // To change `display` (e.g. `display: inline-block;`), we suggest using a common CSS class:
67 | //
68 | // // CSS
69 | // .icon {
70 | // display: inline-block;
71 | // }
72 | //
73 | // // HTML
74 | //
75 | @mixin sprite-width($sprite) {
76 | width: nth($sprite, 5);
77 | }
78 |
79 | @mixin sprite-height($sprite) {
80 | height: nth($sprite, 6);
81 | }
82 |
83 | @mixin sprite-position($sprite) {
84 | $sprite-offset-x: nth($sprite, 3);
85 | $sprite-offset-y: nth($sprite, 4);
86 | background-position: $sprite-offset-x $sprite-offset-y;
87 | }
88 |
89 | @mixin sprite-image($sprite) {
90 | $sprite-image: nth($sprite, 9);
91 | background-image: url(#{$sprite-image});
92 | }
93 |
94 | @mixin sprite($sprite) {
95 | @include sprite-image($sprite);
96 | @include sprite-position($sprite);
97 | @include sprite-width($sprite);
98 | @include sprite-height($sprite);
99 | }
100 |
101 | // The `sprites` mixin generates identical output to the CSS template
102 | // but can be overridden inside of SCSS
103 | //
104 | // @include sprites($spritesheet-sprites);
105 | @mixin sprites($sprites) {
106 | @each $sprite in $sprites {
107 | $sprite-name: nth($sprite, 10);
108 | .#{$sprite-name} {
109 | @include sprite($sprite);
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/docs/gulpfile.js:
--------------------------------------------------------------------------------
1 | // Load in dependencies
2 | var gulp = require('gulp');
3 | var buffer = require('vinyl-buffer');
4 | var csso = require('gulp-csso');
5 | var imagemin = require('gulp-imagemin');
6 | var merge = require('merge-stream');
7 | var phantomjssmith = require('phantomjssmith');
8 | var yaml = require('js-yaml');
9 | var spritesmith = require('../');
10 |
11 | // Define our tasks
12 | gulp.task('sprite', function () {
13 | // Collect png's from images folder and output a .png spritesheet and CSS classes
14 | // Alternative outputs include: SASS, Stylus, LESS, JSON
15 | var spriteData = gulp.src('images/*.png').pipe(spritesmith({
16 | imgName: 'sprite.png',
17 | cssName: 'sprite.css',
18 | algorithm: 'binary-tree'
19 | }));
20 | return spriteData.pipe(gulp.dest('path/to/output/'));
21 | });
22 |
23 | gulp.task('sprite-pipeline', function () {
24 | // Generate our spritesheet
25 | var spriteData = gulp.src('images/*.png').pipe(spritesmith({
26 | imgName: 'sprite.png',
27 | cssName: 'sprite.css'
28 | }));
29 |
30 | // Pipe image stream through image optimizer and onto disk
31 | var imgStream = spriteData.img
32 | // DEV: We must buffer our stream into a Buffer for `imagemin`
33 | .pipe(buffer())
34 | .pipe(imagemin())
35 | .pipe(gulp.dest('path/to/image/folder/'));
36 |
37 | // Pipe CSS stream through CSS optimizer and onto disk
38 | var cssStream = spriteData.css
39 | .pipe(csso())
40 | .pipe(gulp.dest('path/to/css/folder/'));
41 |
42 | // Return a merged stream to handle both `end` events
43 | return merge(imgStream, cssStream);
44 | });
45 |
46 | gulp.task('sprite-algorithm', function () {
47 | var spriteData = gulp.src('images/*.png').pipe(spritesmith({
48 | imgName: 'sprite.png',
49 | cssName: 'sprite.styl',
50 | algorithm: 'alt-diagonal'
51 | }));
52 | return spriteData.pipe(gulp.dest('examples/algorithm/'));
53 | });
54 |
55 | gulp.task('sprite-engine', function () {
56 | var spriteData = gulp.src('images/*.png', {read: false}).pipe(spritesmith({
57 | imgName: 'sprite.png',
58 | cssName: 'sprite.styl',
59 | engine: phantomjssmith
60 | }));
61 | return spriteData.pipe(gulp.dest('examples/engine/'));
62 | });
63 |
64 | gulp.task('sprite-padding', function () {
65 | var spriteData = gulp.src('images/*.png').pipe(spritesmith({
66 | imgName: 'sprite.png',
67 | cssName: 'sprite.styl',
68 | padding: 20 // Exaggerated for visibility, normal usage is 1 or 2
69 | }));
70 | return spriteData.pipe(gulp.dest('examples/padding/'));
71 | });
72 |
73 | gulp.task('sprite-retina', function () {
74 | var spriteData = gulp.src('retina-images/*.png').pipe(spritesmith({
75 | // This will filter out `fork@2x.png`, `github@2x.png`, ... for our retina spritesheet
76 | // The normal spritesheet will now receive `fork.png`, `github.png`, ...
77 | retinaSrcFilter: ['retina-images/*@2x.png'],
78 | imgName: 'sprite.png',
79 | retinaImgName: 'sprite@2x.png',
80 | cssName: 'sprite.styl'
81 | }));
82 | return spriteData.pipe(gulp.dest('examples/retina/'));
83 | });
84 |
85 | gulp.task('sprite-handlebars-template', function () {
86 | var spriteData = gulp.src('images/*.png').pipe(spritesmith({
87 | imgName: 'sprite.png',
88 | cssName: 'sprite.css',
89 | cssTemplate: 'handlebarsStr.css.handlebars'
90 | }));
91 | return spriteData.pipe(gulp.dest('examples/handlebars-template/'));
92 | });
93 |
94 | gulp.task('sprite-handlebars-inheritance', function () {
95 | var spriteData = gulp.src('images/*.png').pipe(spritesmith({
96 | imgName: 'sprite.png',
97 | cssName: 'sprite.scss',
98 | cssTemplate: 'handlebarsInheritance.scss.handlebars'
99 | }));
100 | return spriteData.pipe(gulp.dest('examples/handlebars-inheritance/'));
101 | });
102 |
103 | gulp.task('sprite-template-function', function () {
104 | var spriteData = gulp.src('images/*.png').pipe(spritesmith({
105 | imgName: 'sprite.png',
106 | cssName: 'sprite.yml',
107 | cssTemplate: function (data) {
108 | // Convert sprites from an array into an object
109 | var spriteObj = {};
110 | data.sprites.forEach(function (sprite) {
111 | // Grab the name and store the sprite under it
112 | var name = sprite.name;
113 | spriteObj[name] = sprite;
114 |
115 | // Delete the name from the sprite
116 | delete sprite.name;
117 | });
118 |
119 | // Return stringified spriteObj
120 | return yaml.safeDump(spriteObj);
121 | }
122 | }));
123 | return spriteData.pipe(gulp.dest('examples/template-function/'));
124 | });
125 |
126 | // Define common task for all
127 | gulp.task('sprite-all', [
128 | 'sprite',
129 | 'sprite-pipeline',
130 | 'sprite-algorithm',
131 | 'sprite-engine',
132 | 'sprite-padding',
133 | 'sprite-retina',
134 | 'sprite-handlebars-template',
135 | 'sprite-handlebars-inheritance',
136 | 'sprite-template-function'
137 | ]);
138 |
--------------------------------------------------------------------------------
/test/gulpfile.js:
--------------------------------------------------------------------------------
1 | // Load in dependencies
2 | var gulp = require('gulp');
3 | var merge = require('merge-stream');
4 | var through2 = require('through2');
5 | var spritesmith = require('../');
6 |
7 | // Define our test tasks
8 | var images = [
9 | 'test-files/sprite1.png',
10 | 'test-files/sprite2.png',
11 | 'test-files/sprite3.png'
12 | ];
13 | var retinaImages = [
14 | 'test-files/sprite1.png',
15 | 'test-files/sprite1@2x.png',
16 | 'test-files/sprite2.png',
17 | 'test-files/sprite2@2x.png',
18 | 'test-files/sprite3.png',
19 | 'test-files/sprite3@2x.png'
20 | ];
21 | gulp.task('sprite-default', function () {
22 | return gulp.src(images, {encoding: false})
23 | .pipe(spritesmith({
24 | imgName: 'sprite.png',
25 | cssName: 'sprite.css'
26 | }))
27 | .pipe(gulp.dest('actual-files/default/', {encoding: false}));
28 | });
29 |
30 | gulp.task('sprite-retina', function () {
31 | return gulp.src(retinaImages, {encoding: false})
32 | .pipe(spritesmith({
33 | retinaSrcFilter: 'test-files/*@2x.png',
34 | imgName: 'sprite.png',
35 | retinaImgName: 'sprite@2x.png',
36 | cssName: 'sprite.css'
37 | }))
38 | .pipe(gulp.dest('actual-files/retina/', {encoding: false}));
39 | });
40 |
41 | gulp.task('sprite-two-streams', function () {
42 | var data = gulp.src(images, {encoding: false})
43 | .pipe(spritesmith({
44 | imgName: 'sprite.png',
45 | cssName: 'sprite.css'
46 | }));
47 | var imgStream = data.img.pipe(gulp.dest('actual-files/two-streams/', {encoding: false}));
48 | var cssStream = data.css.pipe(gulp.dest('actual-files/two-streams/'));
49 | return merge(imgStream, cssStream);
50 | });
51 |
52 | gulp.task('sprite-retina-two-streams', function () {
53 | var data = gulp.src(retinaImages, {encoding: false}).pipe(spritesmith({
54 | retinaSrcFilter: 'test-files/*@2x.png',
55 | imgName: 'sprite.png',
56 | retinaImgName: 'sprite@2x.png',
57 | cssName: 'sprite.css'
58 | }));
59 | var imgStream = data.img.pipe(gulp.dest('actual-files/retina-two-streams/', {encoding: false}));
60 | var cssStream = data.css.pipe(gulp.dest('actual-files/retina-two-streams/'));
61 | return merge(imgStream, cssStream);
62 | });
63 |
64 | gulp.task('sprite-retina-same-name', function () {
65 | return gulp.src(retinaImages, {encoding: false})
66 | .pipe(spritesmith({
67 | retinaSrcFilter: 'test-files/*@2x.png',
68 | imgName: 'sprite.png',
69 | retinaImgName: 'sprite@2x.png',
70 | cssVarMap: function (sprite) {
71 | // Coerce all 1x and 2x sprites to same name
72 | // DEV: This emulates `1x/icon.png` and `2x/icon.png` folders
73 | sprite.name = sprite.name.replace('@2x', '');
74 | },
75 | cssName: 'sprite.css'
76 | }))
77 | .pipe(gulp.dest('actual-files/retina-same-name/', {encoding: false}));
78 | });
79 |
80 | gulp.task('sprite-formats', function () {
81 | return gulp.src(images, {read: false, encoding: false})
82 | .pipe(spritesmith({
83 | imgName: 'sprite.jpg',
84 | cssName: 'sprite.css',
85 | imgOpts: {
86 | format: 'png'
87 | },
88 | cssFormat: 'stylus',
89 | engine: 'phantomjssmith',
90 | // Use `top-down` for easier testing
91 | algorithm: 'top-down'
92 | }))
93 | .pipe(gulp.dest('actual-files/formats/', {encoding: false}));
94 | });
95 |
96 | gulp.task('sprite-options', function () {
97 | return gulp.src(images, {encoding: false})
98 | .pipe(spritesmith({
99 | imgName: 'sprite.png',
100 | cssName: 'sprite.css',
101 | imgPath: '../../everywhere.png',
102 | algorithm: 'alt-diagonal'
103 | }))
104 | .pipe(gulp.dest('actual-files/options/', {encoding: false}));
105 | });
106 |
107 | gulp.task('sprite-template', function () {
108 | return gulp.src(images, {encoding: false})
109 | .pipe(spritesmith({
110 | imgName: 'sprite.png',
111 | cssName: 'sprite.scss',
112 | cssTemplate: 'test-files/scss.template.handlebars',
113 | // Use `top-down` for easier testing
114 | algorithm: 'top-down'
115 | }))
116 | .pipe(gulp.dest('actual-files/template/', {encoding: false}));
117 | });
118 |
119 | gulp.task('sprite-spritesheet-name', function () {
120 | return gulp.src(images, {encoding: false})
121 | .pipe(spritesmith({
122 | imgName: 'sprite.png',
123 | cssName: 'sprite.scss',
124 | cssSpritesheetName: 'icons',
125 | // Use `top-down` for easier testing
126 | algorithm: 'top-down'
127 | }))
128 | .pipe(gulp.dest('actual-files/spritesheet-name/', {encoding: false}));
129 | });
130 |
131 | gulp.task('sprite-retina-mapped', function () {
132 | return gulp.src(retinaImages, {encoding: false})
133 | .pipe(spritesmith({
134 | retinaSrcFilter: 'test-files/*@2x.png',
135 | imgName: 'sprite.png',
136 | retinaImgName: 'sprite@2x.png',
137 | cssName: 'sprite.scss',
138 | cssSpritesheetName: 'icons',
139 | cssVarMap: function (sprite) {
140 | // Rename `sprite` to `icon` (e.g. `sprite1` -> `icon1`)
141 | sprite.name = sprite.name.replace('sprite', 'icon');
142 | },
143 | cssRetinaSpritesheetName: 'retina-icons',
144 | cssRetinaGroupsName: 'icon-groups',
145 | // Use `top-down` for easier testing
146 | algorithm: 'top-down'
147 | }))
148 | .pipe(gulp.dest('actual-files/retina-mapped/', {encoding: false}));
149 | });
150 |
151 | gulp.task('sprite-empty', function () {
152 | return gulp.src(images, {encoding: false})
153 | .pipe(through2.obj(
154 | // On data, do nothing and callback
155 | function onEmptyData(file, encoding, cb) {
156 | cb();
157 | },
158 | // On end, callback with nothing
159 | function onEmptyEnd(cb) {
160 | cb();
161 | }
162 | )).pipe(spritesmith({
163 | imgName: 'sprite.png',
164 | cssName: 'sprite.scss'
165 | }))
166 | .pipe(gulp.dest('actual-files/empty/', {encoding: false}));
167 | });
168 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # gulp.spritesmith changelog
2 | 6.13.1 - Updated documentation and tests to support Gulp@5
3 |
4 | 6.13.0 - Upgraded to async@3.2.3 to fix GitHub vulnerability alert
5 |
6 | 6.12.1 - Updated Travis CI Node.js versions
7 |
8 | 6.12.0 - Upgraded to `underscore@1.13.1` to fix GitHub vulnerability warning. Fixes #155
9 |
10 | 6.11.0 - Upgraded to `spritesmith@3.4.0` to propagate `npm audit` fix
11 |
12 | 6.10.1 - Removed vulnerable js-yaml from dev dependencies
13 |
14 | 6.10.0 - Upgraded to spritesheet-templates@10.3.0 to remove LESS JS utilization
15 |
16 | 6.9.0 - Upgraded to `spritesmith@3.3.0` to fix Vinyl@2 and Gulp@4 support. Fixes #135
17 |
18 | 6.8.0 - Moved off of deprecated `gulp-util`
19 |
20 | 6.7.0 - Switched from `twolfson-style` to ESLint
21 |
22 | 6.6.0 - Removed support for Node.js < 4
23 |
24 | 6.5.1 - Documented cache busting support via `gulp-spritesmash`
25 |
26 | 6.5.0 - Added normal/retina name collision detection
27 |
28 | 6.4.0 - Upgraded all dependencies via @dankang in #116
29 |
30 | 6.3.0 - Upgraded to `spritesheet-templates@10.2.0` to move to appropriate SASS/SCSS commenting convention
31 |
32 | 6.2.1 - Upgraded to `spritesheet-templates@10.1.1` to correct `inline-block` examples in templates
33 |
34 | 6.2.0 - Upgraded to `spritesheet-templates@10.1.0` to add HTML comments to non-CSS templates
35 |
36 | 6.1.0 - Upgraded to `spritesmith@3.1.0` to add quality support for JPEGs
37 |
38 | 6.0.1 - Updated donation URL
39 |
40 | 6.0.0 - Upgraded to `spritesmith@3.0.0` and altered `img` contents from `Buffer` to stream
41 |
42 | 5.0.1 - Updated donation URL
43 |
44 | 5.0.0 - Upgraded to `spritesmith-engine-spec@2.0.0`
45 |
46 | 4.3.0 - Upgraded to `spritesmith@1.5.0` to add `specVersion` validation
47 |
48 | 4.2.4 - Updated link to specification
49 |
50 | 4.2.3 - Moved from Gratipay to bit.ly URL for donations
51 |
52 | 4.2.2 - Added newsletter badge to README
53 |
54 | 4.2.1 - Updated node versions to support `>= 0.10.0`
55 |
56 | 4.2.0 - Moved to emitting errors rather than assert to be more gulp-like. Fixes #73
57 |
58 | 4.1.2 - Added `foundry` for release
59 |
60 | 4.1.1 - Added clarification for `retinaSrcFilter` lining up with `gulp.src`
61 |
62 | 4.1.0 - Upgraded to `spritesmith@1.4.0` to add better PNG support
63 |
64 | 4.0.0 - Upgraded to `spritesheet-templates@10.0.0` and moved to @2x suffix to prevent ordering issues
65 |
66 | 3.8.2 - Added back iojs to Travis CI
67 |
68 | 3.8.1 - Added proper `end` handling to split streams in documentation and tests. Fixes #48
69 |
70 | 3.8.0 - Upgraded to `spritesheet-templates@9.6.0` to pick up `json_texture` template
71 |
72 | 3.7.2 - Moved iojs to allowed failure until https://github.com/npm/npm/issues/8406 gets patched
73 |
74 | 3.7.1 - Moved from deprecated `licenses` key to `license` in `package.json`
75 |
76 | 3.7.0 - Fixed retina size assertion logic via @radist2s in #47
77 |
78 | 3.6.1 - Added README touchups via Ensighten/grunt-spritesmith#131
79 |
80 | 3.6.0 - Upgraded to `spritesheet-templates@9.4.0` and added handlebars helper registration
81 |
82 | 3.5.4 - Added `node@0.12` and `iojs` to CI tests
83 |
84 | 3.5.3 - Upgraded to `url2@1.0.4` to fix `git` `node_modules` issues. Fixes #34
85 |
86 | 3.5.2 - Fixed missing output for retina image to `img` stream via @radist2s in #37
87 |
88 | 3.5.1 - Added documentation on retina template data
89 |
90 | 3.5.0 - Added retina spritesheet support
91 |
92 | 3.4.0 - Upgraded to `spritesheet-templates@9.3.1` to pick up `spritesheet_info` in anticipation for retina info
93 |
94 | 3.3.1 - Upgraded to `spritesheet-templates@9.2.2` to pick up more granular templating
95 |
96 | 3.3.0 - Upgraded to `spritesheet-templates@9.2.0` to add inheritance support
97 |
98 | 3.2.0 - Upgraded to `spritesmith@1.3.0` to pick up background fill support for `pixelsmith`. Fixes #33
99 |
100 | 3.1.0 - Upgraded to `spritesheet-templates@9.1.0` to add single sprite fixes/warnings
101 |
102 | 3.0.0 - Upgraded to `spritesheet-templates@9.0.0` to reintroduce `2.6.0` as a major release
103 |
104 | 2.8.0 - Upgraded to `spritesmith@1.2.0` to pick up optimal `binary-tree` fixes
105 |
106 | 2.7.0 - Reverted `2.6.0` to remove breaking changes. Fixes #30
107 |
108 | 2.6.0 - Upgraded to `spritesheet-templates@8.3.0` to pick up `variableNameTransforms` support
109 |
110 | 2.5.2 - Fixed broken test suite due to `spritesheet-templates` patch upgrade
111 |
112 | 2.5.1 - Fixed typo for `imgOpts` in README. Fixes #28
113 |
114 | 2.5.0 - Upgraded to `spritesmith@1.1.0` to pick up `binary-tree` algorithm changes
115 |
116 | 2.4.0 - Upgraded to `spritesheet-templates@8.2.0` to pick up preprocessor `spritesheet` variables and mixins
117 |
118 | 2.3.0 - Upgraded to `spritesheet-templates@8.0.0` to pick up `spritesheet` parameter
119 |
120 | 2.2.0 - Moved from `json2css` to `spritesheet-templates`, its renamed equivalent
121 |
122 | 2.1.0 - Upgraded to `json2css@6.1.0` to pick up CSS selector fix
123 |
124 | 2.0.1 - Added more examples and links to examples from other sections
125 |
126 | 2.0.0 - Major release with multiple breaking changes:
127 |
128 | - Upgraded to `spritesmith@1.0.0`
129 | - Moved to `pixelsmith` as default engine
130 | - Removed all other engines
131 | - Moved to `binary-tree` as default algorithm
132 | - Upgraded to `json2css@6.0.0`
133 | - Renames `cssClass` to `cssSelector` to make it more semantic
134 |
135 | 1.5.0 - Added `twolfson-style` and fixed up lint errors
136 |
137 | 1.4.1 - Updated `gittip` to `gratipay`
138 |
139 | 1.4.0 - Upgraded to `spritesmith@0.20.0` to pick up `phantomjssmith's` JPEG support
140 |
141 | 1.3.0 - Added support for `gulp-newer` by doing nothing when no images are provided. Fixes #17
142 |
143 | 1.2.0 - Moved return stream to `stream.Transform` via @elentok in #16
144 |
145 | 1.1.2 - Corrected example image for README
146 |
147 | 1.1.1 - Updated README
148 |
149 | 1.1.0 - Upgraded to `json2css@5.2.0` to pick up useful CSS comments
150 |
151 | 1.0.0 - Upgraded to `json2css@5.0.0` to collect `scss_maps` alteration
152 |
153 | 0.5.1 - Increased timeout for tests to prevent false negatives. Related to #6
154 |
155 | 0.5.0 - Upgraded to `spritesmith@0.19.0` and added `algorithmOpts` to support skipping image sorting
156 |
157 | 0.4.0 - Upgraded to `json2css@4.4.0` to pick up `scss_maps` height fix
158 |
159 | 0.3.0 - Upgraded to `json2css@4.3.0` to pick up `scss_maps` template
160 |
161 | 0.2.0 - Added support for `cssTemplate` via @backflip in #3
162 |
163 | 0.1.1 - Update all name references from `gulp-spritesmith` to `gulp.spritesmith`
164 |
165 | 0.1.0 - Initial release
166 |
--------------------------------------------------------------------------------
/docs/examples/retina/sprite.styl:
--------------------------------------------------------------------------------
1 | /*
2 | Stylus variables are information about icon's compiled state, stored under its original file name
3 |
4 | .icon-home {
5 | width: $icon_home_width;
6 | }
7 |
8 | The large array-like variables contain all information about a single icon
9 | $icon_home = x y offset_x offset_y width height total_width total_height image_path;
10 |
11 | At the bottom of this section, we provide information about the spritesheet itself
12 | $spritesheet = width height image $spritesheet_sprites;
13 | */
14 | $fork_name = 'fork';
15 | $fork_x = 0px;
16 | $fork_y = 0px;
17 | $fork_offset_x = 0px;
18 | $fork_offset_y = 0px;
19 | $fork_width = 32px;
20 | $fork_height = 32px;
21 | $fork_total_width = 64px;
22 | $fork_total_height = 64px;
23 | $fork_image = 'sprite.png';
24 | $fork = 0px 0px 0px 0px 32px 32px 64px 64px 'sprite.png' 'fork';
25 | $github_name = 'github';
26 | $github_x = 32px;
27 | $github_y = 0px;
28 | $github_offset_x = -32px;
29 | $github_offset_y = 0px;
30 | $github_width = 32px;
31 | $github_height = 32px;
32 | $github_total_width = 64px;
33 | $github_total_height = 64px;
34 | $github_image = 'sprite.png';
35 | $github = 32px 0px -32px 0px 32px 32px 64px 64px 'sprite.png' 'github';
36 | $twitter_name = 'twitter';
37 | $twitter_x = 0px;
38 | $twitter_y = 32px;
39 | $twitter_offset_x = 0px;
40 | $twitter_offset_y = -32px;
41 | $twitter_width = 32px;
42 | $twitter_height = 32px;
43 | $twitter_total_width = 64px;
44 | $twitter_total_height = 64px;
45 | $twitter_image = 'sprite.png';
46 | $twitter = 0px 32px 0px -32px 32px 32px 64px 64px 'sprite.png' 'twitter';
47 | $fork_2x_name = 'fork@2x';
48 | $fork_2x_x = 0px;
49 | $fork_2x_y = 0px;
50 | $fork_2x_offset_x = 0px;
51 | $fork_2x_offset_y = 0px;
52 | $fork_2x_width = 64px;
53 | $fork_2x_height = 64px;
54 | $fork_2x_total_width = 128px;
55 | $fork_2x_total_height = 128px;
56 | $fork_2x_image = 'sprite@2x.png';
57 | $fork_2x = 0px 0px 0px 0px 64px 64px 128px 128px 'sprite@2x.png' 'fork@2x';
58 | $github_2x_name = 'github@2x';
59 | $github_2x_x = 64px;
60 | $github_2x_y = 0px;
61 | $github_2x_offset_x = -64px;
62 | $github_2x_offset_y = 0px;
63 | $github_2x_width = 64px;
64 | $github_2x_height = 64px;
65 | $github_2x_total_width = 128px;
66 | $github_2x_total_height = 128px;
67 | $github_2x_image = 'sprite@2x.png';
68 | $github_2x = 64px 0px -64px 0px 64px 64px 128px 128px 'sprite@2x.png' 'github@2x';
69 | $twitter_2x_name = 'twitter@2x';
70 | $twitter_2x_x = 0px;
71 | $twitter_2x_y = 64px;
72 | $twitter_2x_offset_x = 0px;
73 | $twitter_2x_offset_y = -64px;
74 | $twitter_2x_width = 64px;
75 | $twitter_2x_height = 64px;
76 | $twitter_2x_total_width = 128px;
77 | $twitter_2x_total_height = 128px;
78 | $twitter_2x_image = 'sprite@2x.png';
79 | $twitter_2x = 0px 64px 0px -64px 64px 64px 128px 128px 'sprite@2x.png' 'twitter@2x';
80 | $spritesheet_width = 64px;
81 | $spritesheet_height = 64px;
82 | $spritesheet_image = 'sprite.png';
83 | $spritesheet_sprites = $fork $github $twitter;
84 | $spritesheet = 64px 64px 'sprite.png' $spritesheet_sprites;
85 | $retina_spritesheet_width = 128px;
86 | $retina_spritesheet_height = 128px;
87 | $retina_spritesheet_image = 'sprite@2x.png';
88 | $retina_spritesheet_sprites = $fork_2x $github_2x $twitter_2x;
89 | $retina_spritesheet = 128px 128px 'sprite@2x.png' $retina_spritesheet_sprites;
90 |
91 | /*
92 | These "retina group" variables are mappings for the naming and pairing of normal and retina sprites.
93 |
94 | The list formatted variables are intended for mixins like `retinaSprite` and `retinaSprites`.
95 | */
96 | $fork_group_name = 'fork';
97 | $fork_group = 'fork' $fork $fork_2x;
98 | $github_group_name = 'github';
99 | $github_group = 'github' $github $github_2x;
100 | $twitter_group_name = 'twitter';
101 | $twitter_group = 'twitter' $twitter $twitter_2x;
102 | $retina_groups = $fork_group $github_group $twitter_group;
103 |
104 | /*
105 | The provided mixins are intended to be used with the array-like variables
106 |
107 | .icon-home {
108 | spriteWidth($icon_home)
109 | }
110 |
111 | .icon-email {
112 | sprite($icon_email)
113 | }
114 |
115 | Example usage in HTML:
116 |
117 | `display: block` sprite:
118 |
119 |
120 | To change `display` (e.g. `display: inline-block;`), we suggest using a common CSS class:
121 |
122 | // CSS
123 | .icon {
124 | display: inline-block;
125 | }
126 |
127 | // HTML
128 |
129 | */
130 | spriteWidth($sprite) {
131 | width: $sprite[4];
132 | }
133 |
134 | spriteHeight($sprite) {
135 | height: $sprite[5];
136 | }
137 |
138 | spritePosition($sprite) {
139 | background-position: $sprite[2] $sprite[3];
140 | }
141 |
142 | spriteImage($sprite) {
143 | background-image: url($sprite[8]);
144 | }
145 |
146 | sprite($sprite) {
147 | spriteImage($sprite)
148 | spritePosition($sprite)
149 | spriteWidth($sprite)
150 | spriteHeight($sprite)
151 | }
152 |
153 | /*
154 | The `retinaSprite` mixin sets up rules and a media query for a sprite/retina sprite.
155 | It should be used with a "retina group" variable.
156 |
157 | The media query is from CSS Tricks: https://css-tricks.com/snippets/css/retina-display-media-query/
158 |
159 | $icon_home_group = 'icon-home' $icon_home $icon_home_2x;
160 |
161 | .icon-home {
162 | retinaSprite($icon_home_group)
163 | }
164 | */
165 | spriteBackgroundSize($sprite) {
166 | background-size: $sprite[6] $sprite[7];
167 | }
168 |
169 | retinaSprite($retina_group) {
170 | $normal_sprite = $retina_group[1];
171 | $retina_sprite = $retina_group[2];
172 | sprite($normal_sprite)
173 |
174 | @media (-webkit-min-device-pixel-ratio: 2),
175 | (min-resolution: 192dpi) {
176 | spriteImage($retina_sprite)
177 | spriteBackgroundSize($normal_sprite)
178 | }
179 | }
180 |
181 | /*
182 | The `sprites` mixin generates identical output to the CSS template
183 | but can be overridden inside of Stylus
184 |
185 | This must be run when you have at least 2 sprites.
186 | If run with a single sprite, then there will be reference errors.
187 |
188 | sprites($spritesheet_sprites);
189 | */
190 | sprites($sprites) {
191 | for $sprite in $sprites {
192 | $sprite_name = $sprite[9];
193 | .{$sprite_name} {
194 | sprite($sprite);
195 | }
196 | }
197 | }
198 |
199 | /*
200 | The `retinaSprites` mixin generates a CSS rule and media query for retina groups
201 | This yields the same output as CSS retina template but can be overridden in Stylus
202 |
203 | retinaSprites($retina_groups);
204 | */
205 | retinaSprites($retina_groups) {
206 | for $retina_group in $retina_groups {
207 | $sprite_name = $retina_group[0];
208 | .{$sprite_name} {
209 | retinaSprite($retina_group);
210 | }
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/test/expected-files/retina-mapped/sprite.scss:
--------------------------------------------------------------------------------
1 | // SCSS variables are information about icon's compiled state, stored under its original file name
2 | //
3 | // .icon-home {
4 | // width: $icon-home-width;
5 | // }
6 | //
7 | // The large array-like variables contain all information about a single icon
8 | // $icon-home: x y offset_x offset_y width height total_width total_height image_path;
9 | //
10 | // At the bottom of this section, we provide information about the spritesheet itself
11 | // $spritesheet: width height image $spritesheet-sprites;
12 | $icon1-name: 'icon1';
13 | $icon1-x: 0px;
14 | $icon1-y: 0px;
15 | $icon1-offset-x: 0px;
16 | $icon1-offset-y: 0px;
17 | $icon1-width: 50px;
18 | $icon1-height: 50px;
19 | $icon1-total-width: 100px;
20 | $icon1-total-height: 300px;
21 | $icon1-image: 'sprite.png';
22 | $icon1: (0px, 0px, 0px, 0px, 50px, 50px, 100px, 300px, 'sprite.png', 'icon1', );
23 | $icon2-name: 'icon2';
24 | $icon2-x: 0px;
25 | $icon2-y: 50px;
26 | $icon2-offset-x: 0px;
27 | $icon2-offset-y: -50px;
28 | $icon2-width: 50px;
29 | $icon2-height: 50px;
30 | $icon2-total-width: 100px;
31 | $icon2-total-height: 300px;
32 | $icon2-image: 'sprite.png';
33 | $icon2: (0px, 50px, 0px, -50px, 50px, 50px, 100px, 300px, 'sprite.png', 'icon2', );
34 | $icon3-name: 'icon3';
35 | $icon3-x: 0px;
36 | $icon3-y: 100px;
37 | $icon3-offset-x: 0px;
38 | $icon3-offset-y: -100px;
39 | $icon3-width: 100px;
40 | $icon3-height: 200px;
41 | $icon3-total-width: 100px;
42 | $icon3-total-height: 300px;
43 | $icon3-image: 'sprite.png';
44 | $icon3: (0px, 100px, 0px, -100px, 100px, 200px, 100px, 300px, 'sprite.png', 'icon3', );
45 | $icon1-2x-name: 'icon1@2x';
46 | $icon1-2x-x: 0px;
47 | $icon1-2x-y: 0px;
48 | $icon1-2x-offset-x: 0px;
49 | $icon1-2x-offset-y: 0px;
50 | $icon1-2x-width: 100px;
51 | $icon1-2x-height: 100px;
52 | $icon1-2x-total-width: 200px;
53 | $icon1-2x-total-height: 600px;
54 | $icon1-2x-image: 'sprite@2x.png';
55 | $icon1-2x: (0px, 0px, 0px, 0px, 100px, 100px, 200px, 600px, 'sprite@2x.png', 'icon1@2x', );
56 | $icon2-2x-name: 'icon2@2x';
57 | $icon2-2x-x: 0px;
58 | $icon2-2x-y: 100px;
59 | $icon2-2x-offset-x: 0px;
60 | $icon2-2x-offset-y: -100px;
61 | $icon2-2x-width: 100px;
62 | $icon2-2x-height: 100px;
63 | $icon2-2x-total-width: 200px;
64 | $icon2-2x-total-height: 600px;
65 | $icon2-2x-image: 'sprite@2x.png';
66 | $icon2-2x: (0px, 100px, 0px, -100px, 100px, 100px, 200px, 600px, 'sprite@2x.png', 'icon2@2x', );
67 | $icon3-2x-name: 'icon3@2x';
68 | $icon3-2x-x: 0px;
69 | $icon3-2x-y: 200px;
70 | $icon3-2x-offset-x: 0px;
71 | $icon3-2x-offset-y: -200px;
72 | $icon3-2x-width: 200px;
73 | $icon3-2x-height: 400px;
74 | $icon3-2x-total-width: 200px;
75 | $icon3-2x-total-height: 600px;
76 | $icon3-2x-image: 'sprite@2x.png';
77 | $icon3-2x: (0px, 200px, 0px, -200px, 200px, 400px, 200px, 600px, 'sprite@2x.png', 'icon3@2x', );
78 | $icons-width: 100px;
79 | $icons-height: 300px;
80 | $icons-image: 'sprite.png';
81 | $icons-sprites: ($icon1, $icon2, $icon3, );
82 | $icons: (100px, 300px, 'sprite.png', $icons-sprites, );
83 | $retina-icons-width: 200px;
84 | $retina-icons-height: 600px;
85 | $retina-icons-image: 'sprite@2x.png';
86 | $retina-icons-sprites: ($icon1-2x, $icon2-2x, $icon3-2x, );
87 | $retina-icons: (200px, 600px, 'sprite@2x.png', $retina-icons-sprites, );
88 |
89 | // These "retina group" variables are mappings for the naming and pairing of normal and retina sprites.
90 | //
91 | // The list formatted variables are intended for mixins like `retina-sprite` and `retina-sprites`.
92 | $icon1-group-name: 'icon1';
93 | $icon1-group: ('icon1', $icon1, $icon1-2x, );
94 | $icon2-group-name: 'icon2';
95 | $icon2-group: ('icon2', $icon2, $icon2-2x, );
96 | $icon3-group-name: 'icon3';
97 | $icon3-group: ('icon3', $icon3, $icon3-2x, );
98 | $icon-groups: ($icon1-group, $icon2-group, $icon3-group, );
99 |
100 | // The provided mixins are intended to be used with the array-like variables
101 | //
102 | // .icon-home {
103 | // @include sprite-width($icon-home);
104 | // }
105 | //
106 | // .icon-email {
107 | // @include sprite($icon-email);
108 | // }
109 | //
110 | // Example usage in HTML:
111 | //
112 | // `display: block` sprite:
113 | //
114 | //
115 | // To change `display` (e.g. `display: inline-block;`), we suggest using a common CSS class:
116 | //
117 | // // CSS
118 | // .icon {
119 | // display: inline-block;
120 | // }
121 | //
122 | // // HTML
123 | //
124 | @mixin sprite-width($sprite) {
125 | width: nth($sprite, 5);
126 | }
127 |
128 | @mixin sprite-height($sprite) {
129 | height: nth($sprite, 6);
130 | }
131 |
132 | @mixin sprite-position($sprite) {
133 | $sprite-offset-x: nth($sprite, 3);
134 | $sprite-offset-y: nth($sprite, 4);
135 | background-position: $sprite-offset-x $sprite-offset-y;
136 | }
137 |
138 | @mixin sprite-image($sprite) {
139 | $sprite-image: nth($sprite, 9);
140 | background-image: url(#{$sprite-image});
141 | }
142 |
143 | @mixin sprite($sprite) {
144 | @include sprite-image($sprite);
145 | @include sprite-position($sprite);
146 | @include sprite-width($sprite);
147 | @include sprite-height($sprite);
148 | }
149 |
150 | // The `retina-sprite` mixin sets up rules and a media query for a sprite/retina sprite.
151 | // It should be used with a "retina group" variable.
152 | //
153 | // The media query is from CSS Tricks: https://css-tricks.com/snippets/css/retina-display-media-query/
154 | //
155 | // $icon-home-group: ('icon-home', $icon-home, $icon-home-2x, );
156 | //
157 | // .icon-home {
158 | // @include retina-sprite($icon-home-group);
159 | // }
160 | @mixin sprite-background-size($sprite) {
161 | $sprite-total-width: nth($sprite, 7);
162 | $sprite-total-height: nth($sprite, 8);
163 | background-size: $sprite-total-width $sprite-total-height;
164 | }
165 |
166 | @mixin retina-sprite($retina-group) {
167 | $normal-sprite: nth($retina-group, 2);
168 | $retina-sprite: nth($retina-group, 3);
169 | @include sprite($normal-sprite);
170 |
171 | @media (-webkit-min-device-pixel-ratio: 2),
172 | (min-resolution: 192dpi) {
173 | @include sprite-image($retina-sprite);
174 | @include sprite-background-size($normal-sprite);
175 | }
176 | }
177 |
178 | // The `sprites` mixin generates identical output to the CSS template
179 | // but can be overridden inside of SCSS
180 | //
181 | // @include sprites($spritesheet-sprites);
182 | @mixin sprites($sprites) {
183 | @each $sprite in $sprites {
184 | $sprite-name: nth($sprite, 10);
185 | .#{$sprite-name} {
186 | @include sprite($sprite);
187 | }
188 | }
189 | }
190 |
191 | // The `retina-sprites` mixin generates a CSS rule and media query for retina groups
192 | // This yields the same output as CSS retina template but can be overridden in SCSS
193 | //
194 | // @include retina-sprites($retina-groups);
195 | @mixin retina-sprites($retina-groups) {
196 | @each $retina-group in $retina-groups {
197 | $sprite-name: nth($retina-group, 1);
198 | .#{$sprite-name} {
199 | @include retina-sprite($retina-group);
200 | }
201 | }
202 | }
203 |
--------------------------------------------------------------------------------
/test/gulp-spritesmith_test.js:
--------------------------------------------------------------------------------
1 | var assert = require('assert');
2 | var fs = require('fs');
3 | var rimraf = require('rimraf');
4 | var imageUtils = require('./utils/image.js');
5 | var childUtils = require('./utils/child.js');
6 |
7 | // Clean up actual-files directory
8 | before(function (done) {
9 | rimraf(__dirname + '/actual-files/', done);
10 | });
11 |
12 | describe('gulp.spritesmith', function () {
13 | describe('running a task without any options', function () {
14 | childUtils.run('gulp sprite-default');
15 | imageUtils.loadActual(__dirname + '/actual-files/default/sprite.png');
16 | imageUtils.loadExpected(__dirname + '/expected-files/default/pixelsmith.png');
17 |
18 | it('generates an image', function () {
19 | assert.deepEqual(this.actualPixels, this.expectedPixels);
20 | });
21 |
22 | it('generates a css file', function () {
23 | var actualCss = fs.readFileSync(__dirname + '/actual-files/default/sprite.css', 'utf8');
24 | var expectedCss = fs.readFileSync(__dirname + '/expected-files/default/sprite.css', 'utf8');
25 | assert.strictEqual(actualCss, expectedCss);
26 | });
27 | });
28 |
29 | describe('running a task with retina options', function () {
30 | childUtils.run('gulp sprite-retina');
31 | imageUtils.loadActual(__dirname + '/actual-files/retina/sprite.png');
32 | imageUtils.loadExpected(__dirname + '/expected-files/retina/pixelsmith.png');
33 |
34 | it('generates an image', function () {
35 | assert.deepEqual(this.actualPixels, this.expectedPixels);
36 | });
37 |
38 | describe('with respect to the retina image', function () {
39 | imageUtils.loadActual(__dirname + '/actual-files/retina/sprite@2x.png');
40 | imageUtils.loadExpected(__dirname + '/expected-files/retina/pixelsmith@2x.png');
41 |
42 | it('generates an image', function () {
43 | assert.deepEqual(this.actualPixels, this.expectedPixels);
44 | });
45 | });
46 |
47 | it('generates a css file', function () {
48 | var actualCss = fs.readFileSync(__dirname + '/actual-files/retina/sprite.css', 'utf8');
49 | var expectedCss = fs.readFileSync(__dirname + '/expected-files/retina/sprite.css', 'utf8');
50 | assert.strictEqual(actualCss, expectedCss);
51 | });
52 | });
53 |
54 | describe('returns "img" and "css" streams', function () {
55 | childUtils.run('gulp sprite-two-streams');
56 | imageUtils.loadActual(__dirname + '/actual-files/two-streams/sprite.png');
57 | imageUtils.loadExpected(__dirname + '/expected-files/two-streams/pixelsmith.png');
58 |
59 | it('generates an image', function () {
60 | assert.deepEqual(this.actualPixels, this.expectedPixels);
61 | });
62 |
63 | it('generates a css file', function () {
64 | var actualCss = fs.readFileSync(__dirname + '/actual-files/two-streams/sprite.css', 'utf8');
65 | var expectedCss = fs.readFileSync(__dirname + '/expected-files/two-streams/sprite.css', 'utf8');
66 | assert.strictEqual(actualCss, expectedCss);
67 | });
68 | });
69 |
70 | describe('returns retina "img" in two streams', function () {
71 | childUtils.run('gulp sprite-retina-two-streams');
72 | imageUtils.loadActual(__dirname + '/actual-files/retina-two-streams/sprite.png');
73 | imageUtils.loadExpected(__dirname + '/expected-files/retina-two-streams/pixelsmith.png');
74 |
75 | it('generates an image', function () {
76 | assert.deepEqual(this.actualPixels, this.expectedPixels);
77 | });
78 |
79 | describe('with respect to the retina image', function () {
80 | imageUtils.loadActual(__dirname + '/actual-files/retina-two-streams/sprite@2x.png');
81 | imageUtils.loadExpected(__dirname + '/expected-files/retina-two-streams/pixelsmith@2x.png');
82 |
83 | it('generates an image', function () {
84 | assert.deepEqual(this.actualPixels, this.expectedPixels);
85 | });
86 | });
87 | });
88 |
89 | describe('running a task where a normal and retina image have same name', function () {
90 | childUtils.runSaveError('gulp sprite-retina-same-name');
91 |
92 | it('outputs an error', function () {
93 | assert.notEqual(this.err, null);
94 | assert.notEqual(
95 | this.err.message.indexOf('Normal and retina sprites have same names: ["sprite1","sprite2","sprite3"]'),
96 | -1);
97 | });
98 | });
99 |
100 | describe('running a task with output formats', function () {
101 | childUtils.run('gulp sprite-formats');
102 | imageUtils.loadActual(__dirname + '/actual-files/formats/sprite.jpg');
103 | imageUtils.loadExpected(__dirname + '/expected-files/formats/mint-pngsmith.png');
104 |
105 | it('generates a top-down png (as a .jpg)', function () {
106 | assert.deepEqual(this.actualPixels, this.expectedPixels);
107 | });
108 |
109 | it('generates a Stylus file (as a .css)', function () {
110 | var actualCss = fs.readFileSync(__dirname + '/actual-files/formats/sprite.css', 'utf8');
111 | var expectedCss = fs.readFileSync(__dirname + '/expected-files/formats/sprite.styl', 'utf8');
112 | assert.strictEqual(actualCss, expectedCss);
113 | });
114 | });
115 |
116 | describe('running a task with engine and algorithm options', function () {
117 | childUtils.run('gulp sprite-options');
118 | imageUtils.loadActual(__dirname + '/actual-files/options/sprite.png');
119 | imageUtils.loadExpected(__dirname + '/expected-files/options/mint-pngsmith.png');
120 |
121 | it('generates an alt-diagonal png via the gm engine', function () {
122 | assert.deepEqual(this.actualPixels, this.expectedPixels);
123 | });
124 |
125 | it('generates a CSS file with alt-diagonal coordinates', function () {
126 | var actualCss = fs.readFileSync(__dirname + '/actual-files/options/sprite.css', 'utf8');
127 | var expectedCss = fs.readFileSync(__dirname + '/expected-files/options/sprite.css', 'utf8');
128 | assert.strictEqual(actualCss, expectedCss);
129 | });
130 | });
131 |
132 | describe('running a task with a custom CSS template', function () {
133 | childUtils.run('gulp sprite-template');
134 | imageUtils.loadActual(__dirname + '/actual-files/template/sprite.png');
135 | imageUtils.loadExpected(__dirname + '/expected-files/template/mint-graphicsmagick.png');
136 |
137 | it('generates a top-down png', function () {
138 | assert.deepEqual(this.actualPixels, this.expectedPixels);
139 | });
140 |
141 | it('generates a css file', function () {
142 | var actualCss = fs.readFileSync(__dirname + '/actual-files/template/sprite.scss', 'utf8');
143 | var expectedCss = fs.readFileSync(__dirname + '/expected-files/template/sprite.scss', 'utf8');
144 | assert.strictEqual(actualCss, expectedCss);
145 | });
146 | });
147 |
148 | describe('running a task with a custom spritesheet prefix', function () {
149 | childUtils.run('gulp sprite-spritesheet-name');
150 |
151 | it('generates a css file', function () {
152 | var actualCss = fs.readFileSync(__dirname + '/actual-files/spritesheet-name/sprite.scss', 'utf8');
153 | var expectedCss = fs.readFileSync(__dirname + '/expected-files/spritesheet-name/sprite.scss', 'utf8');
154 | assert.strictEqual(actualCss, expectedCss);
155 | });
156 | });
157 |
158 | describe('running a task with mapped retina options', function () {
159 | childUtils.run('gulp sprite-retina-mapped');
160 |
161 | it('generates a mapped css file', function () {
162 | var actualCss = fs.readFileSync(__dirname + '/actual-files/retina-mapped/sprite.scss', 'utf8');
163 | var expectedCss = fs.readFileSync(__dirname + '/expected-files/retina-mapped/sprite.scss', 'utf8');
164 | assert.strictEqual(actualCss, expectedCss);
165 | });
166 | });
167 |
168 | // DEV: `gulp-newer` presents no input files when the task does not need to be run. See #17
169 | describe('running a task with no input images', function () {
170 | childUtils.run('gulp sprite-empty');
171 |
172 | it('does not generate a top-down png', function () {
173 | var imgExists = fs.existsSync(__dirname + '/actual-files/empty/sprite.png');
174 | assert.strictEqual(imgExists, false);
175 | });
176 |
177 | it('does not generate a css file', function () {
178 | var cssExists = fs.existsSync(__dirname + '/actual-files/empty/sprite.scss');
179 | assert.strictEqual(cssExists, false);
180 | });
181 | });
182 | });
183 |
--------------------------------------------------------------------------------
/lib/gulp-spritesmith.js:
--------------------------------------------------------------------------------
1 | // Load our dependencies
2 | var assert = require('assert');
3 | var async = require('async');
4 | var fs = require('fs');
5 | var path = require('path');
6 | var _ = require('underscore');
7 | var Vinyl = require('vinyl');
8 | var Minimatch = require('minimatch').Minimatch;
9 | var templater = require('spritesheet-templates');
10 | var Spritesmith = require('spritesmith');
11 | var through2 = require('through2');
12 | var url = require('url2');
13 |
14 | function ExtFormat() {
15 | this.formatObj = {};
16 | }
17 | ExtFormat.prototype = {
18 | add: function (name, val) {
19 | this.formatObj[name] = val;
20 | },
21 | get: function (filepath) {
22 | // Grab the extension from the filepath
23 | var ext = path.extname(filepath);
24 | var lowerExt = ext.toLowerCase();
25 |
26 | // Look up the file extenion from our format object
27 | var formatObj = this.formatObj;
28 | var format = formatObj[lowerExt];
29 | return format;
30 | }
31 | };
32 |
33 | // Create img and css formats
34 | var imgFormats = new ExtFormat();
35 | var cssFormats = new ExtFormat();
36 |
37 | // Add our img formats
38 | imgFormats.add('.png', 'png');
39 | imgFormats.add('.jpg', 'jpeg');
40 | imgFormats.add('.jpeg', 'jpeg');
41 |
42 | // Add our css formats
43 | cssFormats.add('.styl', 'stylus');
44 | cssFormats.add('.stylus', 'stylus');
45 | cssFormats.add('.sass', 'sass');
46 | cssFormats.add('.scss', 'scss');
47 | cssFormats.add('.less', 'less');
48 | cssFormats.add('.json', 'json');
49 | cssFormats.add('.css', 'css');
50 |
51 | // Copy/paste helper from gulp
52 | // https://github.com/wearefractal/glob-stream/blob/v5.0.0/index.js#L131-L138
53 | function unrelative(cwd, glob) {
54 | var mod = '';
55 | if (glob[0] === '!') {
56 | mod = glob[0];
57 | glob = glob.slice(1);
58 | }
59 | return mod + path.resolve(cwd, glob);
60 | }
61 |
62 | // Define helper for coordinate naming
63 | function getCoordinateName(filepath) {
64 | // Extract the image name (exlcuding extension)
65 | var fullname = path.basename(filepath);
66 | var nameParts = fullname.split('.');
67 |
68 | // If there is are more than 2 parts, pop the last one
69 | if (nameParts.length >= 2) {
70 | nameParts.pop();
71 | }
72 |
73 | // Return our modified filename
74 | return nameParts.join('.');
75 | }
76 |
77 | // Create a gulp-spritesmith function
78 | function gulpSpritesmith(params) {
79 | var imgName = params.imgName;
80 | var cssName = params.cssName;
81 | assert(imgName, 'An `imgName` parameter was not provided to `gulp.spritesmith` (required)');
82 | assert(cssName, 'A `cssName` parameter was not provided to `gulp.spritesmith` (required)');
83 |
84 | // If there are settings for retina, verify our all of them are present
85 | var retinaSrcFilter = params.retinaSrcFilter;
86 | var retinaImgName = params.retinaImgName;
87 | if (retinaSrcFilter || retinaImgName) {
88 | assert(retinaSrcFilter && retinaImgName, 'Retina settings detected. We must have both `retinaSrcFilter` and ' +
89 | '`retinaImgName` provided for retina to work');
90 | }
91 |
92 | // Define our output streams
93 | var imgStream = through2.obj();
94 | var cssStream = through2.obj();
95 |
96 | // Create a stream to take in images
97 | var images = [];
98 | var onData = function (file, encoding, cb) {
99 | images.push(file);
100 | cb();
101 | };
102 |
103 | // When we have completed our input
104 | var onEnd = function (cb) {
105 | // If there are no images present, exit early
106 | // DEV: This is against the behavior of `spritesmith` but pro-gulp
107 | // DEV: See https://github.com/twolfson/gulp.spritesmith/issues/17
108 | if (images.length === 0) {
109 | imgStream.push(null);
110 | cssStream.push(null);
111 | return cb();
112 | }
113 |
114 | // Determine the format of the image
115 | var imgOpts = params.imgOpts || {};
116 | var imgFormat = imgOpts.format || imgFormats.get(imgName) || 'png';
117 |
118 | // Set up the defautls for imgOpts
119 | imgOpts = _.defaults({}, imgOpts, {format: imgFormat});
120 |
121 | // If we have retina settings, filter out the retina images
122 | var retinaImages;
123 | if (retinaSrcFilter) {
124 | // Filter out our retina files
125 | // https://github.com/wearefractal/glob-stream/blob/v5.0.0/index.js#L84-L87
126 | retinaImages = [];
127 | var retinaSrcPatterns = Array.isArray(retinaSrcFilter) ? retinaSrcFilter : [retinaSrcFilter];
128 | images = images.filter(function filterSrcFile(file) {
129 | // If we have a retina file, filter it out
130 | var matched = retinaSrcPatterns.some(function matchMinimatches(retinaSrcPattern) {
131 | var minimatch = new Minimatch(unrelative(file.cwd, retinaSrcPattern));
132 | return minimatch.match(file.path);
133 | });
134 | if (matched) {
135 | retinaImages.push(file);
136 | return false;
137 | // Otherwise, keep it in the src files
138 | } else {
139 | return true;
140 | }
141 | });
142 |
143 | // If we have a different amount of normal and retina images, complain and leave
144 | if (images.length !== retinaImages.length) {
145 | var err = new Error('Retina settings detected but ' + retinaImages.length + ' retina images were found. ' +
146 | 'We have ' + images.length + ' normal images and expect these numbers to line up. ' +
147 | 'Please double check `retinaSrcFilter`.');
148 | err.images = images;
149 | err.retinaImages = retinaImages;
150 | this.emit('error', err);
151 | imgStream.push(null);
152 | cssStream.push(null);
153 | return cb();
154 | }
155 | }
156 |
157 | // Prepare spritesmith parameters
158 | var spritesmithParams = {
159 | engine: params.engine,
160 | algorithm: params.algorithm,
161 | padding: params.padding || 0,
162 | algorithmOpts: params.algorithmOpts || {},
163 | engineOpts: params.engineOpts || {},
164 | exportOpts: imgOpts
165 | };
166 | var that = this;
167 |
168 | // Construct our spritesmiths
169 | var spritesmith = new Spritesmith(spritesmithParams);
170 | var retinaSpritesmithParams; // eslint-disable-line
171 | var retinaSpritesmith; // eslint-disable-line
172 | if (retinaImages) {
173 | retinaSpritesmithParams = _.defaults({
174 | padding: spritesmithParams.padding * 2
175 | }, spritesmithParams);
176 | retinaSpritesmith = new Spritesmith(retinaSpritesmithParams);
177 | }
178 |
179 | // In parallel
180 | async.parallel([
181 | // Load in our normal images
182 | function generateNormalImages(callback) {
183 | spritesmith.createImages(images, callback);
184 | },
185 | // If we have retina images, load them in as well
186 | function generateRetinaSpritesheet(callback) {
187 | if (retinaImages) {
188 | return retinaSpritesmith.createImages(retinaImages, callback);
189 | } else {
190 | return process.nextTick(callback);
191 | }
192 | }
193 | ], function handleImages(err, resultArr) {
194 | // If an error occurred, emit it
195 | if (err) {
196 | return cb(err);
197 | }
198 |
199 | // Otherwise, validate our images line up
200 | var normalSprites = resultArr[0];
201 | var retinaSprites = resultArr[1];
202 |
203 | // If we have retina images, verify the widths line up
204 | if (retinaSprites) {
205 | // Perform our assertions
206 | var errorEncountered = false;
207 | normalSprites.forEach(function validateImageSizes(normalSprite, i) {
208 | var retinaSprite = retinaSprites[i];
209 | if (retinaSprite.width !== normalSprite.width * 2 || retinaSprite.height !== normalSprite.height * 2) {
210 | errorEncountered = true;
211 | var err = new Error('Normal sprite has inconsistent size with retina sprite. ' +
212 | '"' + images[i].path + '" is ' + normalSprite.width + 'x' + normalSprite.height + ' while ' +
213 | '"' + retinaImages[i].path + '" is ' + retinaSprite.width + 'x' + retinaSprite.height + '.');
214 | err.normalSprite = normalSprite;
215 | err.retinaSprite = retinaSprite;
216 | that.emit('error', err);
217 | }
218 | });
219 |
220 | // If there was an error, then bail out
221 | if (errorEncountered) {
222 | imgStream.push(null);
223 | cssStream.push(null);
224 | return cb();
225 | }
226 | }
227 |
228 | // Process our images now
229 | var result = spritesmith.processImages(normalSprites, spritesmithParams);
230 | var retinaResult;
231 | if (retinaSprites) {
232 | retinaResult = retinaSpritesmith.processImages(retinaSprites, retinaSpritesmithParams);
233 | }
234 |
235 | // START OF DUPLICATE CODE FROM grunt-spritesmith
236 | // Generate a listing of CSS variables
237 | var coordinates = result.coordinates;
238 | var properties = result.properties;
239 | var spritePath = params.imgPath || url.relative(cssName, imgName);
240 | var spritesheetData = {
241 | width: properties.width,
242 | height: properties.height,
243 | image: spritePath
244 | };
245 | var cssVarMap = params.cssVarMap || function noop() {};
246 | var cleanCoords = [];
247 |
248 | // Clean up the file name of the file
249 | Object.getOwnPropertyNames(coordinates).sort().forEach(function (file) {
250 | // Extract out our name
251 | var name = getCoordinateName(file);
252 | var coords = coordinates[file];
253 |
254 | // Specify the image for the sprite
255 | coords.name = name;
256 | coords.source_image = file;
257 | // DEV: `image`, `total_width`, `total_height` are deprecated as they are overwritten in `spritesheet-templates`
258 | coords.image = spritePath;
259 | coords.total_width = properties.width;
260 | coords.total_height = properties.height;
261 |
262 | // Map the coordinates through cssVarMap
263 | coords = cssVarMap(coords) || coords;
264 |
265 | // Save the cleaned name and coordinates
266 | cleanCoords.push(coords);
267 | });
268 |
269 | // If we have retina sprites
270 | var retinaCleanCoords; // eslint-disable-line
271 | var retinaGroups; // eslint-disable-line
272 | var retinaSpritesheetInfo; // eslint-disable-line
273 | if (retinaResult) {
274 | // Generate a listing of CSS variables
275 | var retinaCoordinates = retinaResult.coordinates;
276 | var retinaProperties = retinaResult.properties;
277 | var retinaSpritePath = params.retinaImgPath || url.relative(cssName, retinaImgName);
278 | retinaSpritesheetInfo = {
279 | width: retinaProperties.width,
280 | height: retinaProperties.height,
281 | image: retinaSpritePath
282 | };
283 | // DEV: We reuse cssVarMap
284 | retinaCleanCoords = [];
285 |
286 | // Clean up the file name of the file
287 | Object.getOwnPropertyNames(retinaCoordinates).sort().forEach(function prepareRetinaTemplateData(file) {
288 | var name = getCoordinateName(file);
289 | var coords = retinaCoordinates[file];
290 | coords.name = name;
291 | coords.source_image = file;
292 | coords.image = retinaSpritePath;
293 | coords.total_width = retinaProperties.width;
294 | coords.total_height = retinaProperties.height;
295 | coords = cssVarMap(coords) || coords;
296 | retinaCleanCoords.push(coords);
297 | });
298 |
299 | // Verify we have no conflicting file names (e.g. `1x/home.png` and `2x/home.png`)
300 | // https://github.com/twolfson/gulp.spritesmith/issues/124
301 | var cleanCoordNames = _.pluck(cleanCoords, 'name');
302 | var retinaCleanCoordNames = _.pluck(retinaCleanCoords, 'name');
303 | var intersectingNames = _.intersection(cleanCoordNames, retinaCleanCoordNames);
304 | if (intersectingNames.length) {
305 | throw new Error('Normal and retina sprites have same names: ' + JSON.stringify(intersectingNames) + '. ' +
306 | 'Please rename them to different names (e.g. `-1x`, `-2x`) or use `cssVarMap` to prevent collisions. ' +
307 | 'See https://github.com/twolfson/gulp.spritesmith/issues/124 for more info');
308 | }
309 |
310 | // Generate groups for our coordinates
311 | retinaGroups = cleanCoords.map(function getRetinaGroups(normalSprite, i) {
312 | // Generate our group
313 | // DEV: Name is inherited from `cssVarMap` on normal sprite
314 | return {
315 | name: normalSprite.name,
316 | index: i
317 | };
318 | });
319 | }
320 |
321 | // If we have handlebars helpers, register them
322 | var handlebarsHelpers = params.cssHandlebarsHelpers;
323 | if (handlebarsHelpers) {
324 | Object.keys(handlebarsHelpers).forEach(function registerHelper(helperKey) {
325 | templater.registerHandlebarsHelper(helperKey, handlebarsHelpers[helperKey]);
326 | });
327 | }
328 |
329 | // If there is a custom template, use it
330 | var cssFormat = 'spritesmith-custom';
331 | var cssTemplate = params.cssTemplate;
332 | if (cssTemplate) {
333 | if (typeof cssTemplate === 'function') {
334 | templater.addTemplate(cssFormat, cssTemplate);
335 | } else {
336 | templater.addHandlebarsTemplate(cssFormat, fs.readFileSync(cssTemplate, 'utf8'));
337 | }
338 | // Otherwise, override the cssFormat and fallback to 'json'
339 | } else {
340 | cssFormat = params.cssFormat;
341 | if (!cssFormat) {
342 | cssFormat = cssFormats.get(cssName) || 'json';
343 |
344 | // If we are dealing with retina items, move to retina flavor (e.g. `scss` -> `scss_retina`)
345 | if (retinaGroups) {
346 | cssFormat += '_retina';
347 | }
348 | }
349 | }
350 |
351 | // Render the variables via `spritesheet-templates`
352 | var cssStr = templater({
353 | sprites: cleanCoords,
354 | spritesheet: spritesheetData,
355 | spritesheet_info: {
356 | name: params.cssSpritesheetName
357 | },
358 | retina_groups: retinaGroups,
359 | retina_sprites: retinaCleanCoords,
360 | retina_spritesheet: retinaSpritesheetInfo,
361 | retina_spritesheet_info: {
362 | name: params.cssRetinaSpritesheetName
363 | },
364 | retina_groups_info: {
365 | name: params.cssRetinaGroupsName
366 | }
367 | }, {
368 | format: cssFormat,
369 | formatOpts: params.cssOpts || {}
370 | });
371 | // END OF DUPLICATE CODE FROM grunt-spritesmith
372 |
373 | // Pipe out images as streams and forward their errors
374 | // TODO: Consider making joint stream default
375 | // but allow for split stream which has more distinct errors
376 | // e.g. spritesmith.split() = {css, img}
377 | result.image.on('error', function forwardImgError(err) {
378 | that.emit('error', err);
379 | });
380 | var imgFile = new Vinyl({
381 | path: imgName,
382 | contents: result.image
383 | });
384 | that.push(imgFile);
385 | imgStream.push(imgFile);
386 | if (retinaResult) {
387 | var retinaImgFile = new Vinyl({
388 | path: retinaImgName,
389 | contents: retinaResult.image
390 | });
391 | retinaResult.image.on('error', function forwardImgError(err) {
392 | that.emit('error', err);
393 | });
394 | that.push(retinaImgFile);
395 | imgStream.push(retinaImgFile);
396 | }
397 |
398 | // Close our image stream
399 | imgStream.push(null);
400 |
401 | // Output the CSS
402 | var cssFile = new Vinyl({
403 | path: cssName,
404 | contents: Buffer.from(cssStr)
405 | });
406 | that.push(cssFile);
407 | cssStream.push(cssFile);
408 | cssStream.push(null);
409 | cb();
410 | });
411 | };
412 |
413 | // Return output stream with two sub-streams:
414 | // - master stream includes all files
415 | // - 'css' stream for css only
416 | // - 'img' stream for images only
417 | var retStream = through2.obj(onData, onEnd);
418 | retStream.css = cssStream;
419 | retStream.img = imgStream;
420 | return retStream;
421 | }
422 |
423 | module.exports = gulpSpritesmith;
424 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # gulp.spritesmith [](https://travis-ci.org/twolfson/gulp.spritesmith) [](http://eepurl.com/bD4qkf)
2 |
3 | Convert a set of images into a spritesheet and CSS variables via [gulp][]
4 |
5 | This is the official port of [grunt-spritesmith][], the [grunt][] equivalent of a wrapper around [spritesmith][].
6 |
7 | [gulp]: http://gulpjs.com/
8 | [grunt-spritesmith]: https://github.com/Ensighten/grunt-spritesmith
9 | [grunt]: http://gruntjs.com/
10 | [spritesmith]: https://github.com/Ensighten/spritesmith
11 |
12 | 
13 |
14 | Alternative output formats include [SASS, Stylus, LESS, and JSON][css-formats].
15 |
16 | [css-formats]: #spritesmithparams
17 |
18 | ### Retina support
19 | As of `gulp.spritesmith@3.5.0`, retina spritesheets/templates are supported. See the [Retina parameters section](#retina-parameters) for more information.
20 |
21 | ### Do you like `gulp.spritesmith`?
22 | [Support us via donations][support-us] or [spread word on Twitter][twitter]
23 |
24 | [support-us]: http://bit.ly/support-spritesmith-1
25 | [twitter]: https://twitter.com/intent/tweet?text=CSS%20sprites%20made%20easy%20via%20gulp.spritesmith&url=https%3A%2F%2Fgithub.com%2Ftwolfson%2Fgulp.spritesmith&via=twolfsn
26 |
27 | ## Breaking changes in 4.0.0
28 | We are normalizing sprite variables even further to convert any non-alphanumeric/non-dash/non-underscore character to a delimiter character (e.g. `-`). This allows us to support naming retina sprites with `@2x` suffixes, to prevent regressions like [grunt-spritesmith#137][].
29 |
30 | [grunt-spritesmith#137]: https://github.com/Ensighten/grunt-spritesmith/issues/137
31 |
32 | ## Breaking changes in 5.0.0
33 | We have moved from [spritesmith-engine-spec@1.1.0][] to [spritesmith-engine-spec@2.0.0][]. This means if you use an custom engine (e.g. `gmsmith`, `canvassmith`), then you will need to upgrade it.
34 |
35 | ```bash
36 | npm install my-engine-smith@latest --save-dev
37 | ```
38 |
39 | This is enables us to use streaming outputs from engines in a future release.
40 |
41 | Additionally, we have added support for `buffer` and `stream` content for in-memory engines (e.g. `pixelsmith`, `canvassmith`) which resolves [#53][].
42 |
43 | [spritesmith-engine-spec@1.1.0]: https://github.com/twolfson/spritesmith-engine-spec/tree/1.1.0
44 | [spritesmith-engine-spec@2.0.0]: https://github.com/twolfson/spritesmith-engine-spec/tree/2.0.0
45 | [#53]: https://github.com/twolfson/gulp.spritesmith/issues/53
46 |
47 | ## Breaking changes in 6.0.0
48 | We have completed our integration with streaming outputs from engines. As a result, [Vinyl][] `img` files will have `stream` contents which were previously buffers.
49 |
50 | If your `img` pipeline requires `Buffer` contents, then this can be remedied via [vinyl-buffer][]:
51 |
52 | ```js
53 | // Throws error due to not supporting streams
54 | spriteData.img.pipe(imagemin());
55 |
56 | // Back to operational
57 | var buffer = require('vinyl-buffer');
58 | spriteData.img.pipe(buffer()).pipe(imagemin());
59 | ```
60 |
61 | [vinyl-buffer]: https://github.com/hughsk/vinyl-buffer
62 |
63 | ## Note for Gulp 5.0.0 upgrades
64 | Gulp 5.0.0 introduced default encodings for `src` and `dest` streams of `utf8`.
65 |
66 | Since `gulp.spritesmith` inputs and outputs images, we need to set `{encoding: false}` for the image `.src()` and `.dest()` streams.
67 |
68 | See "[Getting Started](#getting-started)" for an hands-on example.
69 |
70 | ## Getting Started
71 | Install the module with: `npm install gulp.spritesmith`
72 |
73 | ```js
74 | var gulp = require('gulp');
75 | var spritesmith = require('gulp.spritesmith');
76 |
77 | gulp.task('sprite', function () {
78 | var spriteData = gulp.src('images/*.png', {encoding: false}).pipe(spritesmith({
79 | imgName: 'sprite.png',
80 | cssName: 'sprite.css'
81 | }));
82 | return spriteData.pipe(gulp.dest('path/to/output/', {encoding: false}));
83 | });
84 | ```
85 |
86 | ### Continuing the pipeline
87 | In addition to the `spriteData` stream, we offer individual streams for images and CSS. This allows for image optimization and CSS minification.
88 |
89 | ```js
90 | var gulp = require('gulp');
91 | var buffer = require('vinyl-buffer');
92 | var csso = require('gulp-csso');
93 | var imagemin = require('gulp-imagemin');
94 | var merge = require('merge-stream');
95 |
96 | var spritesmith = require('gulp.spritesmith');
97 |
98 | gulp.task('sprite', function () {
99 | // Generate our spritesheet
100 | var spriteData = gulp.src('images/*.png', {encoding: false}).pipe(spritesmith({
101 | imgName: 'sprite.png',
102 | cssName: 'sprite.css'
103 | }));
104 |
105 | // Pipe image stream through image optimizer and onto disk
106 | var imgStream = spriteData.img
107 | // DEV: We must buffer our stream into a Buffer for `imagemin`
108 | .pipe(buffer())
109 | .pipe(imagemin())
110 | .pipe(gulp.dest('path/to/image/folder/', {encoding: false}));
111 |
112 | // Pipe CSS stream through CSS optimizer and onto disk
113 | var cssStream = spriteData.css
114 | .pipe(csso())
115 | .pipe(gulp.dest('path/to/css/folder/'));
116 |
117 | // Return a merged stream to handle both `end` events
118 | return merge(imgStream, cssStream);
119 | });
120 | ```
121 |
122 | ## Documentation
123 | `gulp.spritesmith` presents the `spritesmith` function as its `module.exports`.
124 |
125 | ### `spritesmith(params)`
126 | [gulp][] plugin that returns a [transform stream][] with 2 [readable stream][] properties.
127 |
128 | The input/output streams interact with [Vinyl][] objects which are [gulp's][gulp] format of choice.
129 |
130 | [transform stream]: http://nodejs.org/api/stream.html#stream_class_stream_transform
131 | [readable stream]: http://nodejs.org/api/stream.html#stream_class_stream_readable
132 | [Vinyl]: https://github.com/gulpjs/vinyl
133 |
134 | - params `Object` - Container for `gulp.spritesmith` parameters
135 | - imgName `String` - Filename to save image as
136 | - Supported image extensions are `.png` and `.jpg/jpeg` (limited to specfic engines)
137 | - Image format can be overridden via `imgOpts.format`
138 | - cssName `String` - Filename to save CSS as
139 | - Supported CSS extensions are `.css` (CSS), `.sass` ([SASS][]), `.scss` ([SCSS][]), `.less` ([LESS][]), `.styl/.stylus` ([Stylus][]), and `.json` ([JSON][])
140 | - CSS format can be overridden via `cssFormat`
141 | - imgPath `String` - Optional path to use in CSS referring to image location
142 | - padding `Number` - Optional amount of pixels to include between images
143 | - By default we use no padding between images (`0`)
144 | - An example usage can be found in the [Examples section](#padding)
145 | - algorithm `String` - Optional method for how to pack images
146 | - By default we use `binary-tree`, which packs images as efficiently as possible
147 | - An example usage can be found in the [Examples section](#algorithm)
148 | - More information can be found in the [Algorithms section](#algorithms)
149 | - algorithmOpts `Object` - Options to pass through to algorithm
150 | - For example we can skip sorting in some algorithms via `{algorithmOpts: {sort: false}}`
151 | - This is useful for sprite animations
152 | - See your algorithm's documentation for available options
153 | - https://github.com/twolfson/layout#algorithms
154 | - engine `String` - Optional image generating engine to use
155 | - By default we use `pixelsmith`, a `node` based engine that supports all common image formats
156 | - Alternative engines must be installed via `npm install`
157 | - An example usage can be found in the [Examples section](#engine)
158 | - More information can be found in the [Engines section](#engines)
159 | - engineOpts `Object` - Options to pass through to engine for settings
160 | - For example `phantomjssmith` accepts `timeout` via `{engineOpts: {timeout: 10000}}`
161 | - See your engine's documentation for available options
162 | - imgOpts `Object` - Options to pass through to engine uring export
163 | - For example `gmsmith` supports `quality` via `{imgOpts: {quality: 75}}`
164 | - See your engine's documentation for available options
165 | - cssFormat `String` - CSS format to use
166 | - By default this is the format inferred by `cssName's` extension
167 | - For example `.styl -> stylus`
168 | - For more format options, see our formatting library
169 | - https://github.com/twolfson/spritesheet-templates#templates
170 | - cssTemplate `String|Function` - CSS template to use for rendering output CSS
171 | - This overrides `cssFormat`
172 | - If a `String` is provided, it must be a path to a [handlebars][] template
173 | - An example usage can be found in the [Examples section](#handlebars-template)
174 | - If a `Function` is provided, it must have a signature of `function (data)`
175 | - An example usage can be found in the [Examples section](#template-function)
176 | - For more templating information, see the [Templating section](#templating)
177 | - cssHandlebarsHelpers `Object` - Container for helpers to register to [handlebars][] for our template
178 | - Each key-value pair is the name of a [handlebars][] helper corresponding to its function
179 | - For example, `{half: function (num) { return num/2; }` will add a [handlebars][] helper that halves numbers
180 | - cssVarMap `Function` - Mapping function for each filename to CSS variable
181 | - For more information, see [Variable mapping](#variable-mapping)
182 | - cssSpritesheetName `String` - Name to use for spritesheet related variables in preprocessor templates
183 | - cssOpts `Object` - Options to pass through to templater
184 | - For example `{cssOpts: {functions: false}}` skips output of mixins
185 | - See your template's documentation for available options
186 | - https://github.com/twolfson/spritesheet-templates#templates
187 |
188 | [SASS]: http://sass-lang.com/
189 | [SCSS]: http://sass-lang.com/
190 | [sass-maps]: http://sass-lang.com/documentation/file.SASS_REFERENCE.html#maps
191 | [LESS]: http://lesscss.org/
192 | [Stylus]: http://learnboost.github.com/stylus/
193 | [JSON]: http://json.org/
194 | [handlebars]: http://handlebarsjs.com/
195 |
196 | **Returns**:
197 | - spriteData [`stream.Transform`][transform stream] - Stream that outputs image and CSS as [Vinyl][] objects
198 | - spriteData.img [`stream.Readable`][readable stream] - Stream for image output as a [Vinyl][] object
199 | - `contents` will be a `Stream`
200 | - spriteData.css [`stream.Readable`][readable stream] - Stream for CSS output as a [Vinyl][] object
201 | - `contents` will be a `Buffer`
202 |
203 | ### Retina parameters
204 | `gulp.spritesmith` supports retina spritesheet generation via `retinaSrcFilter` and `retinaImgName`. If at least one of these is provided, then we will expect the other and enable retina spritesheet generation.
205 |
206 | Repeated parameters have the same properties as above but are repeated for clarity with respect to retina spritesheets.
207 |
208 | An example retina spritesheet setup can be found in the [Examples section](#retina-spritesheet).
209 |
210 | We receive both normal and retina sprites from the same `gulp.src` so please include them in your original glob. (e.g. `*.png` should include `icon-home.png` and `icon-home@2x.png`).
211 |
212 | **We strongly encourage using the `@2x` suffix for retina sprites over `-retina` or `-2x`. There are known ordering issues caused when sharing a `-` delimiter between sprite names and the retina suffix (see [grunt-spritesmith#137][]).**
213 |
214 | - params `Object` - Container for `gulp.spritesmith` parameters
215 | - retinaSrcFilter `String|String[]` - Filepaths to filter out from incoming stream for our retina spritesheet
216 | - This can be a glob as with `src` (e.g. `sprite/*@2x.png`)
217 | - The path/glob used should line up with `gulp.src` (e.g. `gulp.src('sprite/*.png', {encoding: false})`, `retinaSrcFilter: 'sprite/*@2x.png'`)
218 | - For example `sprites/*@2x.png` will filter out `sprite1@2x.png` for a separate retina spritesheet
219 | - Under the hood, we will group `sprite1.png` and `sprite1@2x.png` as a group of normal/retina sprites
220 | - retinaImgName `String` - Filename to save retina spritesheet as
221 | - retinaImgPath `String` - Optional path to use in CSS referring to image location
222 | - For example `../sprite@2x.png` will yield CSS with:
223 | - `background-image: url(../sprite@2x.png);`
224 | - padding `Number` - Padding to place to right and bottom between sprites
225 | - By default there is no padding
226 | - In retina spritesheets, this number will be doubled to maintain perspective
227 | - cssFormat - CSS format to use
228 | - By default this is the format inferred by `cssName's` extension
229 | - For example `.styl -> stylus_retina`
230 | - For more format options, see our formatting library
231 | - https://github.com/twolfson/spritesheet-templates#retina-templates
232 | - cssVarMap `Function` - Mapping function for each filename to CSS variable
233 | - This will run through normal and retina spritesheets
234 | - The name used for normal sprites dictates the group name for retina group variables (e.g. `$icon-home` will have group `$icon-home-group`)
235 | - For more information, see [Variable mapping](#variable-mapping)
236 | - cssRetinaSpritesheetName `String` - Name to use for retina spritesheet related variables in preprocessor templates
237 | - cssRetinaGroupsName `String` - Name to use for retina groups related variables in preprocessor templates
238 |
239 | **Returns**:
240 | - spriteData [`stream.Transform`][transform stream] - Stream that outputs image, retina image, and CSS as [Vinyl][] objects
241 | - spriteData.img [`stream.Readable`][readable stream] - Stream for image outputs (normal and retina) as a [Vinyl][] object
242 | - `contents` will be a `Stream`
243 | - spriteData.css [`stream.Readable`][readable stream] - Stream for retina CSS output as a [Vinyl][] object
244 | - `contents` will be a `Buffer`
245 |
246 | ### Algorithms
247 | Images can be laid out in different fashions depending on the algorithm. We use [`layout`][] to provide you as many options as possible. At the time of writing, here are your options for `algorithm`:
248 |
249 | [`layout`]: https://github.com/twolfson/layout
250 |
251 | | `top-down` | `left-right` | `diagonal` | `alt-diagonal` | `binary-tree` |
252 | |---------------------------|-------------------------------|---------------------------|-----------------------------------|---------------------------------|
253 | | ![top-down][top-down-img] | ![left-right][left-right-img] | ![diagonal][diagonal-img] | ![alt-diagonal][alt-diagonal-img] | ![binary-tree][binary-tree-img] |
254 |
255 | [top-down-img]: https://raw.githubusercontent.com/twolfson/layout/2.0.2/docs/top-down.png
256 | [left-right-img]: https://raw.githubusercontent.com/twolfson/layout/2.0.2/docs/left-right.png
257 | [diagonal-img]: https://raw.githubusercontent.com/twolfson/layout/2.0.2/docs/diagonal.png
258 | [alt-diagonal-img]: https://raw.githubusercontent.com/twolfson/layout/2.0.2/docs/alt-diagonal.png
259 | [binary-tree-img]: https://raw.githubusercontent.com/twolfson/layout/2.0.2/docs/binary-tree.png
260 |
261 | More information can be found in the [`layout`][] documentation:
262 |
263 | https://github.com/twolfson/layout
264 |
265 | ### Templating
266 | The `cssTemplate` option allows for using a custom template. An example template can be found at:
267 |
268 | https://github.com/twolfson/spritesheet-templates/blob/9.3.1/lib/templates/stylus.template.handlebars
269 |
270 | The parameters passed into your template are known as `data`. We add some normalized properties via [`spritesheet-templates`][] for your convenience.
271 |
272 | - data `Object` Container for parameters
273 | - sprites `Object[]` - Array of sprite information
274 | - name `String` - Name of the sprite file (sans extension)
275 | - x `Number` - Horizontal position of sprite's left edge in spritesheet
276 | - y `Number` - Vertical position of sprite's top edge in spritesheet
277 | - width `Number` - Width of sprite
278 | - height `Number` - Height of sprite
279 | - total_width `Number` - Width of entire spritesheet
280 | - total_height `Number` - Height of entire spritesheet
281 | - image `String` - Relative URL path from CSS to spritesheet
282 | - escaped_image `String` - URL encoded `image`
283 | - source_image `String` - Path to the original sprite file
284 | - offset_x `Number` - Negative value of `x`. Useful to `background-position`
285 | - offset_y `Number` - Negative value of `y`. Useful to `background-position`
286 | - px `Object` - Container for numeric values including `px`
287 | - x `String` - `x` suffixed with `px`
288 | - y `String` - `y` suffixed with `px`
289 | - width `String` - `width` suffixed with `px`
290 | - height `String` - `height` suffixed with `px`
291 | - total_width `String` - `total_width` suffixed with `px`
292 | - total_height `String` - `total_height` suffixed with `px`
293 | - offset_x `String` - `offset_x` suffixed with `px`
294 | - offset_y `String` - `offset_y` suffixed with `px`
295 | - spritesheet `Object` - Information about spritesheet
296 | - width `Number` - Width of entire spritesheet
297 | - total_height `Number` - Height of entire spritesheet
298 | - image `String` - Relative URL path from CSS to spritesheet
299 | - escaped_image `String` - URL encoded `image`
300 | - px `Object` - Container for numeric values including `px`
301 | - width `String` - `width` suffixed with `px`
302 | - height `String` - `height` suffixed with `px`
303 | - spritesheet_info `Object` - Container for `spritesheet` metadata and its representation
304 | - name `String` - Prefix for spritesheet variables
305 | - retina_sprites `Object[]` - Array of retina sprite information
306 | - This will only be accessible if we are generating a retina spritesheet
307 | - Properties are the same as `sprites` (e.g. `name`, `width`, `source_image`)
308 | - retina_spritesheet `Object` - Information about retina spritesheet
309 | - This will only be accessible if we are generating a retina spritesheet
310 | - Properties are the same as `spritesheet` (e.g. `width`, `px`)
311 | - retina_spritesheet_info `Object` - Container for `retina_spritesheet` metadata and its representation
312 | - This will only be accessible if we are generating a retina spritesheet
313 | - name `String` - Prefix for spritesheet variables
314 | - retina_groups `Object[]` - Array of objects that maps to normal and retina sprites
315 | - This will only be accessible if we are generating a retina spritesheet
316 | - * `Object` - Container for data about sprite mapping
317 | - name `String` - Name to refer to mapping by
318 | - index `Number` - Index of corresponding normal/retina sprites from `data.sprites`/`data.retina_sprites`
319 | - normal `Object` - Normal sprite from `data.sprites` that corresponds to our mapping
320 | - This has all the same properties as `data.sprites[*]` (e.g. `name`, `x`, `offset_y`, `px`)
321 | - retina `Object` - Retina sprite from `data.retina_sprites` that corresponds to our mapping
322 | - This has all the same properties as `data.retina_sprites[*]` (e.g. `name`, `x`, `offset_y`, `px`)
323 | - retina_groups_info `Object` - Optional container for metadata about `retina_groups` and its representation
324 | - This will only be accessible if we are generating a retina spritesheet
325 | - name `String` - Name for `retina_groups`
326 | - options `Object` - Options passed in via `cssOpts` in `gulp.spritesmith` config
327 |
328 | [`spritesheet-templates`]: https://github.com/twolfson/spritesheet-templates
329 |
330 | An example `sprite` is
331 |
332 | ```js
333 | {
334 | "name": "sprite2",
335 | "x": 10,
336 | "y": 20,
337 | "width": 20,
338 | "height": 30,
339 | "total_width": 80,
340 | "total_height": 100,
341 | "image": "nested/dir/spritesheet.png",
342 | "escaped_image": "nested/dir/spritesheet.png",
343 | "source_image": "path/to/original/sprite.png",
344 | "offset_x": -10,
345 | "offset_y": -20,
346 | "px": {
347 | "x": "10px",
348 | "y": "20px",
349 | "width": "20px",
350 | "height": "30px",
351 | "total_width": "80px",
352 | "total_height": "100px",
353 | "offset_x": "-10px",
354 | "offset_y": "-20px"
355 | }
356 | }
357 | ```
358 |
359 | If you are defining a Handlebars template, then you can inherit from an existing template via [`handlebars-layouts`][] (e.g. `{{#extend "scss"}}`). An example usage can be found in the [Examples section](#handlebars-inheritance).
360 |
361 | [`handlebars-layouts`]: https://github.com/shannonmoeller/handlebars-layouts
362 |
363 | Example usages can be found as:
364 |
365 | - [Handlebars template](#handlebars-template)
366 | - [Handlebars inheritance](#handlebars-inheritance)
367 | - [Template function](#template-function)
368 |
369 | #### Variable mapping
370 | The `cssVarMap` option allows customization of the CSS variable names
371 |
372 | > If you would like to customize CSS selectors in the `css` template, please see https://github.com/twolfson/spritesheet-templates#css
373 |
374 | Your `cssVarMap` should be a function with the signature `function (sprite)`. It will receive the same parameters as `sprites` from [Templating](#templating) except for `escaped_image`, `offset_x`,` offset_y`, and `px`.
375 |
376 | ```js
377 | // Prefix all sprite names with `sprite-` (e.g. `home` -> `sprite-home`)
378 | cssVarMap: function (sprite) {
379 | sprite.name = 'sprite_' + sprite.name;
380 | }
381 |
382 | // Generates:
383 | // $sprite_fork_x = 0px;
384 | // $sprite_fork_y = 0px;
385 |
386 | // As oppposed to default:
387 | // $fork_x = 0px;
388 | // $fork_y = 0px;
389 | ```
390 |
391 | ### Engines
392 | An engine can greatly improve the speed of your build (e.g. `canvassmith`) or support obscure image formats (e.g. `gmsmith`).
393 |
394 | All `spritesmith` engines adhere to a common specification:
395 |
396 | https://github.com/twolfson/spritesmith-engine-spec
397 |
398 | This repository adheres to specification version: **2.0.0**
399 |
400 | Below is a list of known engines with their tradeoffs:
401 |
402 | #### pixelsmith
403 | [`pixelsmith`][] is a `node` based engine that runs on top of [`get-pixels`][] and [`save-pixels`][].
404 |
405 | [`pixelsmith`]: https://github.com/twolfson/pixelsmith
406 | [`get-pixels`]: https://github.com/mikolalysenko/get-pixels
407 | [`save-pixels`]: https://github.com/mikolalysenko/save-pixels
408 |
409 | **Key differences:** Doesn't support uncommon image formats (e.g. `tiff`) and not as fast as a compiled library (e.g. `canvassmith`).
410 |
411 | #### phantomjssmith
412 | [`phantomjssmith`][] is a [phantomjs][] based engine. It was originally built to provide cross-platform compatibility but has since been succeeded by [`pixelsmith`][].
413 |
414 | **Requirements:** [phantomjs][] must be installed on your machine and on your `PATH` environment variable. Visit [the phantomjs website][phantomjs] for installation instructions.
415 |
416 | **Key differences:** `phantomjs` is cross-platform and supports all image formats.
417 |
418 | [`phantomjssmith`]: https://github.com/twolfson/phantomjssmith
419 | [phantomjs]: http://phantomjs.org/
420 |
421 | #### canvassmith
422 | [`canvassmith`][] is a [node-canvas][] based engine that runs on top of [Cairo][].
423 |
424 | **Requirements:** [Cairo][] and [node-gyp][] must be installed on your machine.
425 |
426 | Instructions on how to install [Cairo][] are provided in the [node-canvas wiki][].
427 |
428 | [node-gyp][] should be installed via `npm`:
429 |
430 | ```bash
431 | npm install -g node-gyp
432 | ```
433 |
434 | **Key differences:** `canvas` has the best performance (useful for over 100 sprites). However, it is `UNIX` only.
435 |
436 | [`canvassmith`]: https://github.com/twolfson/canvassmith
437 | [node-canvas]: https://github.com/learnboost/node-canvas
438 | [Cairo]: http://cairographics.org/
439 | [node-canvas wiki]: (https://github.com/LearnBoost/node-canvas/wiki/_pages
440 | [node-gyp]: https://github.com/TooTallNate/node-gyp/
441 |
442 | #### gmsmith
443 | [`gmsmith`][] is a [`gm`][] based engine that runs on top of either [Graphics Magick][] or [Image Magick][].
444 |
445 | **Requirements:** Either [Graphics Magick][] or [Image Magick][] must be installed on your machine.
446 |
447 | For the best results, install from the site rather than through a package manager (e.g. `apt-get`). This avoids potential transparency issues which have been reported.
448 |
449 | [Image Magick][] is implicitly discovered. However, you can explicitly use it via `engineOpts`
450 |
451 | ```js
452 | {
453 | engineOpts: {
454 | imagemagick: true
455 | }
456 | }
457 | ```
458 |
459 | **Key differences:** `gmsmith` allows for configuring image quality whereas others do not.
460 |
461 | [`gmsmith`]: https://github.com/twolfson/gmsmith
462 | [`gm`]: https://github.com/aheckmann/gm
463 | [Graphics Magick]: http://www.graphicsmagick.org/
464 | [Image Magick]: http://imagemagick.org/
465 |
466 | ## Examples
467 | ### Algorithm
468 | In this example, we are using the `alt-diagonal` algorithm to guarantee no overlap if images overflow.
469 |
470 | **Configuration:**
471 |
472 | ```js
473 | {
474 | imgName: 'sprite.png',
475 | cssName: 'sprite.styl',
476 | algorithm: 'alt-diagonal'
477 | }
478 | ```
479 |
480 | **Output:**
481 |
482 | 
483 |
484 | ### Engine
485 | In this example, we are using the `phantomjssmith` engine as an alternative to the `pixelsmith` default.
486 |
487 | **Requirements:**
488 |
489 | Install `phantomjssmith` to our `node_modules` via `npm install`.
490 |
491 | ```bash
492 | npm install phantomjssmith
493 | ```
494 |
495 | Alternatively, we can use `--save` or `--save-dev` to save to our `package.json's dependencies` or `devDependenices`.
496 |
497 | ```bash
498 | npm install phantomjssmith --save # Updates {"dependencies": {"phantomjssmith": "1.2.3"}}
499 | npm install phantomjssmith --save-dev # Updates {"devDependencies": {"phantomjssmith": "1.2.3"}}
500 | ```
501 |
502 | **Configuration:**
503 |
504 | ```js
505 | // var phantomjssmith = require('phantomjssmith');
506 | {
507 | imgName: 'sprite.png',
508 | cssName: 'sprite.styl',
509 | engine: phantomjssmith
510 | }
511 | ```
512 |
513 | **Output:**
514 |
515 | 
516 |
517 | ### Padding
518 | The `padding` option allows for inserting spacing between images.
519 |
520 | **Configuration:**
521 |
522 | ```js
523 | {
524 | imgName: 'sprite.png',
525 | cssName: 'sprite.styl',
526 | padding: 20 // Exaggerated for visibility, normal usage is 1 or 2
527 | }
528 | ```
529 |
530 | **Output:**
531 |
532 | 
533 |
534 | ### Retina spritesheet
535 | In this example, we will use generate a normal and retina spritesheet via the `retinaSrcFilter` and `retinaImgName` parameters.
536 |
537 | **Configuration:**
538 |
539 | ```js
540 | {
541 | // This will filter out `fork@2x.png`, `github@2x.png`, ... for our retina spritesheet
542 | // The normal spritesheet will now receive `fork.png`, `github.png`, ...
543 | retinaSrcFilter: ['images/*@2x.png'],
544 | imgName: 'sprite.png',
545 | retinaImgName: 'sprite@2x.png',
546 | cssName: 'sprite.styl'
547 | }
548 | ```
549 |
550 | **Normal spritesheet:**
551 |
552 | 
553 |
554 | **Retina spritesheet:**
555 |
556 | 
557 |
558 | ### Handlebars template
559 | In this example, we will use `cssTemplate` with a `handlebars` template to generate CSS that uses `:before` selectors.
560 |
561 | **Template:**
562 |
563 | ```handlebars
564 | {{#sprites}}
565 | .icon-{{name}}:before {
566 | display: block;
567 | background-image: url({{{escaped_image}}});
568 | background-position: {{px.offset_x}} {{px.offset_y}};
569 | width: {{px.width}};
570 | height: {{px.height}};
571 | }
572 | {{/sprites}}
573 | ```
574 |
575 | **Configuration:**
576 |
577 | ```js
578 | {
579 | imgName: 'sprite.png',
580 | cssName: 'sprite.css',
581 | cssTemplate: 'handlebarsStr.css.handlebars'
582 | }
583 | ```
584 |
585 | **Output:**
586 |
587 | ```css
588 | .icon-fork:before {
589 | display: block;
590 | background-image: url(sprite.png);
591 | background-position: 0px 0px;
592 | width: 32px;
593 | height: 32px;
594 | }
595 | .icon-github:before {
596 | /* ... */
597 | ```
598 |
599 | ### Handlebars inheritance
600 | In this example, we will extend the SCSS template to provide minimal variables. The JSON at the front comes from the original template and is required to provide consistent casing and default options.
601 |
602 | Different block sections for each template are documented in:
603 |
604 | https://github.com/twolfson/spritesheet-templates
605 |
606 | **Template:**
607 |
608 | ```handlebars
609 | {
610 | // Default options
611 | 'functions': true,
612 | 'variableNameTransforms': ['dasherize']
613 | }
614 |
615 | {{#extend "scss"}}
616 | {{#content "sprites"}}
617 | {{#each sprites}}
618 | ${{strings.name}}: ({{px.x}}, {{px.y}}, {{px.offset_x}}, {{px.offset_y}}, {{px.width}}, {{px.height}}, {{px.total_width}}, {{px.total_height}}, '{{{escaped_image}}}', '{{name}}', );
619 | {{/each}}
620 | {{/content}}
621 | {{#content "spritesheet"}}
622 | ${{spritesheet_info.strings.name_sprites}}: ({{#each sprites}}${{strings.name}}, {{/each}});
623 | ${{spritesheet_info.strings.name}}: ({{spritesheet.px.width}}, {{spritesheet.px.height}}, '{{{spritesheet.escaped_image}}}', ${{spritesheet_info.strings.name_sprites}}, );
624 | {{/content}}
625 | {{/extend}}
626 | ```
627 |
628 | **Configuration:**
629 |
630 | ```js
631 | {
632 | imgName: 'sprite.png',
633 | cssName: 'sprite.scss',
634 | cssTemplate: 'handlebarsInheritance.scss.handlebars'
635 | }
636 | ```
637 |
638 | **Output:**
639 |
640 | ```scss
641 | $fork: (0px, 0px, 0px, 0px, 32px, 32px, 64px, 64px, 'sprite.png', 'fork', );
642 | $github: (32px, 0px, -32px, 0px, 32px, 32px, 64px, 64px, 'sprite.png', 'github', );
643 | $twitter: (0px, 32px, 0px, -32px, 32px, 32px, 64px, 64px, 'sprite.png', 'twitter', );
644 | $spritesheet-sprites: ($fork, $github, $twitter, );
645 | $spritesheet: (64px, 64px, 'sprite.png', $spritesheet-sprites, );
646 | /* ... */
647 | ```
648 |
649 | ### Template function
650 | In this example, we will use `cssTemplate` with a custom function that generates YAML.
651 |
652 | **Configuration:**
653 |
654 | ```js
655 | // var yaml = require('js-yaml');
656 | {
657 | imgName: 'sprite.png',
658 | cssName: 'sprite.yml',
659 | cssTemplate: function (data) {
660 | // Convert sprites from an array into an object
661 | var spriteObj = {};
662 | data.sprites.forEach(function (sprite) {
663 | // Grab the name and store the sprite under it
664 | var name = sprite.name;
665 | spriteObj[name] = sprite;
666 |
667 | // Delete the name from the sprite
668 | delete sprite.name;
669 | });
670 |
671 | // Return stringified spriteObj
672 | return yaml.safeDump(spriteObj);
673 | }
674 | }
675 | ```
676 |
677 | **Output:**
678 |
679 | ```yaml
680 | fork:
681 | x: 0
682 | 'y': 0
683 | width: 32
684 | height: 32
685 | source_image: /home/todd/github/gulp.spritesmith/docs/images/fork.png
686 | image: sprite.png
687 | total_width: 64
688 | total_height: 64
689 | escaped_image: sprite.png
690 | offset_x: -0.0
691 | offset_y: -0.0
692 | px:
693 | x: 0px
694 | 'y': 0px
695 | offset_x: 0px
696 | offset_y: 0px
697 | height: 32px
698 | width: 32px
699 | total_height: 64px
700 | total_width: 64px
701 | github:
702 | # ...
703 | ```
704 |
705 | ### Cache busting
706 | `gulp.spritesmith` doesn't directly support cache busting but [`gulp-spritesmash`][] is a plugin that takes `gulp.spritesmith's` output and generates cache busted filenames and CSS URLs. Here's an example usage:
707 |
708 |
709 |
710 | ```js
711 | var gulp = require('gulp');
712 | var buffer = require('vinyl-buffer');
713 | var spritesmash = require('gulp-spritesmash');
714 | var spritesmith = require('gulp.spritesmith');
715 |
716 | gulp.task('sprite', function () {
717 | return gulp.src('images/*.png', {encoding: false})
718 | .pipe(spritesmith({
719 | imgName: 'sprite.png',
720 | cssName: 'sprite.css'
721 | }))
722 | .pipe(buffer())
723 | .pipe(spritesmash());
724 | .pipe(gulp.dest('path/to/output/', {encoding: false}));
725 | });
726 | ```
727 |
728 | [`gulp-spritesmash`]: https://github.com/MasterOfMalt/gulp-spritesmash
729 |
730 | ## Contributing
731 | In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint via `npm run lint` and test via `npm test`.
732 |
733 | ## Attribution
734 | GitHub and Twitter icons were taken from [Alex Peattie's JustVector Social Icons][justvector].
735 |
736 | Fork designed by [P.J. Onori][onori] from The Noun Project.
737 |
738 | [justvector]: http://alexpeattie.com/projects/justvector_icons/
739 | [noun-fork-icon]: http://thenounproject.com/noun/fork/#icon-No2813
740 | [onori]: http://thenounproject.com/somerandomdude
741 |
742 | ## Unlicense
743 | As of Feb 09 2014, Todd Wolfson has released this repository and its contents to the public domain.
744 |
745 | It has been released under the [UNLICENSE][].
746 |
747 | [UNLICENSE]: UNLICENSE
748 |
--------------------------------------------------------------------------------