imagetools, mobile opt

This commit is contained in:
saiminh 2023-08-22 18:05:15 +02:00
parent 1eafc280bd
commit cdfd4c39a6
32 changed files with 1360 additions and 580 deletions

9
globals.d.ts vendored Normal file
View file

@ -0,0 +1,9 @@
declare module "*&imagetools" {
/**
* actual types
* - code https://github.com/JonasKruckenberg/imagetools/blob/main/packages/core/src/output-formats.ts
* - docs https://github.com/JonasKruckenberg/imagetools/blob/main/docs/guide/getting-started.md#metadata
*/
const out;
export default out;
}

605
package-lock.json generated
View file

@ -12,11 +12,13 @@
"mdsvex": "^0.11.0",
"perlin-noise-2d": "^1.0.0",
"pixi-filters": "^5.2.1",
"pixi.js": "^7.2.4"
"pixi.js": "^7.2.4",
"superjson": "^1.13.1"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.20.4",
"@types/node": "^20.5.1",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"eslint": "^8.28.0",
@ -25,11 +27,14 @@
"prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.10.1",
"sass": "^1.64.2",
"sharp": "^0.32.5",
"svelte": "^4.0.5",
"svelte-check": "^3.4.3",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^4.4.2"
"vanilla-lazyload": "^17.8.4",
"vite": "^4.4.2",
"vite-imagetools": "^5.0.8"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@ -1211,6 +1216,34 @@
"integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
"dev": true
},
"node_modules/@rollup/pluginutils": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.3.tgz",
"integrity": "sha512-hfllNN4a80rwNQ9QCxhxuHCGHMAvabXqxNdaChUSSadMre7t4iEUI6fFAhBOn/eIYTgYVhBv7vCLsAJ4u3lf3g==",
"dev": true,
"dependencies": {
"@types/estree": "^1.0.0",
"estree-walker": "^2.0.2",
"picomatch": "^2.3.1"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^1.20.0||^2.0.0||^3.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@rollup/pluginutils/node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true
},
"node_modules/@sveltejs/adapter-auto": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-2.1.0.tgz",
@ -1320,6 +1353,12 @@
"integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==",
"dev": true
},
"node_modules/@types/node": {
"version": "20.5.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz",
"integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==",
"dev": true
},
"node_modules/@types/offscreencanvas": {
"version": "2019.7.0",
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz",
@ -1634,12 +1673,38 @@
"dequal": "^2.0.3"
}
},
"node_modules/b4a": {
"version": "1.6.4",
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz",
"integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==",
"dev": true
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@ -1649,6 +1714,17 @@
"node": ">=8"
}
},
"node_modules/bl": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
"dev": true,
"dependencies": {
"buffer": "^5.5.0",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
}
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@ -1671,6 +1747,30 @@
"node": ">=8"
}
},
"node_modules/buffer": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.1.13"
}
},
"node_modules/buffer-crc32": {
"version": "0.2.13",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
@ -1768,6 +1868,12 @@
"node": ">= 6"
}
},
"node_modules/chownr": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
"dev": true
},
"node_modules/code-red": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.3.tgz",
@ -1780,6 +1886,19 @@
"periscopic": "^3.1.0"
}
},
"node_modules/color": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
"dev": true,
"dependencies": {
"color-convert": "^2.0.1",
"color-string": "^1.9.0"
},
"engines": {
"node": ">=12.5.0"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@ -1798,6 +1917,16 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/color-string": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
"dev": true,
"dependencies": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
}
},
"node_modules/colord": {
"version": "2.9.3",
"resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
@ -1818,6 +1947,20 @@
"node": ">= 0.6"
}
},
"node_modules/copy-anything": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
"integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
"dependencies": {
"is-what": "^4.1.8"
},
"engines": {
"node": ">=12.13"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@ -1873,6 +2016,30 @@
}
}
},
"node_modules/decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"dev": true,
"dependencies": {
"mimic-response": "^3.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"dev": true,
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@ -1905,6 +2072,15 @@
"node": ">=8"
}
},
"node_modules/detect-libc": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz",
"integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/devalue": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.2.tgz",
@ -1940,6 +2116,15 @@
"resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz",
"integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ=="
},
"node_modules/end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"dev": true,
"dependencies": {
"once": "^1.4.0"
}
},
"node_modules/es6-promise": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
@ -2241,12 +2426,27 @@
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
},
"node_modules/expand-template": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
},
"node_modules/fast-fifo": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.0.tgz",
"integrity": "sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw==",
"dev": true
},
"node_modules/fast-glob": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
@ -2355,6 +2555,12 @@
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
"dev": true
},
"node_modules/fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
"dev": true
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -2394,6 +2600,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/github-from-package": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
"dev": true
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@ -2522,6 +2734,26 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/ignore": {
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
@ -2531,6 +2763,18 @@
"node": ">= 4"
}
},
"node_modules/imagetools-core": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/imagetools-core/-/imagetools-core-4.0.5.tgz",
"integrity": "sha512-sNRVfUwkUcsVWNn5inTHDXWzpPRWPWbSgGkuQmlsFCWXAR2+K5R5vG5tC3Qs4LeJaMugKB8hGVm6rvZjFHQrUw==",
"dev": true,
"dependencies": {
"sharp": "^0.32.4"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/immutable": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.2.tgz",
@ -2588,6 +2832,18 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"node_modules/ini": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
"dev": true
},
"node_modules/is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
"dev": true
},
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
@ -2647,6 +2903,17 @@
"@types/estree": "*"
}
},
"node_modules/is-what": {
"version": "4.1.15",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.15.tgz",
"integrity": "sha512-uKua1wfy3Yt+YqsD6mTUEa2zSi3G1oPlqTflgaPJ7z63vUGN5pxFpnQfeSLMFnJDEsdvOtkp1rUWkYjB4YfhgA==",
"engines": {
"node": ">=12.13"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@ -2821,6 +3088,18 @@
"node": ">=10.0.0"
}
},
"node_modules/mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/min-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@ -2863,6 +3142,12 @@
"mkdirp": "bin/cmd.js"
}
},
"node_modules/mkdirp-classic": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
"dev": true
},
"node_modules/mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
@ -2905,6 +3190,12 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/napi-build-utils": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==",
"dev": true
},
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@ -2917,6 +3208,24 @@
"integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==",
"dev": true
},
"node_modules/node-abi": {
"version": "3.47.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.47.0.tgz",
"integrity": "sha512-2s6B2CWZM//kPgwnuI0KrYwNjfdByE25zvAaEpq9IH4zcNsarH8Ihu/UuX6XMPEogDAxkuUFeZn60pXNHAqn3A==",
"dev": true,
"dependencies": {
"semver": "^7.3.5"
},
"engines": {
"node": ">=10"
}
},
"node_modules/node-addon-api": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz",
"integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==",
"dev": true
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@ -3265,6 +3574,60 @@
"node": ">=4"
}
},
"node_modules/prebuild-install": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz",
"integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==",
"dev": true,
"dependencies": {
"detect-libc": "^2.0.0",
"expand-template": "^2.0.3",
"github-from-package": "0.0.0",
"minimist": "^1.2.3",
"mkdirp-classic": "^0.5.3",
"napi-build-utils": "^1.0.1",
"node-abi": "^3.3.0",
"pump": "^3.0.0",
"rc": "^1.2.7",
"simple-get": "^4.0.0",
"tar-fs": "^2.0.0",
"tunnel-agent": "^0.6.0"
},
"bin": {
"prebuild-install": "bin.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/prebuild-install/node_modules/tar-fs": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
"integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
"dev": true,
"dependencies": {
"chownr": "^1.1.1",
"mkdirp-classic": "^0.5.2",
"pump": "^3.0.0",
"tar-stream": "^2.1.4"
}
},
"node_modules/prebuild-install/node_modules/tar-stream": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"dev": true,
"dependencies": {
"bl": "^4.0.3",
"end-of-stream": "^1.4.1",
"fs-constants": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.1.1"
},
"engines": {
"node": ">=6"
}
},
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@ -3312,6 +3675,16 @@
"node": ">=6"
}
},
"node_modules/pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"dev": true,
"dependencies": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"node_modules/punycode": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
@ -3355,6 +3728,50 @@
}
]
},
"node_modules/queue-tick": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
"integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
"dev": true
},
"node_modules/rc": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"dev": true,
"dependencies": {
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
"minimist": "^1.2.0",
"strip-json-comments": "~2.0.1"
},
"bin": {
"rc": "cli.js"
}
},
"node_modules/rc/node_modules/strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@ -3452,6 +3869,26 @@
"node": ">=6"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/sander": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz",
@ -3519,6 +3956,29 @@
"integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==",
"dev": true
},
"node_modules/sharp": {
"version": "0.32.5",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.5.tgz",
"integrity": "sha512-0dap3iysgDkNaPOaOL4X/0akdu0ma62GcdC2NBQ+93eqpePdDdr2/LM0sFdDSMmN7yS+odyZtPsb7tx/cYBKnQ==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
"color": "^4.2.3",
"detect-libc": "^2.0.2",
"node-addon-api": "^6.1.0",
"prebuild-install": "^7.1.1",
"semver": "^7.5.4",
"simple-get": "^4.0.1",
"tar-fs": "^3.0.4",
"tunnel-agent": "^0.6.0"
},
"engines": {
"node": ">=14.15.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@ -3553,6 +4013,60 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/simple-concat": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/simple-get": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"decompress-response": "^6.0.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
},
"node_modules/simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
"dev": true,
"dependencies": {
"is-arrayish": "^0.3.1"
}
},
"node_modules/sirv": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz",
@ -3608,6 +4122,25 @@
"node": ">=10.0.0"
}
},
"node_modules/streamx": {
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.1.tgz",
"integrity": "sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==",
"dev": true,
"dependencies": {
"fast-fifo": "^1.1.0",
"queue-tick": "^1.0.1"
}
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"dev": true,
"dependencies": {
"safe-buffer": "~5.2.0"
}
},
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
@ -3644,6 +4177,17 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/superjson": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/superjson/-/superjson-1.13.1.tgz",
"integrity": "sha512-AVH2eknm9DEd3qvxM4Sq+LTCkSXE2ssfh1t11MHMXyYXFQyQ1HLgVvV+guLTsaQnJU3gnaVo34TohHPulY/wLg==",
"dependencies": {
"copy-anything": "^3.0.2"
},
"engines": {
"node": ">=10"
}
},
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@ -3839,6 +4383,28 @@
"node": ">=12"
}
},
"node_modules/tar-fs": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz",
"integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==",
"dev": true,
"dependencies": {
"mkdirp-classic": "^0.5.2",
"pump": "^3.0.0",
"tar-stream": "^3.1.5"
}
},
"node_modules/tar-stream": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz",
"integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==",
"dev": true,
"dependencies": {
"b4a": "^1.6.4",
"fast-fifo": "^1.2.0",
"streamx": "^2.15.0"
}
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@ -3893,6 +4459,18 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
"node_modules/tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
"dev": true,
"dependencies": {
"safe-buffer": "^5.0.1"
},
"engines": {
"node": "*"
}
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@ -3983,6 +4561,16 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
},
"node_modules/vanilla-lazyload": {
"version": "17.8.4",
"resolved": "https://registry.npmjs.org/vanilla-lazyload/-/vanilla-lazyload-17.8.4.tgz",
"integrity": "sha512-LP1fP0nl7SZom6wojLJXzj2du69txtPfDOoWQWgLDU8mz7NBrWL2Txx6p84f6d+gTEcGbA9lUynAx5CS0rqWsg==",
"dev": true,
"funding": {
"type": "individual",
"url": "https://ko-fi.com/verlok"
}
},
"node_modules/vfile-message": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
@ -4051,6 +4639,19 @@
}
}
},
"node_modules/vite-imagetools": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/vite-imagetools/-/vite-imagetools-5.0.8.tgz",
"integrity": "sha512-oFNfc58iLz1lHFsIKQy+wp0RNcZjiaDeHYTexYowpf4RYx9tZ97eWEcw8lQ1jDT8AnOso6XZi5iGjLNAeTR9Tw==",
"dev": true,
"dependencies": {
"@rollup/pluginutils": "^5.0.2",
"imagetools-core": "^4.0.5"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/vitefu": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.4.tgz",

View file

@ -14,6 +14,7 @@
"devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.20.4",
"@types/node": "^20.5.1",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"eslint": "^8.28.0",
@ -22,11 +23,14 @@
"prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.10.1",
"sass": "^1.64.2",
"sharp": "^0.32.5",
"svelte": "^4.0.5",
"svelte-check": "^3.4.3",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^4.4.2"
"vanilla-lazyload": "^17.8.4",
"vite": "^4.4.2",
"vite-imagetools": "^5.0.8"
},
"type": "module",
"dependencies": {
@ -34,6 +38,7 @@
"mdsvex": "^0.11.0",
"perlin-noise-2d": "^1.0.0",
"pixi-filters": "^5.2.1",
"pixi.js": "^7.2.4"
"pixi.js": "^7.2.4",
"superjson": "^1.13.1"
}
}

