pastelli - Code Cookbook & Code Recipies
I always forget tiny code snippets I need, so I made a blog to keep up with them all.
Ramda.js - Dynamic Filtering
- - Matthew Callis

Searching an array or object for values that match a dynamic set of criteria based on nested and deeply nested attributes, written for a Redux reducer but could be used for anything, demo below. Example JSON based on a playlist of songs from the following games:

Example

Try filters like copyrightYear:1995,dumpedBy:Datschge or gameTitle:Super Mario RPG, or publisherName:Square,dumpedWith:Higan

Code / State

// Filter Predicates
const special = {
  dumpedBy: ['dumper', 'name'],
  dumpedWith: ['dumper', 'system'],
};

// Parse Filters
const filters = R.fromPairs(R.map(R.split(':'), R.split(',', value)));
const keyFilters = R.omit(['dumpedBy', 'dumpedWith'], filters);
const specialFilters = R.pick(['dumpedBy', 'dumpedWith'], filters);

// TODO: Convert this to Ramda.
let predicates = [];
Object.keys(keyFilters).forEach((key) => {
  predicates.push(R.propEq(key, keyFilters[key]));
});

Object.keys(specialFilters).forEach((key) => {
  predicates.push(R.pathEq(special[key], specialFilters[key]));
});

const values = R.values(
  R.map(
    R.prop('gameTitle'),
    R.filter(
      R.allPass(predicates)
    )(state)
  )
);
{
  'sck-main-menu': {
    songTitle: 'Main Menu',
    gameTitle: 'Shin Chou Kouki',
    copyrightYear: '1993',
    publisherName: 'Yanoman',
    dumper: {
      name: 'KungFuFurby',
      system: 'Hardware',
    },
    artist: {
      name: 'Masamichi Iwasaki',
    },
  },
  'sbb1-title-screen': {
    songTitle: 'Title Screen',
    gameTitle: 'Super Black Bass',
    copyrightYear: '1992',
    publisherName: 'Starfish, Hot-B',
    dumper: {
      name: 'Locke_gb7',
      system: 'Higan',
    },
    artist: {
      name: 'Cube',
    },
  },
  'gga3-ackman-and-tenshi': {
    songTitle: 'Ackman and Tenshi',
    gameTitle: 'Go Go Ackman 3',
    copyrightYear: '1995',
    publisherName: 'Banpresto',
    dumper: {
      name: 'Dais',
      system: 'Snes9x',
    },
    artist: {
      name: "K'Mixa",
    },
  },
  'ct-presentiment': {
    songTitle: 'Presentiment',
    gameTitle: 'Chrono Trigger',
    copyrightYear: '1995',
    publisherName: 'Square',
    dumper: {
      name: 'YK',
      system: 'ZSNES',
    },
    artist: {
      name: 'Yasunori Mitsuda',
    },
  },
  'smr-happy-adventure': {
    songTitle: 'Happy Adventure, Delightful Adventure',
    gameTitle: 'Super Mario RPG',
    ost: 'Super Mario RPG Original Sound Version (PSCN-5047)',
    copyrightYear: '1996',
    publisherName: 'Nintendo, Square',
    dumper: {
      name: 'Datschge',
      system: 'Higan',
    },
    artist: {
      name: 'Yoko Shimomura',
    },
  },
  'sd2-fear-of-the-heavens': {
    songTitle: 'Fear of the Heavens',
    gameTitle: 'Secret of Mana',
    ost: 'Seiken Densetsu 2 Original Sound Version (PSCN-5030)',
    copyrightYear: '1993',
    publisherName: 'Square',
    dumper: {
      name: 'Datschge',
      system: 'Hardware',
    },
    artist: {
      name: 'Hiroki Kikuta',
    },
  },
  'sd3-not-awaken': {
    songTitle: 'Not Awaken',
    gameTitle: 'Seiken Densetsu 3',
    ost: 'Seiken Densetsu 3 Original Sound Version (PSCN-5026~8)',
    copyrightYear: '1995',
    publisherName: 'Square',
    dumper: {
      name: 'Datschge',
      system: 'Higan',
    },
    artist: {
      name: 'Hiroki Kikuta',
    },
  },
}
Ramda.js - Deep Merge Objects
- - Matthew Callis

Deep merging of objects, found & copied from this Gist, and on Ramda.js. As always, feel free to make it better! ๐Ÿ›๐Ÿž๐Ÿœ.

