{"_id":"@arcon.mobi/malic-ui","_rev":"7-bf9dc32fb488cf594d7716c59dca189c","name":"@arcon.mobi/malic-ui","dist-tags":{"latest":"5.1.0"},"versions":{"3.2.0":{"name":"@arcon.mobi/malic-ui","version":"3.2.0","keywords":["vue","vue3","liquid-glass","squircle","glass","glassmorphism","backdrop-filter","svg-filter","icons"],"license":"UNLICENSED","_id":"@arcon.mobi/malic-ui@3.2.0","maintainers":[{"name":"aj-abad","email":"ajabad.dev@gmail.com"}],"dist":{"shasum":"7cb5c5f338d6a65031515acf68fb15a5ef3eae7e","tarball":"https://registry.npmjs.org/@arcon.mobi/malic-ui/-/malic-ui-3.2.0.tgz","fileCount":102,"integrity":"sha512-IAQunsQPEQWnHu2DNHxOQAgLdcjXPUkGETktUYBVG2X4iJcvmK7STy+PhDoY4A1nC23CGFuiUMTiGZMy3wDSlA==","signatures":[{"sig":"MEUCIQDY0uGSnbqcWCvi3YvtnTd/yWI4VJPfj3pnsRK3AAq3yQIgYVcy3lGXry6PFDWavoRsD4iM2T0l3roCnP8frrAc4uk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":665133},"main":"./dist/malic-ui.js","type":"module","types":"./dist/types/index.d.ts","module":"./dist/malic-ui.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/malic-ui.js","default":"./dist/malic-ui.js"},"./style.css":"./dist/style.css","./package.json":"./package.json"},"gitHead":"d4a7e6318c33c1510d5c45a78111d8807a328ca0","scripts":{"dev":"storybook dev -p 1009 --exact-port","test":"vitest run","build":"npm run typecheck && npm run build:lib","verify":"npm run typecheck && npm run test && npm run test:browser && npm run build:lib && npm run build:storybook && npm run verify:consumer","prepack":"npm run build:lib","build:lib":"vite build && vue-tsc -b tsconfig.lib.json --force","typecheck":"vue-tsc -p tsconfig.lib.json --noEmit && vue-tsc -p tsconfig.stories.json --noEmit && vue-tsc -p tsconfig.test.json --noEmit && vue-tsc -p tsconfig.browser.json --noEmit && tsc -p tsconfig.node.json --noEmit","test:watch":"vitest","test:browser":"playwright test --pass-with-no-tests","prepublishOnly":"npm run build:lib && npm run verify:consumer","build:storybook":"storybook build -o dist-storybook","verify:consumer":"node tests/consumer/verify.mjs","test:browser:serve":"storybook dev --ci --host 127.0.0.1 -p 1010 --exact-port --quiet"},"_npmUser":{"name":"aj-abad","email":"ajabad.dev@gmail.com"},"_npmVersion":"11.6.2","description":"Vue 3 components for Apple-flavored interface surfaces: Liquid Glass, squircles, and layered Liquid Glass icons.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"24.13.0","_hasShrinkwrap":false,"packageManager":"pnpm@10.34.5","devDependencies":{"vue":"^3.5.41","vite":"^8.2.2","vitest":"^4.1.11","vue-tsc":"^3.3.9","happy-dom":"^20.11.2","storybook":"^10.5.10","typescript":"^5.9.3","@types/node":"^26.2.0","@vue/test-utils":"^2.4.11","@playwright/test":"^1.62.1","@vitejs/plugin-vue":"^6.0.8","@storybook/vue3-vite":"^10.5.10","@vue/server-renderer":"^3.5.41","@storybook/addon-a11y":"^10.5.10","@storybook/addon-docs":"^10.5.10"},"peerDependencies":{"vue":">=3.5.0 <4"},"_npmOperationalInternal":{"tmp":"tmp/malic-ui_3.2.0_1787525916686_0.616015065164357","host":"s3://npm-registry-packages-npm-production"}},"4.0.0":{"name":"@arcon.mobi/malic-ui","version":"4.0.0","keywords":["vue","vue3","liquid-glass","squircle","glass","glassmorphism","backdrop-filter","svg-filter","icons"],"license":"UNLICENSED","_id":"@arcon.mobi/malic-ui@4.0.0","maintainers":[{"name":"aj-abad","email":"ajabad.dev@gmail.com"}],"dist":{"shasum":"e8dc1705b8986da5e39dab19075a14fafcd25844","tarball":"https://registry.npmjs.org/@arcon.mobi/malic-ui/-/malic-ui-4.0.0.tgz","fileCount":102,"integrity":"sha512-AF3OKFmPaPsy9ML7LO7prvrvCFqWXhhSFy78QKnhVWsll4/agEAvlT6XHTuk5fgGxbkgG3p4ZwJjDOSVQU3uIg==","signatures":[{"sig":"MEUCIC+HD9zmnrVWm8pNPUBacc4ltbuwDzQ+DnGWzt5caimQAiEAh2rIx/OkK0tQH9LgElOhRf3SoJrzFmWxBiYXaDMp+T0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":672318},"main":"./dist/malic-ui.js","type":"module","types":"./dist/types/index.d.ts","module":"./dist/malic-ui.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/malic-ui.js","default":"./dist/malic-ui.js"},"./style.css":"./dist/style.css","./package.json":"./package.json"},"gitHead":"37b2810c159bef9135a8b20fa596fbc5bd2cb1f6","scripts":{"dev":"storybook dev -p 1009 --exact-port","test":"vitest run","build":"npm run typecheck && npm run build:lib","verify":"npm run typecheck && npm run test && npm run test:browser && npm run build:lib && npm run build:storybook && npm run verify:consumer","prepack":"npm run build:lib","build:lib":"vite build && vue-tsc -b tsconfig.lib.json --force","typecheck":"vue-tsc -p tsconfig.lib.json --noEmit && vue-tsc -p tsconfig.stories.json --noEmit && vue-tsc -p tsconfig.test.json --noEmit && vue-tsc -p tsconfig.browser.json --noEmit && tsc -p tsconfig.node.json --noEmit","test:watch":"vitest","test:browser":"playwright test --pass-with-no-tests","prepublishOnly":"npm run build:lib && npm run verify:consumer","build:storybook":"storybook build -o dist-storybook","verify:consumer":"node tests/consumer/verify.mjs","test:browser:serve":"storybook dev --ci --host 127.0.0.1 -p 1010 --exact-port --quiet"},"_npmUser":{"name":"aj-abad","email":"ajabad.dev@gmail.com"},"_npmVersion":"11.6.2","description":"Vue 3 components for Apple-flavored interface surfaces: Liquid Glass, squircles, and layered Liquid Glass icons.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"24.13.0","_hasShrinkwrap":false,"packageManager":"pnpm@10.34.5","devDependencies":{"vue":"^3.5.41","vite":"^8.2.2","vitest":"^4.1.11","vue-tsc":"^3.3.9","happy-dom":"^20.11.2","storybook":"^10.5.10","typescript":"^5.9.3","@types/node":"^26.2.0","@vue/test-utils":"^2.4.11","@playwright/test":"^1.62.1","@vitejs/plugin-vue":"^6.0.8","@storybook/vue3-vite":"^10.5.10","@vue/server-renderer":"^3.5.41","@storybook/addon-a11y":"^10.5.10","@storybook/addon-docs":"^10.5.10"},"peerDependencies":{"vue":">=3.5.0 <4"},"_npmOperationalInternal":{"tmp":"tmp/malic-ui_4.0.0_1788302956648_0.20056258846949948","host":"s3://npm-registry-packages-npm-production"}},"4.1.0":{"name":"@arcon.mobi/malic-ui","version":"4.1.0","keywords":["vue","vue3","liquid-glass","squircle","glass","glassmorphism","backdrop-filter","svg-filter","icons"],"license":"UNLICENSED","_id":"@arcon.mobi/malic-ui@4.1.0","maintainers":[{"name":"aj-abad","email":"ajabad.dev@gmail.com"}],"dist":{"shasum":"169b431344d889de9e27c1800f868aee34db0481","tarball":"https://registry.npmjs.org/@arcon.mobi/malic-ui/-/malic-ui-4.1.0.tgz","fileCount":102,"integrity":"sha512-Iik6D/E9BPBN2lMMfox63+TRn2ZTJh3hmcoBvOtQlggeR9wupzAoXvtWP8RldUhymQ61ro4AQ7eZ+BtWHDGNuw==","signatures":[{"sig":"MEUCIQCnfllFNx8daCqO/c8GuVjqbNQAQ0gumheiY69h3N4rNQIgBf9sDcu9wwkiUv7Ld0BPu0KF95NekRoyirgFUZGpH/k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":676007},"main":"./dist/malic-ui.js","type":"module","types":"./dist/types/index.d.ts","module":"./dist/malic-ui.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/malic-ui.js","default":"./dist/malic-ui.js"},"./style.css":"./dist/style.css","./package.json":"./package.json"},"gitHead":"3beaf94475702bb271ee23f292168c377916b13a","scripts":{"dev":"storybook dev -p 1009 --exact-port","test":"vitest run","build":"npm run typecheck && npm run build:lib","verify":"npm run typecheck && npm run test && npm run test:browser && npm run build:lib && npm run build:storybook && npm run verify:consumer","prepack":"npm run build:lib","build:lib":"vite build && vue-tsc -b tsconfig.lib.json --force","typecheck":"vue-tsc -p tsconfig.lib.json --noEmit && vue-tsc -p tsconfig.stories.json --noEmit && vue-tsc -p tsconfig.test.json --noEmit && vue-tsc -p tsconfig.browser.json --noEmit && tsc -p tsconfig.node.json --noEmit","test:watch":"vitest","test:browser":"playwright test --pass-with-no-tests","prepublishOnly":"npm run build:lib && npm run verify:consumer","build:storybook":"storybook build -o dist-storybook","verify:consumer":"node tests/consumer/verify.mjs","test:browser:serve":"storybook dev --ci --host 127.0.0.1 -p 1010 --exact-port --quiet"},"_npmUser":{"name":"aj-abad","email":"ajabad.dev@gmail.com"},"_npmVersion":"11.6.2","description":"Vue 3 components for Apple-flavored interface surfaces: Liquid Glass, squircles, and layered Liquid Glass icons.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"24.13.0","_hasShrinkwrap":false,"packageManager":"pnpm@10.34.5","devDependencies":{"vue":"^3.5.41","vite":"^8.2.2","vitest":"^4.1.11","vue-tsc":"^3.3.9","happy-dom":"^20.11.2","storybook":"^10.5.10","typescript":"^5.9.3","@types/node":"^26.2.0","@vue/test-utils":"^2.4.11","@playwright/test":"^1.62.1","@vitejs/plugin-vue":"^6.0.8","@storybook/vue3-vite":"^10.5.10","@vue/server-renderer":"^3.5.41","@storybook/addon-a11y":"^10.5.10","@storybook/addon-docs":"^10.5.10"},"peerDependencies":{"vue":">=3.5.0 <4"},"_npmOperationalInternal":{"tmp":"tmp/malic-ui_4.1.0_1788307876452_0.1834586961338276","host":"s3://npm-registry-packages-npm-production"}},"4.2.0":{"name":"@arcon.mobi/malic-ui","version":"4.2.0","keywords":["vue","vue3","liquid-glass","squircle","glass","glassmorphism","backdrop-filter","svg-filter","icons"],"license":"UNLICENSED","_id":"@arcon.mobi/malic-ui@4.2.0","maintainers":[{"name":"aj-abad","email":"ajabad.dev@gmail.com"}],"dist":{"shasum":"5c102a06530044f191b1c8359b46a03217951858","tarball":"https://registry.npmjs.org/@arcon.mobi/malic-ui/-/malic-ui-4.2.0.tgz","fileCount":102,"integrity":"sha512-x9+FkUKgF18vLWfrwq3+9FQUthVsnKVnk1h1uVqyLCyhrli3O70FIlWhMW2zML3hXNoxEzt8v5p+hK+yxKnnyA==","signatures":[{"sig":"MEQCIGDWjoqfB+RWPZo/Nc7SXPna+x7ARBPFUECl4/k5VBmHAiBQupF8Kj75h3RPzPTVsZjwzWRIFHfCj4Wt1Mb8SA1fgg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":679219},"main":"./dist/malic-ui.js","type":"module","types":"./dist/types/index.d.ts","module":"./dist/malic-ui.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/malic-ui.js","default":"./dist/malic-ui.js"},"./style.css":"./dist/style.css","./package.json":"./package.json"},"gitHead":"0fa37060dbe775e09b0a6df3220232d7067f6a6a","scripts":{"dev":"storybook dev -p 1009 --exact-port","test":"vitest run","build":"npm run typecheck && npm run build:lib","verify":"npm run typecheck && npm run test && npm run test:browser && npm run build:lib && npm run build:storybook && npm run verify:consumer","prepack":"npm run build:lib","build:lib":"vite build && vue-tsc -b tsconfig.lib.json --force","typecheck":"vue-tsc -p tsconfig.lib.json --noEmit && vue-tsc -p tsconfig.stories.json --noEmit && vue-tsc -p tsconfig.test.json --noEmit && vue-tsc -p tsconfig.browser.json --noEmit && tsc -p tsconfig.node.json --noEmit","test:watch":"vitest","test:browser":"playwright test --pass-with-no-tests","prepublishOnly":"npm run build:lib && npm run verify:consumer","build:storybook":"storybook build -o dist-storybook","verify:consumer":"node tests/consumer/verify.mjs","test:browser:serve":"storybook dev --ci --host 127.0.0.1 -p 1010 --exact-port --quiet"},"_npmUser":{"name":"aj-abad","email":"ajabad.dev@gmail.com"},"_npmVersion":"11.6.2","description":"Vue 3 components for Apple-flavored interface surfaces: Liquid Glass, squircles, and layered Liquid Glass icons.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"24.13.0","_hasShrinkwrap":false,"packageManager":"pnpm@10.34.5","devDependencies":{"vue":"^3.5.41","vite":"^8.2.2","vitest":"^4.1.11","vue-tsc":"^3.3.9","happy-dom":"^20.11.2","storybook":"^10.5.10","typescript":"^5.9.3","@types/node":"^26.2.0","@vue/test-utils":"^2.4.11","@playwright/test":"^1.62.1","@vitejs/plugin-vue":"^6.0.8","@storybook/vue3-vite":"^10.5.10","@vue/server-renderer":"^3.5.41","@storybook/addon-a11y":"^10.5.10","@storybook/addon-docs":"^10.5.10"},"peerDependencies":{"vue":">=3.5.0 <4"},"_npmOperationalInternal":{"tmp":"tmp/malic-ui_4.2.0_1788309149037_0.9684089508529994","host":"s3://npm-registry-packages-npm-production"}},"4.3.0":{"name":"@arcon.mobi/malic-ui","version":"4.3.0","keywords":["vue","vue3","liquid-glass","squircle","glass","glassmorphism","backdrop-filter","svg-filter","icons"],"license":"UNLICENSED","_id":"@arcon.mobi/malic-ui@4.3.0","maintainers":[{"name":"aj-abad","email":"ajabad.dev@gmail.com"}],"dist":{"shasum":"570ecb6324b0242bd99d42d8922286aa3de42b73","tarball":"https://registry.npmjs.org/@arcon.mobi/malic-ui/-/malic-ui-4.3.0.tgz","fileCount":102,"integrity":"sha512-BI8IPz7qZP8zOdciEsyy3safawNkD3Af2WYpx0ZnSPJse8qLaLCJh8weUH6cKuMG6qzr/o57ogTgbolChXvenQ==","signatures":[{"sig":"MEYCIQC/cpypnjPVYfNyIEkm6vxy0rabC7NOOpMmDmx7F1qMqAIhAPIcZxUsr4QF7YhubQty76vbvoaw1WYj2YWphmHaGmpr","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":689961},"main":"./dist/malic-ui.js","type":"module","types":"./dist/types/index.d.ts","module":"./dist/malic-ui.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/malic-ui.js","default":"./dist/malic-ui.js"},"./style.css":"./dist/style.css","./package.json":"./package.json"},"gitHead":"98365831783d1c1d084cab7fd6668dbe4d402bc5","scripts":{"dev":"storybook dev -p 1009 --exact-port","test":"vitest run","build":"npm run typecheck && npm run build:lib","verify":"npm run typecheck && npm run test && npm run test:browser && npm run build:lib && npm run build:storybook && npm run verify:consumer","prepack":"npm run build:lib","build:lib":"vite build && vue-tsc -b tsconfig.lib.json --force","typecheck":"vue-tsc -p tsconfig.lib.json --noEmit && vue-tsc -p tsconfig.stories.json --noEmit && vue-tsc -p tsconfig.test.json --noEmit && vue-tsc -p tsconfig.browser.json --noEmit && tsc -p tsconfig.node.json --noEmit","test:watch":"vitest","test:browser":"playwright test --pass-with-no-tests","prepublishOnly":"npm run build:lib && npm run verify:consumer","build:storybook":"storybook build -o dist-storybook","verify:consumer":"node tests/consumer/verify.mjs","test:browser:serve":"storybook dev --ci --host 127.0.0.1 -p 1010 --exact-port --quiet"},"_npmUser":{"name":"aj-abad","email":"ajabad.dev@gmail.com"},"_npmVersion":"11.6.2","description":"Vue 3 components for Apple-flavored interface surfaces: Liquid Glass, squircles, and layered Liquid Glass icons.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"24.13.0","_hasShrinkwrap":false,"packageManager":"pnpm@10.34.5","devDependencies":{"vue":"^3.5.41","vite":"^8.2.2","vitest":"^4.1.11","vue-tsc":"^3.3.9","happy-dom":"^20.11.2","storybook":"^10.5.10","typescript":"^5.9.3","@types/node":"^26.2.0","@vue/test-utils":"^2.4.11","@playwright/test":"^1.62.1","@vitejs/plugin-vue":"^6.0.8","@storybook/vue3-vite":"^10.5.10","@vue/server-renderer":"^3.5.41","@storybook/addon-a11y":"^10.5.10","@storybook/addon-docs":"^10.5.10"},"peerDependencies":{"vue":">=3.5.0 <4"},"_npmOperationalInternal":{"tmp":"tmp/malic-ui_4.3.0_1788311114981_0.3648944391227509","host":"s3://npm-registry-packages-npm-production"}},"5.0.0":{"name":"@arcon.mobi/malic-ui","version":"5.0.0","keywords":["vue","vue3","liquid-glass","squircle","glass","glassmorphism","backdrop-filter","svg-filter","icons"],"license":"UNLICENSED","_id":"@arcon.mobi/malic-ui@5.0.0","maintainers":[{"name":"aj-abad","email":"ajabad.dev@gmail.com"}],"dist":{"shasum":"7d6ef3b4e35994dbe0c9e2fb18846ba4d6e5dbbc","tarball":"https://registry.npmjs.org/@arcon.mobi/malic-ui/-/malic-ui-5.0.0.tgz","fileCount":106,"integrity":"sha512-9HOoegCeA5wdpnjVjFKOCVTMLbIh9EaRN2VSjRJ7bcWw9d2OhLk5dcfrmmJxuRX4/qBIQLri5+DVkHEVgtpQ5g==","signatures":[{"sig":"MEYCIQDvq+9gkObsMki0FUe65vSfmu2lffW9l9+TTAWYnaU28wIhAJkQZ7xkwNUZ/d0uaEfxlL77D8ToF0P355zNOcz1/9Le","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":715207},"main":"./dist/malic-ui.js","type":"module","types":"./dist/types/index.d.ts","module":"./dist/malic-ui.js","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/malic-ui.js","default":"./dist/malic-ui.js"},"./style.css":"./dist/style.css","./package.json":"./package.json"},"gitHead":"3a939bb8d71efdaf19b58861764dfe7c810976c6","scripts":{"dev":"storybook dev -p 1009 --exact-port","test":"vitest run","build":"npm run typecheck && npm run build:lib","verify":"npm run typecheck && npm run test && npm run test:browser && npm run build:lib && npm run build:storybook && npm run verify:consumer","prepack":"npm run build:lib","build:lib":"vite build && vue-tsc -b tsconfig.lib.json --force","typecheck":"vue-tsc -p tsconfig.lib.json --noEmit && vue-tsc -p tsconfig.stories.json --noEmit && vue-tsc -p tsconfig.test.json --noEmit && vue-tsc -p tsconfig.browser.json --noEmit && tsc -p tsconfig.node.json --noEmit","test:watch":"vitest","test:browser":"playwright test --pass-with-no-tests","prepublishOnly":"npm run build:lib && npm run verify:consumer","build:storybook":"storybook build -o dist-storybook","verify:consumer":"node tests/consumer/verify.mjs","test:browser:serve":"storybook dev --ci --host 127.0.0.1 -p 1010 --exact-port --quiet"},"_npmUser":{"name":"aj-abad","email":"ajabad.dev@gmail.com"},"_npmVersion":"11.6.2","description":"Vue 3 components for Apple-flavored interface surfaces: Liquid Glass, squircles, and layered Liquid Glass icons.","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"24.13.0","_hasShrinkwrap":false,"packageManager":"pnpm@10.34.5","devDependencies":{"vue":"^3.5.41","vite":"^8.2.2","vitest":"^4.1.11","vue-tsc":"^3.3.9","happy-dom":"^20.11.2","storybook":"^10.5.10","typescript":"^5.9.3","@types/node":"^26.2.0","@vue/test-utils":"^2.4.11","@playwright/test":"^1.62.1","@vitejs/plugin-vue":"^6.0.8","@storybook/vue3-vite":"^10.5.10","@vue/server-renderer":"^3.5.41","@storybook/addon-a11y":"^10.5.10","@storybook/addon-docs":"^10.5.10"},"peerDependencies":{"vue":">=3.5.0 <4"},"_npmOperationalInternal":{"tmp":"tmp/malic-ui_5.0.0_1788376991258_0.6921443380603611","host":"s3://npm-registry-packages-npm-production"}},"5.1.0":{"name":"@arcon.mobi/malic-ui","version":"5.1.0","description":"Vue 3 components for Apple-flavored interface surfaces: Liquid Glass, squircles, and layered Liquid Glass icons.","license":"UNLICENSED","type":"module","main":"./dist/malic-ui.js","module":"./dist/malic-ui.js","types":"./dist/types/index.d.ts","exports":{".":{"types":"./dist/types/index.d.ts","import":"./dist/malic-ui.js","default":"./dist/malic-ui.js"},"./style.css":"./dist/style.css","./package.json":"./package.json"},"sideEffects":["**/*.css"],"scripts":{"dev":"storybook dev -p 1009 --exact-port","typecheck":"vue-tsc -p tsconfig.lib.json --noEmit && vue-tsc -p tsconfig.stories.json --noEmit && vue-tsc -p tsconfig.test.json --noEmit && vue-tsc -p tsconfig.browser.json --noEmit && tsc -p tsconfig.node.json --noEmit","test":"vitest run","test:watch":"vitest","test:browser":"playwright test --pass-with-no-tests","test:browser:serve":"storybook dev --ci --host 127.0.0.1 -p 1010 --exact-port --quiet","prepack":"npm run build:lib","prepublishOnly":"npm run build:lib && npm run verify:consumer","build":"npm run typecheck && npm run build:lib","build:lib":"vite build && vue-tsc -b tsconfig.lib.json --force","build:storybook":"storybook build -o dist-storybook","verify:consumer":"node tests/consumer/verify.mjs","verify":"npm run typecheck && npm run test && npm run test:browser && npm run build:lib && npm run build:storybook && npm run verify:consumer"},"peerDependencies":{"vue":">=3.5.0 <4"},"devDependencies":{"@playwright/test":"^1.62.1","@storybook/addon-a11y":"^10.5.10","@storybook/addon-docs":"^10.5.10","@storybook/vue3-vite":"^10.5.10","@types/node":"^26.2.0","@vitejs/plugin-vue":"^6.0.8","@vue/server-renderer":"^3.5.41","@vue/test-utils":"^2.4.11","happy-dom":"^20.11.2","storybook":"^10.5.10","typescript":"^5.9.3","vite":"^8.2.2","vitest":"^4.1.11","vue":"^3.5.41","vue-tsc":"^3.3.9"},"keywords":["vue","vue3","liquid-glass","squircle","glass","glassmorphism","backdrop-filter","svg-filter","icons"],"packageManager":"pnpm@10.34.5","gitHead":"5e033f5f1918704772c9ce5012ec940da6e3e906","_id":"@arcon.mobi/malic-ui@5.1.0","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-wv2ySb2wewjAeIQWlcM0dn723XGLGDUgNYtG7lvSdr30BN4Bl2IIiNh0ti4FLacJIjf0SpV17yKPCSLqc6kPMA==","shasum":"29d0809bb2322e9bb62fca7ec66220cb6ff80f80","tarball":"https://registry.npmjs.org/@arcon.mobi/malic-ui/-/malic-ui-5.1.0.tgz","fileCount":106,"unpackedSize":719094,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQC0d1s+PpTDTnpdlZpXJi/D8IJKLgElB8skE+M3kcA3BwIhANrnS4cjeXDf3qikV2nRarRrBRD5ja2ouEicnlSasBbx"}]},"_npmUser":{"name":"aj-abad","email":"ajabad.dev@gmail.com"},"directories":{},"maintainers":[{"name":"aj-abad","email":"ajabad.dev@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/malic-ui_5.1.0_1788394743381_0.15170784900766732"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-23T22:58:36.503Z","modified":"2026-09-03T00:19:03.664Z","3.2.0":"2026-08-23T22:58:36.868Z","4.0.0":"2026-09-01T22:49:16.775Z","4.1.0":"2026-09-02T00:11:16.630Z","4.2.0":"2026-09-02T00:32:29.223Z","4.3.0":"2026-09-02T01:05:15.449Z","5.0.0":"2026-09-02T19:23:11.403Z","5.1.0":"2026-09-03T00:19:03.501Z"},"license":"UNLICENSED","keywords":["vue","vue3","liquid-glass","squircle","glass","glassmorphism","backdrop-filter","svg-filter","icons"],"description":"Vue 3 components for Apple-flavored interface surfaces: Liquid Glass, squircles, and layered Liquid Glass icons.","maintainers":[{"name":"aj-abad","email":"ajabad.dev@gmail.com"}],"readme":"# Malic UI\n\nVue 3 components for Apple-flavored interface surfaces: refractive **Liquid Glass**, Figma-smoothed **squircles**, and layered **Liquid Glass icons**.\n\nThree families, one package:\n\n| | Components | What it is |\n| --- | --- | --- |\n| **Surfaces** | `LiquidGlass`, `useLiquidGlass` | An SVG refraction filter over whatever the page has painted behind an element |\n| **Shapes** | `Squircle`, `squirclePath`, `squircleStyle` | Continuous-curvature corners, plus the shadow, border and glass a `border-radius` would have got |\n| **Icons** | `LiquidGlassIcon`, `LiquidGlassLayer`, `FlatIconLayer`, `LiquidGlassGroup` | Declarative SVG composited through WebGL2 into an exportable icon raster |\n\nThe first two are page chrome — real DOM, real backdrop, live at 60fps. The third is an offline renderer whose output happens to be a canvas. They share a vocabulary and a stylesheet, not a pipeline.\n\n## Install\n\n```sh\nnpm install malic-ui vue\n```\n\nImport the package stylesheet once in your application entry:\n\n```ts\nimport 'malic-ui/style.css'\n```\n\nVue 3.5 or newer is required. The package has no other runtime dependencies — no Tailwind, no VueUse.\n\n## Surfaces\n\n### `Squircle`\n\nA rounded rectangle with Figma-style corner smoothing, plus the decoration a rounded rectangle would have got from `border-radius`, `border`, `box-shadow` and `backdrop-filter`.\n\n```vue\n<script setup lang=\"ts\">\nimport { Squircle } from 'malic-ui'\nimport 'malic-ui/style.css'\n</script>\n\n<template>\n  <Squircle\n    class=\"p-6\"\n    :appearance=\"{ radius: 24, smoothing: 0.8 }\"\n    glass=\"md\"\n    :liquid-glass=\"true\"\n  >\n    <h2>Refracting the page behind it</h2>\n  </Squircle>\n</template>\n```\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `as` | `string \\| Component` | `'div'` | Root element. Must be single-root and block-level |\n| `appearance` | `SquircleAppearance` | `{}` | Radius, smoothing, border width and border color. Each field accepts a literal or MotionValue-like source |\n| `radius` / `smoothing` | shape values | — | 4.x compatibility aliases; the matching `appearance` field wins |\n| `borderWidth` / `borderColor` | border values | — | 4.x compatibility aliases; the matching `appearance` field wins |\n| `surfaceClass` | `string` | — | Classes for the clipped surface layer. Backgrounds go **here** |\n| `clipContent` | `boolean` | `false` | Clip the slot to the shape too |\n| `contentClass` | `string` | — | Classes for the clipped content layer. `clipContent` only |\n| `glass` | `'sm' \\| 'md' \\| 'lg'` | — | Backdrop blur and saturation over a white gradient |\n| `liquidGlass` | `boolean \\| LiquidGlassOptions` | `false` | Add refraction to the surface |\n| `shadow` | `ShadowPreset \\| layers \\| null` | `'glass'` with glass | Presets `sm`/`md`/`lg`/`xl`/`glass`, or raw `box-shadow`-style layers |\n| `highlight` | `boolean \\| string` | on with glass | Inset hairline; a string is its colour |\n| `borderStyle` | `SquircleBorderStyle \\| SquircleBorderSideStyles` | `'solid'` | `solid`, `dashed` or `dotted`; the tuple is `[top, right, bottom, left]` and also accepts `none` |\n| `rightInset` | `number \\| MotionValueLike<number>` | `0` | Move the right edge in without changing layout width |\n\nExposes `rebuild()`, which regenerates the refractive maps — see [Rebuilding after a transform](#rebuilding-after-a-transform).\n\n#### Why it is layered rather than one clipped div\n\n`clip-path` clips the element's entire subtree, and CSS decoration is shaped by `border-radius`, which knows nothing about the path. So none of it survives being put on a clipped box: an outer `box-shadow` paints outside the border box and is clipped away entirely, a CSS `border` is shaped like the rectangle and gets sliced diagonally at each corner, and any popover a child renders inline is cut off at the edge.\n\nThe two obvious repairs both fail. Wrapping in a parent with `filter: drop-shadow()` shadows the clipped silhouette correctly, but a `filter` establishes a **Backdrop Root** — so `backdrop-filter` on anything inside it samples an empty backdrop and the glass turns flat; shadow would cost glassmorphism. And blurring a clipped caster does nothing, because a CSS `filter` is applied *before* `clip-path`: the blur is cut back to a hard edge.\n\nSo decoration is split into sibling layers, each in whichever technology shapes it correctly, and only the surface is clipped:\n\n| Layer | What it is | Why there |\n| --- | --- | --- |\n| shadow | blurred SVG paths, behind | outside the box, and a sibling — no ancestor filter, so glass survives |\n| surface | clipped `div` or `LiquidGlass` | the one place `backdrop-filter` can be clipped to the shape |\n| strokes | stroked SVG paths, in front | a stroke follows the real path; CSS borders can't |\n| content | the slot, unclipped, in flow | so children can render menus past the edge |\n\nThree consequences worth knowing before the first surprise:\n\n- **Backgrounds go on `surfaceClass`, not `class`.** `class` lands on the unclipped root, so a background there paints a plain rectangle behind the squircle and its corners stick out.\n- **Fade a glass squircle with `--squircle-opacity`, not `opacity`.** An `opacity` below 1 anywhere above the surface is a Backdrop Root, so the glass reads flat for the whole animation and the blur snaps in on the frame it lands. The variable fades each layer instead of the group, so the surface keeps its own live backdrop; it inherits, so it can go on whatever element is actually being animated. Use `--squircle-group-opacity` on a container fading several at once — the two multiply, where a container reusing the inner name would just be shadowed by it. A squircle with no glass has no backdrop to lose and can be faded either way.\n- **Don't put a CSS `border` on the root.** The surface is sized to the padding box, so a border would offset it. Use `borderWidth`.\n\nContent is **not** clipped by default; padding keeps it inside. `clipContent` opts in, for content that paints to the edge anyway — a map canvas, a full-bleed image. It moves the slot into its own clipped layer *between* surface and strokes rather than clipping the root, so the shadow still survives; the content layer is then absolutely positioned, which means the root has to be sized by layout and padding on the root no longer insets it.\n\n#### Animated geometry and appearance\n\n`appearance.radius`, `appearance.smoothing`, `appearance.borderWidth` and\n`appearance.borderColor` accept either their literal value or any object with\nMotion's read-only `get()`/`on('change')` interface. The decorative layers own\nthose subscriptions in a separate render boundary, so animation frames redraw\nthe SVG geometry without evaluating the default slot. malic-ui does not depend\non Motion or own the transition. `rightInset` accepts the same kind of source\noutside `appearance`, since it changes the visible viewport rather than the\nsurface's style.\n\n```vue\n<script setup lang=\"ts\">\nimport { animate, useMotionValue, useTransform } from 'motion-v'\nimport { Squircle, type SquircleAppearance } from 'malic-ui'\n\nconst progress = useMotionValue(0)\nconst appearance: SquircleAppearance = {\n  radius: useTransform(progress, [0, 1], [12, 28]),\n  smoothing: useTransform(progress, [0, 1], [0.4, 0.8]),\n  borderWidth: useTransform(progress, [0, 1], [1, 3]),\n  borderColor: useTransform(\n    progress,\n    [0, 1],\n    ['rgba(0, 0, 0, 0.08)', 'rgba(0, 129, 104, 0.8)'],\n  ),\n}\n\nconst expand = () => animate(progress, 1, { type: 'spring', stiffness: 500, damping: 40 })\n</script>\n\n<template>\n  <Squircle :appearance=\"appearance\" @click=\"expand\">…</Squircle>\n</template>\n```\n\nKeep the `appearance` object stable and pass Motion values themselves. Mirroring\ntheir latest value into Vue state would put the parent back on the per-frame\nrender path. Animated radii should publish numeric pixel values; radius tokens\nremain useful as static appearance values. With refractive `liquidGlass`, the\nSVG silhouette follows the animation live and the expensive refractive maps\nrebuild after the shape has been still for 150 ms.\n\nBorder style, width and color may each use one value around the whole outline or\nfour values in CSS order. Scalar properties repeat on every side. Each corner's\nmiter follows the adjacent widths so their inner edges meet without a notch; if\none side is omitted with `none` or a zero tuple width, its neighbor extends all\nthe way through that corner:\n\n```vue\n<Squircle\n  :appearance=\"{\n    borderWidth: [2, 4, 6, 0],\n    borderColor: ['red', 'blue', 'green', 'transparent'],\n  }\"\n  :border-style=\"['solid', 'dashed', 'dotted', 'none']\"\n/>\n```\n\n#### Squircles without the component\n\n`squircleStyle` returns a cached `clip-path` for a squircle whose size is known at author time — an icon chip, a swatch — skipping the `ResizeObserver`, the second render pass measuring forces, and the per-instance `<clipPath>`:\n\n```ts\nimport { squircleStyle } from 'malic-ui'\n\nconst chip = squircleStyle({ width: 40, height: 40, radius: 'lg' })\n// → { clipPath: 'path(\"M …\")' }\n```\n\nIt **does** clip children, which the component deliberately does not, so keep it to surfaces whose content stays inside. `squirclePath({ width, height, radius, smoothing, x?, y? })` returns the raw `d` if you want to draw the shape yourself; `radius` may be one px value or `[topLeft, topRight, bottomRight, bottomLeft]`. Every command after the opening `M` is relative, so `x`/`y` let several shapes share one user space. `radiusToPx`, `radiiToPx` and `RADIUS_TOKENS` resolve Tailwind's `rounded-*` keys.\n\n### `LiquidGlass`\n\nA refractive glass surface over whatever the page has painted behind it. The element keeps its own background, padding and children; all this adds is a generated SVG filter in `backdrop-filter`, so the backdrop bends through a bezel that follows the element's silhouette.\n\n```vue\n<script setup lang=\"ts\">\nimport { LiquidGlass } from 'malic-ui'\n</script>\n\n<template>\n  <LiquidGlass\n    class=\"glass-nav\"\n    :options=\"{ bezelWidth: 20, glassThickness: 1, refractiveIndex: 1.5 }\"\n  >\n    <p>Your content here</p>\n  </LiquidGlass>\n</template>\n\n<style scoped>\n.glass-nav {\n  border-radius: 9999px;\n  padding: 1rem;\n  background: rgb(255 255 255 / 0.5);\n  /* Fallback for everything that is not Chromium. */\n  backdrop-filter: blur(1rem);\n}\n</style>\n```\n\n| Prop | Type | Default | Description |\n| --- | --- | --- | --- |\n| `options` | `LiquidGlassOptions` | `{}` | See below |\n| `tag` | `string` | `'div'` | Element to render |\n| `disabled` | `boolean` | `false` | Same as `options.disabled`; either source turns it off |\n\n| Option | Type | Default | Description |\n| --- | --- | --- | --- |\n| `bezelWidth` | `number` | `20` | Width of the refractive bezel in px |\n| `glassThickness` | `number` | `0.8` | Thickness of the virtual glass surface |\n| `refractiveIndex` | `number` | `1.5` | Refractive index — glass is 1.5, water 1.33 |\n| `specularOpacity` | `number` | `0.4` | Specular rim highlight opacity, 0–1 |\n| `specularAngle` | `number` | `-60` | Light source angle in degrees |\n| `specularPower` | `number` | `6` | Specular sharpness exponent |\n| `blurAmount` | `number` | `0.5` | Gaussian blur in px after refraction |\n| `shape` | `GlassShape` | `{ type: 'rounded-rect' }` | Silhouette to build the bezel around |\n| `disabled` | `boolean` | `false` | Turn the effect off entirely |\n\nExposes `rebuild()`.\n\n#### Shape: the bezel has to match the clip\n\nThe bezel is drawn per pixel from how far that pixel is from the silhouette edge and which way the edge faces, so it only lines up if it is built from the same shape the element is clipped to. Get that wrong and the error shows exactly where a corner is: the bezel bulges past the clip on the diagonal and leaves a flat, unrefracted band along each side.\n\n```ts\ntype GlassShape =\n  // A rounded rectangle. Omit `radius` to read the element's own border-radius.\n  | { type: 'rounded-rect'; radius?: number }\n  // A Figma-smoothed squircle, matching `Squircle` and `squircleStyle`.\n  | { type: 'squircle'; radius?: number | RadiusToken; smoothing?: number }\n  // Any outline, in the element's user space with the origin top-left.\n  | { type: 'path'; d: string }\n```\n\nA `rounded-rect` has a closed-form distance field and is the fast path — it is also the default, read from the element's computed `border-radius` (percentages resolved against the box, clamped to a pill). A `squircle` or a `path` has no closed form, so the outline is flattened and every pixel inside the bezel gets its exact distance to the nearest segment; the cost scales with perimeter × bezel width rather than with area.\n\n**`Squircle` wires this up for you.** It hands its surface the very `d` it is clipping with, so the two can never drift:\n\n```vue\n<!-- The bezel refracts around the smoothed corner, not a circular one. -->\n<Squircle :appearance=\"{ radius: 32, smoothing: 0.8 }\" :liquid-glass=\"true\">…</Squircle>\n```\n\nYou only need `shape` by hand when you clip an element yourself.\n\n#### Where the glass stops\n\nChromium clips a `backdrop-filter` to the element's border box and its\n`border-radius`, and to nothing else. A `clip-path` is not consulted — not on\nthe element, not on an ancestor — and a plain `blur()` spills exactly as far as\na filter reference does. So a squircle-clipped surface would paint its filtered\nbackdrop right out to the corners of its bounding rectangle, outside the shape,\nwhere the surface has no background of its own to cover it.\n\nThe filter therefore stops itself: a third generated image holds the silhouette,\nand the whole chain is composited `in` it. Where the output is transparent the\nunfiltered backdrop shows through, which is what the clip would have given. It\nworks for any silhouette rather than the one shape CSS can describe, and it\ncosts one more image per rebuild.\n\nNothing about this needs configuring — the mask comes from the same distance\nfield as the other two maps, so it always agrees with the bezel.\n\n#### Turning it off\n\n`disabled` takes the effect off the element without unmounting or restyling it: nothing is generated, nothing is observed, and no inline `backdrop-filter` is written, so the element falls back to whatever CSS it carries. Bind it to a breakpoint or a preference rather than rendering a second copy of the element or beating the inline style with `!important`.\n\n```vue\n<script setup>\nimport { useMediaQuery } from '@vueuse/core'\n\nconst isDesktop = useMediaQuery('(min-width: 768px)')\n</script>\n\n<template>\n  <LiquidGlass :disabled=\"!isDesktop\" class=\"card\">…</LiquidGlass>\n</template>\n```\n\nToggling it back on regenerates the maps at the size the element has by then — but the last generated pair is cached, so if nothing that feeds them has changed (size, shape, or any option) it is reused rather than redrawn. Generating them is a per-pixel pass plus two PNG encodes, which is what makes that cache the thing that lets `disabled` be driven from something as hot as a scroll threshold:\n\n```vue\n<script setup>\nimport { useWindowScroll } from '@vueuse/core'\n\nconst { y } = useWindowScroll()\nconst atTop = computed(() => y.value < 10)\n</script>\n\n<template>\n  <!-- Bare over the hero, glass once the page moves. -->\n  <LiquidGlass :disabled=\"atTop\" class=\"nav\">…</LiquidGlass>\n</template>\n```\n\n#### Rebuilding after a transform\n\nThe element is watched with a `ResizeObserver`, which only fires on **layout** changes — while the size the maps are built from is the *rendered* one. An element whose rendered size is driven by a transform (a reveal animation that scales it in, say) therefore has to say when it has settled. `Squircle` forwards the same method.\n\n```vue\n<script setup>\nimport { useTemplateRef } from 'vue'\n\nconst glass = useTemplateRef('glass')\n</script>\n\n<template>\n  <motion.div\n    :initial=\"{ scale: 0.86 }\"\n    :animate=\"{ scale: 1 }\"\n    @animation-complete=\"glass?.rebuild()\"\n  >\n    <LiquidGlass ref=\"glass\">…</LiquidGlass>\n  </motion.div>\n</template>\n```\n\n#### `useLiquidGlass`\n\nFor custom layouts, drive the composable directly and wire up the SVG filter and `backdrop-filter` yourself. It accepts a plain object, a ref, or a getter — pass one of the latter two if any option has to change after mount:\n\n```ts\nimport { useLiquidGlass } from 'malic-ui'\n\nconst {\n  filterId, glassRef, dispUrl, specUrl, scale, filterWidth, filterHeight,\n  isReady, isSupported, blurAmount, isDisabled, rebuild,\n} = useLiquidGlass(() => ({ bezelWidth: 20, disabled: !isDesktop.value }))\n```\n\n#### Browser support\n\nSVG filter references in `backdrop-filter` are Chromium-only. Support is detected once at mount from two signals, because neither is enough alone: the property has to *parse* a `url()` reference (which rules out Safari 17 and earlier, where only `-webkit-backdrop-filter` ever existed), and the engine has to be Chromium (which rules out Firefox, where the reference parses and is then ignored). Client hints answer the second question where they exist, with `window.chrome` and the user agent as fallbacks — `window.chrome` alone is not enough, since plain Chromium builds don't expose it and support the effect perfectly well.\n\nEverywhere the answer is no, nothing is generated and no inline filter is written, so the element keeps whatever CSS fallback it carries. Give every glass surface a plain `backdrop-filter: blur()` in CSS; `Squircle`'s `glass` presets already do.\n\n## Liquid Glass icons\n\nConsumers author normal SVG geometry inside `FlatIconLayer` and `LiquidGlassLayer`. Malic UI rasterizes those live sources, composites the icon through WebGL2 when available, and automatically falls back to Canvas 2D. The visible result is a canvas-backed raster image and can be exported as PNG.\n\n### Basic usage\n\n```vue\n<script setup lang=\"ts\">\nimport {\n  FlatIconLayer,\n  LiquidGlassIcon,\n  LiquidGlassLayer,\n} from 'malic-ui'\nimport 'malic-ui/style.css'\n</script>\n\n<template>\n  <LiquidGlassIcon\n    view-box=\"0 0 256 256\"\n    :size=\"256\"\n    :resolution=\"1024\"\n    label=\"Add\"\n    :surface=\"{\n      type: 'linear-gradient',\n      angle: 90,\n      stops: [\n        { offset: 0, color: '#ff6b6b' },\n        { offset: 1, color: '#5f67ff' },\n      ],\n    }\"\n  >\n    <template #default>\n      <FlatIconLayer :opacity=\"0.35\">\n        <template #default>\n          <circle cx=\"128\" cy=\"128\" r=\"96\" fill=\"#ffffff\" />\n        </template>\n      </FlatIconLayer>\n\n      <LiquidGlassLayer\n        :material=\"{\n          blur: 0.35,\n          frost: 0.25,\n          translucency: 0.46,\n          specular: 0.8,\n          shadow: { opacity: 0.5, kind: 'layer-color' },\n        }\"\n      >\n        <template #default>\n          <path d=\"M224 128a8 8 0 0 1-8 8h-80v80a8 8 0 0 1-16 0v-80H40a8 8 0 0 1 0-16h80V40a8 8 0 0 1 16 0v80h80a8 8 0 0 1 8 8Z\" />\n        </template>\n      </LiquidGlassLayer>\n    </template>\n  </LiquidGlassIcon>\n</template>\n```\n\n### Shared SVG definitions\n\nPut gradients, masks, filters, and clip paths used by more than one layer in the root `defs` slot. IDs and all local references are scoped per icon and layer during rasterization.\n\n```vue\n<LiquidGlassIcon :surface=\"surface\">\n  <template #defs>\n    <linearGradient id=\"shared-paint\">\n      <stop offset=\"0\" stop-color=\"#ffffff\" />\n      <stop offset=\"1\" stop-color=\"#8ba7ff\" />\n    </linearGradient>\n  </template>\n\n  <template #default>\n    <FlatIconLayer>\n      <template #default>\n        <circle cx=\"128\" cy=\"128\" r=\"80\" fill=\"url(#shared-paint)\" />\n      </template>\n    </FlatIconLayer>\n  </template>\n</LiquidGlassIcon>\n```\n\n### Export\n\nThe root component exposes rendering and canvas export methods. Exports wait for the newest requested reactive frame before reading the canvas.\n\n```vue\n<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport type { LiquidGlassIconExpose } from 'malic-ui'\n\nconst icon = ref<LiquidGlassIconExpose | null>(null)\n\nasync function download() {\n  const blob = await icon.value?.toBlob('image/png')\n  if (!blob) return\n\n  const url = URL.createObjectURL(blob)\n  const anchor = document.createElement('a')\n  anchor.href = url\n  anchor.download = 'icon.png'\n  anchor.click()\n  URL.revokeObjectURL(url)\n}\n</script>\n```\n\n`toDataURL(type?, quality?)`, `render()`, and `getCanvas()` are also available.\n\n### `LiquidGlassIcon`\n\n#### Props\n\n| Prop | Type | Default |\n| --- | --- | --- |\n| `surface` | `SurfacePaint` | Required |\n| `viewBox` | `string` | `\"0 0 256 256\"` |\n| `size` | `number \\| string` | `256` |\n| `resolution` | `number` | `1024`, clamped to `64…4096` |\n| `appearance` | `IconAppearance` (six renditions; see below) | `'default'` |\n| `tint` | `{ color: string; strength?: number }` | Purple at `0.65` |\n| `colorSpace` | `'srgb' \\| 'display-p3'` | `'srgb'` |\n| `lightAngle` | `number` | `135` degrees |\n| `label` | `string` | Decorative when omitted |\n| `specularPolicy` | `'all' \\| 'topmost'` | `'all'` |\n\nNumber `size` values are CSS pixels. String values such as `\"12rem\"` pass through to the wrapper.\n\n`IconAppearance` is `'default' | 'dark' | 'clear-light' | 'clear-dark' | 'tinted-light' | 'tinted-dark'`. The legacy `'clear'` spelling remains accepted as an alias for `'clear-light'`. Clear renditions retain refraction, frost, and edge light while contributing no opaque gray surface; tinted renditions use the root `tint`. Use `colorSpace=\"display-p3\"` with CSS colors such as `color(display-p3 1 0.25 0.1)` for wide-gamut rasterization and compositing.\n\n#### Events\n\n| Event | Meaning |\n| --- | --- |\n| `ready` | First successful frame committed |\n| `rendered` | A current frame committed, with backend, duration, and resolution |\n| `backend-change` | WebGL activation, fallback, loss, or restoration |\n| `error` | Typed validation, rasterization, WebGL, Canvas, or export failure |\n\nThe last successful frame remains visible if a newer frame fails.\n\n### `LiquidGlassGroup`\n\nWrap layers in `LiquidGlassGroup` to treat them as one glass object, mirroring Icon Composer's groups.\n\n```vue\n<LiquidGlassGroup :material=\"{ translucency: 0.5, specular: 1 }\" lighting=\"combined\">\n  <LiquidGlassLayer><template #default><circle cx=\"100\" cy=\"128\" r=\"60\" /></template></LiquidGlassLayer>\n  <LiquidGlassLayer><template #default><circle cx=\"156\" cy=\"128\" r=\"60\" /></template></LiquidGlassLayer>\n</LiquidGlassGroup>\n```\n\n| Prop | Type | Default |\n| --- | --- | --- |\n| `id` | `string` | SSR-stable generated ID |\n| `material` | `GlassMaterial` | Package default material |\n| `lighting` | `'combined' \\| 'individual'` | `'combined'` |\n| `opacity` | `number` | `1` |\n| `blend` | `BlendMode` | `'normal'` |\n\nWith `combined` lighting, glass-enabled member layers are composited together and the group material is applied once to the union silhouette — one rim highlight, one shadow, and no seams where shapes overlap. With `individual`, each glass member receives its own lighting pass. The material always belongs to the group, matching the Icon Composer schema; member `material` values inside a group are ignored. Group opacity and blend are applied once to the finished group, while flat members remain ordinary artwork. Groups cannot be nested, IDs must be unique, members must occupy one contiguous z-order block, and an icon may contain at most four groups.\n\n### Layer props\n\nBoth layer components accept:\n\n| Prop | Type | Default |\n| --- | --- | --- |\n| `id` | `string` | SSR-stable generated ID |\n| `position` | `{ x: number; y: number }` | View-box center |\n| `scale` | `number` | `1` |\n| `opacity` | `number` | `1`, clamped to `0…1` |\n| `blend` | `BlendMode` | `'normal'` |\n| `fill` | `LayerPaint` | `{ type: 'source' }` |\n| `visible` | `boolean` | `true` |\n| `appearances` | `LayerAppearanceOverrides` | None |\n\n`LiquidGlassLayer` additionally accepts `material: GlassMaterial`. `FlatIconLayer` deliberately has no material prop and bypasses all glass passes.\n\nPositions use root view-box units. Scale is centered on the full view box. SVG `transform` attributes inside the slot remain part of the authored geometry.\n\n`appearances` specializes `fill`, `opacity`, `blend`, or `hidden` for any of the six renditions without duplicating geometry:\n\n```vue\n<LiquidGlassLayer\n  :appearances=\"{\n    dark: { opacity: 0.75 },\n    'tinted-light': { fill: { type: 'solid', color: '#fff' }, blend: 'screen' },\n    'clear-dark': { hidden: true },\n  }\"\n/>\n```\n\n### Paint and material types\n\n```ts\ntype SurfacePaint =\n  | { type: 'solid'; color: string }\n  | { type: 'linear-gradient'; angle?: number; stops: readonly ColorStop[] }\n\ntype LayerPaint =\n  | { type: 'source' }\n  | { type: 'solid'; color: string }\n  | { type: 'linear-gradient'; angle?: number; stops: readonly ColorStop[] }\n\ninterface GlassMaterial {\n  blur?: number\n  frost?: number\n  translucency?: number\n  specular?: false | number\n  shadow?: false | {\n    opacity?: number\n    kind?: 'neutral' | 'layer-color' | 'none'\n  }\n  darkening?: number\n  monochrome?: number\n}\n```\n\nMaterial values use the `0…1` range. `blur` controls backdrop diffusion while `frost` independently controls optical scattering/milkiness, allowing the parity harness to calibrate each response without conflating them. Defaults are `blur: 0.25`, `frost: 0.25`, `translucency: 0.5`, `specular: 1`, and a `neutral` shadow at `0.5`. `neutral` is a soft black drop, `layer-color` blurs the artwork's own per-pixel colors onto the backdrop, and `none` disables the shadow. The deprecated `{ strength, type: 'chromatic' }` form remains accepted and maps to `{ opacity, kind: 'layer-color' }`. Invalid numeric values are normalized with development warnings. Invalid paint definitions, duplicate layer/group IDs, missing parent context, and unsafe SVG resources surface typed errors.\n\n### SVG authoring rules\n\n- Supply geometry such as `<path>`, `<circle>`, and `<g>`—not a nested root `<svg>`.\n- Prefer SVG presentation attributes or inline styles. Common inherited presentation properties and `currentColor` are resolved for standalone rasterization.\n- Shared definitions belong in the root `defs` slot. Layer-local `<defs>` may stay inside a layer.\n- Reactive attributes, nested children, `v-if`, `v-for`, and keyed moves are observed automatically. Source DOM order is the z-order.\n- External `<image>` sources must be same-origin, `data:`, or `blob:` URLs. External `<use>` references are rejected.\n- Empty layers render transparently.\n\n### Rendering behavior\n\nMalic UI first attempts WebGL2 and uses a bounded shared renderer pool across component instances. Jobs sharing a resolution are serialized and copied into instance-owned scratch canvases before the lease is released. If WebGL2 is unavailable or its context is lost, rendering continues through Canvas 2D.\n\nThe WebGL2 glass material builds a signed distance field with a GPU jump-flood pass. The nearest silhouette coordinate drives a scale-independent spherical edge profile: the backdrop refracts through it with slight chromatic dispersion, a rim highlight follows the edges facing the light, and a weaker highlight appears opposite. This remains stable at corners, thin shapes, disconnected geometry, and production resolution. Backdrop blur uses a bounded dual-Kawase downsample/upsample pyramid, avoiding stretched sampling taps and banding at high blur values; its radius mapping lives in `blurPyramid.ts` for harness calibration. Blur and compositing run in linear light, and frost is applied as a separate scattering response. Artwork colors are otherwise passed through faithfully. The Canvas 2D fallback preserves the same composition, frost, shadow, and edge-lighting model with a native filter blur and no chromatic refraction.\n\nThe declared `surface` is the backdrop sampled by the glass pipeline. The component does not sample arbitrary HTML or imagery behind it on the page. In clear renditions it is used only for glass sampling and dimming; the exported icon remains transparent outside its authored glass/content coverage.\n\nThe composition is full-bleed: the surface and layers cover the whole square canvas, and the continuous-curvature squircle mask (nominal corner radius 25.8% of the icon size, matching the iOS 26 grid) is applied by a final icon-edge glass pass that refracts and highlights the composition's rim. Exports are transparent outside the mask and contain no baked outer drop shadow — apply page shadows in CSS if desired.\n\nAlthough layer authoring uses SVG, the final visible output is a canvas/raster image. This keeps glass compositing and deterministic PNG export consistent across arbitrary SVG sources.\n\n## SSR\n\nPackage imports and server rendering do not access `window`, `document`, `Image`, canvas, `ResizeObserver`, or WebGL. IDs come from Vue's SSR-stable `useId()`, so a filter or clip path the server printed is the one the client hydrates onto.\n\nIcons begin rendering after client mount; the server output contains the wrapper, a placeholder canvas, and the hidden SVG source tree. Surfaces render their real markup from the first byte — a squircle's clipped surface layer is there, falling back to a plain `border-radius` until layout has a box to measure, and its shadow and stroke layers, which have nothing to draw without one, are simply absent.\n\n## Browser support\n\n- Modern browsers with Canvas 2D, SVG serialization, `MutationObserver`, and Blob URLs.\n- WebGL2 is optional but recommended for icons; Canvas 2D is the fallback.\n- `createImageBitmap` is preferred when available; an `HTMLImageElement` decoder is used otherwise.\n- `Squircle` works everywhere `clip-path` does. Only the refractive `LiquidGlass` layer is Chromium-only — see [Browser support](#browser-support) under surfaces.\n\n## Development\n\n```sh\nnpm install\nnpm run dev        # Storybook on :1009\nnpm run verify\n```\n\n`npm run dev` opens the Storybook, which is both the component documentation and the fixture surface the Chromium suite drives — stories under `Surfaces`, `Icons` and `Shapes`, plus an `Internal` section holding the two fixtures that exist only for the tests.\n\nBecause the specs navigate to story iframes rather than to a page written for them, a demo and the test that guards it cannot drift. `Surfaces → LiquidGlass → Bezel follows the clip` renders the same squircle twice — once with the bezel built from its outline, once from a rounded rectangle of the same radius — and `tests/browser/surface.spec.ts` reads both displacement maps back out of it to check the bezel lands inside the clip.\n\n`npm run verify` runs strict Vue/TypeScript checking, unit and SSR tests, the Chromium suite, the library and Storybook builds, and the packed-package consumer build.\n","readmeFilename":"README.md"}