diff --git a/demo-vue/.gitignore b/demo-vue/.gitignore
new file mode 100644
index 000000000..a547bf36d
--- /dev/null
+++ b/demo-vue/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/demo-vue/index.html b/demo-vue/index.html
new file mode 100644
index 000000000..6636765cf
--- /dev/null
+++ b/demo-vue/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + Vue
+
+
+
+
+
+
diff --git a/demo-vue/package.json b/demo-vue/package.json
new file mode 100644
index 000000000..c94b20f90
--- /dev/null
+++ b/demo-vue/package.json
@@ -0,0 +1,26 @@
+{
+ "name": "demo-vue",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "npyjs": "^0.6.0",
+ "onnxruntime-web": "^1.18.0",
+ "underscore": "^1.13.6",
+ "vue": "^3.4.21"
+ },
+ "devDependencies": {
+ "@types/underscore": "^1.11.15",
+ "@vitejs/plugin-vue": "^5.0.4",
+ "autoprefixer": "^10.4.19",
+ "postcss": "^8.4.38",
+ "tailwindcss": "^3.4.4",
+ "vite": "^5.3.1",
+ "vite-plugin-cross-origin-isolation": "^0.1.6"
+ }
+}
diff --git a/demo-vue/postcss.config.js b/demo-vue/postcss.config.js
new file mode 100644
index 000000000..2e7af2b7f
--- /dev/null
+++ b/demo-vue/postcss.config.js
@@ -0,0 +1,6 @@
+export default {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
diff --git a/demo-vue/src/App.vue b/demo-vue/src/App.vue
new file mode 100644
index 000000000..8671a0fb6
--- /dev/null
+++ b/demo-vue/src/App.vue
@@ -0,0 +1,215 @@
+
+
+
+
+
+
![]()
+
![]()
+
+
+
+
+
diff --git a/demo-vue/src/assets/dogs.jpg b/demo-vue/src/assets/dogs.jpg
new file mode 100644
index 000000000..deeafdbc1
Binary files /dev/null and b/demo-vue/src/assets/dogs.jpg differ
diff --git a/demo-vue/src/main.js b/demo-vue/src/main.js
new file mode 100644
index 000000000..2425c0f74
--- /dev/null
+++ b/demo-vue/src/main.js
@@ -0,0 +1,5 @@
+import { createApp } from 'vue'
+import './style.css'
+import App from './App.vue'
+
+createApp(App).mount('#app')
diff --git a/demo-vue/src/maskUtils.tsx b/demo-vue/src/maskUtils.tsx
new file mode 100644
index 000000000..709c77e28
--- /dev/null
+++ b/demo-vue/src/maskUtils.tsx
@@ -0,0 +1,47 @@
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+// All rights reserved.
+
+// This source code is licensed under the license found in the
+// LICENSE file in the root directory of this source tree.
+
+// Convert the onnx model mask prediction to ImageData
+function arrayToImageData(input: any, width: number, height: number) {
+ const [r, g, b, a] = [0, 114, 189, 255]; // the masks's blue color
+ const arr = new Uint8ClampedArray(4 * width * height).fill(0);
+ for (let i = 0; i < input.length; i++) {
+
+ // Threshold the onnx model mask prediction at 0.0
+ // This is equivalent to thresholding the mask using predictor.model.mask_threshold
+ // in python
+ if (input[i] > 0.0) {
+ arr[4 * i + 0] = r;
+ arr[4 * i + 1] = g;
+ arr[4 * i + 2] = b;
+ arr[4 * i + 3] = a;
+ }
+ }
+ return new ImageData(arr, height, width);
+}
+
+// Use a Canvas element to produce an image from ImageData
+function imageDataToImage(imageData: ImageData) {
+ const canvas = imageDataToCanvas(imageData);
+ const image = new Image();
+ image.src = canvas.toDataURL();
+ return image;
+}
+
+// Canvas elements can be created from ImageData
+function imageDataToCanvas(imageData: ImageData) {
+ const canvas = document.createElement("canvas");
+ const ctx = canvas.getContext("2d");
+ canvas.width = imageData.width;
+ canvas.height = imageData.height;
+ ctx?.putImageData(imageData, 0, 0);
+ return canvas;
+}
+
+// Convert the onnx model mask output to an HTMLImageElement
+export function onnxMaskToImage(input: any, width: number, height: number) {
+ return imageDataToImage(arrayToImageData(input, width, height));
+}
diff --git a/demo-vue/src/style.css b/demo-vue/src/style.css
new file mode 100644
index 000000000..bd6213e1d
--- /dev/null
+++ b/demo-vue/src/style.css
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
\ No newline at end of file
diff --git a/demo-vue/tailwind.config.js b/demo-vue/tailwind.config.js
new file mode 100644
index 000000000..fc3ea8c11
--- /dev/null
+++ b/demo-vue/tailwind.config.js
@@ -0,0 +1,8 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+}
\ No newline at end of file
diff --git a/demo-vue/vite.config.js b/demo-vue/vite.config.js
new file mode 100644
index 000000000..59e7ebaca
--- /dev/null
+++ b/demo-vue/vite.config.js
@@ -0,0 +1,8 @@
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import crossOriginIsolation from 'vite-plugin-cross-origin-isolation'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [vue(),crossOriginIsolation()],
+})