const mergePlan = (x, y) => {
  if(Array.isArray(x) && Array.isArray(y)) {
    return uniq(concat(x, y));
  }

  if(typeof x === 'object' && typeof y === 'object'){
    return mergeWith(mergePlan, x, y)
  }

  return y;
}

const deepMerge = mergeWith(mergePlan);

Example

Ramda.js - Modify Nested Data Structures
- - Matthew Callis

Modifying various nested data structures within the example object below and on Ramda.js. As always, feel free to make it better! ๐Ÿ›๐Ÿž๐Ÿœ.

const store = {
  open: false,
  name: 'Cat Store',
  cats: {
    number: 3,
    names: {
      language: '๐Ÿ‡ฉ๐Ÿ‡ช',
      fat: 'Moe',
      small: 'Kittioto',
      fast: 'Fishsticks',
    },
  },
  catToys: {
    'faux-fur-mouse': {
      price: 1,
      images: [{
        title: 'Mouse',
        icons: [{ name: 'mouse', icon: '๐Ÿญ' }],
      }],
    },
  },
};

// Add Key / Update Key / Modify Key
assoc('open', true, store);
  โžœ  {
    open: true,
    name: 'Cat Store',
    cats: {
      number: 3,
      names: {
        language: '๐Ÿ‡ฉ๐Ÿ‡ช',
        fat: "Moe",
        small: "Kittioto",
        fast: "Fishsticks",
      },
    },
    catToys: {
      'faux-fur-mouse': {
        price: 1,
        images: [{
          title: 'Mouse',
          icons: [{ name: 'mouse', icon: '๐Ÿญ' }],
        }],
      },
    },
  }

// Add Nested Key / Update Nested Key / Modify Nested Key
assocPath(['cats', 'names', 'language'], '๐Ÿ‡บ๐Ÿ‡ธ', store);
  โžœ  {
    open: false,
    name: 'Cat Store',
    cats: {
      number: 3,
      names: {
        language: '๐Ÿ‡บ๐Ÿ‡ธ',
        fat: "Moe",
        small: "Kittioto",
        fast: "Fishsticks",
      },
    },
    catToys: {
      'faux-fur-mouse': {
        price: 1,
        images: [{
          title: 'Mouse',
          icons: [{ name: 'mouse', icon: '๐Ÿญ' }],
        }],
      },
    },
  }

// Remove Key / Delete Key
dissoc('open', store);
  โžœ  {
    name: 'Cat Store',
    cats: {
      number: 3,
      names: {
        language: '๐Ÿ‡ฉ๐Ÿ‡ช',
        fat: "Moe",
        small: "Kittioto",
        fast: "Fishsticks",
      },
    },
    catToys: {
      'faux-fur-mouse': {
        price: 1,
        images: [{
          title: 'Mouse',
          icons: [{ name: 'mouse', icon: '๐Ÿญ' }],
        }],
      },
    },
  }

// Remove Nested Key / Delete Nested Key
dissocPath(['cats', 'names', 'language'], store);
  โžœ  {
    open: false,
    name: 'Cat Store',
    cats: {
      number: 3,
      names: {
        fat: "Moe",
        small: "Kittioto",
        fast: "Fishsticks",
      },
    },
    catToys: {
      'faux-fur-mouse': {
        price: 1,
        images: [{
          title: 'Mouse',
          icons: [{ name: 'mouse', icon: '๐Ÿญ' }],
        }],
      },
    },
  }

// Update Deeply Nested Object in an Array / List
const imagesLens = lensPath(['catToys', 'faux-fur-mouse', 'images']);
const images = view(imagesLens, store);
  โžœ  [{
    title: 'Mouse',
    icons: [{ name: 'mouse', icon: '๐Ÿญ' }],
  }]

const imageIndex = findIndex(propEq('title', 'Mouse'))(images);
   โžœ  0

const image = find(propEq('title', 'Mouse'))(images);
  โžœ  {
    title: 'Mouse',
    icons: [{ name: 'mouse', icon: '๐Ÿญ' }],
  }

const icons = [{ name: 'hamster', icon: '๐Ÿน' }];

// Replace
const newImage = assoc('icons', icons, image);
  โžœ  {
    title: 'Mouse',
    icons: [{ name: 'hamster', icon: '๐Ÿน' }],
  }

// Merge
const newImage = assoc('icons', uniq(concat(icons, image.icons)), image);
  โžœ  {
    title: 'Mouse',
    icons: [
      { name: 'hamster', icon: '๐Ÿน' }
      { name: 'mouse', icon: '๐Ÿญ' }
    ],
  }

