diff --git a/globals.d.ts b/globals.d.ts new file mode 100644 index 0000000..90ee200 --- /dev/null +++ b/globals.d.ts @@ -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; +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 81ec6f8..f128cb7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 5766cf0..13fde94 100644 --- a/package.json +++ b/package.json @@ -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" } } diff --git a/src/ambient.d.ts b/src/ambient.d.ts new file mode 100644 index 0000000..7c4d21c --- /dev/null +++ b/src/ambient.d.ts @@ -0,0 +1,5 @@ +// Squelch warnings of image imports from your assets dir +declare module '$lib/assets/*' { + const meta + export default meta +} \ No newline at end of file diff --git a/src/bg.svg b/src/bg.svg deleted file mode 100644 index 318a13a..0000000 --- a/src/bg.svg +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/lib/assets/work/adidas/adidas_hero.jpg b/src/lib/assets/work/adidas/adidas_hero.jpg new file mode 100644 index 0000000..5d0e9ae Binary files /dev/null and b/src/lib/assets/work/adidas/adidas_hero.jpg differ diff --git a/src/lib/assets/work/formo/formo-rec.mp4 b/src/lib/assets/work/formo/formo-rec.mp4 new file mode 100644 index 0000000..d779f44 Binary files /dev/null and b/src/lib/assets/work/formo/formo-rec.mp4 differ diff --git a/src/lib/assets/work/formo/formo-rec.webm b/src/lib/assets/work/formo/formo-rec.webm new file mode 100644 index 0000000..9765a14 Binary files /dev/null and b/src/lib/assets/work/formo/formo-rec.webm differ diff --git a/src/lib/assets/work/formo/formo_hero.png b/src/lib/assets/work/formo/formo_hero.png new file mode 100644 index 0000000..679e5ff Binary files /dev/null and b/src/lib/assets/work/formo/formo_hero.png differ diff --git a/src/lib/assets/work/jpl/jpl_hero.jpg b/src/lib/assets/work/jpl/jpl_hero.jpg new file mode 100644 index 0000000..7912ec0 Binary files /dev/null and b/src/lib/assets/work/jpl/jpl_hero.jpg differ diff --git a/src/lib/components/Header.svelte b/src/lib/components/Header.svelte new file mode 100644 index 0000000..31a05fe --- /dev/null +++ b/src/lib/components/Header.svelte @@ -0,0 +1,36 @@ + + +
+ + +
+ + \ No newline at end of file diff --git a/src/lib/components/HomeCanvas.svelte b/src/lib/components/HomeCanvas.svelte index ce6a074..ca2df3a 100644 --- a/src/lib/components/HomeCanvas.svelte +++ b/src/lib/components/HomeCanvas.svelte @@ -16,179 +16,195 @@ export let imgsToCanvas: Array = []; 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 = []; - let elems: Array = []; - - 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 = []; - let imgElems: Array = []; - - 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 = []; + let elems: Array = []; + + 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 = []; + let imgElems: Array = []; + + 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(() => { diff --git a/src/lib/components/MainNav.svelte b/src/lib/components/MainNav.svelte index 13168b5..2cf7e30 100644 --- a/src/lib/components/MainNav.svelte +++ b/src/lib/components/MainNav.svelte @@ -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}); diff --git a/src/lib/components/SmoothScroll.svelte b/src/lib/components/SmoothScroll.svelte new file mode 100644 index 0000000..6053897 --- /dev/null +++ b/src/lib/components/SmoothScroll.svelte @@ -0,0 +1,36 @@ + + +
+
+ +
+
\ No newline at end of file diff --git a/src/lib/components/WorkCanvas.svelte b/src/lib/components/WorkCanvas.svelte index 441af5a..330255b 100644 --- a/src/lib/components/WorkCanvas.svelte +++ b/src/lib/components/WorkCanvas.svelte @@ -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 = []; let imgElems: Array = []; @@ -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 diff --git a/src/lib/importMarkdown.ts b/src/lib/importMarkdown.ts index 94b1e8e..f2cbe0c 100644 --- a/src/lib/importMarkdown.ts +++ b/src/lib/importMarkdown.ts @@ -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 } }) ) diff --git a/src/lib/styles/global.scss b/src/lib/styles/global.scss index 0aa939f..51ef663 100644 --- a/src/lib/styles/global.scss +++ b/src/lib/styles/global.scss @@ -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%; } \ No newline at end of file diff --git a/src/lib/utils/createCanvasImg.ts b/src/lib/utils/createCanvasImg.ts index ca96156..ea2bd6d 100644 --- a/src/lib/utils/createCanvasImg.ts +++ b/src/lib/utils/createCanvasImg.ts @@ -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); diff --git a/src/lib/utils/createCanvasText.ts b/src/lib/utils/createCanvasText.ts index 4af9cdd..a1e3c41 100644 --- a/src/lib/utils/createCanvasText.ts +++ b/src/lib/utils/createCanvasText.ts @@ -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, { diff --git a/src/lib/utils/image.ts b/src/lib/utils/image.ts new file mode 100644 index 0000000..f171453 --- /dev/null +++ b/src/lib/utils/image.ts @@ -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); + } + }; \ No newline at end of file diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 3533e8d..bd1f054 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,33 +1,19 @@ - - +
{#key data.pathname} +
+ + >
+ {/key} - - \ No newline at end of file diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 6bf4146..00e2da3 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,31 +1,34 @@ - -
-
-

Simon Flöter creates products that stand out.

-
-
-

As a Creative Web Developer ...

-
-
-

I specialise in delivering beautifully crafted bespoke websites.

-

Averse to blindly following the latest tech trends, I put the experience of both my client and the product's audience first.

+
+
+

Simon Flöter creates products that stand out.

+
+
+

As a Creative Web Developer ...

+
+
+

I specialise in delivering beautifully crafted bespoke websites.

+ +
-
-

I consult on the best suited technology and approach for every project and execute it.

-

Whether it is pure HTML/CSS/Javascript, a 'monolithic' CMS like WordPress, a modern framework like React/Svelte, or a combination.

+ -
- -
-
-

As a UX & Graphic Designer...

-
-
-

I worked for a wide range of clients, including Booking.com and Adidas, but also with startups and independent brands.

+
+
+

As a UX & Graphic Designer...

+
+ +
+

I have designed Websites, Housestyles, Typefaces, Advertising campaigns and Print publications for them.

+
-
-

I have designed Websites, Housestyles, Typefaces, Advertising campaigns and Print publications for them.

+ -
- -
-
-

I create products that help great companies reach their audiences. Need help?

- -
-
+
+
+

I create products that help great companies reach their audiences. Need help?

+ +
+
\ No newline at end of file diff --git a/src/routes/api/image-placeholders.ts b/src/routes/api/image-placeholders.ts new file mode 100644 index 0000000..ffbd439 --- /dev/null +++ b/src/routes/api/image-placeholders.ts @@ -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', + }; + } +}; \ No newline at end of file diff --git a/src/routes/test/+page.svelte b/src/routes/test/+page.svelte new file mode 100644 index 0000000..f6ffdb5 --- /dev/null +++ b/src/routes/test/+page.svelte @@ -0,0 +1,15 @@ + +

hakc

+ my donkey diff --git a/src/routes/work/+page.server.ts b/src/routes/work/+page.server.ts index 96b92e4..66e0484 100644 --- a/src/routes/work/+page.server.ts +++ b/src/routes/work/+page.server.ts @@ -8,4 +8,4 @@ export async function load() { return { posts } -} \ No newline at end of file +} diff --git a/src/routes/work/+page.svelte b/src/routes/work/+page.svelte index 0c82f75..0279c88 100644 --- a/src/routes/work/+page.svelte +++ b/src/routes/work/+page.svelte @@ -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; @@ -23,32 +24,50 @@