5
src/ambient.d.ts vendored Normal file
View file

@ -0,0 +1,5 @@
// Squelch warnings of image imports from your assets dir
declare module '$lib/assets/*' {
const meta
export default meta
}

View file

@ -1,118 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1366 768" style="enable-background:new 0 0 1366 768;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#000000;stroke-miterlimit:10;}
</style>
<g>
<path class="st0" d="M-129.8-37.1c0,0,48.3-107.4,220.3-114.1c172-6.7,393.3,153.3,570.7,108s632.7-294.7,745.3-164"/>
<path class="st0" d="M-129.8-28c0,0,48.7-105.5,220.7-112.1c172-6.7,392.9,150.1,570.3,104.8s630.6-290,745.1-161.1"/>
<path class="st0" d="M-129.8-18.9c0,0,49.1-103.5,221.1-110.2c172-6.7,392.6,146.9,569.9,101.5s628.6-285.3,744.9-158.3"/>
<path class="st0" d="M-129.8-9.7c0,0,49.5-101.6,221.5-108.3c172-6.7,392.2,143.6,569.5,98.3s626.5-280.6,744.7-155.4"/>
<path class="st0" d="M-129.8-0.6c0,0,49.9-99.6,221.9-106.3S483.8,33.5,661.2-11.9s624.5-275.9,744.6-152.6"/>
<path class="st0" d="M-129.8,8.5c0,0,50.2-97.7,222.2-104.4S483.8,41.3,661.2-4s622.4-271.2,744.4-149.7"/>
<path class="st0" d="M-129.8,17.6c0,0,50.6-95.7,222.6-102.4c172-6.7,391,133.9,568.3,88.6s620.4-266.5,744.2-146.9"/>
<path class="st0" d="M-129.8,26.7c0,0,51-93.8,223-100.5c172-6.7,390.6,130.7,567.9,85.4s618.3-261.8,744-144"/>
<path class="st0" d="M-129.8,35.8c0,0,51.4-91.9,223.4-98.5c172-6.7,390.2,127.5,567.6,82.1s616.3-257.1,743.8-141.1"/>
<path class="st0" d="M-129.8,45c0,0,51.8-89.9,223.8-96.6S483.8,72.6,661.2,27.3s614.2-252.4,743.6-138.3"/>
<path class="st0" d="M-129.8,54.1c0,0,52.2-88,224.2-94.6s389.5,121,566.8,75.7s612.2-247.8,743.4-135.4"/>
<path class="st0" d="M-129.8,63.2c0,0,52.6-86,224.6-92.7S483.8,88.3,661.2,43s610.1-243.1,743.2-132.6"/>
<path class="st0" d="M-129.8,72.3c0,0,53-84.1,225-90.7s388.7,114.5,566,69.2s608.1-238.4,743-129.7"/>
<path class="st0" d="M-129.8,81.4c0,0,53.4-82.1,225.4-88.8s388.3,111.3,565.6,66S1267.2-175,1404-68.2"/>
<path class="st0" d="M-129.8,90.5c0,0,53.7-80.2,225.7-86.8s387.9,108.1,565.2,62.7s604-229,742.6-124"/>
<path class="st0" d="M-129.8,99.7c0,0,54.1-78.2,226.1-84.9s387.5,104.8,564.8,59.5s602-224.3,742.4-121.1"/>
<path class="st0" d="M-129.8,108.8c0,0,54.5-76.3,226.5-82.9s387.1,101.6,564.5,56.3s599.9-219.6,742.2-118.3"/>
<path class="st0" d="M-129.8,117.9c0,0,54.9-74.3,226.9-81S483.8,135.3,661.2,90S1259-125,1403.2-25.4"/>
<path class="st0" d="M-129.8,127c0,0,55.3-72.4,227.3-79s386.3,95.2,563.7,49.8S1257-112.4,1403-14.8"/>
<path class="st0" d="M-129.8,136.1c0,0,55.7-70.4,227.7-77.1s386,91.9,563.3,46.6S1254.9-99.9,1402.8-4.1"/>
<path class="st0" d="M-129.8,145.3c0,0,56.1-68.5,228.1-75.2c172-6.7,385.6,88.7,562.9,43.4S1252.9-87.4,1402.6,6.6"/>
<path class="st0" d="M-129.8,154.4c0,0,56.5-66.5,228.5-73.2c172-6.7,385.2,85.5,562.5,40.1s589.7-196.1,741.2-104"/>
<path class="st0" d="M-129.8,163.5c0,0,56.9-64.6,228.9-71.3s384.8,82.2,562.1,36.9s587.6-191.5,741-101.1"/>
<path class="st0" d="M-129.8,172.6c0,0,57.2-62.6,229.2-69.3c172-6.7,384.4,79,561.7,33.7S1246.7-49.8,1402,38.7"/>
<path class="st0" d="M-129.8,181.7c0,0,57.6-60.7,229.6-67.4c172-6.7,384,75.8,561.3,30.4s583.5-182.1,740.7-95.4"/>
<path class="st0" d="M-129.8,190.8c0,0,58-58.8,230-65.4c172-6.7,383.6,72.5,561,27.2s581.5-177.4,740.5-92.5"/>
<path class="st0" d="M-129.8,200c0,0,58.4-56.8,230.4-63.5c172-6.7,383.2,69.3,560.6,24s579.4-172.7,740.3-89.7"/>
<path class="st0" d="M-129.8,209.1c0,0,58.8-54.9,230.8-61.5c172-6.7,382.8,66.1,560.2,20.7s577.4-168,740.1-86.8"/>
<path class="st0" d="M-129.8,218.2c0,0,59.2-52.9,231.2-59.6c172-6.7,382.5,62.8,559.8,17.5s575.3-163.3,739.9-84"/>
<path class="st0" d="M-129.8,227.3c0,0,59.6-51,231.6-57.6c172-6.7,382.1,59.6,559.4,14.3s573.3-158.6,739.7-81.1"/>
<path class="st0" d="M-129.8,236.4c0,0,60-49,232-55.7s381.7,56.4,559,11s571.2-153.9,739.5-78.3"/>
<path class="st0" d="M-129.8,245.5c0,0,60.3-47.1,232.3-53.7s381.3,53.1,558.6,7.8s569.2-149.2,739.3-75.4"/>
<path class="st0" d="M-129.8,254.7c0,0,60.7-45.1,232.7-51.8s380.9,49.9,558.2,4.6s567.1-144.5,739.1-72.5"/>
<path class="st0" d="M-129.8,263.8c0,0,61.1-43.2,233.1-49.8c172-6.7,380.5,46.7,557.9,1.3s565.1-139.9,738.9-69.7"/>
<path class="st0" d="M-129.8,272.9c0,0,61.5-41.2,233.5-47.9c172-6.7,380.1,43.4,557.5-1.9s563-135.2,738.7-66.8"/>
<path class="st0" d="M-129.8,282c0,0,61.9-39.3,233.9-45.9c172-6.7,379.7,40.2,557.1-5.1s561-130.5,738.5-64"/>
<path class="st0" d="M-129.8,291.1c0,0,62.3-37.3,234.3-44c172-6.7,379.4,37,556.7-8.4s559-125.8,738.3-61.1"/>
<path class="st0" d="M-129.8,300.3c0,0,62.7-35.4,234.7-42.1c172-6.7,379,33.7,556.3-11.6s556.9-121.1,738.1-58.2"/>
<path class="st0" d="M-129.8,309.4c0,0,63.1-33.4,235.1-40.1s378.6,30.5,555.9-14.8S1216,138,1399.1,199.1"/>
<path class="st0" d="M-129.8,318.5c0,0,63.5-31.5,235.5-38.2s378.2,27.3,555.5-18.1s552.8-111.7,737.7-52.5"/>
<path class="st0" d="M-129.8,327.6c0,0,63.8-29.5,235.8-36.2s377.8,24,555.1-21.3s550.8-107,737.5-49.7"/>
<path class="st0" d="M-129.8,336.7c0,0,64.2-27.6,236.2-34.3s377.4,20.8,554.7-24.5s548.7-102.3,737.3-46.8"/>
<path class="st0" d="M-129.8,345.8c0,0,64.6-25.7,236.6-32.3s377,17.6,554.4-27.8s546.7-97.6,737.1-44"/>
<path class="st0" d="M-129.8,355c0,0,65-23.7,237-30.4c172-6.7,376.6,14.3,554-31s544.6-92.9,736.9-41.1"/>
<path class="st0" d="M-129.8,364.1c0,0,65.4-21.8,237.4-28.4c172-6.7,376.2,11.1,553.6-34.2s542.6-88.2,736.8-38.2"/>
<path class="st0" d="M-129.8,373.2c0,0,65.8-19.8,237.8-26.5c172-6.7,375.9,7.9,553.2-37.5s540.5-83.6,736.6-35.4"/>
<path class="st0" d="M-129.8,382.3c0,0,66.2-17.9,238.2-24.5c172-6.7,375.5,4.6,552.8-40.7s538.5-78.9,736.4-32.5"/>
<path class="st0" d="M-129.8,391.4c0,0,66.6-15.9,238.6-22.6c172-6.7,375.1,1.4,552.4-43.9s536.4-74.2,736.2-29.7"/>
<path class="st0" d="M-129.8,400.5c0,0,66.9-14,238.9-20.6c172-6.7,374.7-1.8,552-47.1s534.4-69.5,736-26.8"/>
<path class="st0" d="M-129.8,409.7c0,0,67.3-12,239.3-18.7c172-6.7,374.3-5,551.6-50.4s532.3-64.8,735.8-23.9"/>
<path class="st0" d="M-129.8,418.8c0,0,67.7-10.1,239.7-16.7c172-6.7,373.9-8.3,551.3-53.6s530.3-60.1,735.6-21.1"/>
<path class="st0" d="M-129.8,427.9c0,0,68.1-8.1,240.1-14.8c172-6.7,373.5-11.5,550.9-56.8s528.2-55.4,735.4-18.2"/>
<path class="st0" d="M-129.8,437c0,0,68.5-6.2,240.5-12.8c172-6.7,373.1-14.7,550.5-60.1s526.2-50.7,735.2-15.4"/>
<path class="st0" d="M-129.8,446.1c0,0,68.9-4.2,240.9-10.9c172-6.7,372.8-18,550.1-63.3s524.1-46,735-12.5"/>
<path class="st0" d="M-129.8,455.3c0,0,69.3-2.3,241.3-9s372.4-21.2,549.7-66.5s522.1-41.3,734.8-9.7"/>
<path class="st0" d="M-129.8,464.4c0,0,69.7-0.3,241.7-7s372-24.4,549.3-69.8s520-36.6,734.6-6.8"/>
<path class="st0" d="M-129.8,473.5c0,0,70.1,1.6,242.1-5.1s371.6-27.7,548.9-73s518-32,734.4-3.9"/>
<path class="st0" d="M-129.8,482.6c0,0,70.4,3.6,242.4-3.1s371.2-30.9,548.5-76.2s515.9-27.3,734.2-1.1"/>
<path class="st0" d="M-129.8,491.7c0,0,70.8,5.5,242.8-1.2s370.8-34.1,548.1-79.5s513.9-22.6,734,1.8"/>
<path class="st0" d="M-129.8,500.8c0,0,71.2,7.4,243.2,0.8s370.4-37.4,547.8-82.7S1173,401,1395,423.6"/>
<path class="st0" d="M-129.8,510c0,0,71.6,9.4,243.6,2.7c172-6.7,370-40.6,547.4-85.9s509.8-13.2,733.6,7.5"/>
<path class="st0" d="M-129.8,519.1c0,0,72,11.3,244,4.7c172-6.7,369.6-43.8,547-89.2s507.8-8.5,733.4,10.4"/>
<path class="st0" d="M-129.8,528.2c0,0,72.4,13.3,244.4,6.6s369.3-47.1,546.6-92.4s505.7-3.8,733.2,13.2"/>
<path class="st0" d="M-129.8,537.3c0,0,72.8,15.2,244.8,8.6c172-6.7,368.9-50.3,546.2-95.6s503.7,0.9,733.1,16.1"/>
<path class="st0" d="M-129.8,546.4c0,0,73.2,17.2,245.2,10.5c172-6.7,368.5-53.5,545.8-98.9s501.6,5.6,732.9,18.9"/>
<path class="st0" d="M-129.8,555.5c0,0,73.5,19.1,245.5,12.5c172-6.7,368.1-56.8,545.4-102.1s499.6,10.3,732.7,21.8"/>
<path class="st0" d="M-129.8,564.7c0,0,73.9,21.1,245.9,14.4c172-6.7,367.7-60,545-105.3s497.5,15,732.5,24.6"/>
<path class="st0" d="M-129.8,573.8c0,0,74.3,23,246.3,16.4c172-6.7,367.3-63.2,544.7-108.6s495.5,19.7,732.3,27.5"/>
<path class="st0" d="M-129.8,582.9c0,0,74.7,25,246.7,18.3c172-6.7,366.9-66.5,544.3-111.8s493.4,24.3,732.1,30.4"/>
<path class="st0" d="M-129.8,592c0,0,75.1,26.9,247.1,20.3s366.5-69.7,543.9-115s491.4,29,731.9,33.2"/>
<path class="st0" d="M-129.8,601.1c0,0,75.5,28.9,247.5,22.2c172-6.7,366.2-72.9,543.5-118.3s489.3,33.7,731.7,36.1"/>
<path class="st0" d="M-129.8,610.2c0,0,75.9,30.8,247.9,24.1s365.8-76.2,543.1-121.5s487.3,38.4,731.5,38.9"/>
<path class="st0" d="M-129.8,619.4c0,0,76.3,32.8,248.3,26.1c172-6.7,365.4-79.4,542.7-124.7s485.2,43.1,731.3,41.8"/>
<path class="st0" d="M-129.8,628.5c0,0,76.7,34.7,248.7,28s365-82.6,542.3-128c177.3-45.3,483.2,47.8,731.1,44.7"/>
<path class="st0" d="M-129.8,637.6c0,0,77,36.7,249,30c172-6.7,364.6-85.9,541.9-131.2c177.3-45.3,481.1,52.5,730.9,47.5"/>
<path class="st0" d="M-129.8,646.7c0,0,77.4,38.6,249.4,31.9s364.2-89.1,541.5-134.4c177.3-45.3,479.1,57.2,730.7,50.4"/>
<path class="st0" d="M-129.8,655.8c0,0,77.8,40.5,249.8,33.9c172-6.7,363.8-92.3,541.2-137.7c177.3-45.3,477,61.9,730.5,53.2"/>
<path class="st0" d="M-129.8,665c0,0,78.2,42.5,250.2,35.8s363.4-95.6,540.8-140.9c177.3-45.3,475,66.6,730.3,56.1"/>
<path class="st0" d="M-129.8,674.1c0,0,78.6,44.4,250.6,37.8c172-6.7,363-98.8,540.4-144.1c177.3-45.3,472.9,71.3,730.1,58.9"/>
<path class="st0" d="M-129.8,683.2c0,0,79,46.4,251,39.7s362.7-102,540-147.3c177.3-45.3,470.9,75.9,729.9,61.8"/>
<path class="st0" d="M-129.8,692.3c0,0,79.4,48.3,251.4,41.7c172-6.7,362.3-105.2,539.6-150.6c177.3-45.3,468.9,80.6,729.7,64.7"/>
<path class="st0" d="M-129.8,701.4c0,0,79.8,50.3,251.8,43.6c172-6.7,361.9-108.5,539.2-153.8c177.3-45.3,466.8,85.3,729.5,67.5"/>
<path class="st0" d="M-129.8,710.5c0,0,80.1,52.2,252.1,45.6c172-6.7,361.5-111.7,538.8-157c177.3-45.3,464.8,90,729.3,70.4"/>
<path class="st0" d="M-129.8,719.7c0,0,80.5,54.2,252.5,47.5c172-6.7,361.1-114.9,538.4-160.3c177.3-45.3,462.7,94.7,729.2,73.2"/>
<path class="st0" d="M-129.8,728.8c0,0,80.9,56.1,252.9,49.5c172-6.7,360.7-118.2,538-163.5c177.3-45.3,460.7,99.4,729,76.1"/>
<path class="st0" d="M-129.8,737.9c0,0,81.3,58.1,253.3,51.4c172-6.7,360.3-121.4,537.7-166.7c177.3-45.3,458.6,104.1,728.8,79"/>
<path class="st0" d="M-129.8,747c0,0,81.7,60,253.7,53.3s359.9-124.6,537.3-170c177.3-45.3,456.6,108.8,728.6,81.8"/>
<path class="st0" d="M-129.8,756.1c0,0,82.1,62,254.1,55.3c172-6.7,359.6-127.9,536.9-173.2c177.3-45.3,454.5,113.5,728.4,84.7"/>
<path class="st0" d="M-129.8,765.2c0,0,82.5,63.9,254.5,57.2s359.2-131.1,536.5-176.4c177.3-45.3,452.5,118.2,728.2,87.5"/>
<path class="st0" d="M-129.8,774.4c0,0,82.9,65.9,254.9,59.2c172-6.7,358.8-134.3,536.1-179.7c177.3-45.3,450.4,122.9,728,90.4"/>
<path class="st0" d="M-129.8,783.5c0,0,83.3,67.8,255.3,61.1S483.8,707,661.2,661.7S1109.5,789.3,1389,755"/>
<path class="st0" d="M-129.8,792.6c0,0,83.6,69.8,255.6,63.1c172-6.7,358-140.8,535.3-186.1s446.3,132.2,727.6,96.1"/>
<path class="st0" d="M-129.8,801.7c0,0,84,71.7,256,65s357.6-144,534.9-189.4s444.3,136.9,727.4,99"/>
<path class="st0" d="M-129.8,810.8c0,0,84.4,73.6,256.4,67c172-6.7,357.2-147.3,534.6-192.6s442.2,141.6,727.2,101.8"/>
<path class="st0" d="M-129.8,820c0,0,84.8,75.6,256.8,68.9S483.8,738.4,661.2,693s440.2,146.3,727,104.7"/>
<path class="st0" d="M-129.8,829.1c0,0,85.2,77.5,257.2,70.9c172-6.7,356.4-153.7,533.8-199.1s438.1,151,726.8,107.5"/>
<path class="st0" d="M-129.8,838.2c0,0,85.6,79.5,257.6,72.8s356.1-157,533.4-202.3s436.1,155.7,726.6,110.4"/>
<path class="st0" d="M-129.8,847.3c0,0,86,81.4,258,74.8c172-6.7,355.7-160.2,533-205.5s434,160.4,726.4,113.3"/>
<path class="st0" d="M-129.8,856.4c0,0,86.4,83.4,258.4,76.7c172-6.7,355.3-163.4,532.6-208.8s432,165.1,726.2,116.1"/>
<path class="st0" d="M-129.8,865.5c0,0,86.8,85.3,258.8,78.7c172-6.7,354.9-166.7,532.2-212s429.9,169.8,726,119"/>
<path class="st0" d="M-129.8,874.7c0,0,87.1,87.3,259.1,80.6c172-6.7,354.5-169.9,531.8-215.2s427.9,174.5,725.8,121.8"/>
<path class="st0" d="M-129.8,883.8c0,0,87.5,89.2,259.5,82.6c172-6.7,354.1-173.1,531.4-218.5S1087,927,1386.8,872.6"/>
<path class="st0" d="M-129.8,892.9c0,0,87.9,91.2,259.9,84.5c172-6.7,353.7-176.4,531.1-221.7s423.8,183.8,725.4,127.5"/>
<path class="st0" d="M-129.8,902c0,0,88.3,93.1,260.3,86.4s353.3-179.6,530.7-224.9s421.8,188.5,725.3,130.4"/>
<path class="st0" d="M-129.8,911.1c0,0,88.7,95.1,260.7,88.4c172-6.7,353-182.8,530.3-228.2c177.3-45.3,419.7,193.2,725.1,133.3"/>
<path class="st0" d="M-129.8,920.2c0,0,89.1,97,261.1,90.3s352.6-186.1,529.9-231.4c177.3-45.3,417.7,197.9,724.9,136.1"/>
<path class="st0" d="M-129.8,929.4c0,0,89.5,99,261.5,92.3c172-6.7,352.2-189.3,529.5-234.6c177.3-45.3,415.6,202.6,724.7,139"/>
<path class="st0" d="M-129.8,938.5c0,0,89.9,100.9,261.9,94.2s351.8-192.5,529.1-237.9c177.3-45.3,413.6,207.3,724.5,141.8"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View file