const newImages = update(imageIndex, newImage, images);
  โžœ  [{
        title: 'Mouse',
        icons: [{ name: 'hamster', icon: '๐Ÿน' }],
      }]

set(imagesLens, newImages, store);
  โžœ  {
    open: false,
    name: 'Cat Store',
    cats: {
      number: 3,
      names: {
        language: '๐Ÿ‡ฉ๐Ÿ‡ช',
        fat: "Moe",
        small: "Kittioto",
        fast: "Fishsticks",
      },
    },
    catToys: {
      'faux-fur-mouse': {
        price: 1,
        images: [{
          title: 'Mouse',
          icons: [{ name: 'hamster', icon: '๐Ÿน' }],
        }],
      },
    },
  }
Data URI Base64 Conversion
- - Matthew Callis

Yet another data URI generator, file to base64 converter, every other combination of these terms.

Data URI Drag & Drop

Dropping large files will eat lots of memory, but should eventually resolve.

Source

const output = document.querySelector('.output');
let uploaded_files = {};
function readFile(file) {
  const reader = new FileReader();
  reader.addEventListener('load', () => {
    uploaded_files = R.merge(
      uploaded_files,
      {
        [`${file.name}_${Date.now()}`]: reader.result,
      }
    );
    const purposed_output = JSON.stringify(uploaded_files, null, 2);
    if (purposed_output !== output.textContent) {
      requestAnimationFrame(() => output.textContent = purposed_output);
    }
  });
  reader.readAsDataURL(file);
}

output.addEventListener('dragover', (event) => {
  event.stopPropagation();
  event.preventDefault();
}, true);

output.addEventListener('drop', (event) => {
  event.preventDefault();
  event.stopPropagation();

  const data_transfer = event.dataTransfer;
  if (data_transfer.items) {
    for (let i = 0; i < data_transfer.items.length; i++) {
      if (data_transfer.items[i].kind === 'file') {
        readFile(data_transfer.items[i].getAsFile());
      }
    }
  } else {
    for (let i = 0; i < data_transfer.files.length; i++) {
      readFile(data_transfer.files[i].name);
    }
  }
});
Walking Ness (Earthbound / Mother 2 / ใƒžใ‚ถใƒผ2 ใ‚ฎใƒผใ‚ฐใฎ้€†่ฅฒ) Sprite Animation
- - Matthew Callis

This is a simple animation I use on eludevisibility.org and this site. Itโ€™s a simple CSS only animation of Ness from Earthbound, walking 9 directions. I can make other characters if thereโ€™s interest. Probably refactor this a bit too. Some CSS animation paths from this amazing post.

@mixin keyframes($name) {
  @-webkit-keyframes #{$name} {
    @content;
  }

  @-moz-keyframes #{$name} {
    @content;
  }

  @-ms-keyframes #{$name} {
    @content;
  }

  @keyframes #{$name} {
    @content;
  }
}

@mixin animation($val...) {
  -webkit-animation: $val;
  -moz-animation: $val;
  -ms-animation: $val;
  -o-animation: $val;
  animation: $val;
}

@mixin animation-fill-mode($val) {
  -webkit-animation-fill-mode: $val;
  -moz-animation-fill-mode: $val;
  -ms-animation-fill-mode: $val;
  -o-animation-fill-mode: $val;
  animation-fill-mode: $val;
}

@mixin animation-delay($val) {
  -webkit-animation-delay: $val;
  -moz-animation-delay: $val;
  -ms-animation: $val;
  -o-animation-delay-delay: $val;
  animation-delay: $val;
}

@mixin mask-size($val) {
  -webkit-mask-size: $val;
  -moz-mask-size: $val;
  -o-mask-size: $val;
  mask-size: $val;
}

@mixin mask-image($val) {
  -webkit-mask-image: $val;
  -moz-mask-image: $val;
  -o-mask-image: $val;
  mask-image: $val;
}

@mixin mirror($x, $y) {
  -webkit-transform: scaleX($x) scaleY($y);
  -moz-transform: scaleX($x) scaleY($y);
  -o-transform: scaleX($x) scaleY($y);
  transform: scaleX($x) scaleY($y);
}

// Directions
@include keyframes(diagonal-slide-south-east) {
  0% { left: 0; top: 0; }
  100% { left: 100%; top: 100%; }
}

@include keyframes(diagonal-slide-south-west) {
  0% { right: 0; top: 0; }
  100% { right: 100%; top: 100%; }
}

@include keyframes(diagonal-slide-north-west) {
  0% { right: 0; bottom: 0; }
  100% { right: 100%; bottom: 100%; }
}