Casestudies

-
- {#each data.posts as work} - workClickHandler(e) }> - {work.meta.title} -

{work.meta.title}

-
- {/each} - {#each data.posts as work} - workClickHandler(e) }> - {work.meta.title} -

{work.meta.title}

-
- {/each} - {#each data.posts as work} - workClickHandler(e) }> - {work.meta.title} -

{work.meta.title}

-
- {/each} - {#each data.posts as work} - workClickHandler(e) }> - {work.meta.title} -

{work.meta.title}

-
- {/each} -
+
+ {#each data.posts as work} + workClickHandler(e) }> + {work.meta.title} +

{work.meta.title}

+
+ {/each} + {#each data.posts as work} + workClickHandler(e) }> + {work.meta.title} +

{work.meta.title}

+
+ {/each} + {#each data.posts as work} + workClickHandler(e) }> + {work.meta.title} +

{work.meta.title}

+
+ {/each} +
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'); })
- {data.title} - + {data.title}
-
+
{#if visible} -
-

{@html data.svg}

+
+

{data.title}

{@html data.Content.html}
@@ -65,18 +136,10 @@
\ No newline at end of file diff --git a/src/routes/work/md/jpl.md b/src/routes/work/md/jpl.md index b035936..1bc50e3 100644 --- a/src/routes/work/md/jpl.md +++ b/src/routes/work/md/jpl.md @@ -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: '' --- -
-

Client: Adidas E-commerce dept

- Tasks: -
    -
  • Visual Design
  • -
  • Campaign asset production
  • -
  • Illustration
  • -
-
-
-

Adidas, 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.

-
+ +## 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. \ No newline at end of file diff --git a/src/routes/work/work.scss b/src/routes/work/work.scss index f0fb534..bfa581b 100644 --- a/src/routes/work/work.scss +++ b/src/routes/work/work.scss @@ -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; diff --git a/src/routes/work/workUtils.ts b/src/routes/work/workUtils.ts index 9b33f9b..9727db3 100644 --- a/src/routes/work/workUtils.ts +++ b/src/routes/work/workUtils.ts @@ -8,6 +8,42 @@ workbulge.subscribe(value => { bulge.factor = value; }) +export function initWorkPage( h1: HTMLElement, canvasImgElems: Array) { + + 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) { - - 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 - } } \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index c126657..89989a4 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -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()] });