@ -0,0 +1,36 @@
<script>
import Logo from "./Logo.svelte";
import MainNav from "./MainNav.svelte";
</script>
<header class="header-nav">
<a href="/" class="logo">
<Logo />
</a>
<MainNav />
</header>
<style lang="scss">
.logo {
height: 36px;
width: auto;
position: fixed;
bottom: 0;
z-index: 4;
display: block;
margin: var(--spacing-nav);
cursor: url('/pointer.svg'), auto;
}
.header-nav {
@media screen and (max-width: 767px) {
background-color: var(--color-bg);
width: 100%;
height: calc(36px + 2 * var(--spacing-nav));
position: fixed;
bottom: 0;
left: 0;
z-index: 3;
border-top: 1px solid var(--color-text);
}
}
</style>

View file

@ -16,179 +16,195 @@ export let imgsToCanvas: Array<HTMLElement> = [];
let app: PIXI.Application;
let canvas: HTMLCanvasElement;
onMount(()=>{
gsap.registerPlugin(PixiPlugin, ScrollTrigger, SplitText);
app = new PIXI.Application({
resizeTo: window,
antialias: true,
autoDensity: true,
resolution: 2,
backgroundAlpha: 0,
view: canvas,
});
//for debugging but Typescript has an issue with this:
// globalThis.__PIXI_APP__ = app as any;
PixiPlugin.registerPIXI(PIXI);
function xFrac(x: number){
return window.innerWidth * x;
}
function yFrac(y: number){
return window.innerHeight * y;
}
let group = new PIXI.Container();
group.pivot.set(window.innerWidth / 2, window.innerHeight / 2);
group.x = window.innerWidth / 2;
group.y = window.innerHeight / 2;
app.stage.addChild(group);
let recty = new PIXI.Graphics();
recty.beginFill('rgb(0, 0, 0)');
recty.drawRect(0, 0, xFrac(1), yFrac(1));
recty.endFill();
recty.alpha = 0;
recty.pivot.set(xFrac(.5), yFrac(.5));
recty.x = xFrac(0.5);
recty.y = yFrac(0.5);
group.addChild(recty);
let center = [0.5, 0.5];
let bulgefilter = new BulgePinchFilter();
bulgefilter.radius = xFrac(0.45);
bulgefilter.strength = 0;
bulgefilter.center = center;
bulgefilter.resolution = 2;
app.stage.filters = [bulgefilter];
gsap.to(bulgefilter, {
strength: 0.5,
duration: 2,
delay: 1,
ease: 'elastic.out',
});
window.addEventListener('mousedown', ()=>{
gsap.to(bulgefilter, {
strength: 0,
duration: 1,
ease: 'elastic.out',
});
})
window.addEventListener('mouseup', ()=>{
gsap.to(bulgefilter, {
strength: 0.5,
duration: 2,
ease: 'elastic.out',
});
})
/*----------------------------------
* Convert text to canvas using
* createCanvasText function
----------------------------------*/
let canvasTexts: Array<PIXI.Text> = [];
let elems: Array<HTMLElement> = [];
async function convertText(){
await tick();
textsToCanvas.forEach((element) => {
elems.push(element);
let canvasText = createCanvasText(element, app.stage);
canvasTexts.push(canvasText);
})
}
/*----------------------------------
* Function to update text on canvas
* runs in the Ticker
----------------------------------*/
function updateText(){
canvasTexts.forEach((text, index) => {
let headlinePosition = elems[index].getBoundingClientRect();
text.position.set(headlinePosition.x, headlinePosition.y);
text.alpha = elems[index].style.opacity as unknown as number;
})
}
/*----------------------------------
* Convert images to canvas
* createCanvacImgs function
----------------------------------*/
let canvasImgs: Array<PIXI.Sprite> = [];
let imgElems: Array<HTMLElement> = [];
function convertImgs(){
imgsToCanvas.forEach((element) => {
imgElems.push(element);
let canvasImg = createCanvasImg(element, app.stage);
canvasImgs.push(canvasImg);
})
}
setTimeout(() => {
convertImgs();
convertText();
}, 100);
// convertImgs();
// convertText();
/*----------------------------------
* Function to update text on canvas
* runs in the Ticker
----------------------------------*/
function updateImgs(){
canvasImgs.forEach((image, index) => {
let imagePosition = imgElems[index].getBoundingClientRect();
image.position.set(imagePosition.x, imagePosition.y);
image.width = imagePosition.width;
image.height = imagePosition.height;
})
}
/*----------------------------------
* Mousemove events
*----------------------------------*/
let tween = {
x: 0.5,
y: 0.5,
};
window.addEventListener('mousemove', (e) => {
const pointerX = e.clientX / window.innerWidth;
const pointerY = e.clientY / window.innerHeight;
const pointerXfrac = pointerX - 0.5;
const pointerYfrac = pointerY - 0.5;
let is_fine = window.matchMedia('(pointer:fine)').matches
let is_coarse = window.matchMedia('(pointer:coarse)').matches
// center = [(0.5 + pointerXfrac/10),(0.5 + pointerYfrac/10)];
gsap.to(tween, {
duration: .5,
ease: 'power3.out',
overwrite: true,
x: 0.5 + pointerXfrac/10,
y: 0.5 + pointerYfrac/10,
gsap.registerPlugin(PixiPlugin, ScrollTrigger, SplitText);
app = new PIXI.Application({
resizeTo: window,
antialias: true,
autoDensity: true,
resolution: 2,
backgroundAlpha: 0,
view: canvas,
});
//for debugging but Typescript has an issue with this:
// globalThis.__PIXI_APP__ = app as any;
PixiPlugin.registerPIXI(PIXI);
function xFrac(x: number){
return window.innerWidth * x;
}
function yFrac(y: number){
return window.innerHeight * y;
}
let group = new PIXI.Container();
group.pivot.set(window.innerWidth / 2, window.innerHeight / 2);
group.x = window.innerWidth / 2;
group.y = window.innerHeight / 2;
app.stage.addChild(group);
let recty = new PIXI.Graphics();
recty.beginFill('rgb(0, 0, 0)');
recty.drawRect(0, 0, xFrac(1), yFrac(1));
recty.endFill();
recty.alpha = 0;
recty.pivot.set(xFrac(.5), yFrac(.5));
recty.x = xFrac(0.5);
recty.y = yFrac(0.5);
group.addChild(recty);
let center = [0.5, 0.5];
let bulgefilter = new BulgePinchFilter();
bulgefilter.radius = xFrac(0.45);
bulgefilter.strength = 0;
bulgefilter.center = center;
bulgefilter.resolution = 2;
app.stage.filters = [bulgefilter];
gsap.to(bulgefilter, {
strength: is_fine ? 0.5 : 0.4,
duration: 1.5,
delay: 1,
ease: 'elastic.out(1.75, 0.3)',
});
window.addEventListener( is_fine ? 'mousedown' : 'touchstart', (e)=>{
let target = e.target as HTMLElement;
if (target.tagName === 'H1' || target.tagName === 'H2' || target.tagName === 'P'){
gsap.to(bulgefilter, {
strength: 0,
duration: 1,
ease: 'elastic.out',
});
}
})
window.addEventListener( is_fine ? 'mouseup' : 'touchend', (e)=>{
let target = e.target as HTMLElement;
if (target.tagName === 'H1' || target.tagName === 'H2' || target.tagName === 'P'){
gsap.to(bulgefilter, {
strength: 0.5,
duration: 2,
ease: 'elastic.out',
});
}
})
/*----------------------------------
* Convert text to canvas using
* createCanvasText function
----------------------------------*/
let canvasTexts: Array<PIXI.Text> = [];
let elems: Array<HTMLElement> = [];
async function convertText(){
await tick();
textsToCanvas.forEach((element) => {
elems.push(element);
let canvasText = createCanvasText(element, app.stage);
canvasTexts.push(canvasText);
})
}
/*----------------------------------
* Function to update text on canvas
* runs in the Ticker
----------------------------------*/
function updateText(){
canvasTexts.forEach((text, index) => {
let headlinePosition = elems[index].getBoundingClientRect();
text.position.set(headlinePosition.x, headlinePosition.y);
text.alpha = elems[index].style.opacity as unknown as number;
})
}
/*----------------------------------
* Convert images to canvas
* createCanvacImgs function
----------------------------------*/
let canvasImgs: Array<PIXI.Sprite> = [];
let imgElems: Array<HTMLElement> = [];
function convertImgs(){
imgsToCanvas.forEach((element) => {
imgElems.push(element);
let canvasImg = createCanvasImg(element as HTMLImageElement, app.stage);
canvasImgs.push(canvasImg);
})
}
setTimeout(() => {
convertImgs();
convertText();
}, 100);
// convertImgs();
// convertText();
/*----------------------------------
* Function to update text on canvas
* runs in the Ticker
----------------------------------*/
function updateImgs(){
canvasImgs.forEach((image, index) => {
let imagePosition = imgElems[index].getBoundingClientRect();
image.position.set(imagePosition.x, imagePosition.y);
image.width = imagePosition.width;
image.height = imagePosition.height;
})
}
/*----------------------------------
* Mousemove events
*----------------------------------*/
let tween = {
x: 0.5,
y: is_fine ? 0.5 : 250/window.innerHeight,
};
if (is_fine) {
window.addEventListener('mousemove', (e) => {
const pointerX = e.clientX / window.innerWidth;
const pointerY = e.clientY / window.innerHeight;
const pointerXfrac = pointerX - 0.5;
const pointerYfrac = pointerY - 0.5;
// center = [(0.5 + pointerXfrac/10),(0.5 + pointerYfrac/10)];
gsap.to(tween, {
duration: .5,
ease: 'power3.out',
overwrite: true,
x: 0.5 + pointerXfrac/10,
y: 0.5 + pointerYfrac/10,
})
})
}
/*----------------------------------
* The Ticker
* ----------------------------------*/
let elapsed = 0.0;
app.ticker.add((delta) => {
elapsed += delta;
bulgefilter.center = [(tween.x + Math.sin(elapsed/200)/20 ),(tween.y + Math.cos(elapsed/200)/20 )];
updateImgs();
updateText();
})
})
/*----------------------------------
* The Ticker
* ----------------------------------*/
let elapsed = 0.0;
app.ticker.add((delta) => {
elapsed += delta;
bulgefilter.center = [(tween.x + Math.sin(elapsed/200)/20 ),(tween.y + Math.cos(elapsed/200)/20 )];
updateImgs();
updateText();
})
window.addEventListener('resize', (e) => {
tween.y = is_fine ? 0.5 : 250/window.innerHeight;
})
}) // <- end onMount
onDestroy(() => {

View file

@ -26,7 +26,6 @@
//Toggle menu
let checkbox = document.getElementById('menustate') as HTMLInputElement;
checkbox.addEventListener('change', (e)=> {
console.log(checkbox.checked);
if (checkbox.checked) {
gsap.to('.content > *', {duration: 0.75, y: -200, autoAlpha: 0.5, ease: 'power2.inOut'});
gsap.to('#nav', {duration: 0.5, autoAlpha: 1, y: 0, ease: 'power4.out', delay: 0.1});

View file

@ -0,0 +1,36 @@
<script lang='ts'>
import { onMount } from "svelte";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/dist/ScrollTrigger";
import { ScrollSmoother } from "gsap/dist/ScrollSmoother";
let smoother: ScrollSmoother;
onMount( () => {
gsap.registerPlugin(ScrollTrigger, ScrollSmoother);
ScrollTrigger.normalizeScroll(true)
setTimeout(() => {
smoother = ScrollSmoother.create({
smooth: 1.5,
effects: true,
normalizeScroll: true
});
}, 300);
return () => {
ScrollTrigger.getAll().forEach((trigger) => {
trigger.kill();
});
smoother?.kill();
};
});
</script>
<div id="smooth-wrapper">
<div id="smooth-content">
<slot />
</div>
</div>

View file

@ -19,6 +19,9 @@ let canvas: HTMLCanvasElement;
onMount(()=>{
let is_fine = window.matchMedia('(pointer:fine)').matches
let is_landscape = window.matchMedia('(orientation:landscape)').matches
gsap.registerPlugin(PixiPlugin, ScrollTrigger, SplitText);
app = new PIXI.Application({
@ -30,7 +33,6 @@ onMount(()=>{
view: canvas,
});
//for debugging but Typescript has an issue with this:
// globalThis.__PIXI_APP__ = app as any;
@ -61,8 +63,8 @@ onMount(()=>{
let center = [0.5, 0.5];
let bulgefilter = new BulgePinchFilter();
bulgefilter.radius = xFrac(0.5);
bulgefilter.strength = bulgeFactor;
bulgefilter.radius = is_landscape ? xFrac(0.5) : xFrac(0.6);
bulgefilter.strength = is_landscape ? bulgeFactor : bulgeFactor * 1.25;
bulgefilter.center = center;
bulgefilter.resolution = 2;
// app.stage.filters = [bulgefilter];
@ -99,13 +101,15 @@ onMount(()=>{
canvasTexts.forEach((text, index) => {
let headlinePosition = elems[index].getBoundingClientRect();
text.position.set(headlinePosition.x, headlinePosition.y);
text.alpha = elems[index].style.opacity as unknown as number;
// text.position.x = headlinePosition.x;
// ^ This bcs pos:fixed doesn't update fast enough when mobile browser chrome changes on scroll
text.alpha = elems[index].style.opacity as unknown as number || 0.3;
})
}
/*----------------------------------
* Convert images to canvas
* createCanvacImgs function
* createCanvasImgs function
----------------------------------*/
let canvasImgs: Array<PIXI.Sprite> = [];
let imgElems: Array<HTMLElement> = [];
@ -113,7 +117,7 @@ onMount(()=>{
function convertImgs(){
imgsToCanvas.forEach((element) => {
imgElems.push(element);
let canvasImg = createCanvasImg(element, app.stage);
let canvasImg = createCanvasImg(element as HTMLImageElement, app.stage);
// canvasImg.tint = 0xff9494;
canvasImgs.push(canvasImg);
})
@ -140,33 +144,32 @@ onMount(()=>{
convertImgs();
convertText();
}, 100);
// convertImgs();
// convertText();
/*----------------------------------
* Mousemove events
*----------------------------------*/
let tween = {
x: 0,
y: 0,
x: 0.5,
y: is_landscape ? 0.5 : 0.4,
};
window.addEventListener('mousemove', (e) => {
const pointerX = e.clientX / window.innerWidth;
const pointerY = e.clientY / window.innerHeight;
const pointerXfrac = pointerX - 0.5;
const pointerYfrac = pointerY - 0.5;
// rgbFilter.red = [pointerXfrac * 10, pointerYfrac * 10];
// rgbFilter.green = [pointerXfrac * -10, pointerYfrac * -10];
gsap.to(tween, {
duration: .5,
ease: 'power3.out',
overwrite: true,
x: pointerX,
y: pointerY,
if (is_fine){
window.addEventListener('mousemove', (e) => {
const pointerX = e.clientX / window.innerWidth;
const pointerY = e.clientY / window.innerHeight;
const pointerXfrac = pointerX - 0.5;
const pointerYfrac = pointerY - 0.5;
// rgbFilter.red = [pointerXfrac * 10, pointerYfrac * 10];
// rgbFilter.green = [pointerXfrac * -10, pointerYfrac * -10];
gsap.to(tween, {
duration: .5,
ease: 'power3.out',
overwrite: true,
x: pointerX,
y: pointerY,
})
})
})
}
/*----------------------------------
@ -179,17 +182,17 @@ onMount(()=>{
// bulgefilter.center = center;
// bulgefilter.center = [(center[0] + Math.sin(elapsed/200)/20 ),(center[1] + Math.cos(elapsed/200)/20 )];
bulgefilter.center = [tween.x, tween.y];
bulgefilter.strength = bulgeFactor;
bulgefilter.strength = is_landscape ? bulgeFactor : bulgeFactor * 1.25;
updateImgs();
updateText();
})
}) // <- end onMount
onDestroy(() => {
if (browser){
app.destroy(true, true);
}
}) // <- end onDestroy
if (browser){
app.destroy(true, true);
}
}) // <- end onDestroy
</script>

View file

@ -5,6 +5,8 @@ type Post = {
description: string
tags: string[]
header_bg_image: string
svg: string
video: string
}
default: {
render: () => string
@ -25,11 +27,17 @@ export const fetchMarkdownPosts = async () => {
const data: unknown = await resolver()
const postData = data as Post
const content = postData.default.render() as unknown as { html: string }
const srcJson = await import(/* @vite-ignore */'./assets' + postData.metadata.header_bg_image + '?w=336&format=webp')
const src = JSON.stringify(srcJson.default).replaceAll('"', '')
const srcsetJson = await import(/* @vite-ignore */'./assets' + postData.metadata.header_bg_image + '?w=1344;672;336&format=webp&as=srcset')
const srcset = JSON.stringify(srcsetJson.default).replaceAll('"', '')
return {
meta: postData.metadata,
path: postPath,
Content: content.html
Content: content.html,
src,
srcset
}
})
)

View file

@ -38,6 +38,9 @@ h1, h2, h3, h4, h5 {
font-style: italic;
letter-spacing: -0.02em;
}
h2 {
font-size: 1.5em;
}
ul, ol {
padding-left: 0;
}
@ -131,4 +134,9 @@ a {
& > :last-child {
margin-bottom: 0;
}
}
.content{
position: absolute;
top: 0;
width: 100%;
}

View file

@ -1,10 +1,10 @@
import * as PIXI from 'pixi.js';
export default function createCanvasText( element: HTMLElement, stage: PIXI.Container ){
export default function createCanvasText( element: HTMLImageElement, stage: PIXI.Container ){
const elem = element;
// console.log(elem);
const elemSrc = elem.getAttribute('src') || '';
const elemSrc = elem.currentSrc || '';
const elemPosition = elem.getBoundingClientRect();
const canvasImg = PIXI.Sprite.from(elemSrc);

View file

@ -5,13 +5,13 @@ export default function createCanvasText( element: HTMLElement, stage: PIXI.Con
const elem = element;
const elemStyles = window.getComputedStyle(elem);
const elemFontSize = elemStyles.getPropertyValue('font-size');
const elemFontWeight = elemStyles.getPropertyValue('font-weight');
const elemFontFamily = elemStyles.getPropertyValue('font-family');
const elemFontStyle = elemStyles.getPropertyValue('font-style');
const elemLetterSpacing = parseInt(elemStyles.getPropertyValue('letter-spacing'));
const elemColor = elemStyles.getPropertyValue('color');
const elemAlignment = elemStyles.getPropertyValue('text-align');
const elemFontSize = elemStyles.getPropertyValue('font-size') || '16px';
const elemFontWeight = elemStyles.getPropertyValue('font-weight') || 'normal';
const elemFontFamily = elemStyles.getPropertyValue('font-family') || 'Arial';
const elemFontStyle = elemStyles.getPropertyValue('font-style') || 'normal';
const elemLetterSpacing = parseInt(elemStyles.getPropertyValue('letter-spacing')) || 0;
const elemColor = elemStyles.getPropertyValue('color') || 'black';
const elemAlignment = elemStyles.getPropertyValue('text-align') || 'left';
const elemPosition = elem.getBoundingClientRect();
const canvasText = new Text(elem?.textContent as string, {

52
src/lib/utils/image.ts Normal file
View file

@ -0,0 +1,52 @@
import sharp from 'sharp';
export const IMAGE_DIR='/src/lib/assets/';
export async function dominantColour({ source }: { source: string }){
try {
const image = sharp(source);
const{ dominant }=await image.stats();
return dominant;
} catch (error) {
console.error('Error determining dominant colour: ', source);
}
}
export async function lowResolutionPlaceholder({ source }: { source: string }) {
try {
const image = sharp(source);
const buffer = await image
.resize(10)
.jpeg({
quality: 50,
progressive: true,
optimiseScans: true,
chromaSubsampling: '4:2:0',
trellisQuantisation: true,
quantisationTable: 2,
})
.toBuffer({ resolveWithObject: false });
return `data:image/jpeg;base64,${(await buffer).toString('base64')}`;
} catch (error) {
console.error('Error generating low resolution placeholder: ', source);
}
}
export const dominantColourPlaceholder = async ({ source }: {source: string})=>{
try{
const dominant = await dominantColour({ source }) as { r: number; g: number; b: number };
const{ r, g, b }= dominant;
const buffer = await sharp({
create:{
width:3,
height:2,
channels:3,
background:{ r, g, b },
},
})
.jpeg()
.toBuffer({resolveWithObject:false});
return`data:image/jpeg;base64,${buffer.toString('base64')}`;
}catch(error){
console.error('Error determining dominant colour: ', source);
}
};

View file

@ -1,33 +1,19 @@
<script lang='ts'>
import '$lib/styles/global.scss';
import Logo from '$lib/components/Logo.svelte';
import MainNav from '$lib/components/MainNav.svelte';
import Header from '$lib/components/Header.svelte';
import { fade } from 'svelte/transition';
export let data;
</script>
<a href='/' class="logo"><Logo /></a>
<MainNav />
<Header />
{#key data.pathname}
<div
class="content"
in:fade={{ duration: 100, delay: 0 }}
out:fade={{ duration: 100, delay: 100 }}
>
>
<slot />
</div>
{/key}
<style lang="scss">
.logo {
height: 36px;
width: auto;
position: fixed;
bottom: 0;
z-index: 4;
display: block;
margin: var(--spacing-nav);
cursor: url('/pointer.svg'), auto;
}
</style>

View file

@ -1,31 +1,34 @@
<script lang='ts'>
import HomeCanvas from '$lib/components/HomeCanvas.svelte';
import { onMount } from 'svelte';
import { gsap } from 'gsap';
import ScrollTrigger from 'gsap/dist/ScrollTrigger';
import SplitText from 'gsap/dist/SplitText';
import { onMount, onDestroy } from 'svelte';
import { disableScrollHandling } from '$app/navigation';
let canvasElems: Array<HTMLElement>;
onMount(() => {
onMount( () => {
disableScrollHandling();
gsap.registerPlugin( ScrollTrigger, SplitText );
const sections = document.querySelectorAll('section');
sections.forEach( (section) => {
if ( section.classList.contains('splash')){
let split = new SplitText(section.querySelectorAll('h1'), { type: 'lines', linesClass: 'lineChildren' });
gsap.set(split.lines, {
opacity: 1,
y: window.innerHeight,
let split = new SplitText(section.querySelectorAll('h1'), { type: 'words', wordsClass: 'lineChildren' });
gsap.set(split.words, {
opacity: 0,
y: 60,
transformOrigin: '50% 100%'
})
gsap.to(split.lines, {
duration: 1,
gsap.to(split.words, {
duration: 0.5,
opacity: 1,
y: 0,
stagger: 0.075,
ease: 'power4.out',
stagger: 0.033,
ease: 'back.out',
delay: .3
})
}
else {
@ -33,83 +36,75 @@
gsap.set(split.lines, { transformOrigin: '0% 100%' });
gsap.set(split.lines, { yPercent: 100, opacity: 0 });
gsap.to(split.lines, { duration: 1, yPercent: 0, opacity: 1, stagger: 0.1, ease: 'power4.out',
scrollTrigger: { scroller: '.scroller', trigger: split.lines, start: 'top 90%', end: 'bottom 70%', scrub: true, id: 'sth2' }
scrollTrigger: { trigger: split.lines, start: 'top 90%', end: 'bottom 70%', scrub: false }
})
if (section.querySelector('p')) {
let splitp = new SplitText(section.querySelectorAll('p'), { type: 'lines', linesClass: 'lineChildren' });
gsap.set(splitp.lines, { transformOrigin: '0% 100%' });
gsap.set(splitp.lines, { yPercent: 100, autoAlpha: 0 });
gsap.to(splitp.lines, { duration: 1, yPercent: 0, autoAlpha: 1, stagger: 0.05, ease: 'power4.out',
scrollTrigger: { scroller: '.scroller', trigger: splitp.lines, start: 'top 80%', end: 'bottom 40%', scrub: true }
gsap.set(splitp.lines, { yPercent: 100, opacity: 0 });
gsap.to(splitp.lines, { duration: 1, yPercent: 0, opacity: 1, stagger: 0.05, ease: 'power4.out',
scrollTrigger: { trigger: splitp.lines, start: 'top 80%', end: 'bottom 40%', scrub: false }
})
}
}
if (section.querySelector('.cols-2')){
gsap.set(section.querySelector('.cols-2'), { autoAlpha: 0 });
gsap.to(section.querySelector('.cols-2'), { duration: 1, autoAlpha: 1, ease: 'power4.out',
scrollTrigger: { scroller: '.scroller', trigger: section.querySelector('.cols-2'), start: 'top 80%', end: 'bottom 40%', scrub: true }
})
}
})
canvasElems = Array.from(document.querySelectorAll('.lineChildren'));
return () => {
gsap.killTweensOf(canvasElems);
ScrollTrigger.getAll().forEach( instance => instance.kill() );
}
});
</script>
<article class="scroller">
<section class="splash">
<h1>Simon Flöter creates products that stand out.</h1>
</section>
<section class="intro">
<h2>As a Creative Web Developer ...</h2>
<div class="cols-2">
<div>
<p>I specialise in delivering beautifully crafted bespoke websites.</p>
<p>Averse to blindly following the latest tech trends, I put the experience of both my client and the product's audience first.</p>
<article class="scroller">
<section class="splash">
<h1>Simon Flöter creates products that stand out.</h1>
</section>
<section class="intro">
<h2>As a Creative Web Developer ...</h2>
<div class="cols-2">
<div>
<p>I specialise in delivering beautifully crafted bespoke websites.</p>
<!-- <p>Averse to blindly following the latest tech trends, I put the experience of both my client and the product's audience first.</p>
</div>
<div>
<p>I consult on the best suited technology and approach for every project and execute it.</p>
<p>Whether it is pure HTML/CSS/Javascript, a 'monolithic' CMS like WordPress, a modern framework like React/Svelte, or a combination.</p> -->
</div>
</div>
<div>
<p>I consult on the best suited technology and approach for every project and execute it.</p>
<p>Whether it is pure HTML/CSS/Javascript, a 'monolithic' CMS like WordPress, a modern framework like React/Svelte, or a combination.</p>
<div class="cta">
<a href="/work" class="button">Learn More</a>
<a href="/work" class="button button--primary">Hire Simon</a>
</div>
</div>
<div class="cta">
<a href="/work" class="button">Learn More</a>
<a href="/work" class="button button--primary">Hire Simon</a>
</div>
</section>
<section class="more">
<h2>As a UX & Graphic Designer...</h2>
<div class="cols-2">
<div>
<p>I worked for a wide range of clients, including Booking.com and Adidas, but also with startups and independent brands.</p>
</section>
<section class="more">
<h2>As a UX & Graphic Designer...</h2>
<div class="cols-2">
<!-- <div>
<p>I worked for a wide range of clients, including Booking.com and Adidas, but also with startups and independent brands.</p>
</div> -->
<div>
<p>I have designed Websites, Housestyles, Typefaces, Advertising campaigns and Print publications for them.</p>
</div>
</div>
<div>
<p>I have designed Websites, Housestyles, Typefaces, Advertising campaigns and Print publications for them.</p>
<div class="cta">
<a href="/work" class="button">Learn More</a>
<a href="/work" class="button button--primary">Hire Simon</a>
</div>
</div>
<div class="cta">
<a href="/work" class="button">Learn More</a>
<a href="/work" class="button button--primary">Hire Simon</a>
</div>
</section>
<section class="more">
<h2>I create products that help great companies reach their audiences. Need help?</h2>
<div class="cta">
<a href="/work" class="button button--xl">Reach out!</a>
</div>
</section>
</article>
</section>
<section class="more">
<h2>I create products that help great companies reach their audiences. Need help?</h2>
<div class="cta">
<a href="/work" class="button button--xl">Reach out!</a>
</div>
</section>
</article>
<HomeCanvas textsToCanvas={canvasElems}/>
<style lang="scss">
.scroller {
font-size: clamp(32px, 4.5vw, 4.5vw);
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow-y: scroll;
}
section {
scroll-snap-align: start;
@ -140,30 +135,41 @@
font-style: normal;
opacity: 0;
margin: 0;
-webkit-touch-callout: none; /* Safari */
-webkit-user-select: none; /* Chrome */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none;
}
h1 {
letter-spacing: -0.05em;
line-height: .9;
font-size: 17vw;
margin-top: -.5em;
text-align: center;
// text-align: center;
@media screen and (min-width: 768px) {
font-size: 12vw;
}
}
h2 {
font-size: 1.25em;
margin-bottom: 1em;
font-weight: 800;
font-style: italic;
margin-bottom: .5em;
}
.cols-2 {
@media screen and (min-width: 768px) {
margin: 0;
display: grid;
grid-template-columns: 1fr 1fr;
gap: .5em;
border-top: 2px solid var(--color-text);
margin-top: 0.125em;
padding-top: 0.125em;
}
p {
font-size: 0.7em;
-webkit-touch-callout: none; /* Safari */
-webkit-user-select: none; /* Chrome */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none;
}
a {
-webkit-touch-callout: none; /* Safari */
-webkit-user-select: none; /* Chrome */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none;
}
</style>

View file

@ -0,0 +1,33 @@
import { dominantColourPlaceholder, IMAGE_DIR, lowResolutionPlaceholder } from '$lib/utils/image'
import path from 'path';
const __dirname = path.resolve();
export async function POST({request}: {request: Request}) {
try {
const { images } = await request.json();
const dominantColourPromises = images.map((element: string)=>{
const source = path.join(__dirname, IMAGE_DIR, element);
return dominantColourPlaceholder({ source });
});
const placeholderPromises = images.map((element: string) => {
const source = path.join(__dirname, IMAGE_DIR, element);
return lowResolutionPlaceholder({ source });
});
const dominantColours =await Promise.all(dominantColourPromises);
const placeholders = await Promise.all(placeholderPromises);
return {
body:JSON.stringify({ placeholders, dominantColours }),
};
} catch (err) {
console.log('Error: ', err);
return {
status: 500,
error: 'Error retrieving data',
};
}
};

View file

@ -0,0 +1,15 @@
<script lang="ts">
import myImgSrcSetWebp from '$lib/assets/work/formo/formo_hero.png?w=1344;672;336&format=webp&as=srcset'
import myImg from '$lib/assets/work/formo/formo_hero.png?w=200'
console.log(myImgSrcSetWebp)
console.log(myImg)
</script>
<h1>hakc</h1>
<img
src={myImg}
srcset={myImgSrcSetWebp}
sizes="(min-width: 768px) 10vw, 100vw"
alt="my donkey"
width="700"
/>

View file

@ -8,4 +8,4 @@ export async function load() {
return {
posts
}
}
}

View file

@ -3,6 +3,7 @@
import { onMount } from 'svelte';
import { workClickHandler, initWorkPage } from './workUtils.js';
import { workbulge } from '$lib/utils/stores.js';
import { fade } from 'svelte/transition';
export let data;
let canvasTextElems: Array<HTMLElement>;
@ -23,32 +24,50 @@
</script>
<h1 class="headline"><span>Casestudies</span></h1>
<div class="works">
{#each data.posts as work}
<a href="{work.path}" class="work" on:click={ (e) => workClickHandler(e) }>
<img class="workhero" src="{work.meta.header_bg_image}" alt="{work.meta.title}"/>
<h2>{work.meta.title}</h2>
</a>
{/each}
{#each data.posts as work}
<a href="{work.path}" class="work" on:click={ (e) => workClickHandler(e) }>
<img class="workhero" src="{work.meta.header_bg_image}" alt="{work.meta.title}"/>
<h2>{work.meta.title}</h2>
</a>
{/each}
{#each data.posts as work}
<a href="{work.path}" class="work" on:click={ (e) => workClickHandler(e) }>
<img class="workhero" src="{work.meta.header_bg_image}" alt="{work.meta.title}"/>
<h2>{work.meta.title}</h2>
</a>
{/each}
{#each data.posts as work}
<a href="{work.path}" class="work" on:click={ (e) => workClickHandler(e) }>
<img class="workhero" src="{work.meta.header_bg_image}" alt="{work.meta.title}"/>
<h2>{work.meta.title}</h2>
</a>
{/each}
</div>
<div class="works">
{#each data.posts as work}
<a href="{work.path}" class="work" on:click={ (e) => workClickHandler(e) }>
<img
class="workhero"
src={work.src}
srcset={work.srcset}
sizes="(min-width: 768px) 20vw, 100vw"
alt={work.meta.title}
width="800"
height="600"
/>
<h2>{work.meta.title}</h2>
</a>
{/each}
{#each data.posts as work}
<a href="{work.path}" class="work" on:click={ (e) => workClickHandler(e) }>
<img
class="workhero"
src={work.src}
srcset={work.srcset}
sizes="(min-width: 768px) 30vw, 100vw"
alt={work.meta.title}
width="800"
height="600"
/>
<h2>{work.meta.title}</h2>
</a>
{/each}
{#each data.posts as work}
<a href="{work.path}" class="work" on:click={ (e) => workClickHandler(e) }>
<img
class="workhero"
src={work.src}
srcset={work.srcset}
sizes="(min-width: 768px) 20vw, 100vw"
alt={work.meta.title}
width="800"
height="600"
/>
<h2>{work.meta.title}</h2>
</a>
{/each}
</div>
<WorkCanvas
textsToCanvas={canvasTextElems}
imgsToCanvas={canvasImgElems}

View file

@ -1,6 +1,10 @@
export async function load({ params }){
try {
const post = await import(`../md/${params.slug}.md`)
const srcJson = await import(/* @vite-ignore */`../../../lib/assets${post.metadata.header_bg_image}?w=336&format=webp`)
const src = JSON.stringify(srcJson.default).replaceAll('"', '')
const srcsetJson = await import(/* @vite-ignore */`../../../lib/assets${post.metadata.header_bg_image}?w=1344;672;336&format=webp&as=srcset`);
const srcSet = JSON.stringify(srcsetJson.default).replaceAll('"', '')
const { title, date, header_bg_image, svg, video } = post.metadata
const Content = post.default.render()
@ -11,6 +15,8 @@ export async function load({ params }){
svg,
video,
Content,
src,
srcSet
}
} catch (error) {
console.error(error)

View file

@ -1,27 +1,88 @@
<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import { gsap } from 'gsap';
import { fly } from 'svelte/transition';
import { ScrollTrigger } from 'gsap/dist/ScrollTrigger';
export let data;
gsap.registerPlugin(ScrollTrigger);
let visible = false;
function animForDesktop() {
ScrollTrigger.getAll().forEach(t => t.kill());
gsap.to('.hero', { duration: .6, x: "-10%", ease: "cubic.inOut" })
gsap.from('.work', {
xPercent: 100,
duration: .66,
ease: "cubic.out",
})
let heroheight = document.querySelector('.heromask')?.getBoundingClientRect().height || 100;
gsap.fromTo('.heromask', {
clipPath: "polygon(0 0, 100% 0, 100% 100%, 0% 100%)",
},{
clipPath: "polygon(0 0, 50% 0, 25% 100%, 0% 100%)",
duration: .6,
ease: "cubic.inOut"
ease: "cubic.inOut",
onComplete: () => {
gsap.fromTo('.heromask', {
clipPath: "polygon(0 0, 50% 0, 25% 100%, 0% 100%)",
},{
clipPath: "polygon(0 0, 30% 0, 25% 100%, 0% 100%)",
duration: .6,
ease: "none",
scrollTrigger: {
trigger: '.work',
start: '0px 0px',
end: `0px -${heroheight * 0.3}px`,
scrub: true,
}
})
}
})
}
function animForMobile() {
ScrollTrigger.getAll().forEach(t => t.kill());
gsap.to('.hero', { duration: .6, x: 0, ease: "cubic.inOut" })
gsap.from('.work', {
opacity: 0,
y: 100,
duration: .66,
ease: "cubic.inOut",
})
gsap.to('.heromask', {
clipPath: "polygon(0 0, 100% 0, 100% 90%, 0% 100%)",
clipPath: "polygon(0 0, 100% 0, 100% 75%, 0% 100%)",
duration: .6,
ease: "cubic.inOut"
ease: "cubic.inOut",
onComplete: () => {
gsap.to('.heromask', {
ease: "power1.out",
scrollTrigger: {
trigger: '.work',
start: '0px -10px',
end: `0px -20px`,
scrub: false,
onEnterBack: () => {
gsap.to('.heromask', {
clipPath: "polygon(0 0, 100% 0, 100% 75%, 0% 100%)",
duration: .6,
ease: "expo.out",
})
},
onEnter: () => {
gsap.to('.heromask', {
clipPath: "polygon(0 0, 100% 0, 100% 0%, 0% 0%)",
duration: .6,
ease: "expo.out",
})
}
}
})
}
})
}
function animForSize(){
@ -33,30 +94,40 @@
}
onMount(() => {
let workheros = document.querySelector('.hero');
console.log(workheros);
visible = true;
animForSize();
window.addEventListener('resize', () => {
let portrait = window.matchMedia("(orientation: portrait)");
portrait.addEventListener("change", function(e) {
animForSize();
})
document.body.classList.add('work');
})
onDestroy(() => {
document.body.classList.remove('work');
})
</script>
<div class="heromask">
<img class="hero" src="{data.header_bg_image}" alt="{data.title}" />
<!-- <video class="herovid" autoplay muted loop playsinline>
<source src="{data.video}" type="video/mp4">
</video> -->
<img
class="hero"
src={data.src}
srcset={data.srcSet}
alt="{data.title}"
loading="eager"
decoding="sync"
/>
</div>
<div class="subnav">
<a href="/work" class="subnav-item">← Back</a>
</div>
<article>
<article class="work">
{#if visible}
<div class="work-content" in:fly={{ x: '10vw', duration: 400, delay: 400, opacity:0 }}>
<h1>{@html data.svg}</h1>
<div class="work-content">
<h1><span class="svg-logo">{@html data.svg}</span><span class="name">{data.title}</span></h1>
<div class="work-content-text">
{@html data.Content.html}
</div>
@ -65,18 +136,10 @@
</article>
<style lang="scss">
article:after {
content: '';
position: fixed;
right: 0; bottom: 0; left: 0;
height: calc(36px + 2 * var(--spacing-outer));
z-index: 1;
border-top: 1px solid var(--color-text);
background: #00117f;
@media screen and (min-width: 768px) {
content: none;
}
article {
width: 100vw;
overflow: hidden;
padding-bottom: 60px;
}
.subnav {
position: fixed;
@ -108,24 +171,8 @@
position: relative;
perspective: 400px;
}
.herovid{
width: 100%;
height: 100%;
object-fit: cover;
z-index: 0;
display: block;
position: absolute;
top: -10%;
left: -10%;
perspective: 300px;
animation: fadein 2s .5s both;
}
@keyframes fadein {
from { opacity: 0; transform: rotateX(0deg); }
to { opacity: 1; transform: rotateX(45deg);}
}
.work-content {
padding: var(--spacing-outer);
padding: 0 var(--spacing-outer);
padding-top: calc(100vw / var(--aspect-ratio-heroes) + 1.5em);
position: relative;
z-index: 1;
@ -142,19 +189,38 @@
}
}
.work-content-text {
border-top: 1px solid var(--color-text);
@media screen and (min-width: 768px) {
border-top: 1px solid var(--color-text);
}
}
h1 {
position: relative;
z-index: 1;
}
h1 {
max-width: 200px;
margin: 0;
padding: 0 0 1em 0;
@media screen and (min-width: 768px) {
max-width: 400px;
padding: 0 0 1em 0;
}
& .name {
display: none;
}
& .svg-logo :global(svg) {
width: auto;
height: auto;
max-width: 250px;
max-height: 80px;
margin-bottom: 1em;
@media screen and (min-width: 768px) {
max-width: 400px;
max-height: 200px;
}
}
}
:global(.header-nav){
transition: all .3s cubic-bezier(0.075, 0.82, 0.165, 1);
}
:global(.work .header-nav){
transform: translateY(100%);
}
</style>

View file

@ -3,19 +3,13 @@ title: JustPeace Labs
header_bg_image: /work/jpl/jpl_hero.jpg
description: JustPeace Labs is a non-profit organization that works with local communities to build peace and prevent violence.
order: 11
svg: '<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="enable-background:new 0 0 1440 900" viewBox="0 0 1440 900">
<path d="M1440 900v-.5l-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.5-14.3-14.2-8.2.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.2.5-14.3-14.2-8.3.5-14.3-14.2-8.2.5-14.3-14.1-8.3.4-14.2-14.1-8.3.4-14.3-14.1-8.3.4-14.3-14.1-8.2.4-14.3-14.1-8.3.4-14.3-14.1-8.3.5-14.2-14.2-8.3.5-14.3-14.2-8.3.4-11.9H707.9l-.1.6 14.1 8.3-.4 14.3 14.1 8.2-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.2-.5 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.2-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.2-.5 14.3 14.2 8.3-.5 14.2 14.2 8.3-.5 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.2-.5 14.3 14.1 8.3-.4 14.3 14.1 8.2-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.5 14.2 14.2 8.3-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.5 14.3 14.2 8.3-.5 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.2 14.1 8.3-.4 14.3 14.1 8.3-.4 14.3 14.1 8.2V900z" style="fill:#ffb7ab"/>
</svg>'
svg: '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="Layer_1" x="0" y="0" viewBox="0 0 240 63" style="enable-background:new 0 0 240 63" xml:space="preserve"><style>.st0{fill:currentColor}.st1{fill:currentColor}</style><g id="Layer_1-2"><path class="st0" d="M82.4 23.4c.4-2.3.6-4.7.5-7.1V3.1h4.6v13.1c.1 2.5 0 5-.3 7.5-.8 4.1-4.9 6-7.4 6.1l-1.1-2.4c1.9-.6 3.3-2.1 3.7-4zM92 3.1h4.5v12.3c0 5.1 1.6 6.2 4.4 6.2s4.3-1.3 4.3-6.2V3.1h4.5v12.7c0 6.1-3 9.5-8.9 9.5-6.6 0-8.8-3.8-8.8-9.6V3.1zM114 20.3c1.7.9 3.7 1.4 5.7 1.4 2.4 0 3.2-.8 3.2-2.2s-.9-2.2-4.2-3.9c-2.6-1.3-5.4-3.2-5.4-6.8 0-4.3 3.5-5.9 7.7-5.9 2-.1 3.9.4 5.7 1.3l-.8 3.6c-1.4-.9-3.1-1.4-4.7-1.4-2.4 0-3.3.9-3.3 2.2 0 1.6 1.1 2.2 3.8 3.7 3.4 1.8 6 3.4 6 7 0 4-3.1 6.1-7.5 6.1-2.3 0-4.5-.4-6.6-1.3l.4-3.8zM135.3 6.6H129V3.1h17.2v3.5h-6.3V25h-4.6V6.6zM149.4 3.1h1.4c2.4 0 4.4-.2 6.5-.2 5 0 8 2.2 8 7.6 0 5-3.1 8-8.8 8H154V25h-4.6V3.1zm7 11.8c2.2 0 4.3-.9 4.3-4.6 0-2.8-1.5-4.3-4.4-4.2-.8 0-1.6.1-2.4.2v8.4c.8.2 1.6.2 2.5.2zM168.4 3.1h13.4v3.5H173V12h6.8v3.5H173v5.9h9.7V25h-14.3V3.1zM192.8 2.9h4.6l8.2 22.1h-5l-1.5-4.6H191l-1.5 4.6h-4.9l8.2-22.1zm5.3 14.2-2.4-7.5-.6-2.3-.6 2.3-2.4 7.5h6zM216.4 2.9c2 0 4 .3 6 .9l-.7 4c-1.5-.9-3.2-1.3-5-1.3-3.6 0-6.3 2.7-6.3 7.3s2.5 7.9 6.7 7.9c1.8 0 3.5-.5 5.1-1.4v3.8c-1.7.8-3.6 1.2-5.5 1.1-6.8 0-11-4.5-11-11.1 0-7.3 4.7-11.2 10.7-11.2zM225.7 3.1h13.4v3.5h-8.8V12h6.7v3.5h-6.7v5.9h9.7V25h-14.3V3.1z"/><path class="st1" d="M80.4 39h2.5v20H92v2H80.4V39zM98 52.1c2.1-.7 4.2-1 6.4-1v-1.9c0-2.7-1.4-3.1-3.8-3.1-1.7.1-3.4.5-4.8 1.4l-.6-1.6c1.8-1 3.9-1.6 6-1.6 3.3 0 5.6.9 5.6 5v11.9h-1c-.8 0-1.3-.1-1.3-1.2v-.6c-1.4 1.2-3.2 1.8-5.1 1.8-2.9 0-5-1.7-5-4.6 0-2.1 1.3-3.6 3.6-4.5zm2.2 7.3c1.5 0 3-.5 4.2-1.4v-5.3c-1.7 0-3.4.2-5.1.8-1.6.6-2.5 1.5-2.5 3 0 1.7 1 2.9 3.4 2.9zM112 37h2.4v6.8l-.1 2.5c1.3-1.3 3.1-2 5-2 3.6 0 6.5 2.6 6.5 7.8s-3.3 9.1-8.3 9.1c-1.9 0-3.8-.4-5.5-1.2V37zm5.8 22.4c2.9 0 5.5-2.3 5.6-7 0-4.1-1.6-6.3-4.7-6.3-1.6 0-3.1.6-4.2 1.7v10.9c.9.6 2.1.8 3.3.7zM129.4 58.2c1.5.8 3.1 1.2 4.7 1.2 2.1 0 3.6-.8 3.6-2.5s-2-2.5-3.9-3.3c-2.5-1-4.7-2.4-4.7-5.1s2.7-4.1 5.7-4.2c1.5 0 2.9.3 4.2.9l-.4 1.8c-1.1-.6-2.4-.9-3.7-.9-2.4 0-3.6.9-3.6 2.2 0 1.7 1.4 2.5 3.6 3.4s5 2.2 5 5-2.2 4.5-5.7 4.5c-1.8 0-3.6-.4-5.2-1.2l.4-1.8zM7.2 31.7c0-12.2 8.9-22.6 21-24.4L27.1 0C11.6 2.4.1 15.7 0 31.5c0 6.8 2.2 13.5 6.2 19l5.8-4.3C8.9 42 7.2 36.9 7.2 31.7zM17.1 51.4l-4.2 5.7c4.2 3.1 9.1 5.1 14.2 5.9l1-7c-4-.6-7.8-2.2-11-4.6zM36.5 0l-1.1 7.3c13.5 2 22.7 14.5 20.7 28-.6 3.9-2.1 7.7-4.5 10.9l5.7 4.2c4.1-5.5 6.3-12.1 6.2-19 .1-15.7-11.4-29-27-31.4zM35.5 56l1 7c5.2-.8 10-2.8 14.2-5.9l-4.2-5.7c-3.2 2.4-7 4-11 4.6z"/></g></svg>'
---
<div class="infobox">
<p>Client: <a href="https://www.adidas-group.com/en/">Adidas E-commerce dept</a></p>
Tasks:
<ul>
<li>Visual Design</li>
<li>Campaign asset production</li>
<li>Illustration</li>
</ul>
</div>
<div>
<p><span class="drop_cap">A</span>didas, as you might have heard, is an international sports and lifestyle clothing brand. I worked on several digital campaigns as a graphic designer and illustrator.</p>
</div>
## JPL's Mission
The startup has declared their mission "to empower local communities to be active participants in creating lasting just peace through the use of technology". I created a logo and housestyle for them that conveyes their goals and products.
## The "broken peace" logo
Since 1958, the Symbol for the British nuclear disarmament movement by Gerald Holtom is used as an international symbol for peace.
Clients of JustPeace Labs are peace builders. The logo is a 'broken' peace sign with only the frame intact. It stands for the technological and ethical frameworks that JPL aims to provide that can be used to achieve long lasting, just peace.

View file

@ -1,13 +1,14 @@
h1 {
font-size: 12vw;
font-size: 16vw;
font-style: italic;
margin: 0.5em 0 0.5em 0;
margin: 0 0 0.5em 0;
letter-spacing: -0.04em;
text-align: center;
position: fixed;
top: 0;
width: 100%;
visibility: hidden;
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
@media screen and (min-width: 768px) {
font-size: 7vw;
@ -21,9 +22,7 @@ h1 {
h2 {
line-height: 1.1;
letter-spacing: -0.025em;
// font-weight: 400;
font-size: 2.5vw;
// visibility: hidden;
opacity: 0;
position: absolute;
left: .5em;
@ -31,7 +30,6 @@ h2 {
transform: scale(0.8) translateY(100%);
margin: 0;
padding: 0.1em 0.4em 0.2em 0.4em;
// border-radius: .25em;
text-align: center;
transform-origin: center center;
width: auto;
@ -48,17 +46,19 @@ h2 {
.works {
padding: 15vw 0.5em 0.5em 0.5em;
display: flex;
gap: 0.5em;
gap: 0.25em;
flex-wrap: wrap;
@media screen and (min-width: 768px) {
gap: 0.25em;
padding: 8.5vw 0.5em 0.5em 0.5em;
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding-bottom: 20svh;
}
}
.work {
flex: 0 0 100%;
flex: 0 0 calc(50% - 0.125em );
display: block;
position: relative;
padding: 0;
@ -68,11 +68,11 @@ h2 {
@media screen and (min-width: 768px) {
flex: 0 0 calc(33% - .125em);
}
}
.workhero {
width: 100%;
height: auto;
aspect-ratio: var(--aspect-ratio-heroes);
object-fit: fill;
visibility: hidden;

View file

@ -8,6 +8,42 @@ workbulge.subscribe(value => {
bulge.factor = value;
})
export function initWorkPage( h1: HTMLElement, canvasImgElems: Array<HTMLElement>) {
workbulge.set(0.25);
gsap.registerPlugin( SplitText );
const h1Text = h1?.innerHTML || '';
h1.innerHTML = h1Text + h1Text + h1Text + h1Text || '';
h1.style.overflow = 'hidden';
h1.style.whiteSpace = 'nowrap';
const spans = Array.from(h1.querySelectorAll('span'));
spans.forEach((span) => {
gsap.set(span, { opacity: 0, y: window.innerHeight })
gsap.to(span, { opacity: 1, y: 0, duration: 1, ease: 'power3.out' })
gsap.to(span, { xPercent: -100, duration: 4, ease: 'none', repeat: -1 })
});
gsap.set(canvasImgElems, {
opacity: 0, yPercent: 100
})
gsap.to(canvasImgElems, {
duration: 1,
opacity: 1,
yPercent: 0,
stagger: 0.05,
ease: 'elastic.out(0.75, 0.5)',
delay: 0.3
})
return {
text: spans,
images: canvasImgElems
}
}
export function workClickHandler(e:Event){
e.preventDefault();
const target = e.target as HTMLElement;
@ -20,8 +56,11 @@ export function workClickHandler(e:Event){
targetImg.style.height = `${targetImgRect.height}px`;
targetImg.style.top = `${targetImgRect.top}px`;
targetImg.style.left = `${targetImgRect.left}px`;
const clone = targetImg.cloneNode(true) as HTMLElement;
targetImg.parentElement?.insertBefore(clone, targetImg);
targetImg.style.position = 'fixed';
gsap.to('.work:not(.active) .workhero', {
duration: .3,
opacity: 0,
@ -48,59 +87,14 @@ export function workClickHandler(e:Event){
workbulge.set(bulge.factor);
}
})
gsap.to('h1', {
gsap.to('h1 span', {
duration: .3,
yPercent: -200,
yPercent: -100,
opacity: 0,
ease: 'circ.inOut',
})
setTimeout(() => {
goto(originalLink);
}, 600);
}
export function initWorkPage( h1: HTMLElement, canvasImgElems: Array<HTMLElement>) {
workbulge.set(0.25);
gsap.registerPlugin( SplitText );
console.log('initWorkPage:', h1);
const h1Text = h1?.innerHTML || '';
h1.innerHTML = h1Text + h1Text + h1Text + h1Text || '';
h1.style.overflow = 'hidden';
h1.style.whiteSpace = 'nowrap';
h1.querySelectorAll('span').forEach((span) => {
gsap.to(span, {xPercent: -100, duration: 4, ease: 'none', repeat: -1 })
});
const split = new SplitText(h1, { type: 'words', wordsClass: 'words' });
gsap.set(split.words, {
opacity: 0, yPercent: -10
})
gsap.to(split.words, {
duration: 1,
opacity: 1,
yPercent: 0,
stagger: 0.1,
ease: 'power4.out',
})
gsap.set(canvasImgElems, {
opacity: 1, yPercent: 100
})
gsap.to(canvasImgElems, {
duration: 1,
opacity: 1,
yPercent: 0,
stagger: 0.05,
ease: 'power4.out',
})
return {
text: Array.from(split.words),
images: canvasImgElems
}
}

View file

@ -1,7 +1,8 @@
import { sveltekit } from '@sveltejs/kit/vite';
import{ imagetools }from'vite-imagetools';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()]
plugins: [imagetools(),sveltekit()]
});