@include keyframes(diagonal-slide-north-east) {
  0% { left: 0; bottom: 0; }
  100% { left: 100%; bottom: 100%; }
}

@include keyframes(vertical-slide-south) {
  0% { top: 0%; }
  100% { top: 100%; }
}

@include keyframes(vertical-slide-north) {
  0% { bottom: 0%; }
  100% { bottom: 100%; }
}

@include keyframes(horizontal-slide-west) {
  0% { right: 0%; }
  100% { right: 100%; }
}

@include keyframes(horizontal-slide-east) {
  0% { left: 0%; }
  100% { left: 100%; }
}

@include keyframes(horizontal-slide-west-transform) {
  0% {
    -webkit-transform: translateX(100%);
    -moz-transform: translateX(100%);
    transform: translateX(100%);
  }
  100% {
    -webkit-transform: translateX(0%);
    -moz-transform: translateX(0%);
    transform: translateX(0%);
  }
}

@include keyframes(horizontal-slide-east-transform) {
  0% {
    -webkit-transform: translateX(0%);
    -moz-transform: translateX(0%);
    transform: translateX(0%);
  }
  100% {
    -webkit-transform: translateX(100%);
    -moz-transform: translateX(100%);
    transform: translateX(100%);
  }
}

// http://tobiasahlin.com/blog/curved-path-animations-in-css/
@include keyframes(x-axis-bounce) {
  50% {
    -webkit-animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64);
    -moz-animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64);
    animation-timing-function: cubic-bezier(0.3, 0.27, 0.07, 1.64);
    -webkit-transform: translateX(100px);
    -moz-transform: translateX(100px);
    transform: translateX(100px);
  }
}

@include keyframes(y-axis-bounce) {
  50% {
    -webkit-animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1);
    -moz-animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1);
    animation-timing-function: cubic-bezier(0.02, 0.01, 0.21, 1);
    -webkit-transform: translateY(100px);
    -moz-transform: translateY(100px);
    transform: translateY(100px);
  }
}

// Base Styles
#sprites {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
}
.sprites {
  -webkit-transform: translate3d(0px, 0px, 0px);
  -moz-transform: translate3d(0px, 0px, 0px);
  transform: translate3d(0px, 0px, 0px);
  -webkit-transform: translateZ(0);
  -moz-transform: translateZ(0);
  transform: translateZ(0);
}
.sprite {
  background-repeat: no-repeat;
  position: absolute;
  image-rendering: optimizeSpeed;
  image-rendering: -o-crisp-edges;
  image-rendering: -moz-crisp-edges;
  image-rendering: optimize-contrast;
  image-rendering: -webkit-optimize-contrast;
  image-rendering: pixelated;
  -ms-interpolation-mode: nearest-neighbor;
}

