added skottie renderer
diff --git a/images/index.js b/images/index.js
index 10fc63d..3e1d51d 100644
--- a/images/index.js
+++ b/images/index.js
@@ -48,7 +48,7 @@
     {
       name: 'renderer',
       alias: 'r',
-      type: (value) => (['svg', 'canvas'].includes(value) ? value : 'svg'),
+      type: (value) => (['svg', 'canvas', 'skottie'].includes(value) ? value : 'svg'),
       description: 'The renderer to use',
     },
   ];
@@ -63,25 +63,105 @@
     ...defaultSettings,
     ...commandLineArgs(opts),
   };
+  console.log(settings);
   return settings;
 };
 
 const wait = (time) => new Promise((resolve) => setTimeout(resolve, time));
 
+const files = [
+  {
+    path: '/js/main.js',
+    filePath: './js/main.js',
+    type: 'js',
+
+  },
+  {
+    path: '/js/screenshot.js',
+    filePath: './js/screenshot.js',
+    type: 'js',
+
+  },
+  {
+    path: '/js/screenshot_skottie.js',
+    filePath: './js/screenshot_skottie.js',
+    type: 'js',
+
+  },
+  {
+    path: '/js/canvasSnapshot.js',
+    filePath: './js/canvasSnapshot.js',
+    type: 'js',
+
+  },
+  {
+    path: '/js/wait.js',
+    filePath: './js/wait.js',
+    type: 'js',
+
+  },
+  {
+    path: '/lottie.js',
+    filePath: 'node_modules/lottie-web/build/player/lottie.min.js',
+    type: 'js',
+
+  },
+  {
+    path: '/canvaskit.js',
+    filePath: 'node_modules/canvaskit-wasm/bin/full/canvaskit.js',
+    type: 'js',
+
+  },
+  {
+    path: '/lottie.json',
+    // filePath: '../examples/rectangle.json',
+    filePath: './data.json',
+    type: 'json',
+  },
+  {
+    path: '/screenshot.html',
+    filePath: './screenshot.html',
+    type: 'html',
+  },
+  {
+    path: '/canvasKit.wasm',
+    filePath: 'node_modules/canvaskit-wasm/bin/full/canvaskit.wasm',
+    type: 'wasm',
+  },
+];
+
+const getEncoding = (() => {
+  const encodingMap = {
+    js: 'utf8',
+    json: 'utf8',
+    html: 'utf8',
+  };
+  return (fileType) => encodingMap[fileType];
+})();
+
+const getContentTypeHeader = (() => {
+  const encodingMap = {
+    js: { 'Content-Type': 'application/javascript' },
+    json: { 'Content-Type': 'application/json' },
+    html: { 'Content-Type': 'text/html; charset=utf-8' },
+    wasm: { 'Content-Type': 'application/wasm' },
+  };
+  return (fileType) => encodingMap[fileType];
+})();
+
 const startServer = async () => {
-  const lottieJS = await readFile('node_modules/lottie-web/build/player/lottie.min.js', 'utf8');
-  const screenshotJS = await readFile('screenshot.js', 'utf8');
-  const driverHTML = await readFile('screenshot.html', 'utf8');
-  const lottieJSON = await readFile('../examples/rectangle.json', 'utf8');
   const app = express();
-  app.get('/screenshot.html', (req, res) => res.send(driverHTML));
-  app.get('/screenshot_live.html', async (req, res) => {
-    const file = await readFile('screenshot.html', 'utf8');
-    res.send(file);
-  });
-  app.get('/lottie.js', (req, res) => res.send(lottieJS));
-  app.get('/screenshot.js', (req, res) => res.send(screenshotJS));
-  app.get('/lottie.json', (req, res) => res.send(lottieJSON));
+  await Promise.all(files.map(async (file) => {
+    const fileData = await readFile(file.filePath, getEncoding(file.type));
+    app.get(file.path, async (req, res) => {
+      res.writeHead(200, getContentTypeHeader(file.type));
+      // TODO: comment line. Only for live updates.
+      const fileData = await readFile(file.filePath, getEncoding(file.type));
+      res.end(fileData);
+    });
+    return file;
+  }));
+
   app.get('/*', async (req, res) => {
     try {
       if (req.originalUrl.indexOf('.json') !== -1) {
diff --git a/images/js/canvasSnapshot.js b/images/js/canvasSnapshot.js
new file mode 100644
index 0000000..1ba2b46
--- /dev/null
+++ b/images/js/canvasSnapshot.js
@@ -0,0 +1,24 @@
+const snapshot = (canvas, container, width, height) => {
+  const canvasElement = document.createElement('canvas');
+  container.appendChild(canvasElement);
+  canvasElement.width = width;
+  canvasElement.height = height;
+  canvasElement.style.width = `${width}px`;
+  canvasElement.style.height = `${height}px`;
+  canvasElement.style.display = 'inline-block';
+  canvasElement.style.verticalAlign = 'top';
+  const canvasContext = canvasElement.getContext('2d');
+  canvasContext.drawImage(
+    canvas,
+    0,
+    0,
+    canvas.width,
+    canvas.height,
+    0,
+    0,
+    canvasElement.width,
+    canvasElement.height,
+  );
+};
+
+export default snapshot;
diff --git a/images/js/main.js b/images/js/main.js
new file mode 100644
index 0000000..dc7df99
--- /dev/null
+++ b/images/js/main.js
@@ -0,0 +1,34 @@
+import lottieScreenshot from './screenshot.js'; // eslint-disable-line import/extensions
+import skottieScreenshot from './screenshot_skottie.js'; // eslint-disable-line import/extensions
+
+const buildRenderSettings = async (searchParams) => {
+  const defaultValues = {
+    renderer: 'skottie',
+    sampleRate: 1,
+    resolution: 1,
+    path: 'lottie.json',
+  };
+  searchParams.forEach((value, key) => {
+    defaultValues[key] = value;
+  });
+
+  return defaultValues;
+};
+
+const start = async () => {
+  const url = new URL(window.location);
+  const renderSettings = await buildRenderSettings(url.searchParams);
+  if (renderSettings.renderer === 'canvas' || renderSettings.renderer === 'svg') {
+    await lottieScreenshot.start(renderSettings);
+  } else if (renderSettings.renderer === 'skottie') {
+    await skottieScreenshot.start(renderSettings);
+  }
+  window._finished = true; // eslint-disable-line no-underscore-dangle
+};
+
+try {
+  start();
+} catch (err) {
+  console.log('ERROR'); // eslint-disable-line no-console
+  console.log(err.message); // eslint-disable-line no-console
+}
diff --git a/images/js/screenshot.js b/images/js/screenshot.js
new file mode 100644
index 0000000..a765617
--- /dev/null
+++ b/images/js/screenshot.js
@@ -0,0 +1,82 @@
+import canvasSnapshot from './canvasSnapshot.js'; // eslint-disable-line import/extensions
+import wait from './wait.js'; // eslint-disable-line import/extensions
+
+const loadAnimation = async (renderSettings) => new Promise((resolve, reject) => {
+  const elem = document.getElementById('lottie');
+  const animData = {
+    container: elem,
+    renderer: renderSettings.renderer,
+    loop: true,
+    autoplay: true,
+    rendererSettings: {
+      progressiveLoad: false,
+      preserveAspectRatio: 'xMidYMid meet',
+      imagePreserveAspectRatio: 'xMidYMid meet',
+      filterSize: {
+        width: '500%',
+        height: '500%',
+        x: '-200%',
+        y: '-200%',
+      },
+    },
+    path: renderSettings.path,
+  };
+  const anim = lottie.loadAnimation(animData);
+  anim.addEventListener('DOMLoaded', () => {
+    resolve(anim);
+    elem.style.width = `${anim.animationData.w}px`;
+    elem.style.height = `${anim.animationData.h}px`;
+  });
+  anim.onError = (errorType) => {
+    reject(errorType);
+  };
+});
+
+const createSVGSnapshot = (element, container, width, height) => {
+  const innerContent = element.innerHTML;
+  const iframeElement = document.createElement('iframe');
+  container.appendChild(iframeElement);
+  iframeElement.style.width = `${width}px`;
+  iframeElement.style.height = `${height}px`;
+  iframeElement.style.border = 'none';
+  iframeElement.contentWindow.document.open();
+  iframeElement.contentWindow.document.write(innerContent);
+  iframeElement.contentWindow.document.close();
+};
+
+const takeSnapshots = async (anim, renderSettings) => {
+  let currentFrame = 0;
+  const sampleRate = renderSettings.sampleRate > 0 ? renderSettings.sampleRate : 1;
+  const elem = document.getElementById('lottie');
+  const snapshotsContainer = document.getElementById('snapshotsContainer');
+  const width = anim.animationData.w * renderSettings.resolution;
+  const height = anim.animationData.h * renderSettings.resolution;
+
+  while (currentFrame < anim.totalFrames) {
+    anim.resize();
+    anim.goToAndStop(currentFrame);
+    if (renderSettings.renderer === 'svg') {
+      createSVGSnapshot(elem, snapshotsContainer, width, height);
+    } else if (renderSettings.renderer === 'canvas') {
+      const canvas = elem.getElementsByTagName('canvas')[0];
+      canvasSnapshot(canvas, snapshotsContainer, width, height);
+    }
+    currentFrame += 1 / sampleRate;
+    await wait(1); // eslint-disable-line no-await-in-loop
+  }
+};
+
+const start = async (renderSettings) => {
+  try {
+    const anim = await loadAnimation(renderSettings);
+    await takeSnapshots(anim, renderSettings);
+    window._finished = true; // eslint-disable-line no-underscore-dangle
+  } catch (err) {
+    console.log('ERROR'); // eslint-disable-line no-console
+    console.log(err.message); // eslint-disable-line no-console
+  }
+};
+
+export default {
+  start,
+};
diff --git a/images/js/screenshot_skottie.js b/images/js/screenshot_skottie.js
new file mode 100644
index 0000000..3662914
--- /dev/null
+++ b/images/js/screenshot_skottie.js
@@ -0,0 +1,87 @@
+import canvasSnapshot from './canvasSnapshot.js'; // eslint-disable-line import/extensions
+import wait from './wait.js'; // eslint-disable-line import/extensions
+
+const loadSkottieModule = async () => {
+  const canvasKit = await window.CanvasKitInit({
+    locateFile: () => 'canvaskit.wasm',
+  });
+  return canvasKit;
+};
+
+const createCanvas = async (animationData) => {
+  const canvas = document.createElement('canvas');
+  canvas.width = animationData.w;
+  canvas.height = animationData.h;
+  canvas.setAttribute('id', 'skottie-canvas');
+  const lottie = document.getElementById('lottie');
+  lottie.appendChild(canvas);
+  return canvas;
+};
+
+const getAnimationData = async (rendererSettings) => {
+  const fetchResponse = await fetch(rendererSettings.path);
+  const animData = await fetchResponse.json();
+  return animData;
+};
+
+const createSkottiePlayer = async (canvasKit, animationData, canvas) => {
+  // const { devicePixelRatio } = window; // TODO: check if using the pixel ratio is preferred.
+  const devicePixelRatio = 1;
+  canvas.width = devicePixelRatio * animationData.w; // eslint-disable-line no-param-reassign
+  canvas.height = devicePixelRatio * animationData.h; // eslint-disable-line no-param-reassign
+  const surface = canvasKit.MakeCanvasSurface(canvas);
+  const skcanvas = surface.getCanvas();
+  const animation = canvasKit.MakeManagedAnimation(
+    JSON.stringify(animationData), {}, '',
+  );
+
+  const goToAndStop = (pos) => {
+    animation.seekFrame(pos);
+    const bounds = canvasKit.LTRBRect(
+      0,
+      0,
+      animationData.w * devicePixelRatio,
+      animationData.h * devicePixelRatio,
+    );
+    animation.render(skcanvas, bounds);
+    surface.flush();
+  };
+  return {
+    goToAndStop,
+  };
+};
+
+const iterateFrames = async (player, animationData, canvas, renderSettings) => {
+  const snapshotsContainer = document.getElementById('snapshotsContainer');
+  let currentFrame = 0;
+  const sampleRate = renderSettings.sampleRate > 0 ? renderSettings.sampleRate : 1;
+  const totalFrames = animationData.op - animationData.ip;
+  while (currentFrame < totalFrames) {
+    player.goToAndStop(currentFrame);
+    canvasSnapshot(
+      canvas,
+      snapshotsContainer,
+      animationData.w * renderSettings.resolution,
+      animationData.h * renderSettings.resolution,
+    );
+    await wait(1); // eslint-disable-line no-await-in-loop
+    currentFrame += 1 / sampleRate;
+  }
+};
+
+const start = async (rendererSettings) => {
+  try {
+    const canvasKit = await loadSkottieModule();
+    const animationData = await getAnimationData(rendererSettings);
+    const canvas = await createCanvas(animationData);
+    const skottiePlayer = await createSkottiePlayer(canvasKit, animationData, canvas);
+    await iterateFrames(skottiePlayer, animationData, canvas, rendererSettings);
+  } catch (error) {
+    console.log('ERROR'); // eslint-disable-line no-console
+    console.log(error.message); // eslint-disable-line no-console
+  }
+};
+
+export default {
+  start,
+};
diff --git a/images/js/wait.js b/images/js/wait.js
new file mode 100644
index 0000000..009da81
--- /dev/null
+++ b/images/js/wait.js
@@ -0,0 +1,4 @@
+const wait = (time = 1) => new Promise((resolve) => setTimeout(resolve, time));
+
+export default wait;
+
diff --git a/images/package-lock.json b/images/package-lock.json
index 6c66d2d..39ec3e9 100644
--- a/images/package-lock.json
+++ b/images/package-lock.json
@@ -282,6 +282,11 @@
       "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
       "dev": true
     },
+    "canvaskit-wasm": {
+      "version": "0.30.0",
+      "resolved": "https://registry.npmjs.org/canvaskit-wasm/-/canvaskit-wasm-0.30.0.tgz",
+      "integrity": "sha512-iow8oe8NXJ5o16a1yZDp4rhEEhsfzAzmPFIIgIV/++QCPojM+5vXM2mS9GVRzdm2V3EWBc8Wbc7yDd854f7meQ=="
+    },
     "chalk": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
diff --git a/images/package.json b/images/package.json
index 66602b3..1f83417 100644
--- a/images/package.json
+++ b/images/package.json
@@ -4,6 +4,7 @@
   "description": "",
   "main": "index.js",
   "dependencies": {
+    "canvaskit-wasm": "^0.30.0",
     "command-line-args": "^5.2.0",
     "express": "^4.17.1",
     "lottie-web": "^5.7.14",
diff --git a/images/screenshot.html b/images/screenshot.html
index d08c20e..06af0a1 100644
--- a/images/screenshot.html
+++ b/images/screenshot.html
@@ -25,6 +25,7 @@
 
     </style>
     <script src="lottie.js" ></script>
+    <script src="canvaskit.js" ></script>
 
 
 
@@ -33,7 +34,7 @@
 <div id="lottie"></div>
 <div id="snapshotsContainer"></div>
 
-<script src="screenshot.js" ></script>
+<script src="js/main.js" type="module" ></script>
 
 </body>
 </html>
diff --git a/images/screenshot.js b/images/screenshot.js
deleted file mode 100644
index d308974..0000000
--- a/images/screenshot.js
+++ /dev/null
@@ -1,116 +0,0 @@
-const wait = (time = 1) => new Promise((resolve) => setTimeout(resolve, time));
-
-const buildRenderSettings = async (searchParams) => {
-  const defaultValues = {
-    renderer: 'svg',
-    sampleRate: 1,
-    resolution: 1,
-    path: 'lottie.json',
-  };
-  searchParams.forEach((value, key) => {
-    defaultValues[key] = value;
-  });
-
-  return defaultValues;
-};
-
-const loadAnimation = async (renderSettings) => new Promise((resolve, reject) => {
-  const elem = document.getElementById('lottie');
-  const animData = {
-    container: elem,
-    renderer: renderSettings.renderer,
-    loop: true,
-    autoplay: true,
-    rendererSettings: {
-      progressiveLoad: false,
-      preserveAspectRatio: 'xMidYMid meet',
-      imagePreserveAspectRatio: 'xMidYMid meet',
-      filterSize: {
-        width: '500%',
-        height: '500%',
-        x: '-200%',
-        y: '-200%',
-      },
-    },
-    path: renderSettings.path,
-  };
-  const anim = lottie.loadAnimation(animData);
-  anim.addEventListener('DOMLoaded', () => {
-    resolve(anim);
-    elem.style.width = `${anim.animationData.w}px`;
-    elem.style.height = `${anim.animationData.h}px`;
-  });
-  anim.onError = (errorType) => {
-    reject(errorType);
-  };
-});
-
-const createSVGSnapshot = (element, container, width, height) => {
-  const innerContent = element.innerHTML;
-  const iframeElement = document.createElement('iframe');
-  container.appendChild(iframeElement);
-  iframeElement.style.width = `${width}px`;
-  iframeElement.style.height = `${height}px`;
-  iframeElement.style.border = 'none';
-  iframeElement.contentWindow.document.open();
-  iframeElement.contentWindow.document.write(innerContent);
-  iframeElement.contentWindow.document.close();
-};
-
-const createCanvasSnapshot = (element, container, width, height) => {
-  const innerContent = element.getElementsByTagName('canvas')[0];
-  const canvasElement = document.createElement('canvas');
-  container.appendChild(canvasElement);
-  canvasElement.width = width;
-  canvasElement.height = height;
-  canvasElement.style.width = `${width}px`;
-  canvasElement.style.height = `${height}px`;
-  const canvasContext = canvasElement.getContext('2d');
-  canvasContext.drawImage(
-    innerContent,
-    0,
-    0,
-    innerContent.width,
-    innerContent.height,
-    0,
-    0,
-    canvasElement.width,
-    canvasElement.height,
-  );
-};
-
-const takeSnapshots = async (anim, renderSettings) => {
-  let currentFrame = 0;
-  const sampleRate = renderSettings.sampleRate > 0 ? renderSettings.sampleRate : 1;
-  const elem = document.getElementById('lottie');
-  const snapshotsContainer = document.getElementById('snapshotsContainer');
-  const width = anim.animationData.w * renderSettings.resolution;
-  const height = anim.animationData.h * renderSettings.resolution;
-
-  while (currentFrame < anim.totalFrames) {
-    anim.resize();
-    anim.goToAndStop(currentFrame);
-    if (renderSettings.renderer === 'svg') {
-      createSVGSnapshot(elem, snapshotsContainer, width, height);
-    } else if (renderSettings.renderer === 'canvas') {
-      createCanvasSnapshot(elem, snapshotsContainer, width, height);
-    }
-    currentFrame += 1 / sampleRate;
-    await wait(1); // eslint-disable-line no-await-in-loop
-  }
-};
-
-const start = async () => {
-  const url = new URL(window.location);
-  const renderSettings = await buildRenderSettings(url.searchParams);
-  const anim = await loadAnimation(renderSettings);
-  await takeSnapshots(anim, renderSettings);
-  window._finished = true; // eslint-disable-line no-underscore-dangle
-};
-
-try {
-  start();
-} catch (err) {
-  console.log('ERROR'); // eslint-disable-line no-console
-  console.log(err.message); // eslint-disable-line no-console
-}