// Earthbound / Mother 2 - Ness
.ness {
  width: 16px;
  height: 24px;

  &.north-west {
    @include animation(diagonal-slide-north-west 30s linear 0s infinite);
    bottom: 0;
    right: 0;
    background-image: url(data:image/gif;base64,R0lGODlhEAAYAPMMAPAAYMiYeJCggMjIyPCQkPDw8PCwkODQIHBw8FBwYPCQADAgIP///wAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJEAAMACwAAAAAEAAYAEAEfpDJSatcxqzN+2JLYRzIUh6HsqgXUgLAAs9xTC1E0OkW6HqVDkxD3Nw2NVrscyF4gDfSD3VgXjaJnwK1siYSC0FhIAiXvwnL0woavGCYmYyJhCtrH8waugho9kYTOIBqGwE6gYImCCglfBmOVVRcai4lCphsV3JwPWAcn2kTEQAh+QQFEAAMACwAAAAAEAAYAAAEgpBJuapdk1oAzPIexiwDsnDAh57YgpjcicbpKKczLW73uoeX4A8orFACxOJkQShaMqOmExoNXKxUTcBqzLpei4NYBA2PL9RvwqxYtDOLguGwFtvJI4PB5B6/lxZgCoN4cR0vYE9LAwIpFQYpjIUCAgsJaySXIpeYnGuanBKenhWXEhEAOw==);
  }
  &.north {
    @include animation(vertical-slide-north 30s linear 0s infinite);
    bottom: 0;
    left: 50%;
    background-image: url(data:image/gif;base64,R0lGODlhEAAYAPMMAPAAYPCQkMjIyMiYePDw8JCggHBw8PCwkODQIFBwYPCQADAgIP///wAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJEAAMACwAAAAAEAAYAEAEg5BJuapdk57L68DLUSALYprlQYAAsLSw22IZ09G1LQgVYBg4ygy2mfFst9tkEbg1ayXgxUDKWICK7CKRqDC43YJ4262Al6HK5uDy2oYxmY/Wi8/c6aSa3kw+rQEfHn9QQCcLQIWGCgsKJAYbGhuNJAiMIZFoShlhYjwLYiucZWRgXBIRACH5BAUQAAwALAAAAAAQABgAAASGkEm2ql1zWnBW95UmLADglWaJUYaKoqQpxfFLz9Vrr1fvUx+fpUMZCC9ESuC4WGaaQmdGaawMpFPKL8taIL4Lw+qJEF8MiDFQjFAsFGmDeEY4pL94b4Ho+cC9bn08CwkJbwpuZmpaQlxhLRUCI1kLBAUFkZeYCRKFhhWFC5qEhZ2enhalDBEAOw==);
  }
  &.north-east {
    @include animation(diagonal-slide-north-east 30s linear 0s infinite);
    bottom: 0;
    left: 0;
    background-image: url(data:image/gif;base64,R0lGODlhEAAYAPMMAPAAYMiYeJCggMjIyPCQkPDw8PCwkODQIHBw8FBwYPCQADAgIP///wAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJEAAMACwAAAAAEAAYAEAEfZDJSatcOOtlzJqLEh7HgpiHUWDAAryw2yInGGgB8VnMRu8UjGf40lxksFYLE9xodJUFqURDlKIikoiWyEgS4IVAIB4UyOCo0+JCemKIAQsZi+2cTs8RL7yB+FBsGAE3TGoaVgc/QFJTJSUmHYwKlCY/PD1FdjxdC50YCRMRACH5BAUQAAwALAAAAAAQABgAAASEkEm2ql0zV7O4AcAlLSEIcOaCDFVpgmSIIG382tVop2GuX8AOhhK8GDi/YicwJCoJTWcQmhkxLQFq9Re4bkeHsGoWnQDDhzJFsVCIE+TqAv0+GArR9vzAVh3LbQpsZBZyFjMzH3hmAiwnFgCNTQsJCSyUCQsCAkOVmZWYoKESop6mCRIRADs=);
  }
  &.east {
    @include animation(horizontal-slide-east 30s linear 0s infinite);
    top: 50%;
    left: 0;
    background-image: url(data:image/gif;base64,R0lGODlhEAAYALMMAPDw8MjIyPCQAJCggODQIPCQkMiYeFBwYHBw8PAAYPCwkDAgIP///wAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJEAAMACwAAAAAEAAYAAAEeZDJSatdOFuZlVreciVLYpIJoDFleaImEojtiyK4yGW8sbK8hcHg+eiAGB8x9Jn0iszmDqMoWItHztJa8PguRK4wixQWvxcCIYnZLAiCBU5N5sRzOESdqlLT3SF5ehtAgoOEVAoqhE4ndQeQkAsDAQAqkRSRBzyQExEAIfkEBRAADAAsAAAAABAAGAAABI6QSbmqnZjZUhZfmZYsSTkmwCWS5lkiAUiyJoncIGXthqrtC4NBQaxMeEGiYrE8WobKZdFZUXAKytwReiX2QslrUKurQBVfMIFgNqrZN1xIQxAsEGvf0Y64IxQpczt4RH1gcRZ9Mjo9cTh/C4ELAQlLOwcGJTEaMW4UCgmbBweRC6OnpDGjDKMVqKemBwwRADs=);
  }
  &.south-east {
    @include animation(diagonal-slide-south-east 30s linear 0s infinite);
    top: 0;
    left: 0;
    background-image: url(data:image/gif;base64,R0lGODlhEAAYAPMMAPCwkJCggPCQAMjIyPCQkODQIMiYeFBwYPAAYHBw8PDw8DAgIP///wAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJEAAMACwAAAAAEAAYAEAEi5BJtqqtU1bAweqfsWRLkpTmmXgagiwukprHSC6GAWZkitokF8zleVkol1wlJwJSCIQOB+pcCFC+E+/jmZkwkoN4IQ4oyGfxzfP5vIKvmDA1sCXvwA2X6wGIJjhQUgBUPE8cFQcEThoFFk2MSAWOk5MLjiQKHgKVBScsgFgqWjxjQgcvB4ZjFjVkExEAIfkEBRAADAAsAAABABAAFwAABI6QSbaqrTNXsBdAS0YhIIlwoDWWJpi8Q7iQM/neRyhdBo/tvN7CQPx1ABxksgdUJpEe5s5AIDgBVd1kUb1mRRQrZ3EgaLcVovK8FRTSP9Gi8E7QCwk25U2vvPQLAnMJAApzb2wWhBx5CjlbCH9+HwGPOwqRN4SVlhQBmBcLlToHpaIBZKaqBxKmqaU5ZBIRADs=)
  }
  &.south {
    @include animation(vertical-slide-south 30s linear 0s infinite);
    top: 0;
    left: 50%;
    background-image: url(data:image/gif;base64,R0lGODlhEAAYAPMKAPCwkPDw8PCQkMiYeODQIPAAYFBwYHBw8MjIyDAgIP///wAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJEAAKACwAAAAAEAAYAEAEi1BJlapNU6YBeurAB2JJEB5oeiRHqBnqUcwJnVFcN2C3xq4JhGHIuxQ+s6ONUhk4m0/LJCEQgDpV3pRAiHG1zBhKKiEGDBX0UD2cFkKhT2WKSNWSyqNvc4kWdx4jgX9VVwBVOzdUcR8CYFNAOyyPHyhcl3YaHpecchk/YysIQmBoNBVCRBloaUStEhEAIfkEBRAACgAsAAAAABAAGAAABI1QSZmqTTOrVEDyXzVdxVecXEkhR5ueJUoZbQ2n2FYN18CLuoTvN7xseABPUqnECJefZFRKGQgEy+SVl0lcs4Brrou1hMeaZ5KroRx2lXc7QSDUWnX0B1+v13J7CXd/AAGAHn2JUWMWgy6MBggIgoJ/XQaYk5VAI5iRFigGEp4JpAYVBoaYo6eomBaiChEAOw==)
  }
  &.south-west {
    @include animation(diagonal-slide-south-west 30s linear 0s infinite);
    top: 0;
    right: 0;
    background-image: url(data:image/gif;base64,R0lGODlhEAAYAPMMAPCwkJCggPCQAMjIyPCQkODQIMiYeFBwYPAAYHBw8PDw8DAgIP///wAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJEAAMACwAAAAAEAAYAAAEipBJtqqtMy8EVveYdCEeYm6kOCQsapKneLD0iy5TZVy7lS+GoK7noxg6gKQHGQIilUklTkQgRJPVnaZ6BVSn20MFC85QosKyRmcpqCmJBa0lKC/chTzeDfbE53JxGh0JegV1AAp2gYBKZoGMcW9wfy1mEmIImSQHBxmdCwpiCgGgnZ4TYguqFZ0TEQAh+QQFEAAMACwAAAEAEAAXAAAEjpBJtqqtMy8EVveYdCEeYm6kOCQsapKneLD0iy5TZVy7lS+GoK7noxg6gKQHGQIilUklTkQgRJPVnaZ6BVSn20MFC85QosKQmQKsFATlXKJATyzocUrrXriX3X0KAHMLcDkHCgt2SXZqFAcBHI2KCSkykIM0lYkakBcbCgFTB2KkC6RiAaKoEmKnqK6kEhEAOw==);
  }
  &.west {
    @include animation(horizontal-slide-west 30s linear 0s infinite);
    top: 50%;
    right: 0;
    background-image: url(data:image/gif;base64,R0lGODlhEAAYAPMMAHBw8MjIyPCQAPCwkDAgIODQIPCQkMiYeFBwYPAAYPDw8JCggP///wAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJEAAMACwAAAAAEAAYAEAEeZDJSeskA49xSCdgRQDkCBACIREBkLzEK8fq1Rk4V1sMoWwhXg8IDF5AH5ByN9zgDBklDwkqFJgXUglIQXh9isCC4C1blsajLxGbsbMktgz2Xmk4SWnzvsnbnDk6UwcbOnoiViUCV2dWVj5RZ1olWBRtdTxfSmUIExEAIfkEBRAACwAsAAAAABAAGAAABI1wSUmqnZgaQ/adlpIQSTmOVACYpHkSFCCfLglT1WHtNz78Bx0PNCD8BjphhfIzHpE74m9jKH4oh+kG2APpqNCM96jsggjCQsEMkskIarZFDSAI1mKCYvCuC8wEAD8FdVcLMBWFgW8gCkZ1bm9ChwElBwg8AwkBNwSVRRgWnAsImJylqJiOpaSYqagVrBEAOw==);
  }
}

Example